kestrelのfanout-queuesについて
前回のエントリ
kestrelの作者さんによるkestrelの紹介 - na
の続きです。kestrelの作者さんによるfanout-queuesの解説です。Twitterのいわゆるファンアウト処理の根幹となる機能の説明になります。
前回紹介した記事の11ヵ月後の記事で、kestrel 1.2の話になります。kestrelのバージョンは現在1.2.2なので、そんなに古い内容ではありません。new featureとして紹介しているので、以前はない機能だったはずです。
1.2の新機能として以下のものを紹介しています。
- 起動時、ポートをlistenする前にキューファイルをロードするようにしたよ。*1
- "open"オプションによるトランザクションを、"abort"オプションによって明示的にロールバックできるようにしたよ。
- "peek"オプションでキューの先頭から1件取得だけするようにしたよ。
- max_item_sizeとsync_journalというオプションを追加したよ。*2
- DELETEコマンドでキューが削除できるようにした。ジャーナルからも完全に消すから戻せないよ。*3
- バグ直したよ。
- いい感じにドキュメントを書いたよ。http://github.com/robey/kestrel/blob/master/docs/guide.md
以下、fanout-queuesについて和訳します。
ファンアウトキュー
ファンアウトキューは階層関係を持った「親」のキューになります。「親」のキューに項目が追加されると、同じ項目が自動的にすべての「子」のキューにも追加されます。子キューはそれぞれのジャーナルファイルを持った、独立したキューです。ある1つの子キューからキュー項目が削除されても、それはほかの子キュー(兄弟たち)からは削除されません。各子キューに別々の項目を追加することだって可能です。ただファンアウトキューのポイントは、親に追加した項目がすべての子に自動的に追加されることです。
子キューは、キューの名前に"+"が含まれていると自動的に作成されます。たとえば"orders+audit"という名前のキューを作れば、それは"orders"という名前のキューの子になります。子キューが作られると、すぐに新しいキュー項目を受け取るようになります。ただし、既に親キューが持っているキュー項目がコピーされることはありません。このファンアウト処理は子キューがDELETEされるまで続きます。
各子キューは親キューと同じ設定を持ちます。子キュー独自の設定はありません。
子キューが増えると、ファンアウト処理によってキュー項目がたくさんコピーされるため、余分にメモリとディスクを消費します。
シンプルな実装になっているので、変なトリックを使っているよりもきっと分かりやすいと思います。
以上です。
せっかくだから実際にやってみましょう。まずは以下のコマンドでkestrelを起動しておきます。ビルドとか起動の方法については以前のエントリ id:hito_asa:20101014 を参照してみてください。
java -jar kestrel-1.2.2.jar
別のターミナルを開いて、telnetでkestrelに接続します。
telnet localhost 22133
まずは以下のように"orders"というキューにa,bという2つの値を入れてみます。
その後にdump_statsコマンドで"orders"キューの状態を確認してみます。
set orders 0 0 1 <= 入力 a <= 入力 STORED set orders 0 0 1 <= 入力 b <= 入力 STORED dump_stats <= 入力 queue 'orders' { items=2 bytes=2 total_items=2 logsize=44 expired_items=0 mem_items=2 mem_bytes=2 age=0 discarded=0 waiters=0 open_transactions=0 } END
続けて以下のように"orders+audit"というキューにpeekコマンドを送ります。peekでもgetでもなんでもいいんですが、一度参照されるとキューが作成されます。
再びdump_statsコマンドで"orders+audit"というキューが作成されたことを確認してみます。
get orders+audit/peek <= 入力 END dump_stats <= 入力 queue 'orders+audit' { items=0 bytes=0 total_items=0 logsize=0 expired_items=0 mem_items=0 mem_bytes=0 age=0 discarded=0 waiters=0 open_transactions=0 } queue 'orders' { items=2 bytes=2 total_items=2 logsize=44 expired_items=0 mem_items=2 mem_bytes=2 age=0 discarded=0 waiters=0 open_transactions=0 children=orders+audit } END
orders+auditという名前の空のキューが出来たのがわかると思います。
また、ordersのほうの一番下に"children=orders+audit"という値が増えています。これでキューの親子関係が作成されていることも分かります。
では、親の"orders"キューに項目を追加してみます。既に"a"と"b"が入っているので、"c"と"d"を入れてみます。
set orders 0 0 1 <= 入力 c <= 入力 STORED set orders 0 0 1 <= 入力 d <= 入力 STORED
ここで、dump_statsコマンドを実行して確認すると。
dump_stats <= 入力 queue 'orders+audit' { items=2 bytes=2 total_items=2 logsize=44 expired_items=0 mem_items=2 mem_bytes=2 age=0 discarded=0 waiters=0 open_transactions=0 } queue 'orders' { items=4 bytes=4 total_items=4 logsize=88 expired_items=0 mem_items=4 mem_bytes=4 age=0 discarded=0 waiters=0 open_transactions=0 children=orders+audit } END
"orders"のitemsは4になり、子キューである"orders+audit"のitemsも2になっています。親キューに入れたものが子キューにも入りました。あとは、適当にGETして内容を確認してみましょう。
get orders <= 入力 VALUE orders 0 1 a END get orders <= 入力 VALUE orders 0 1 b END get orders <= 入力 VALUE orders 0 1 c END get orders <= 入力 VALUE orders 0 1 d END get orders+audit VALUE orders+audit 0 1 c END get orders+audit VALUE orders+audit 0 1 d END
以上です。