RabbitMQはSidekiqと同等以上だと思う: 後編(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

原文が長いため、3本に分割します。

RabbitMQはSidekiqと同等以上だと思う: 後編(翻訳)

特殊な機能

RabbitMQは、AMQPにさらなるマジックを加えてくれます。header exchangeの項でも述べたように、これはAMQPの標準にはない機能です。私が個人的に多用しているのはdirect reply-toです。direct reply-toは、プロデューサー(producer)とコンシューマーの間の同期的コミュニケーションのひとつの形態です。これによってプロデューサーがメッセージをパブリッシュしてコンシューマーの処理完了を待ち、結果を直接プロデューサーに返すことができるので、メッセージの処理結果をさらに処理する場合に便利です。たとえば、IoTデバイスではハートビート信号をサーバーにログ出力することで、接続中であることと正しく設定されていることを示し、スマートロックがかかっている場合にIoTデバイスのハートビートを非同期に処理できます。というのも、結果そのものはサーバーにとってもデバイスにとっても実際には重要ではないからです。しかしpingチェックは重要であり、データが古くなったことによるアクセス権エラーの発生を回避するために同期的に扱われる必要があります。

direct reply-toメッセージが使われている様子

他に私がよく使う機能にdead letteringというものもあります。これは、メッセージがexchangeやキューで拒否された場合に自動で再キューイングするものです。この機能は、エラーハンドリングや指数的バックオフ(exponential back-off)、スケジューリングされたメッセージ処理などで便利です。

訳注: dead letterは「配達不能郵便」の他に「空文、死文」という意味もあります。

dead letterキューが使われている様子

Alternate exchangeは、サービスの廃止処理(deprecation)を進めるのに便利です。これは、メインのexchangeがメッセージの受け取りを拒否した場合のメッセージ送信先となるexchangeを指定します

alternate exchangeが使われている様子

他にpriority queuespriority consumersという機能もあります。priority queueはコンピュータサイエンスで標準の「優先度付きキュー」のことで、キューに0から255までの優先度を与えて、優先度の高いメッセージから先に処理を開始するというものです。これは前述のdirect reply-toと同じ理由で便利ですが、direct reply-toは非同期です。一方priorityコンシューマーはフェイルオーバー形式です。priorityコンシューマーは、自分がアクティブな場合にメッセージを扱います。priorityコンシューマーがすべてアクティブでなくなると、それ以外のコンシューマーがメッセージを扱うようになります。

最後はTTLです。これはメッセージの生存期間(time to live)を指定するもので、メッセージの生存期間がTTL値を超えると自動的にキューで拒否されるようになります。ただしこの機能には1つ注意点があります。このルールを強制できるのは、メッセージがキューの先頭にある場合に限られます。たとえば、当初キューに2件のメッセージがあり、1件目のメッセージのTTLが300で2件目のメッセージのTTLが100だとしましょう。TTL=300の期限が切れるまでは、1件目のメッセージはキューの先頭にあり、どちらのメッセージもキュー上にあります。(1件目のTTL=300のメッセージの)期限が切れると、その瞬間2件目のメッセージが自動的にキューの先頭に移動し、それからその瞬間に自動的に期限切れになります(TTLを超えたので)。これは一見無害に見えますが、dead letteringによるアーカイブ化と組み合わせたときに(オフセット配信など)多数の問題が発生する可能性があります。

TTLメッセージにdead letteringを組み合わせた場合の様子

プラグイン

これは私にとってRabbitMQでもっとも重要な機能です。プラグインを用いてRabbitMQに欲しい機能を追加できます。その好例が管理コンソールで、これもプラグインであり、利用前に有効にして置かなければなりません。

RabbitMQはプラグインを用いることで、通信プロトコルとしてAMQPのみならずSTOMPMQTT、そしてWebSocketsをもサポートします。

その他に、相互通信可能な隔離されたクラスタやインスタンス上でRabbitMQを実行するフェデレーション(federation)プラグインもあります。しくみはMastodonのそれと似ていて、あらゆるユーザーは、どのサーバーにサインアップしたかにかかわらず、相互通信可能です。フェデレーションは莫大な負荷をさばく場合に便利です。たとえば、非常に多様なコンピュータから送信されるログをRabbitMQ経由で扱う場合、1つのフェデレーションクラスタ(federated cluster)はログを扱い、それ以外はすべて別のフェデレーションクラスタで扱うことができます。このように、クラスタの負荷に応じて2つのクラスタをそれぞれ独立にスケールすることができ、足手まといになる問題を回避できます(高負荷サービスに引きずられてシステム全体の速度が低下する場合)。

RabbitMQフェデレーションをIoTアプリに使った例

まとめ

SidekiqをRabbitMQに置き換えることで、デバッグのしやすさ、スケーリング、フォールトトレーランス、メモリ消費において多くのメリットを得られます。業界標準のメッセージキュープロトコルを多数サポートし、他の「バックグラウンドワーカー」ライブラリをまるっと置き換えるのに使えます。

ジョブ実行や永続性を保証したキューが必要であれば、Sidekiqの代わりにRabbitMQを使ってみましょう。cronジョブやunique jobのようにSidekiqにはあってもRabbitMQにまだない機能がありますが、クライアント側で追加は可能です。RabbitMQの提供する機能は過剰なぐらい多いので、最初は便利に思えなくても、将来モノリスがサービス指向アーキテクチャに成長するうえで役に立つようになるでしょう。

RabbitMQを始めるにあたり、まずはSneakers(バックグラウンドジョブ)やBunny(AMQPクライアント)をざっと眺め、基本コンセプトを読んで理解しておき、それからマニュアルを読みましょう。Ruby on Railsをお使いの方は、移行を楽にするSneakersとActiveJobを統合する方法をご覧ください。

Sidekiqももちろん優秀です!実行や永続性の保証が不要なプロジェクトや、既にSidekiq Proライセンスをお持ちの場合は、当面Sidekiqを使い続けることをおすすめします。私自身は、実行保証やローリング再起動といった機能が有料である点を残念に思いますが、Sidekiq Proライセンスを購入すれば、自力でホストしたRabbitMQインスタンスでは得られないサポートを得られ、さまざまな実ビジネス指向の機能も利用できるようになります

関連記事

Rails: RedisキャッシュとRackミドルウェアでパフォーマンスを改善(翻訳)

RailsのPostgreSQL上でマルチテナントのジョブキューシステムを独自構築する(翻訳)

デザインも頼めるシステム開発会社をお探しならBPS株式会社までどうぞ 開発エンジニア積極採用中です! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の半分ほど、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れてそれぞれ一部を翻訳。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好き。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

週刊Railsウォッチ

インフラ

ActiveSupport探訪シリーズ