小咄:blazeds+amf client+mysqlで実現するkey-value storage

Post on 25-May-2015

3.220 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

小咄:BlazeDS+AMF Client+MySQLで実現するKey-Value Storage

HBaseが重い

事の顛末クローリングしたブログ記事をHBaseに保存してた。

→2009/03ころからデータ参照処理が非常に時間がかかるようになる。(テーブル数:1000弱 データサイズ:5,000万レコード超)→今まで1時間で終わっていた処理が5時間くらいかかるように・・・・・・→キィィィィィィィィィ!!

元々HBaseって使い辛いよね

✓書き込んだデータがHDFSのノード上に伝播されるまでタイムラグがある。

✓カウント文が無い。(countコマンドはあるが、全レコードをgetしてその件数を数えてる)

✓まだバグが多い。

では何故HBaseを使っていた?

見栄

key-value store• 何を期待している?

- 処理パフォーマンス、シンプルさ- keyさえ分かれば値が取得できる- valueに何でも放り込んでおける(スキーマレス)

- スケーラビリティ- keyさえ分かればデータがどこにあっても良い

• 何を期待していない?- 高機能

- たとえばSQLみたいなDSLによる操作- ロールバック機構

key-value store• とは言えどもこれは有った方が良い

- 処理パフォーマンス - バックアップ機能- 手軽にレプリケーションできる- ある程度の信頼性

- データが高負荷時に突然破損しない程度

- データリスト/keyリストの取得機能- データ件数取得機能

比較•memcached•Tokyo Cabinet/Tokyo Tyrant•Voldemort•Apache CouchDB•HBase(一応)

比較(完全に主観)パフォーマンス レプリケーション バックアップ 信頼性

memcached ◎ ?cloneプロジェクトがいくつかある

× ◎

TokyoCabinet/TokyoTyrant ○ ◎ ◎ ○

Voldemort △ ○採用ストレージによる

○採用ストレージによる

CouchDB △ × × △

HBase × ◎ ◎ ×

TokyoTyrantは悪く無い• スループットもmemcachedの倍遅い程度• レプリケーション機能標準採用• 比較的堅牢、信頼性がある(mixiのログイン機能他多くの高トラフィックシステムに使われている)

• インターフェースmemcached互換

• ただし使い辛い部分も• テーブル単位でデータを保存するには個数分インスタンス立ち上げ

• keyリストは取れるがカウント文的なものは無い

こんな記事

記事要約• スキーマ追加に伴うインデックス追加が大変• CouchDBみたいなスキーマレスな仕組みにしたい。しかしCouchDBは不安定

• MySQLで良いじゃん。• valueはJSONで保存• 実体テーブルと参照用インデックステーブルを分離実データは実体テーブル上にuuid-bodyの対で保存参照テーブルでは実体検索用のカラムを保持

• 負荷減った

これだ

構成CREATE TABLE entities ( added_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, id BINARY(16) NOT NULL, updated TIMESTAMP NOT NULL, body MEDIUMBLOB, UNIQUE KEY (id), KEY (updated)) ENGINE=InnoDB;

実体テーブル

参照テーブルCREATE TABLE index_user_id ( user_id BINARY(16) NOT NULL, entity_id BINARY(16) NOT NULL UNIQUE, PRIMARY KEY (user_id, entity_id)) ENGINE=InnoDB;

{ "id": "71f0c4d2291844cca2df6f486e96e37c", "user_id": "f48b0440ca0c4f66991c4d5f6a078eaf", "feed_id": "f48b0440ca0c4f66991c4d5f6a078eaf", "title": "We just launched a new backend system for FriendFeed!", "link": "http://friendfeed.com/e/71f0c4d2-2918-44cc-a2df-6f486e96e37c", "published": 1235697046, "updated": 1235697046,}※bodyの中身(value)はJSONで保存

アプリ

※user_id→entry_id(key)検索用

データ登録時CREATE TABLE entities ( added_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, id BINARY(16) NOT NULL, updated TIMESTAMP NOT NULL, body MEDIUMBLOB, UNIQUE KEY (id), KEY (updated)) ENGINE=InnoDB;

実体テーブル

参照テーブルCREATE TABLE index_user_id ( user_id BINARY(16) NOT NULL, entity_id BINARY(16) NOT NULL UNIQUE, PRIMARY KEY (user_id, entity_id)) ENGINE=InnoDB;

{ "id": "71f0c4d2291844cca2df6f486e96e37c", "user_id": "f48b0440ca0c4f66991c4d5f6a078eaf", "feed_id": "f48b0440ca0c4f66991c4d5f6a078eaf", "title": "We just launched a new backend system for FriendFeed!", "link": "http://friendfeed.com/e/71f0c4d2-2918-44cc-a2df-6f486e96e37c", "published": 1235697046, "updated": 1235697046,}※bodyの中身(value)はJSONで保存

アプリ

※user_id→entry_id(key)検索用

1.実体を実体テーブルに保存

