SlideShare a Scribd company logo

1

handlersocket plugin for mysql 2010/06/29  Tech セミナー @ 代々木 株式会社 DeNA  システム統括本部  IT 基盤部 樋口 証  <higuchi dot akira at dena dot jp>

2

Who am I? DeNA IT 基盤部 システムのパフォーマンス最適化 障害の分析 ミドルウェア開発 IPA  未踏 スーパークリエータ  (2005 年 ) 1993 年ころから GNU/Linux 利用 Fedora:  yum install KoboDeluxe Debian:  apt-get install kobodeluxe サーバソフトウェアを多数開発

3

handlersocket plugin について

4

handlersocket plugin とは MySQL の非 SQL なインタフェース

5

ねらい 単純な CRUD 処理を高速に実行したい。 SQL 処理を省略 単純な処理に適用可能な最適化 しかも同じデータを MySQL でも処理できるようにしたい。 単純かつ速度が必要な部分だけを非 SQL に置き換えたい SQL から少しずつ移行したい

6

handlersocket plugin  の概要 InnoDB 等のストレージエンジンへの非 SQL インタフェースを提供 TCP/IP でリクエストを受け、ストレージエンジンを直接叩く 独自プロトコルを喋る C++ と Perl のクライアントライブラリを用意 Linux 専用 配布場所は DeNA 技術ブログで案内します http://engineer.dena.jp/

7

構成 mysqld client app Handler Interface Innodb MyISAM Other storage engines … SQL Layer Handlersocket Plugin Listener for libmysql libmysql libhsclient Applications

8

参考 :  非 SQL for MySQL mycached http://developer.cybozu.co.jp/kazuho/2009/08/mycached-memcac.html handlersocket と同様に handler インタフェースを叩く memcached プロトコルを喋る NDB API http://dev.mysql.com/doc/ndbapi/en/index.html ndbcluster 専用 handlersocket より下の層 ( ストレージエンジン内部 ) を叩く

9

性能

10

性能比較 ( 参照クエリ ) 単純な参照クエリで数倍~ 10 倍程度 取得する列数が多い場合に特に有効

11

handlersocket の機能 ( 参照系 ) 擬似 SQL で書くと… SELECT f1,..,fn FROM db.table WHERE k1,…,km = v1,…,vm ORDER BY index_i LIMIT offset, limit (k1,…,km) は index_i のキー列 ( 又はその prefix) WHERE 句で索引に入っていない列についての条件でフィルタすることはできない いずれサポートしたい 比較条件に使える演算子は =, >=, >, <=, < 索引を使った検索のみサポートする MySQL の HANDLER クエリに近い

12

handlersocket の機能 ( 更新系 ) 参照クエリで得た行の UPDATE と DELETE 行の INSERT トランザクションはサポートしない 更新系クエリは row-based の形式でバイナリログに記録される 書き込みは durable

13

実行例 create table db1.table1 (k int key, v char(20)) insert into db1.table1 values (234, 'foo'), (678, ‘bar’) $ telnet localhost 9998 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. P  0  db1  table1  PRIMARY k,v 0  1 0  =  1  234 0  2  234  foo 0  =  1  678 0  2  678  bar db1.table1 の PK を開く k = 234  を検索 k = 678  を検索

14

何故速くなるのか SQL パース処理をしていない ->  CPU 消費が少ない リクエストを集約実行している ->  CPU 消費やディスク IO が少ない 独自プロトコルで通信する ->  ネットワーク消費が少ない

15

CPU 消費の削減

16

oprofile – libmysql/mysqld SELECT v from table where k = ?  を大量に実行し、 oprofile で CPU 消費量をしらべる samples|  %| ------------------ 9669940 53.1574 mysqld 4438098 24.3970 vmlinux 1835976 10.0927 libpthread-2.5.so 1680656  9.2389 libc-2.5.so 397970  2.1877 e1000e 89136  0.4900 oprofiled 42881  0.2357 oprofile

17

