More Related Content Similar to ツイートID生成とツイッターリアルタイム検索システムの話 Similar to ツイートID生成とツイッターリアルタイム検索システムの話 (20) More from Preferred Networks More from Preferred Networks (20) ツイートID生成とツイッターリアルタイム検索システムの話2. 自己紹介
l 岩田 英一郎 (@eiichiroi)
l 元さいたまな人
l 経歴
l 2009年6月∼ アルバイト
l 2010年3月 埼玉大学 大学院理工学研究科 修了
l 2010年8月∼ PFI入社
l 所属
l 製品開発部
l Sedueプロジェクト
l 仕事
l Sedue(検索エンジン)の開発
l コア∼運用ツールを幅広く
l 研究開発成果の取り込み
2
3. 本日の内容
l ツイートID生成システムSnowflakeの解説
l ツイートIDの構造と生成方法
l リアルタイム検索システムEarlybirdの解説
l 5億ツイート/日(約6000ツイート/秒)で増え続けるツイートを即時
に検索できるシステム
l アーキテクチャの概要
l インデックスの構成
3
8. ツイートID生成システムSnowflakeとは
l ユニークなIDを生成するネットワークサービス
l ツイッターのツイートID(ステータスID)の割り当てに使われている
l ツイッター社がOSSで公開中 (*)
l 特徴
l 64 bitのIDを生成
l ざっくり時刻順
l 速い
l 10000 ID/秒 のスピードでIDを生成できる(1プロセスあたり)
l レスポンス 2 ms (+ネットワークのレイテンシ)
l スケールする
l 複数のマシン・プロセスで協調動作しない
l 並べただけスケールする(はず)
(*) https://github.com/twitter/snowflake 8
9. Snowflakeが開発されるまで
l ツイートの流速増加とツイッターのシステム移行
l 5億ツイート/日(約6000ツイート/秒) (*1)
l 2012年10月時点
l MySQLからCassandraやGizzard(Sharded MySQL)への移行
l CassandraがID生成をデフォルトで提供していない
l ステータスIDの変遷 (*2, *3, *4)
l 2006年5月∼: 符号付き32bit
l 2009年6月∼: 符号無し32bit
l 2009年9月∼: 64bit
l 2010年11月∼: 64bit(現状のsnowflake)
l 要求
l スケールする(分散できる)
(*1) Report: Twitter hits half a billion tweets a day
(*2) Twitpocalypse - TwitterメッセージIDの64ビット科- いよいよ明日に実施
9
(*3) Status IDs are changing on 21st September
(*4) Announcing Snowflake
10. 生成するIDの構造
41bit 10bit 12bit
時刻 マシンID 連番
l 64bitを3つのブロックに分割
l 時刻(41bit、69年分)
l (おそらく)snowflakeの運用開始時刻からの経過時間(ミリ秒)
l 2010年11月4日...(epoch: 1288834974657)が基点
l マシンID(10bit、1024台分)
l データセンターID(上位5bit)、ワーカーID(下位5bit)
l 起動時にZookeeperか設定ファイルから取得
l 連番(12bit、4096個)
l 同時刻・同マシンでのID重複回避用、ワーカー別
l 参考: バルス砲 25088 ツイート/秒
10
11. ツイートIDのデコード(デモ)
l ツイートID = 279622981959970816
l 時刻 = 1355502288700 (2012-12-15 01:24:48 +0900)
l マシンID = 39
l データセンタID = 1
l ワーカーID = 7
l 連番 = 0
11
13. 生成するIDの特徴 - k-sorted
l 系列α = (a1, ..., an) が k-sorted であるとは、
l 全ての 1 ≦ i, j ≦ n に対して、 i < j-k ならば ai ≦ aj
k
l 概要
a1 ... ai ... ai-k+1 ... an
l 0-sortedは普通のソートと等価
l 距離 k 以内の要素間での順序は不問
l 例: (2, 1, 3)は1-sorted
l k-sortedの性質 (*1, *2)
l 系列αとkが与えられたときに、k-soterdかどうかはO(n)で判定可能
l 系列αが与えられたときに、最も小さいkの値をO(n)で計算可能
l 2つのk-sorted系列が与えられたときに、それらをマージした1つの
k-sorted系列をO(n)で計算可能
l 系列αをk-sortedを満たすようにするには、O(n log k)で計算可能
(*1) Roughly Sorting: A Generalization of Sorting
13
(*2) Roughly Sorting: Sequential and Parallel Approach
14. 生成するIDの特徴 - k-sortedのkの値
41bit 10bit 12bit
時刻 マシンID 連番
l 複数のマシンで完全に同じ時刻を参照できたと仮定すると...
l 222 -sorted: 22bit = 10bit(マシンID)+12bit(連番)
l 精度: 1ミリ秒
l 232-sorted: 32bit = 約10bit(時刻)+10bit(マシンID)+12bit(連番)
l 精度: 1秒
l 実際にはマシンID、連番が疎なので k はそこまで大きくないはず
l 3000 ツイート/秒なら、連番は3くらい
l NTPの精度はミリ秒単位 (*)
l 現実的にはこちらの方が精度のネックになりそう
l kの値自体にあまり意味はないはず
14
(*) http://www2.nict.go.jp/aeri/sts/tsp/PubNtp/qa.html#q2-2
15. その他
l マシンIDや連番の実際の値 (*)
l データセンターIDは1
l ワーカーIDは0∼4
l 連番は0∼2
l モノトニックタイム
l 設定で変更できない単調増加な時刻
l linuxではclock_gettime()などで取得可能
l 時刻が巻き戻ると厄介
l IDの一意性を保証するのが面倒になる
l snowflakeでは巻き戻りが発生したときはエラー
l 最後にIDを生成した時刻を記憶しておくだけ
(*) はてな匿名ダイアリー snowflakeの実際
15
16. ツイートID生成システムSnowflakeとは(再掲)
l ユニークなIDを生成するネットワークサービス
l ツイッターのツイートID(ステータスID)の割り当てに使われている
l ツイッター社がOSSで公開中 (*)
l 特徴
l 64 bitのIDを生成
l ざっくり時刻順
l 速い
l 10000 ID/秒 のスピードでIDを生成できる(1プロセスあたり)
l レスポンス 2 ms (+ネットワークのレイテンシ)
l スケールする
l 複数のマシン・プロセスで協調動作しない
l 並べただけスケールする(はず)
(*) https://github.com/twitter/snowflake 16
17. リアルタイム検索システムEarlybirdの概要
l ツイッターリアルタイム検索エンジン
l Java製
l オープンソースの全文検索ライブラリLuceneを魔改造
l 転置インデックス
l クエリ言語(Boolean query)
l AND/OR/NOT
l フレーズクエリ
l ワイルドカードクエリは未対応
l 2010年10月にMySQLベースの検索システムから移行
l 出典
l Earlybird: Real-Time Search at Twitter, ICDE 2012
l Michael Busch, Krishna Gade, Brian Larson, Patrick Lok,
Samuel Luckenbill, and Jimmy Lin
17
18. Earlybirdの性能の実績値
l ツイートの登録速度
l 3000 ツイート/秒 (2012年10月時点で6000 ツイート/秒)
l ツイート登録後すぐに検索可能に
l ∼10秒以内
l ※検索対象は6∼9日以内のツイートのみ
l 検索性能
l 低レイテンシ(平均50 ms)
l 高スループット(20億件/日 ≒ 2300qps)
18
19. Earlybirdのアーキテクチャ •
•
ツイートのトークナイズ
メタ情報(言語など)を付与
• 動的更新の通知
• リツイート数の更新
• お気に入りの更新
• ...
• 登録先のツイート
• ハッシュでパーティション
• ハッシュの方式は不明
• ツイートの検索
• クエリのパース
• ランキング
• 複数のEarlybirdへ問い合わせ
• リツイート数
• Userのローカルソーシャルグラフを渡す
• お気に入り数
• 問い合わせ結果のマージ
• ...
• Userのローカルソーシャルグラフ 19
20. • 更新するインデックスを限定
Earlybirdの構成 • 1億件/台
• 12インデックス/台
• マシンスペック
Earlybird • クアッドコア2つ
• RAM 72GB
• 64GBをJVMのヒープに割当
...
Optimized Index(11個) Active Index(1個)
• 検索(読込)専用 • 検索(読込)+文書登録(書込)
• 224 ≒ 1600万件/インデックス • 更新が速いデータ構造
• 圧縮(圧縮率55%程度) • 一杯になったら裏で最適化
• 1600万件で3.7GB程度 • 1600万件で6.7GB程度
20
21. 辞書の構成(1/2)
l 辞書
l 単語とPosting List(その単語を含む文書IDのリスト)を紐付ける
l 自作ハッシュテーブルで実装
l オープンアドレス法をArrayで実装
l Java標準のHashMapはGCと相性が悪い
l チェーンで繋いだオブジェクト達の寿命が長い
l 辞書に含める情報
l (0) 単語ID
l (1) その単語のPosting Listの長さ
l (2) その単語のPosting Listの末尾へのポインタ
l ※それぞれ別々の配列で管理(詳細は次スライド)
l 単語IDを配列のインデックスとしてアクセスする
l 速度とメモリ効率を上げるため(Java...)
21
22. 辞書の構成(2/2)
辞書
自作ハッシュテーブル
単語の数
単語 単語ID
0 1 ...
pfiseminar 0
(1) Posting Listの長さ 4 77 ...
なう 1
(2) 末尾へのポインタ ...
:
:
転置インデックス
4
「pfiseminar」に対応するPosting List ... ... ... ...
77
「なう」に対応するPosting List ... ...
:
:
22
23. Active Index
l 要求
l 文書登録(書込)処理が高速 (全サーバで6000ツイート/秒)
l 検索(読込)処理も並列処理
l 時刻降順に検索したい (とにかく最近の情報が重要)
l 特徴
l (1) Posting Listは文書ID昇順
l (2) Postingは32bit整数
l (3) Posting Listのメモリはまとめて確保
l 削除の対応方法は不明
l 削除フラグを持ってフィルタリングしているとか?
23
24. Active Index - (1) Posting Listは文書ID昇順
l 利点
l 文書登録時には、Posting Listの末尾に追加するだけ
文書ID: 15
pfiseminar 2 7 11 15 pfiseminar
なう
l 検索時には、Posting Listの末尾から逆順に るだけ
pfiseminar 2 7 11 15 pfiseminar
l 欠点
l Posting Listの差分圧縮と相性が悪い
l 検索時にPosting Listを逆順に れる差分圧縮は複雑
‒ ブロックベースのPForDelataとか
l 文書登録のレイテンシが増加
l Active IndexでのPosting List圧縮は諦め
24
25. Active Index - (2) Postingは32bit整数
※ビットレイアウトは違うかも
8bit 24bit
単語位置 文書ID
l 文書ID(24bit)
l 1インデックス辺り224(≒ 1600万)件が上限
l 単語位置(8bit)
l 140文字なので8bitで十分
l 1件にある単語が複数回出現するときは、別のPostingとして扱う
l 利点
l コンパクト
l Posting Listが整数配列になり、メモリの事前割り当てが容易
l ブロック単位でまとめて割り当てちゃう
l キャッシュにも優しい
25
26. Active Index - (3) Posting Listのメモリはまとめて
pool 3
pool 2
pool 1
pool 0
l 4種類のpool
l 1poolあたり215 posting(必要に応じて拡張)、複数のsliceからなる
l sliceのサイズが異なる(21, 24, 27, 211)
l sliceを繋げて長いPosting Listを実現
l sliceのサイズが小さい方から、slice単位で順に割り当てて行く
l sliceの最初の要素は、前のsliceの末尾へのポインタ(32bit)
l 文書集合中の単語の分布はジップの法則でモデル化している
l 長いPosting Listが少数、短いPosting Listが多数
l 工夫しないとメモリ効率が悪く速度が遅くなってしまう
26
l この実装では、Posting Listの拡張時にメモリコピーが発生しない
27. Active Index - (3) Posting Listのメモリはまとめて
※ビットレイアウトは違うかも
11bit 19bit 2bit
pool 3 offset in slice slice index 11
7bit 23bit 2bit
pool 2 offset in slice slice index 10
4bit 26bit 2bit
pool 1 offset slice index 01
1bit 29bit 2bit
pool 0 o slice index 00
pool index
l sliceのポインタ
27
l 32bitでpostingと同じサイズ
28. Optimized Index
l 要求
l 検索(読込)処理のみ
l 文書登録(書込)処理は受け付けない
l 特徴
l Active Indexが一杯(223件)になったら裏でOptimized Indexを構築
l Optimized Index構築後、スワップ(古いインデックスは削除)
l 短いPosting Listは時刻降順にソート
l 検索時には先頭から順方向に る
l 長いPosting List(長さ1000以上)はブロック単位で圧縮
l PForDeltaやSimple9と似たような感じ
l Active Indexの55%くらいのメモリ使用量
l 1600万件6.7GBが3.7GB程度に
28
29. Optimized Index - 長いPosting Listの圧縮
4byte 4byte 248byte 4byte 4byte
posting header (文書IDの差分, 単語位置)の組n個を圧縮したもの posting header ...
256byte/block
l 時刻降順のPosting Listを適当に区切ってブロック単位で圧縮
l 固定長ブロック256byteを複数並べたもの
l 先頭4byte: ブロックのスキップ用
l ブロック先頭の生posting1つ
l 次の4byte: ブロックのヘッダ(解凍時に必要)
l 圧縮されている文書数 n
l 圧縮のビット幅 b = ceil(max(gap)) + ceil(max(pos))
‒ n * (ceil(max(gap)) + ceil(max(pos))) <= 1984(= 248*8)
l 残り248byte: 圧縮
l n個の(文書IDの差分, 単語位置)の組を圧縮したもの
29
30. まとめ
l ツイートID生成システムSnowflakeの解説
l ツイートID構造と生成方法
l ざっくり時刻順、速い、スケール
l リアルタイム検索システムEarlybirdの解説
l 5億ツイート/日(約6000ツイート/秒)で増え続けるツイートを即時
に検索できるシステム
l アーキテクチャの概要
l インデックスの構成
l Active Index
l Optimized Index
30