2.検索用のレコードを参照テーブルに保存

※非同期で登録も可能

データ参照時CREATE TABLE entities ( added_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, id BINARY(16) NOT NULL, updated TIMESTAMP NOT NULL, body MEDIUMBLOB, UNIQUE KEY (id), KEY (updated)) ENGINE=InnoDB;

実体テーブル

参照テーブルCREATE TABLE index_user_id ( user_id BINARY(16) NOT NULL, entity_id BINARY(16) NOT NULL UNIQUE, PRIMARY KEY (user_id, entity_id)) ENGINE=InnoDB;

{ "id": "71f0c4d2291844cca2df6f486e96e37c", "user_id": "f48b0440ca0c4f66991c4d5f6a078eaf", "feed_id": "f48b0440ca0c4f66991c4d5f6a078eaf", "title": "We just launched a new backend system for FriendFeed!", "link": "http://friendfeed.com/e/71f0c4d2-2918-44cc-a2df-6f486e96e37c", "published": 1235697046, "updated": 1235697046,}※bodyの中身(value)はJSONで保存

アプリ

※user_id→entry_id(key)検索用

1.keyが明示な場合は直接実体テーブルに参照に行く

2.keyが不明な場合、参照テーブルから条件に合致する

key情報を取得する

FriendFeed版スキーマレスDBの利点

• key-value storeのメリットを享受しながら、MySQLの性能(パフォーマンス、利便性、信頼性)や実績/ノウハウをそのまま使用できる

• 参照テーブルを用意する事で普通のDBと同じような操作が可能になる

• インデックス追加のコストが低い• 検索用の参照テーブルを非同期で作成すれば良い• 要件によっては非同期に更新しても良い。I/O負荷の分散/平板化がしやすい

データをJSON形式で保存する功罪

• メリット• スキーマレス(何でも放り込める)• 可視性。何か有った時に目で確認→直接編集できる

• 標準フォーマット(RFC4627)• デメリット

• バイナリ形式に比してデータが冗長になる• バイナリを扱うには文字列符号化が必要• BLOBに可変長のデータを放り込むためフラグメントが起こりやすい

• 生理的に嫌

参照テーブルを非同期で更新することの功罪

• メリット• 更新処理を非同期にすることができる。• インデックスの追加やデータリカバリが容易• スループットの向上。I/O負荷の平板化

• デメリット• 更新したデータが、更新直後に参照できない可能性がある(ACIDモデルの崩壊)

CAP定理• Consistency(一貫性)、Availability(可用性)、Partition

tolerance(並列性)の3つ全てを同時には満たせない、という定理。http://www.cs.berkeley.edu/~brewer/cs262b-2004/PODC-keynote.pdf

Consistency

Availability Partition tolerance

CAP定理• Webサービスでは「A」「P」は必須• 「C」で妥協するしかない

ここを工夫するConsistency

Availability Partition tolerance

Consistency• Strong Consistency

- 誰かがデータを更新したら、次の人は必ず最新のデータにアクセスできる

• Weak Consistency- 誰かがデータを更新したら、次の人は必ず最新のデータにアクセスできる「とは限らない」

• Eventual Consistency- データが複製されるための十分な時間を経て、その後更新がされていなければ必ず最新のデータにアクセスできる

- MySQLのレプリケーションなんかもそうだよね

ACIDからBASEへ?• ACID

Atomicity (原子性)/Consistency (一貫性)/Isolation (独立性、隔離性)/Durability (永続性)

• BASE- Basically (基本的に大丈夫)- Avaiable(使用可能であること) - Soft State (柔軟な状態管理。通信中に絶えず相手の動作を確認するインターネットのようなモデル)

- Eventual Consistency

ACIDからBASEへ?• http://subtech.g.hatena.ne.jp/mala/20090303/1236054662

「正確さのために無駄なロックが発生したり、インデックスを肥大化させて、速度を犠牲にしてしまう。(よくあるパターンだと思う) 細かいことを気にしなければコンピューターの性能はもっと引き出せるはず。」(mala氏)

• どうしてもStrong Consistencyにしたい場合は実体/参照テーブルを同期書き込み、そうでもない場合は非同期書き込みにしておけば皆が幸せになれる。

ここまでのまとめ• MySQLをkey-value storeとして使う、というアイデア

• 実際にFriend Feedで採用されている• 他のkey-value storeを採用するより信頼性やパフォーマンス、何より実績がある安心感

• 実体テーブルと参照テーブルを分けることにより一般的なRDBと同じような使い方ができる

MySQLでkey-value storeってありだよね!

つづく

MySQLへの接続問題• JDBCドライバ初期化→DB接続のオーバーヘッドが

Javaだと結構負担になる• 軽量言語では無問題かもしれないが・・・

• アプリ→MySQLで直接繋ぐと色々と問題が• セキュリティ問題(3306ポートを空ける?)• DBCPなどでpoolingさせると基本的にコネクションがステートフル状態になる

