handlersocket 20140218

Post on 27-May-2015

3.358 Views

Category:

Documents

3 Downloads

Preview:

Click to see full reader

TRANSCRIPT

HandlerSocket 2.0

2014/02/18 @  渋谷ヒカリエ DeNA セミナールーム

株式会社ディー・エヌ・エー樋口 証

3 行でまとめると

• HandlerSocket は、 MariaDB ・ MySQL の「非 SQL 」フロントエンド

• 性能向上、通信量削減、メモリ使用量削減等の効果がある

• version 2 でクエリ解釈ロジックを外部モジュールで定義できるようになり、従来よりも複雑なクエリをサポート

0

200000

400000

600000

800000

1000000

1200000

1 2 4 8 16 32 64 128

256

512

1024

2048

4096

8192

1638

4

3276

8

# of concurrent connections

quer

ies

per

seco

nd

SELECT querySELECT query (thread pool)HandlerSocket

HandlerSocket 開発のねらい

• DB キャッシュ用サーバを置くことによるシステムの複雑化や不整合問題を回避すること

• 予測可能で安定した性能を出すことで、性能問題起因のシステム障害を起こさないようにすること

• 同時接続数や通信量などのネックを回避し、システム全体のスケーラビリティを確保すること

基本的な情報

HandlerSocket を使うには

• MariaDB 5.3 以降に含まれている– MariaDB のサイトにドキュメントもある

https://mariadb.com/kb/en/handlersocket/

• インストール手順概略 :– my.cnf にいくつか設定を書く– 以下のクエリを実行し plugin をロード

install plugin handlersocket soname ‘handlersocket.so’

– telnet でポート 9998 に繋ぎ、改行を打つと反応が返ってくれば ok

構成

Handler Interface

Innodb MyISAM Other storage engines …

SQL Layer HandlerSocket Plugin

Listener for libmysqlclient

libmysqlclient libhsclient

Applications

mysqld

client app

port 3306port 9998, 9999

HandlerSocket クライアント

• 各言語のクライアントライブラリがあるhttps://github.com/DeNA/HandlerSocket-Plugin-for-MySQL

• プロトコルが単純なので、クライアントライブラリを使わずに実装することも可能

実行例

• create table db1.table1 (k int key, v char(20))• insert into db1.table1 values (234, 'foo'), (678, ‘bar’)

$ telnet localhost 9998Trying 127.0.0.1...Connected to localhost.Escape character is '^]'.P 0 db1 table1 PRIMARY k,v0 10 = 1 2340 2 234 foo0 = 1 6780 2 678 bar

db1.table1 の PK を開く

k = 234 を検索

k = 678 を検索

HandlerSocket の機能

HandlerSocket の主な機能 ( 参照系 )

• Primary Key や Unique Key を使った行取得

• 範囲取得– 比較条件に使える演算子は =, >=, >, <=, <

HandlerSocket の主な機能 ( 更新系 )

• 参照クエリで得た行の UPDATE と DELETE• 行の INSERT• Atomic な Increment/Decrement

• 更新系クエリは row-based の形式でバイナリログに記録される– MySQL のレプリケーション機能を使える

• ACID特性は MySQL と同じ– 書き込みは同期的、 ( 設定によるが )durable

MySQL と HandlerSocket の通信プロトコル比較

MySQL で通信内容が冗長になるケース

write(3, "L\0\0\0\3select column0,column1,column2,column3,column4 from db_1.table_1 where k=15", 80) = 80

