Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

The Overall Architecture of ROMA

2,859 views

Published on

We present the overall architecture of ROMA, which is a distributed key-value store in Ruby.

Published in: Technology
  • Be the first to comment

The Overall Architecture of ROMA

  1. 1. ROMA R akuten O n- M emory A rchitecture 楽天株式会社 楽天技術研究所 西澤無我| 2009年2月20日
  2. 2. ROMA について <ul><li>複数マシンから構成される P2P を利用した </li></ul><ul><li>Ruby 実装の key-value store </li></ul>ROMA (key-value store)
  3. 3. ROMA の特徴 ROMA <ul><li>社内クラウド </li></ul><ul><ul><li>高負荷な状況であっても、十分高速なデータアクセス </li></ul></ul><ul><ul><li>部分障害が起きても、データを喪失しづらい </li></ul></ul>エンドユーザ Web ( アプリケーション ) サーバ GET GET PUT
  4. 4. Consistent Hashing <ul><li>Pure P2P で自律的にノードを管理 </li></ul><ul><li>環状 (Consistent Hashing) </li></ul><ul><ul><li>各ノードはユニークなハッシュ値 (SHA-1) をもつ </li></ul></ul><ul><ul><li>その範囲は 0 ~ 2^64 の整数 </li></ul></ul>ROMA
  5. 5. Zero-hop でのデータ探索 (1/2) <ul><li>各ノードが環全体のノード情報を保持 </li></ul><ul><ul><li>1,000 台程度のノード情報であるため </li></ul></ul><ul><li>クライアントが環情報を保持することも可能 </li></ul><ul><ul><li>ROMA に初めてアクセスした際、クライアントは環情報を取得 </li></ul></ul>ROMA 担当ノード ① データを GET/PUT ③ 担当ノードから 値を GET/PUT ② 担当ノードを計算 コーディネータ クライアント
  6. 6. Zero-hop でのデータ探索 (2/2) <ul><li>各ノードが環全体のノード情報を保持 </li></ul><ul><ul><li>1,000 台程度のノード情報であるため </li></ul></ul><ul><li>クライアントが環情報を保持することも可能 </li></ul><ul><ul><li>ROMA に初めてアクセスした際、クライアントは環情報を取得 </li></ul></ul>ROMA 担当ノード ③ 担当ノードから値を GET/PUT ② 担当ノードを計算 ① データを GET/PUT クライアント
  7. 7. ROMA Client <ul><li>クライアントと ROMA 間は独自プロトコルを用意 </li></ul><ul><ul><li>現在、 Ruby, Java によるクライアント実装 </li></ul></ul><ul><li>開発者に分散を意識させない </li></ul><ul><ul><li>どのマシンにデータが格納されているのか、開発者は意識する必要なし </li></ul></ul>#!/usr/local/bin/ruby require ‘RClient’ rc = ROMA::Client.new rc.open(“roma0”, 3300) # 任意の ROMA プロセスを指定 rc[“muga”] = “data” # ROMA にデータを PUT data = rc[“muga”] # ROMA からデータを GET rc[“muga”] = nil # ROMA からデータを DELETE ※ Ruby 実装のクライアント API の例
  8. 8. Replication (1/2) <ul><li>データが PUT されたとき、 担当ノードはその左右のノードにレプリカを PUT </li></ul><ul><ul><li>プライマリが左右にデータのバックアップを配置 </li></ul></ul><ul><ul><li>ROMA が自動的に行う </li></ul></ul><ul><ul><li>デフォルトでデータの冗長度 ( 多重度 ) は 3 </li></ul></ul>ROMA 担当ノード ① 担当ノードに 値が PUT ② 左右のノードにレプリカを PUT
  9. 9. Replication (2/2) <ul><li>基本的に、単一の担当ノードが PUT/GET を引き受ける </li></ul><ul><ul><li>※ 左右のノードに PUT/GET があると、それは別の意味になる(後述) </li></ul></ul><ul><li>左右のノードにデータが PUT されるまで、クライアントは待つ </li></ul><ul><ul><li>プライマリによるロック </li></ul></ul><ul><ul><li>レプリカの一貫性を保ちやすい(アプリ開発者が楽になる) </li></ul></ul><ul><ul><li>プライマリのノードが性能のボトルネック </li></ul></ul>ROMA 担当ノード ① 担当ノードに 値が PUT ② 左右のノードにレプリカを PUT
  10. 10. Replica Synchronization (1/2) <ul><li>障害時でなくとも、 replication に失敗するケース </li></ul><ul><ul><li>例:忙しすぎて左隣のノードはレスポンスを返せない </li></ul></ul><ul><li>担当ノードは replication に失敗しても、 自身さえ更新できれば成功のレスポンスを返す </li></ul><ul><ul><li>ただし、担当ノードのそのデータにダーティフラグが立つ </li></ul></ul><ul><ul><li>本当はデータの PUT 失敗 </li></ul></ul>ROMA 担当ノード ① 担当ノードに 値が PUT ② 左右のノードにレプリカを PUT
  11. 11. Replica Synchronization (2/2) <ul><li>ダーティーフラグはいずれ解消される </li></ul><ul><li>そのデータは非同期に synchronization </li></ul><ul><ul><li>担当ノードは、ダーティーフラグが立っているデータを検索 </li></ul></ul><ul><ul><li>左右のノードから、異なる値を持つデータを更新 </li></ul></ul><ul><ul><ul><li>シンクロ前にマスター、右ノードが停止してしまうと一貫性は保たれない </li></ul></ul></ul><ul><ul><ul><li>マスターのみ停止したら、キーの更新の時刻を比較 </li></ul></ul></ul>ROMA 担当ノード ① 担当ノードに 値が PUT ② 左右のノードにレプリカを PUT
  12. 12. ノードの Join (1/3) <ul><li>新規のノードの ROMA への参加 </li></ul><ul><ul><li>起動直後、自分のノードのハッシュ値を計算 </li></ul></ul><ul><ul><li>ネットワーク上の全てのマシンに対し、そのハッシュ値をブロードキャスト </li></ul></ul><ul><ul><li>ROMA のノードが応答 </li></ul></ul><ul><ul><li>その隣に新規ノードは入る </li></ul></ul>ROMA 新規ノード ① ブロードキャスト ② ROMA ノードが応答
  13. 13. 各ノードのデータ領域 LS P RS LS P RS LS P RS LS P RS <ul><li>各ノードは 3 つのデータ領域をもつ </li></ul><ul><ul><li>P: 自分が担当しているデータを格納する領域 </li></ul></ul><ul><ul><li>LS: 左のノードが担当しているデータの複製を格納する領域 </li></ul></ul><ul><ul><li>RS: 右のノードが担当しているデータの複製を格納する領域 </li></ul></ul>冗長度 3 冗長度 3 ROMA
  14. 14. ノードの Join (2/3) <ul><li>新規ノードに、左右のノードからデータがコピーされる </li></ul>LS P RS LS P RS LS P RS LS P RS LS P RS ROMA
  15. 15. ノードの Join (3/3) LS P <ul><li>リハッシュ後に、新規ノードはサービス開始 </li></ul>LS P RS LS P RS P RS LS P RS LS RS ROMA
  16. 16. 環情報の更新 ROMA <ul><li>ノード参加の事実を ROMA 全体に通知 </li></ul><ul><ul><li>新しく参加したノードが主導で、環情報を更新 </li></ul></ul><ul><ul><li>環全体にじわじわと情報が伝わっていく </li></ul></ul>
  17. 17. 障害ノードの切り離し <ul><li>どのようにノードの障害を検知するか? </li></ul><ul><li>ノード障害が検知できれば、そのノードを切り離して環情報の更新をすればよい </li></ul>ROMA 障害ノード
  18. 18. ノードの障害検知 (1/2) <ul><li>ハートビートを左右のノードに飛ばして、生存確認 </li></ul><ul><ul><li>( デフォルトで ) 3 秒間隔 </li></ul></ul><ul><ul><li>左右のノードのみ </li></ul></ul><ul><ul><ul><li>左右のノードとは、コネクションを張りっぱなし </li></ul></ul></ul><ul><li>左右が障害と判断したら、真ん中のノードは障害ノード </li></ul><ul><ul><li>現在、ノードの負荷状況によっては誤検知がある </li></ul></ul><ul><ul><ul><li>例 : GC が動作しており、定期的なハートビートが送れない </li></ul></ul></ul>ROMA
  19. 19. ノードの障害検知 (2/2) <ul><li>左右のノードへのデータの PUT/GET による障害検知 </li></ul><ul><ul><li>① ダウンした担当ノードにデータの PUT を依頼 </li></ul></ul><ul><ul><li>② データの PUT に失敗 </li></ul></ul><ul><ul><li>③ 右隣がマスターとなっていると考え、右隣にデータに PUT を依頼 </li></ul></ul><ul><ul><li>しかし、右隣のノードがセカンダリーのままだと、 </li></ul></ul><ul><ul><li>④ 右セカンダリーはクライアントに ダーティフラグ付き のデータを返し、ダウン検知開始 </li></ul></ul>セカンダリー 担当ノード セカンダリー ① ② ③
  20. 20. 障害ノードの切り離し <ul><li>切り離しを行った後は、データの冗長度 2 </li></ul>LS P LS P RS LS P RS P RS LS P RS LS RS 離脱ノード 離脱ノード 冗長度 2 冗長度 2 ROMA
  21. 21. 永続化 <ul><li>デフォルトでは、 redo log と snapshot の構成 </li></ul><ul><ul><li>クエリを redo log ファイルに書き込む </li></ul></ul><ul><ul><li>定期的に redo log を snapshot へ </li></ul></ul><ul><li>Tokyo Cabinet に格納できたら </li></ul><ul><ul><li>Tokyo Cabinet は速いから </li></ul></ul>ROMA (key-value store) データ データ データ データ データ データ
  22. 22. まとめ <ul><li>ROMA </li></ul><ul><ul><li>複数マシンから構成されるオンメモリストレージ </li></ul></ul><ul><ul><li>P2P を利用した key-value store の Ruby 実装 </li></ul></ul><ul><li>アーキテクチャ </li></ul><ul><ul><li>P2P の環状モデル </li></ul></ul><ul><ul><li>レプリカの一貫性をある程度意識したモデル </li></ul></ul><ul><li>今後の展開 </li></ul><ul><ul><li>拡張ライブラリによるパフォーマンス・チューニング </li></ul></ul><ul><ul><li>モデルを改変しやすくできるフレームワーク化 </li></ul></ul>

×