• あまり分散環境には向かない

proxy

拠点B

拠点A

Proxy的な機能が有った方が便利なケースが多い

MySQL

MySQL

MySQL

MySQL

Proxy

Proxy

memcache

アプリ

アプリ

アプリ

負荷分散 負荷分散

クラスタリング

接続プール

キャッシュ

HTTPベースの接続

Proxyのインターフェースをどうするか

• できればHTTP/ステートレス通信ベース• 標準技術である、NAT越え問題など

• とはいえREST、JSONなどのテキストベースではデータサイズのオーバーヘッドが大きい

こんな記事

こんな記事

要約• AMF(Action Message Format)→AdobeがFlashで採用しているデータフォーマット バイナリベース。HTTP上でやり取りできる。 現在オープンソース化

• BlazeDS→LifeCycle Data Service ES(Flash リモーティングサーバ)のオープンソース版ミドルウェア。 AMF経由でのRPC、メッセージパッシングに対応

• BlazeDSはJava実装。Tomcat上で動作。• AMFはオープンソースのため、Java用のクライアント実装も公開されている

• Ajax+JSONより4倍速い?

これだ

パフォーマンス測定(BlazeDS × JSON)

• RPCサーバ側からクライアント側にHello World文字列を返却する処理を以下の方式で実装- 一般的なWebアプリケーション(SpringMVC。

GETのレスポンスで文字列を返却)- BlazeDS + SpringFramework + Java AMF Client で文字列返却(AMF経由でバイナリ通信)

- BlazeDS + SpringFramework + Java AMF Client でJavaオブジェクトをシリアライズして返却

パフォーマンス測定(BlazeDS × JSON)

0

10,000

20,000

30,000

40,000

HTTP文字列 AMF文字列 AMオブジェクト

ステートレスステートフル

※1万回処理を実施※単位はミリ秒

パフォーマンス測定(BlazeDS × JSON)

4倍速いっぽい

パフォーマンス測定(JDBC × Proxy)

• クライアント側からDBにselect/insert/update/deleteの処理を以下の方式で実装- JDBCドライバを読み込み直接接続- singleton形式で初期化したDataSourceを使用し接続

- Proxy経由でAMF形式で接続(Proxy内ではDataSourceをsingletonで保持)

0

1,000

2,000

3,000

4,000

JDBC直接 DataSource Proxy

insert updateselect delete

パフォーマンス測定(JDBC × Proxy)

※100回処理を実施※単位はミリ秒

パフォーマンス測定(JDBC × Proxy)

• 直接DataSouceで接続するのに比べ、BlazeDSのProxy経由の方が若干遅い(通信オーバーヘッド分)

• しかしProxyの利便性により相殺できるレベル• Hadoop上のMap/Reduceタスクのように

singletonモデルが扱い辛い場合にProxy接続は便利

パフォーマンス測定(Proxy × Tokyo Tyrant)

• Tokyo Cabinet / Tokyo Tyrant に対して先ほどの「JDBC×Proxy」と同様の処理を実施。※set(insert),get(select)のみ

0

250

500

750

1,000

DataSource Proxy Tokyo Tyrant

put/insertget/select

パフォーマンス測定(Proxy×Tokyo Tyrant)

※100回処理を実施※単位はミリ秒

パフォーマンス測定(Proxy × Tokyo Tyrant)

• Tokyo Tyrantの方が圧倒的に速い• 用途によっては、実体データをTokyo

Tyrantに保存する形で実装しても良さそう

Tomcat

springframework

今回はBlazeDSを用いて以下のような構成に

MySQL

BlazeDS

アプリ

アプリ

アプリproxyサービス

スキーマレスDB接続

接続プール

HTTPベースの接続(AMF)

MyISAM

MySQL

レプリケーション

現在取り扱っているデータ件数

データ更新 データ参照

データ量 350万/日 -

APIコール数 500万/日 1,550万/日

※4/19付けの結果※APIサーバ:1台※DBサーバ:1台

処理にはまだまだ余裕がある。

BlazeDS使用の際の注意点• ステートフル通信をエミュレートするために、接続時にセッションオブジェクトが作成される。デフォルト設定で大量のリクエストを発行するとOut Of Memoryが発生する可能性がある。→セッションの保持期間を短くするか、セッション保持をしないようパッチを当てる(今回は前者で対応)

• RPC接続時にBlazeDS上でExceptionがthrowされてもクライアント側には通知されない→エラーコード等をクライアント側に返却する必要あり

まとめ• MySQLでkey-value storeってありだよね• アプリ−MySQL間でProxy的な機能があると利便性が増す

• BlazeDSはTomcat上で動作、Java実装、AMFが扱えるということで便利。

• BlazeDS(AMF)のRPCはプレーンテキストのHTTPより4倍くらい速い

• 数千万ヒット/日:1台 程度の負荷は実用的に耐えられる実績も既にある。

ご清聴ありがとうございました

質疑応答

top related