• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Handlersocket 20110517
 

Handlersocket 20110517

on

  • 6,149 views

 

Statistics

Views

Total Views
6,149
Views on SlideShare
4,337
Embed Views
1,812

Actions

Likes
6
Downloads
50
Comments
0

10 Embeds 1,812

http://d.hatena.ne.jp 1739
http://webcache.googleusercontent.com 42
http://infra.rrdtool.net 14
http://hatenatunnel.appspot.com 9
http://localhost 3
https://si0.twimg.com 1
http://timprx.appspot.com 1
http://freeandroidgames.appspot.com 1
http://gaeforyou.appspot.com 1
http://cache.yahoofs.jp 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Handlersocket 20110517 Handlersocket 20110517 Presentation Transcript

    • HandlerSocket plugin for MySQL 2011/05/17 NoSQL セミナー @ 渋谷 株式会社 DeNA システム統括本部 IT 基盤部 樋口 証 <higuchi dot akira at dena dot jp>
    • 概要
    • HandlerSocket plugin とは
      • MySQL の非 SQL なインタフェース
      • ○ NoSQL
      • × NoRDB
    • HandlerSocket plugin の概要
      • InnoDB 等のストレージエンジンへの非 SQL インタフェースを提供
      • TCP/IP でリクエストを受け、ストレージエンジンを直接叩く
      • 独自プロトコルを喋る
      • C++ と Perl のクライアントライブラリを用意
        • PHP, Java, Python, Ruby, JavaScript(node.js), Scala のライブラリが存在
      • Linux/FreeBSD/MacOS で動作
        • Linux に最もチューニングされている
      • BSD ライセンス
        • https://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL
    • 構成 mysqld client app Handler Interface Innodb MyISAM Other storage engines … SQL Layer HandlerSocket Plugin Listener for libmysql libmysql libhsclient Applications
    • ねらい
      • 単純な CRUD 処理を高速に実行したい。
        • SQL 処理を省略
        • 単純な処理に適用可能な最適化
      • しかも同じデータを MySQL でも処理できるようにしたい。
        • 単純かつ速度が必要な部分だけを非 SQL に置き換えたい
        • SQL から少しずつ移行したい
    • 参考 : 非 SQL for MySQL (HandlerSocket 以前のもの )
      • 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 より下の層 ( ストレージエンジン内部 ) を叩く
    • 時系列
      • 2010/03 このころ開発を始める
      • 2010/04 最初のバージョンが完成
      • 2010/06 DeNA Technology Seminar #2 で社外に初めて公開
      • 2010/08 github でソースを公開
      • 2010/08 mobage で本格利用開始
    • その後の動向 (1)
      • Percona Server に HandlerSocket が取り込まれる
        • Percona Server now both SQL and NOSQL
        • http://www.mysqlperformanceblog.com/2010/12/14/percona-server-now-both-sql-and-nosql/
    • その後の動向 (2)
      • 2011/04 MySQL Conference & Expo 2011
        • DeNA 松信が HandlerSocket について講演
        • DeNA が Corporate Contributor of the Year 2011 を受賞
        • DeNA is Japan's biggest social game provider and run hundreds of MySQL servers to provide their services. So it is not surprising they also employ some of Japan's best and world famous MySQL experts to work on their LAMP stack. This team produced one of the most interesting innovations MySQL has seen for a while: HandlerSocket is MySQL's answer to the NoSQL trend, and with a vengeance. With read-transactions now running over 700% faster, it makes MySQL the fastest NoSQL key-value solution out there. And you get best of both worlds: MySQL and NoSQL in the same package.
      -> MySQL + HandlerSocket で KVS と同等以上の 性能が出せることを示した
    • その後の動向 (3)
      • 2011/04 MySQL の memcached インタフェース
        • NoSQL to MySQL with Memcached
        • http ://dev.mysql.com/tech-resources/articles/nosql-to-mysql-with-memcached.html
        • ... The HandlerSocket development at DeNA is a great example of community innovation, with a solution implemented as a custom plug-in and protocol for the MySQL server daemon.
      -> MySQL の NoSQL インタフェースが流行?
    • mobage での利用
    • mobage への導入
      • 2010/08 mobage で本格利用開始
        • サービスを停止せずに移行
      • 導入以降トラブルは一度も無し
        • 導入時と同じ mysqld プロセスが動き続けている
      • 一度 HandlerSocket プラグインを更新
        • mysqld は停止せずにプラグインだけを入れ替え
    • 最初の適用箇所
      • MySQL + memcached で構成されていた
      • クエリは単純だが数が膨大
      • 既存構成の問題 :
        • 同時接続数の問題で、 mysql の持続接続の利用が難しかった
        • memcached とのデータ同期のための仕組みが複雑で運用に負担がかかっていた
        • ネットワークトラフィックが必要以上に出てしまっていた
    • 導入効果
      • MySQL と memcached サーバの負荷削減
      • アプリケーションの CPU 負荷削減
        • 20% ~ 35% 程度削減
      • ネットワークトラフィックの削減
        • 適用箇所の 70% 程度削減
    • HandlerSocket の利点
    • 利点 (libmysql と比較して )
      • CPU を喰わない
        • サーバ側、クライアント側のいずれも効果あり
        • 特に単純なクエリで差が大きい
      • ネットワークトラフィックが減らせる
        • 特に単純なクエリで差が大きい
      • 同時接続数がほぼ無制限
        • 少なくとも 65000 本までは可能
        • 同時接続数を増やしても性能劣化が殆ど無い
    • HandlerSocket に向いているケース
      • データサイズが十分小さくメモリに乗る
      • 単純なクエリ、サーバの CPU がネック
      • 単純なクエリ、トラフィックがネック
      • 同時接続数が多すぎて持続接続が使えない
    • HandlerSocket に不向きなケース
      • クエリが複雑で HandlerSocket で実現困難
      • クエリ一回あたりの CPU 使用量が多く CPU ネック
      • データサイズが大きく Disk IO がネック
    • 機能
    • HandlerSocket の機能 ( 参照系 )
      • Primary Key や Unique Key を使った列取得
      • 範囲取得
        • 比較条件に使える演算子は =, >=, >, <=, <
      • SQL の’ IN’ のような複数列取得
    • HandlerSocket の機能 ( 更新系 )
      • 参照クエリで得た行の UPDATE と DELETE
      • 行の INSERT
      • トランザクションはサポートしない
      • 更新系クエリは row-based の形式でバイナリログに記録される
        • MySQL のレプリケーション機能を使える
      • 書き込みは durable
    • 実行例
      • 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 を検索
    • 性能
    • ネックの箇所を見極める
      • テストのネック箇所を見極めないと正確な性能比較ができない
        • サーバの CPU ?
        • クライアントの CPU ?
        • サーバやクライアントのコードの問題?
          • スケーラビリティに問題がある?
          • 例えば Lock contention のせいで CPU を使い切れないなど
        • ネットワーク周り?
          • 帯域の限界に達している?
          • ネットワークドライバがスケーラビリティの問題を抱えていることも
    • おおよその性能
      • 8 Core HT 付きのサーバ、 1Gb の NIC 一個、 InnoDB 、 adaptive hash index 有効
        • libmysql: ~ 100,000 qps
          • CPU が頭打つ
        • HandlerSocket: ~ 300,000 qps
          • ネットワーク周りがネックになる
          • CPU は頭打たない
        • HandlerSocket(pipelined): ~ 3,000,000 qps
          • CPU が頭打つ
    • libmysql との性能比較 ( 参照クエリ )
      • 単純な参照クエリで数倍~ 10 倍程度
      • 取得する列数が多い場合に特に有効
    • 何故速くなるのか
      • SQL パース処理をしていない
        • -> CPU 消費が少ない
      • リクエストを集約実行している
        • -> CPU 消費やディスク IO が少ない
      • 独自プロトコルで通信する
        • -> ネットワーク消費が少ない
    • CPU 消費の削減
    • 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
    • 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,
    • 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
    • oprofile – libmysql/mysqld
      • libmysql/mysqld 使用時の CPU 消費 :
        • mysqld 内で多くの CPU 時間を使用
        • 特に SQL パース処理周辺が CPU 使用
        • カーネル内ではタスク切り替えに CPU 使用
    • 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
    • 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()
    • 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
    • oprofile – HandlerSocket
      • HandlerSocket 使用時の CPU 消費 :
        • カーネルが最も多く CPU を使用
        • カーネル内では network 周りで CPU 使用
        • mysqld 内では innodb の中が使用量多い
        • 特に adaptive hash index 検索処理
    • 並列処理の最適化
    • 並列処理モデル比較
      • mysqld の並列処理モデル :
        • MySQL 5 では接続あたり 1 スレッド
        • MySQL 6 でスレッドプールもサポート
          • SQL 実行を少数スレッドで実行
          • メモリ消費の上限が抑えられる
    • 並列処理モデル比較
      • HandlerSocket の並列処理モデル :
        • 少数のスレッド
        • 各スレッドは複数の接続を処理
          • 既定では epoll 使用
          • 同時接続数は事実上無制限
          • メモリ消費が少ない
    • HandlerSocket スレッドの動作 各接続からリクエストを読む DB ロック、 readview 取得 各接続からのリクエストを実行 DB ロック解除 各接続へ結果を返す ここの処理が (1/ 接続数 ) 回 程度で済む HandlerSocket の参照系ワーカースレッド の動作
    • HandlerSocket スレッドの動作 各接続からリクエストを読む DB ロック、トランザクション開始 各接続からのリクエストを実行 コミット、 DB ロック解除 各接続へ結果を返す HandlerSocket の更新系ワーカースレッド の動作 複数のリクエストを一つの トランザクション内で実行
    • 更新処理の性能について
      • 前提 :
        • 同期書き込み (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
          • 書き込みはシリアライズされるので、常にスレーブが追いつく
    • HandlerSocket の排他制御
      • MyISAM ならテーブルロックがかかる
        • shared-exclusive lock
      • InnoDB ならテーブルロックはかからない。ただし更新系トランザクションは一度に一つだけ実行されるよう排他制御される。
        • そうしないとレコードロックを持ち合ってデッドロックするから
        • 更新系スレッドは参照系スレッドをブロックしない
      • HandlerSocket のリクエスト自体はデッドロックフリー
        • そもそも単純なリクエストしかサポートしていないので。
    • 通信の最適化
    • C/S プロトコル比較
      • write(3, &quot;L0003select column0,column1,column2,column3,column4 from db_1.table_1 where k=15&quot;, 80) = 80
      • read(3, &quot;100100560023def4 db_1 7 table_1 7 table_1 7 column0 7 column0 fr0<00037520000000060033def4 db_1 7 table_1 7 table_1 7 column1 7 column1 fr0<00037520000000060043def4 db_1 7 table_1 7 table_1 7 column2 7 column2 fr0<00037520000000060053def4 db_1 7 table_1 7 table_1 7 column3 7 column3 fr0<00037520000000060063def4 db_1 7 table_1 7 table_1 7 column4 7 column4 fr0<0003752000000500737600&quot;0n0010001 0 001 1 001 2 001 3 001 4 500t37600&quot;0&quot;, 16384) = 327
      libmysql/mysqld でこのクエリを実行すると… SELECT column0, column1, column2, column3, column4 FROM db_1.table_1 where k = 15
    • C/S プロトコル比較 write(3, &quot;1t=t1t15n&quot;, 9) = 9 read(3, &quot;0t5t0t1t2t3t4n&quot;, 8192) = 14 HandlerSocket で同等のクエリを実行すると… 14 bytes 327 bytes response 9 bytes 80 bytes request HandlerSocket libmysql
    • 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 を喰う。
    • クライアントライブラリ
    • libhsclient
      • HandlerSocket 用クライアントライブラリ
        • C++
        • 低水準インタフェース
    • 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 ], ]);
    • 設定ガイド
    • HandlerSocket の設定
      • HandlerSocket_threads = 16
        • 参照系ワーカスレッド数
        • CPU コア数の 2 倍程度を推奨
      • HandlerSocket_thread_wr = 1
        • 更新系ワーカスレッド数
        • 増やしても余りメリットなさそう
      • HandlerSocket_port = 9998
        • 参照系ワーカスレッド用ポート
      • HandlerSocket_port_wr = 9999
        • 更新系ワーカスレッド用ポート
    • その他の設定
      • 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 つ消費するので大きく
    • その他の設定
      • innodb_adaptive_hash_index = 1
        • B-Tree に加えて Hash 索引を on-demand に付ける機能
        • 完全に Hash に乗れば HandlerSocket 経由の参照が~ 30% 程度速くなる
        • Hash 索引作成中は一時的に参照が遅くなる
        • メモリを喰うのが嫌なら無効にしたほうがよい
    • durability に関連する設定
      • sync_binlog = 1
        • binlog を同期書き込み
      • innodb_flush_log_at_trx_commit = 1
        • innodb の WAL を同期書き込み
      • innodb_support_xa = 1
        • 内部的に XA を使って binlog と innodb を同期
    • ベンチマーク
    • ベンチマーク
      • サーバ
        • 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) 書き込み
    • スループット
    • スループット ( 書き込み )
    • 最大レスポンス時間
    • 平均レスポンス時間
    • 今後の予定と課題
    • 課題
      • ビルドが多少面倒
        • mysql のソースコードがビルド時に必要
      • mysql バイナリ互換性問題
        • mysql のバージョンやビルドオプションの違いによって plugin のバイナリ互換性が無くなる
    • 今後の予定
      • ドキュメントを書く
        • undocumented な機能が多数存在
      • 不可分な read-modify-write 操作のサポート
        • 一部機能は実装済
      • InnoDB 以外のエンジンでの検証
      • クライアントライブラリの整備
      • スクリプトエンジン orJVM を埋め込む?