read(3, "\1\0\0\1\0056\0\0\2\3def\4db_1\7table_1\7table_1\7column0\7column0\f\r\0<\0\0\0\375\200\0\0\0\0006\0\0\3\3def\4db_1\7table_1\7table_1\7column1\7column1\f\r\0<\0\0\0\375\200\0\0\0\0006\0\0\4\3def\4db_1\7table_1\7table_1\7column2\7column2\f\r\0<\0\0\0\375\200\0\0\0\0006\0\0\5\3def\4db_1\7table_1\7table_1\7column3\7column3\f\r\0<\0\0\0\375\200\0\0\0\0006\0\0\6\3def\4db_1\7table_1\7table_1\7column4\7column4\f\r\0<\0\0\0\375\200\0\0\0\0\5\0\0\7\376\0\0\"\0\n\0\0\10\0010\0011\0012\0013\0014\5\0\0\t\376\0\0\"\0", 16384) = 327

libmysqlclient/mysqld でこのクエリを実行すると…

SELECT column0, column1, column2, column3, column4 FROM db_1.table_1 where k = 15

MySQL で通信内容が冗長になるケース

write(3, "1\t=\t1\t15\n", 9) = 9read(3, "0\t5\t0\t1\t2\t3\t4\n", 8192) = 14

HandlerSocket で同等のクエリを実行すると…

libmysqlclient HandlerSocket

request 80 bytes 9 bytes

response 327 bytes 14 bytes

MySQL で通信内容が冗長になるケース

• 結果セットメタデータが大きい– 各列について、 DB名、テーブル名、テーブル別名、列名、列の別名がメタデータに含まれる

http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol#Field_Packet

– mysql 4.0 までのプロトコルではメタデータが少し小さい。 4.1以降で大きくなった。

• 列が多く行が少ないとき相対的に大きい– メタデータは結果セットに一つだけ付くから

• HANDLER クエリや SSPS を使っても減らすことができない

MySQL の性能を引き出すためのその他の機能

MariaDB の thread pool について

• MariaDB には thread pool の実装がある (既定では off)thread-handling=pool-of-threads

• 有効にすると SQL クエリについても同時接続数を増やしたときの性能劣化が小さくなる– HandlerSocket を使った場合と似た特性になる

• 但し HandlerSocket を使うときは thread pool無効にしておいたほうがよいかもしれない– sleep しうる処理は one-thread-per-connection のほ

うが向いている

0

20000

40000

60000

80000

100000

120000

140000

160000

180000

200000

1 2 4 8 16 32 64 128

256

512

1024

2048

4096

8192

1638

4

3276

8

# of concurrent connections

quer

ies

per

seco

nd

SELECT query

SELECT query (thread pool)

HANDLER クエリ

• 索引に対する低レベルアクセスを行うクエリ

• 参照クエリのみサポート• SELECT クエリよりも速いことが多い• ただし取得する列を指定することができ

ず、常に全フィールド取得になってしまう

Server-Side Prepared Statement

• 少しだけ性能が上がることがある

HandlerSocket リクエストの pipelining

• HandlerSocket プロトコルは pipeline 化可能– HandlerSocket の実装は pipeline 化されたリ

クエストに対して最適化されている• プロトコルは単純な行ベースなので、接

続を集約して pipeline 化するプロキシを簡単に作れる

0

500000

1000000

1500000

2000000

2500000

1 2 4 8 16 32 64 128

256

512

1024

2048

4096

8192

1638

4

3276

8

# of concurrent connections

quer

ies

per

seco

nd

SELECT querySELECT query (thread pool)HandlerSocketHandlerSocket (pipelining x5)HANDLER query (thread pool)HANDLER query SSPS (thread pool)

ベンチマークについて• Xeon E5-2670 2.6GHz, 16core 32論理 CPU の半分を mysqld, 半分をクライアントに割り当て

• internet domain socket で通信• innodb テーブル• innodb_adaptive_hash_index = 1• handlersocket_threads = 16

HandlerSocket 2.0 について

version 2.0 の変更点

• クエリ解釈ロジックを外部モジュールで定義できるようになる– 従来サポートしていなかった種類のクエリを

外部モジュールで実装可能• 外部モジュールは、サービスを停止せず

に更新可能–古いバージョンの外部モジュールは参照が無

くなった時点でアンロードされる