oprofile – libmysql/mysqld mysqld 内の CPU 消費 samples  %  symbol name 748022  7.7355  MYSQLparse(void*) 219702  2.2720  my_pthread_fastmutex_lock 205606  2.1262  make_join_statistics(JOIN*, TABLE_LIST*, 198234  2.0500  btr_search_guess_on_hash 180731  1.8690  JOIN::optimize() 177120  1.8317  row_search_for_mysql 171185  1.7703  lex_one_token(void*, void*) 162683  1.6824  alloc_root 131823  1.3632  read_view_open_now 122795  1.2699  mysql_select(THD*, Item***, TABLE_LIST*, 100276  1.0370  open_table(THD*, TABLE_LIST*, st_mem_root*, 99575  1.0297  mem_pool_fill_free_list 96434  0.9973  build_template(row_prebuilt_struct*, THD*, 86349  0.8930  get_hash_symbol(char const*, unsigned int,

18

oprofile – libmysql/mysqld カーネル内の CPU 消費 samples  %  symbol name 204393  4.6054  schedule 118648  2.6734  tcp_sendmsg 115832  2.6099  tcp_recvmsg 106537  2.4005  tcp_v4_rcv 103915  2.3414  tcp_ack 103534  2.3328  system_call 93864  2.1150  dev_queue_xmit 86831  1.9565  __mod_timer 85891  1.9353  tcp_rcv_established 84083  1.8946  .text.task_rq_lock

19

oprofile – libmysql/mysqld libmysql/mysqld 使用時の CPU 消費 : mysqld 内で多くの CPU 時間を使用 特に SQL パース処理周辺が CPU 使用 カーネル内ではタスク切り替えに CPU 使用

20

oprofile – handlersocket 先の SQL クエリと同等の処理を handlersocket で実行し、 oprofile で CPU 消費量をしらべる samples|  %| ------------------ 1919039 51.0453 vmlinux 811998 21.5987 mysqld 421215 11.2041 libpthread-2.5.so 207166  5.5105 e1000e 191566  5.0955 handlersocket.so 188618  5.0171 libc-2.5.so 13622  0.3623 oprofiled 5707  0.1518 oprofile

21

oprofile – handlersocket mysqld 内の CPU 消費 samples  %  symbol name 119684  14.7394  btr_search_guess_on_hash 58202  7.1678  row_search_for_mysql 46946  5.7815  mutex_delay 38617  4.7558  my_pthread_fastmutex_lock 37707  4.6437  buf_page_get_known_nowait 36528  4.4985  rec_get_offsets_func 34625  4.2642  build_template(row_prebuilt_struct*, THD*, TABLE*,  20024  2.4660  row_sel_store_mysql_rec 19347  2.3826  btr_cur_search_to_nth_level 16701  2.0568  row_sel_convert_mysql_key_to_innobase 13343  1.6432  cmp_dtuple_rec_with_match 11381  1.4016  ha_innobase::index_read(unsigned char*,  11176  1.3764  dict_index_copy_types 10762  1.3254  mtr_memo_slot_release 10734  1.3219  ha_innobase::init_table_handle_for_HANDLER()

22

oprofile – handlersocket カーネル内の CPU 消費 samples  %  symbol name 129038  6.7241  tcp_sendmsg 80080  4.1729  tcp_v4_rcv 69658  3.6298  dev_queue_xmit 66171  3.4481  .text.skb_release_data 63316  3.2994  __qdisc_run 60279  3.1411  tcp_recvmsg 59703  3.1111  ip_output 58462  3.0464  .text.skb_release_head_state 48876  2.5469  tcp_ack 48733  2.5394  __alloc_skb 45660  2.3793  ip_queue_xmit 44671  2.3278  tcp_transmit_skb

23

oprofile – handlersocket handlersocket 使用時の CPU 消費 : カーネルが最も多く CPU を使用 カーネル内では network 周りで CPU 使用 mysqld 内では innodb の中が使用量多い 特に adaptive hash index 検索処理

24

並列処理の最適化

25

並列処理モデル比較 mysqld の並列処理モデル : MySQL 5 では接続あたり 1 スレッド MySQL 6 でスレッドプールもサポート SQL 実行を少数スレッドで実行 メモリ消費の上限が抑えられる

26

並列処理モデル比較 handlersocket の並列処理モデル : 少数のスレッド 各スレッドは複数の接続を処理 既定では epoll 使用 同時接続数は事実上無制限 メモリ消費が少ない

27

handlersocket スレッドの動作 各接続からリクエストを読む DB ロック、 readview 取得 各接続からのリクエストを実行 DB ロック解除 各接続へ結果を返す ここの処理が (1/ 接続数 )  回 程度で済む handlersocket の参照系ワーカースレッド の動作

28

handlersocket スレッドの動作 各接続からリクエストを読む DB ロック、トランザクション開始 各接続からのリクエストを実行 コミット、 DB ロック解除 各接続へ結果を返す handlersocket の更新系ワーカースレッド の動作 複数のリクエストを一つの トランザクション内で実行

29

更新処理の性能について 前提 : 同期書き込み (durable) sync_binlog = 1 innodb_flush_log_at_trx_commit  = 1 innodb_support_xa = 1 バッテリ付き write-back cache  又は SSD 性能 : mysql:  ~ 1000 qps innodb plugin  で  sync_binlog = 0  だと group commit が効いてさらに速くなるが、スレーブが追いつかない handlersocket:  ~ 30000 qps 書き込みはシリアライズされるので、常にスレーブが追いつく

30

handlersocket の排他制御 MyISAM ならテーブルロックがかかる shared-exclusive lock InnoDB ならテーブルロックはかからない。ただし更新系トランザクションは一度に一つだけ実行されるよう排他制御される。 そうしないとレコードロックを持ち合ってデッドロックするから 更新系スレッドは参照系スレッドをブロックしない handlersocket のリクエスト自体はデッドロックフリー そもそも単純なリクエストしかサポートしていないので。

31

通信の最適化

32

C/S プロトコル比較 write(3, &quot;Lselect column0,column1,column2,column3,column4 from db_1.table_1 where k=15&quot;, 80) = 80 read(3, &quot;056def db_1  table_1  table_1  column0  column0 <7500006def db_1  table_1  table_1  column1  column1 <7500006def db_1  table_1  table_1  column2  column2 <7500006def db_1  table_1  table_1  column3  column3 <7500006def db_1  table_1  table_1  column4  column4 <750076amp;quot;001 0 01 1 01 2 01 3 01 4 76amp;quot;&quot;, 16384) = 327 libmysql/mysqld でこのクエリを実行すると… SELECT column0, column1, column2, column3, column4 FROM db_1.table_1 where k = 15

33

C/S プロトコル比較 write(3, &quot;1=115&quot;, 9)  = 9 read(3, &quot;0501234&quot;, 8192)  = 14 handlersocket で同等のクエリを実行すると… 14 bytes 327 bytes response 9 bytes 80 bytes request handlersocket libmysql

34

mysqld/libmysql のプロトコル 結果セットのメタデータが大きい 各列について、 DB 名 、 テーブル名 、 テーブル別名 、 列名 、 列の別名 がメタデータに含まれる http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol#Field_Packet mysql 4.0 までのプロトコルではメタデータが少し小さい。 4.1 以降で大きくなった。 列が多く行が少ないとき相対的に大きい メタデータは結果セットに一つだけ付くから HANDLER クエリでも同様にメタデータが付く server-side prepared statement を使っても同様 プロトコル圧縮を使うと 1/3 程度になる。ただし CPU を喰う。

35

クライアントライブラリ

36

libhsclient handlersocket 用クライアントライブラリ C++ 低水準インタフェース

37

DB::HandlerSocket Perl 用クライアントライブラリ xs 経由で libhsclient を呼んでいる my $cli = new DB::HandlerSocket( {host => ‘localhost’, port => 9999}); $cli->open_index(1, ‘db1’, ‘table1’, ‘PRIMARY’, ‘k,v’); my $res = $cli->exec_multi([ [ 1, ‘=‘, [ ’33’ ], 1, 0 ], [ 1, ‘=‘, [ ’44’ ], 1, 0, ‘U’, [ ’44’, ‘hoge’ ] ], [ 1, ‘>=‘, [ ’55’ ], 10, 20 ], ]);

38

設定ガイド

39

handlersocket の設定 handlersocket_threads = 16 参照系ワーカスレッド数 CPU コア数の 2 倍程度を推奨 handlersocket_thread_wr = 1 更新系ワーカスレッド数 増やしても余りメリットなさそう handlersocket_port = 9998 参照系ワーカスレッド用ポート handlersocket_port_wr = 9999 更新系ワーカスレッド用ポート

40

その他の設定 innodb_buffer_pool_size を限界まで大きく それでも参照が Disk ネックになるならデータ分割 innodb_log_file_size, innodb_log_files_in_group 大きいとテーブルスペースへの書き戻しが減る 更新系を速くしたいなら限界まで大きく innodb_thread_concurrency = 0 innodb 内の並列度の上限。 0 にすると無効。 open_files_limit = 65535 mysql が開けるファイルディスクリプタ数 handlersocket 接続一本あたり 1 つ消費するので大きく

41

その他の設定 innodb_adaptive_hash_index = 1 B-Tree に加えて Hash 索引を on-demand に付ける機能 完全に Hash に乗れば handlersocket 経由の参照が~ 30% 程度速くなる Hash 索引作成中は一時的に参照が遅くなる メモリを喰うのが嫌なら無効にしたほうがよい

42

durability に関連する設定 sync_binlog = 1 binlog を同期書き込み innodb_flush_log_at_trx_commit = 1 innodb の WAL を同期書き込み innodb_support_xa = 1 内部的に XA を使って binlog と innodb を同期

43

ベンチマーク

44

ベンチマーク サーバ Core2Quad Q6600 CentOS 5.4 EXPI9301CT(e1000e) Intel X25-E (write-back cache disabled) クライアントとは 1000base 接続 クライアントのほうが高速のため、全てのワークロードでクライアント側はボトルネックになっていない スキーマ : CREATE TABLE table1 (k varchar(32) KEY, v varchar(32)) engine = INNODB; read テスト : 1000 万レコード SELECT v from table1 where k = ? ランダムアクセスするようキーは乱数で生成 write テスト : 1000 万レコード UPDATE table SET v = ? where k = ? ランダムアクセスするようキーは乱数で生成 binlog 有効 動機的 (durable) 書き込み

45

スループット

46

スループット ( 書き込み )

47

最大レスポンス時間

48

平均レスポンス時間

49

今後の予定 (?) と課題

50

課題 ビルドが多少面倒 mysql のソースコードがビルド時に必要 mysql バイナリ互換性問題 mysql のバージョンやビルドオプションの違いによって plugin のバイナリ互換性が無くなる

51

今後の予定 (?) where 句のようなフィルタのサポート 不可分な read-modify-write 操作のサポート SQL 実行機能? (stateless なクエリのみサポート ) InnoDB 以外のエンジンでの検証 クライアントライブラリの整備

More Related Content

HandlerSocket plugin for MySQL

  • 1. handlersocket plugin for mysql 2010/06/29 Tech セミナー @ 代々木 株式会社 DeNA システム統括本部 IT 基盤部 樋口 証 <higuchi dot akira at dena dot jp>
  • 2. Who am I? DeNA IT 基盤部 システムのパフォーマンス最適化 障害の分析 ミドルウェア開発 IPA 未踏 スーパークリエータ (2005 年 ) 1993 年ころから GNU/Linux 利用 Fedora: yum install KoboDeluxe Debian: apt-get install kobodeluxe サーバソフトウェアを多数開発
  • 4. handlersocket plugin とは MySQL の非 SQL なインタフェース
  • 5. ねらい 単純な CRUD 処理を高速に実行したい。 SQL 処理を省略 単純な処理に適用可能な最適化 しかも同じデータを MySQL でも処理できるようにしたい。 単純かつ速度が必要な部分だけを非 SQL に置き換えたい SQL から少しずつ移行したい
  • 6. handlersocket plugin の概要 InnoDB 等のストレージエンジンへの非 SQL インタフェースを提供 TCP/IP でリクエストを受け、ストレージエンジンを直接叩く 独自プロトコルを喋る C++ と Perl のクライアントライブラリを用意 Linux 専用 配布場所は DeNA 技術ブログで案内します http://engineer.dena.jp/
  • 7. 構成 mysqld client app Handler Interface Innodb MyISAM Other storage engines … SQL Layer Handlersocket Plugin Listener for libmysql libmysql libhsclient Applications
  • 8. 参考 : 非 SQL for MySQL mycached http://developer.cybozu.co.jp/kazuho/2009/08/mycached-memcac.html handlersocket と同様に handler インタフェースを叩く memcached プロトコルを喋る NDB API http://dev.mysql.com/doc/ndbapi/en/index.html ndbcluster 専用 handlersocket より下の層 ( ストレージエンジン内部 ) を叩く
  • 10. 性能比較 ( 参照クエリ ) 単純な参照クエリで数倍~ 10 倍程度 取得する列数が多い場合に特に有効
  • 11. handlersocket の機能 ( 参照系 ) 擬似 SQL で書くと… SELECT f1,..,fn FROM db.table WHERE k1,…,km = v1,…,vm ORDER BY index_i LIMIT offset, limit (k1,…,km) は index_i のキー列 ( 又はその prefix) WHERE 句で索引に入っていない列についての条件でフィルタすることはできない いずれサポートしたい 比較条件に使える演算子は =, >=, >, <=, < 索引を使った検索のみサポートする MySQL の HANDLER クエリに近い
  • 12. handlersocket の機能 ( 更新系 ) 参照クエリで得た行の UPDATE と DELETE 行の INSERT トランザクションはサポートしない 更新系クエリは row-based の形式でバイナリログに記録される 書き込みは durable
  • 13. 実行例 create table db1.table1 (k int key, v char(20)) insert into db1.table1 values (234, 'foo'), (678, ‘bar’) $ telnet localhost 9998 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. P 0 db1 table1 PRIMARY k,v 0 1 0 = 1 234 0 2 234 foo 0 = 1 678 0 2 678 bar db1.table1 の PK を開く k = 234 を検索 k = 678 を検索
  • 14. 何故速くなるのか SQL パース処理をしていない -> CPU 消費が少ない リクエストを集約実行している -> CPU 消費やディスク IO が少ない 独自プロトコルで通信する -> ネットワーク消費が少ない
  • 16. oprofile – libmysql/mysqld SELECT v from table where k = ?  を大量に実行し、 oprofile で CPU 消費量をしらべる samples| %| ------------------ 9669940 53.1574 mysqld 4438098 24.3970 vmlinux 1835976 10.0927 libpthread-2.5.so 1680656 9.2389 libc-2.5.so 397970 2.1877 e1000e 89136 0.4900 oprofiled 42881 0.2357 oprofile
  • 17. oprofile – libmysql/mysqld mysqld 内の CPU 消費 samples % symbol name 748022 7.7355 MYSQLparse(void*) 219702 2.2720 my_pthread_fastmutex_lock 205606 2.1262 make_join_statistics(JOIN*, TABLE_LIST*, 198234 2.0500 btr_search_guess_on_hash 180731 1.8690 JOIN::optimize() 177120 1.8317 row_search_for_mysql 171185 1.7703 lex_one_token(void*, void*) 162683 1.6824 alloc_root 131823 1.3632 read_view_open_now 122795 1.2699 mysql_select(THD*, Item***, TABLE_LIST*, 100276 1.0370 open_table(THD*, TABLE_LIST*, st_mem_root*, 99575 1.0297 mem_pool_fill_free_list 96434 0.9973 build_template(row_prebuilt_struct*, THD*, 86349 0.8930 get_hash_symbol(char const*, unsigned int,
  • 18. oprofile – libmysql/mysqld カーネル内の CPU 消費 samples % symbol name 204393 4.6054 schedule 118648 2.6734 tcp_sendmsg 115832 2.6099 tcp_recvmsg 106537 2.4005 tcp_v4_rcv 103915 2.3414 tcp_ack 103534 2.3328 system_call 93864 2.1150 dev_queue_xmit 86831 1.9565 __mod_timer 85891 1.9353 tcp_rcv_established 84083 1.8946 .text.task_rq_lock
  • 19. oprofile – libmysql/mysqld libmysql/mysqld 使用時の CPU 消費 : mysqld 内で多くの CPU 時間を使用 特に SQL パース処理周辺が CPU 使用 カーネル内ではタスク切り替えに CPU 使用
  • 20. oprofile – handlersocket 先の SQL クエリと同等の処理を handlersocket で実行し、 oprofile で CPU 消費量をしらべる samples| %| ------------------ 1919039 51.0453 vmlinux 811998 21.5987 mysqld 421215 11.2041 libpthread-2.5.so 207166 5.5105 e1000e 191566 5.0955 handlersocket.so 188618 5.0171 libc-2.5.so 13622 0.3623 oprofiled 5707 0.1518 oprofile
  • 21. oprofile – handlersocket mysqld 内の CPU 消費 samples % symbol name 119684 14.7394 btr_search_guess_on_hash 58202 7.1678 row_search_for_mysql 46946 5.7815 mutex_delay 38617 4.7558 my_pthread_fastmutex_lock 37707 4.6437 buf_page_get_known_nowait 36528 4.4985 rec_get_offsets_func 34625 4.2642 build_template(row_prebuilt_struct*, THD*, TABLE*, 20024 2.4660 row_sel_store_mysql_rec 19347 2.3826 btr_cur_search_to_nth_level 16701 2.0568 row_sel_convert_mysql_key_to_innobase 13343 1.6432 cmp_dtuple_rec_with_match 11381 1.4016 ha_innobase::index_read(unsigned char*, 11176 1.3764 dict_index_copy_types 10762 1.3254 mtr_memo_slot_release 10734 1.3219 ha_innobase::init_table_handle_for_HANDLER()
  • 22. oprofile – handlersocket カーネル内の CPU 消費 samples % symbol name 129038 6.7241 tcp_sendmsg 80080 4.1729 tcp_v4_rcv 69658 3.6298 dev_queue_xmit 66171 3.4481 .text.skb_release_data 63316 3.2994 __qdisc_run 60279 3.1411 tcp_recvmsg 59703 3.1111 ip_output 58462 3.0464 .text.skb_release_head_state 48876 2.5469 tcp_ack 48733 2.5394 __alloc_skb 45660 2.3793 ip_queue_xmit 44671 2.3278 tcp_transmit_skb
  • 23. oprofile – handlersocket handlersocket 使用時の CPU 消費 : カーネルが最も多く CPU を使用 カーネル内では network 周りで CPU 使用 mysqld 内では innodb の中が使用量多い 特に adaptive hash index 検索処理
  • 25. 並列処理モデル比較 mysqld の並列処理モデル : MySQL 5 では接続あたり 1 スレッド MySQL 6 でスレッドプールもサポート SQL 実行を少数スレッドで実行 メモリ消費の上限が抑えられる
  • 26. 並列処理モデル比較 handlersocket の並列処理モデル : 少数のスレッド 各スレッドは複数の接続を処理 既定では epoll 使用 同時接続数は事実上無制限 メモリ消費が少ない
  • 27. handlersocket スレッドの動作 各接続からリクエストを読む DB ロック、 readview 取得 各接続からのリクエストを実行 DB ロック解除 各接続へ結果を返す ここの処理が (1/ 接続数 ) 回 程度で済む handlersocket の参照系ワーカースレッド の動作
  • 28. handlersocket スレッドの動作 各接続からリクエストを読む DB ロック、トランザクション開始 各接続からのリクエストを実行 コミット、 DB ロック解除 各接続へ結果を返す handlersocket の更新系ワーカースレッド の動作 複数のリクエストを一つの トランザクション内で実行
  • 29. 更新処理の性能について 前提 : 同期書き込み (durable) sync_binlog = 1 innodb_flush_log_at_trx_commit = 1 innodb_support_xa = 1 バッテリ付き write-back cache 又は SSD 性能 : mysql: ~ 1000 qps innodb plugin で sync_binlog = 0 だと group commit が効いてさらに速くなるが、スレーブが追いつかない handlersocket: ~ 30000 qps 書き込みはシリアライズされるので、常にスレーブが追いつく
  • 30. handlersocket の排他制御 MyISAM ならテーブルロックがかかる shared-exclusive lock InnoDB ならテーブルロックはかからない。ただし更新系トランザクションは一度に一つだけ実行されるよう排他制御される。 そうしないとレコードロックを持ち合ってデッドロックするから 更新系スレッドは参照系スレッドをブロックしない handlersocket のリクエスト自体はデッドロックフリー そもそも単純なリクエストしかサポートしていないので。
  • 32. C/S プロトコル比較 write(3, &quot;Lselect column0,column1,column2,column3,column4 from db_1.table_1 where k=15&quot;, 80) = 80 read(3, &quot;056def db_1 table_1 table_1 column0 column0 <7500006def db_1 table_1 table_1 column1 column1 <7500006def db_1 table_1 table_1 column2 column2 <7500006def db_1 table_1 table_1 column3 column3 <7500006def db_1 table_1 table_1 column4 column4 <750076amp;quot;001 0 01 1 01 2 01 3 01 4 76amp;quot;&quot;, 16384) = 327 libmysql/mysqld でこのクエリを実行すると… SELECT column0, column1, column2, column3, column4 FROM db_1.table_1 where k = 15
  • 33. C/S プロトコル比較 write(3, &quot;1=115&quot;, 9) = 9 read(3, &quot;0501234&quot;, 8192) = 14 handlersocket で同等のクエリを実行すると… 14 bytes 327 bytes response 9 bytes 80 bytes request handlersocket libmysql
  • 34. mysqld/libmysql のプロトコル 結果セットのメタデータが大きい 各列について、 DB 名 、 テーブル名 、 テーブル別名 、 列名 、 列の別名 がメタデータに含まれる http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol#Field_Packet mysql 4.0 までのプロトコルではメタデータが少し小さい。 4.1 以降で大きくなった。 列が多く行が少ないとき相対的に大きい メタデータは結果セットに一つだけ付くから HANDLER クエリでも同様にメタデータが付く server-side prepared statement を使っても同様 プロトコル圧縮を使うと 1/3 程度になる。ただし CPU を喰う。
  • 37. DB::HandlerSocket Perl 用クライアントライブラリ xs 経由で libhsclient を呼んでいる my $cli = new DB::HandlerSocket( {host => ‘localhost’, port => 9999}); $cli->open_index(1, ‘db1’, ‘table1’, ‘PRIMARY’, ‘k,v’); my $res = $cli->exec_multi([ [ 1, ‘=‘, [ ’33’ ], 1, 0 ], [ 1, ‘=‘, [ ’44’ ], 1, 0, ‘U’, [ ’44’, ‘hoge’ ] ], [ 1, ‘>=‘, [ ’55’ ], 10, 20 ], ]);
  • 39. handlersocket の設定 handlersocket_threads = 16 参照系ワーカスレッド数 CPU コア数の 2 倍程度を推奨 handlersocket_thread_wr = 1 更新系ワーカスレッド数 増やしても余りメリットなさそう handlersocket_port = 9998 参照系ワーカスレッド用ポート handlersocket_port_wr = 9999 更新系ワーカスレッド用ポート
  • 40. その他の設定 innodb_buffer_pool_size を限界まで大きく それでも参照が Disk ネックになるならデータ分割 innodb_log_file_size, innodb_log_files_in_group 大きいとテーブルスペースへの書き戻しが減る 更新系を速くしたいなら限界まで大きく innodb_thread_concurrency = 0 innodb 内の並列度の上限。 0 にすると無効。 open_files_limit = 65535 mysql が開けるファイルディスクリプタ数 handlersocket 接続一本あたり 1 つ消費するので大きく
  • 41. その他の設定 innodb_adaptive_hash_index = 1 B-Tree に加えて Hash 索引を on-demand に付ける機能 完全に Hash に乗れば handlersocket 経由の参照が~ 30% 程度速くなる Hash 索引作成中は一時的に参照が遅くなる メモリを喰うのが嫌なら無効にしたほうがよい
  • 42. durability に関連する設定 sync_binlog = 1 binlog を同期書き込み innodb_flush_log_at_trx_commit = 1 innodb の WAL を同期書き込み innodb_support_xa = 1 内部的に XA を使って binlog と innodb を同期
  • 44. ベンチマーク サーバ Core2Quad Q6600 CentOS 5.4 EXPI9301CT(e1000e) Intel X25-E (write-back cache disabled) クライアントとは 1000base 接続 クライアントのほうが高速のため、全てのワークロードでクライアント側はボトルネックになっていない スキーマ : CREATE TABLE table1 (k varchar(32) KEY, v varchar(32)) engine = INNODB; read テスト : 1000 万レコード SELECT v from table1 where k = ? ランダムアクセスするようキーは乱数で生成 write テスト : 1000 万レコード UPDATE table SET v = ? where k = ? ランダムアクセスするようキーは乱数で生成 binlog 有効 動機的 (durable) 書き込み
  • 50. 課題 ビルドが多少面倒 mysql のソースコードがビルド時に必要 mysql バイナリ互換性問題 mysql のバージョンやビルドオプションの違いによって plugin のバイナリ互換性が無くなる
  • 51. 今後の予定 (?) where 句のようなフィルタのサポート 不可分な read-modify-write 操作のサポート SQL 実行機能? (stateless なクエリのみサポート ) InnoDB 以外のエンジンでの検証 クライアントライブラリの整備