本当は昨日書こうと思ってたが、忘年会だしその日の記事は忘れることにした。
RabbitMQ自体は基本的にメッセージを送って受け取るという簡単なもので、そんなに難しくない。
ただ実運用に載せるにあたってはRabbitMQ / AMQPにおける用語や概念を理解したり、調査したり、理解が出来たら次はその中からどの手段を使うか選んだりしないといけない。ここでは個人的に自分が理解に苦労したなーと思う用語の説明をまとめておこうと思う。
ラウンドロビン
まずラウンドロビンという言葉を知らなかったのは不勉強から来るものだったが、それがRabbitMQで何を意味するのかを理解するのに時間がかかった。単に「あるQueueに接続しているConsumerが複数あったらメッセージを持ってないConsumerから先にどんどんメッセージを突っ込む。」という程度の意味だ。
RabbitMQはpre-fetchといって一度にConsumerに渡すメッセージの個数・サイズを指定することが出来るが、送るメッセージの中身をRabbitMQ自身は知らないので*1渡したメッセージでConsumerの処理がどのくらい重くなるのかは渡してからでないと分からない。だから一度にあまりにたくさんのメッセージをConsumerに送りすぎると、その中のメッセージの処理の重さによっては他のConsumerが暇で一個のConsumerがやたら処理に時間がかかってしまったりする。それを避けたいならprefetch_count = 1
と設定してね、というのがWork QueuesのFair dispatchの概要だ。
メッセージサイズはConsumerに食わせるときにだけ問題になるのではなく
RabbitMQ » Blog Archive » RabbitMQ Performance Measurements, part 2 - Messaging that just works
にRabbitMQの性能について記載がある。
Exchange
Exchangeも地味に苦労した。ExchangeとはQueueにメッセージを送信するルールを決めているもので、11日めの記事で扱ったチュートリアルには出てこなかったが、Producerがメッセージを送る際、実際には直接Queueに送るのではなくてExchangeを通して送ることになる。このことはAMQPプロトコルの仕様上決まっている。RabbitMQで使えるExchangeのルールは種類がいくつかあってdirect
、fanout
、topic
、header
の4つがある。
詳しくは3.3.1 Exchangeの節(英語)を読んでもらうこととして簡単に書くと以下
direct
: あるExchangeとQueueを結びつける際にはbinding keyというもの(中身はただの文字列)を設定する。direct
が設定されたExchangeを通してメッセージを送ると、メッセージに付与されたrouting keyとbinding keyを比較して一致したQueueにメッセージを送る。fanout
: あるExchangeは複数のQueueと結びつけることが出来る。fanout
が設定されたExchangeを通してメッセージを送ると、routing keyもbinding keyも無視して、結びついているQueue全部に同じメッセージを送る。topic
:topic
が設定されたExchangeにメッセージを送るとメッセージに付与されたrouting keyとbinding keyが部分一致するQueueに対してメッセージを送る。header
: routing keyは見ず、メッセージを送る際に付与されたリクエストヘッダーを読み込み、メッセージを送るべきQueueを決定する。
ConnectionとChannelの違い
ConnectionとChannelの違いが最初は分からなかった。ぶっちゃけライブラリを使うだけだと「どっちも接続してるやろ」としか思えないが、要するにConnectionというのは物理的にRabbitMQとアプリケーション間のコネクションを張ることを言ってて、Channelは確立されたConnctionの中で「まるで複数のTCP / IPコネクションが張られたかのように見せる」ためのもの、と分かった。なので、Connectionを通してExchangeやQueueを宣言するのではなく、Channnelを通してExchangeやQueueを宣言する。
ドキュメントが見つからないこともありました
ていうか一番ショックがでかかったのは見つからないどころかドキュメントのリンクが死んだことだった。
これな↓
以下のtweetはまだ実践してない。
なるほど。いくつかのクラスで思い当たるものがある。全部はさすがに無理だけど、気付いたものからやってみようかな。 / “ドキュメントの場所を知らせるために、落ちるテストを作る - $shibayu36->blog;” http://t.co/tFz8bmLodH
— きみー (@kimikimi714) 2014, 4月 13
その他のこと
割と致命的だったよなと思うのが「AMQPというプロトコルでしゃべる」という先輩の言葉の使い方を理解できてなかったことで、「『プロトコルでしゃべる』って何だよ。言葉なの?プログラミング言語でもしゃべるとは言わないのに、どういうことなの」と思いながら聞いてた。意味は「AMQPという通信手段で通信を行う」ことを「AMQPというプロトコルでしゃべる」と表現していた。なんでしゃべるっていうのかは知らない。まぁでも英語のドキュメントとか見ると確かに「(何かのアプリケーション) speaks (何かのプロトコル)」という表現があるので、ただの直訳なんだと思う。
参考リンク
先人たちの知恵はすごい。巨人の肩の上に立つ。
- RabbitMQ - Messaging that just works
- RabbitMQ - AMQP 0-9-1 Complete Reference Guide
- Home | AMQP
- pdezwart/php-amqp · GitHub
- 卜部昌平のあまりreblogしないtumblr - RabbitMQ と再送について
- RabbitMQ調べた - new takyam();
- RabbitMQ Tutorial - "Work Queues" を翻訳してみた|Na-ga Tech
- AMQPによるメッセージング | GREE Engineers' Blog
- RabbitMQ に流れる全メッセージを JSON でダンプしてみる | CUBE SUGAR STORAGE
これだけのことをまるで全部自分が調べたかのように書いたが、最初の方は結構先輩たちに「すみません!分からないんで教えてください!!」と聞いて回った。いやがられても粘ることは大事だと思う。Google先生が使えるのは調べ方の当てが既にあるときだけだし。
*1:メッセージの中身は見ようと思えば見ることが可能である。だがキューという性質上「○番目のメッセージを見たい」という選択は不可能で、「次に渡そうとしているメッセージから○個分全部」という指定しか出来ない。なのでメッセージを渡す段階までこない限り、メッセージの処理がどのくらいConsumerにとって重いものなのかは分からない。まぁ「そんな重いメッセージ初めから乗せんな!」って話ではある。