ねらい• Stored procedure のように手軽に HandlerSock

etへ機能追加できるようにしたい• SQL に代わるクエリ言語を外部モジュールとし

て実装する– 従来の HandlerSocket クエリは拡張性に乏しいので抜本的に直したい

• 将来的には SQL も HandlerSocket 上に実装するかもしれない– SQL であっても現在の HandlerSocket と同等の性能

を出すことは可能

構成

Handler Interface

Storage engines

Transaction management etc.hs module

HandlerSocket Listener

API for hs modules

clients

prepare, execute response

find, update, etc. result

port 9998, 9999

hs module

hsmod_module

hsmod_worker

hsmod_conn

hsmod_stmt

モジュールがロードされたときに 1 つだけ作成される

ワーカースレッドにつき 1 つ作成される

クライアント接続につき 1 つ作成される

ステートメントが prepare されるごとに作成されるクエリが実行されると execute メソッドが呼ばれる

prepare

create

create

API for hs modules

関数 コンテキスト 動作

hs_open_index prepare テーブルと索引を開く

hs_get_field_num prepare, execute 指定された名前のフィールドを捜し、その番号を返す

hs_find_first

hs_find_next

hs_find_finish

execute 索引から条件にマッチするレコードを探す

hs_field_get execute 現在選択されている行の指定された列の値を取得

hs_update_row execute 現在選択されている行を指定された値で更新

hs_delete_row execute 現在選択されている行を削除

hs_insert_row execute 行を作成

hs_push_response prepare, execute クライアントへレスポンスを返す

hsmod_pxc

• HS2.0 クエリ (仮 ) を実行する hs module 実装

• コンパイルに pxc が必要https://github.com/ahiguti/pxc

HS2.0 クエリ (仮 ) – 単純なクエリ

(do (open hstestdb hstesttbl PRIMARY idx0) (foreach idx0 = (?0) 1 (response (idx0.v))))

テーブル hstestdb.hstesttbl の PK を開き、 idx0 という名前をつける。 idx0 のキーが実行時引数の 0番に一致する行に対し、その行のフィールド v の値を返す。

これは以下の SQL クエリと同等の結果を返す

SELECT v from hstestdb.hstesttbl where k = ?

HS2.0 クエリ (仮 ) – inner join

(do (open hstestdb hstesttbl PRIMARY idx0)

(open hstestdb hst2 PRIMARY idx1)

(foreach idx0 = (?0) 1

(foreach idx1 = (idx0.v) 1

(response (idx0.k idx0.v idx1.k idx1.v)))))

これは以下の SQL クエリと同等の結果を返す

SELECT t0.k, t0.v, t1.k, t1.v

FROM hstestdb.hstesttbl t0

INNER JOIN hstestdb.hst2 t1

ON t0.v = t1.k

WHERE t0.k = ?

0

200000

400000

600000

800000

1000000

1200000

1 2 4 8 16 32 64 128

256

512

1024

2048

4096

8192

1638

4

# of concurrent connections

quer

ies

per

seco

nd

HS2.0, simple queryHS2.0, inner join

version 2.0 でもできないこと

• 自動コミットを抑制はできない– HandlerSocket ではレスポンスが返った時点

で必ずコミット済み– lock を保持したまま sleep することが無いよ

うにしている• rollback はできない

– 複数リクエストを一つのトランザクションの中で実行しているから

SQL をサポート?

• SQL をパースし、実行戦略を決めて HS2.0 クエリ (仮 ) を組み立てればよい

• 変換は prepare段階で行えるので、 execute の性能には影響しない– したがって SQL であっても現在の HandlerS

ocket と同等の性能を出すことができる• 実装するかどうか未定

• 以下のブランチで開発中https://code.launchpad.net/~maria-captains/maria/10.0-hs-devel

• 移動するかも。その場合は以下のアドレスから辿れるようにする。https://launchpad.net/~ahiguti100

top related