読者です 読者をやめる 読者になる 読者になる

ローグウェーブソフトウェアのブログ

開発をシンプルに 安全で高品質のコードを 素早くお客様のもとへ

ActiveMQのデスティネーションポリシー: AbortかAckAbortか - CodeBuzzから

OpenLogic 記事紹介

ローグウェーブ OpenLogicサービスのサポートアーキテクト Justin がApache ActiveMQの2つのポリシーについて解説しているのでご紹介します。ActiveMQは私たちに寄せられる質問の多さでは4番目にランクインします(上からApache httpdTomcatWildfly/JBossActiveMQCentOSこちらのスライドを参照)。

f:id:RWSJapan:20160720172437p:plain

ActiveMQのデスティネーションポリシー: AbortかAckAbortか

blog.klocwork.com

ActiveMQが遅いコンシューマ(Consumers、消費者)の接続を強制的に切断する際に2種類のデスティネーションポリシーがあります。AbortSlowConsumerStrategy とAbortSlowAckConsumerStrategyの2つがそれで、あるコンシューマが別のコンシューマの処理を遅らせていたり、バックログのメッセージがブローカーを遅くしている時などに確固とした解決方法を提供します。

この2つがもとにしているメカニズムはドキュメントが不十分ということもあり、あまり正しく理解されていません。しかしお使いのメッセージングシステムでどちらを採用するべきなのかを判断するためには、この2つの方法がそれぞれどのように遅いコンシューマを検出するのかを知っておくことが大切です。

AbortSlowConsumerStrategy はコンシューマのプリフェッチバッファを見てそのコンシューマが遅いのかどうか、クライアントとの接続を切断したほうがよいのかを判断します。この時注意すべきは、チェックする際にはプリフェッチバッファの実際の内容を見るのではなく、メッセージの個数が変わったかどうかだけで判断する、ということです。このチェックを定期的に、デフォルトでは30秒ごとに行います。

ということは、もしプリフェッチバッファのサイズを1に設定したとして(複数のコンシューマが永続的メッセージを扱うなら多くの場合はこの値がベストです)、このチェックを行ってもコンシューマの実際の状態を正しく判断できないということになります。というのも、もしメッセージシステムが定常的にプリフェッチにメッセージを送信し(これは適切に設定されたメッセージングシステムの正しい挙動です)、毎回チェックが実行された場合、プリフェッチ内にメッセージが1つ存在することになりますが、AbortSlowConsumerStrategy はコンシューマが遅延しているかどうかをバッファ内のメッセージの数の変化だけで判断しているため、遅延が発生していると誤って判断してしまい(いわゆる擬陽性、false positiveの判断)を引き起こし、そのコンシューマはアボートされてしまうでしょう。仮にプリフェッチバッファのサイズをより大きくとったとしても(デフォルトは1000)、負荷が高くなるとメッセージサイズはすぐに1000に達し、結局同様の擬陽性が生じてしまうのです。

試してみましょう

Logging Interceptorをオンにして、logAllをtrueにしてください。そしてdestination policyをAbortSlowConsumerStrategy に設定します。

<destinationPolicy>
    <policyMap>
      <policyEntries>
        <policyEntry queue=">" >
          <slowConsumerStrategy>
            <abortSlowConsumerStrategy />
          </slowConsumerStrategy>
        </policyEntry>
      </policyEntries>
    </policyMap>
  </destinationPolicy>

高頻度の負荷をかけ、遅いコンシューマがどのように追い出されるのかログを見てみましょう。30秒ごとにコンシューマのコネクションが「遅い」とマークされて終了するのがわかるでしょうか。せっかくなのでついでにこのポリシーのパラメータcheckPeriodを無理やり低い値、5msくらいに落としてみましょう。サンプリングレートが短いので、チェックは非常に正確になります。

この不整合は既にコミュニティにJIRA AMQ-6231としてレポートされています。コミュニティは修正ではなく回避策(workaround)を提案しています。その回避策こそAbortSlowAckConsumerStrategyです。なお、AbortSlowAckConsumerStrategy はActiveMQのバージョン5.9で初めて導入されました。もし古いバージョンをまだ使っているのであれば、上記のcheckPeriod が唯一の回避策になります。その場合チェックが頻繁になるためより多くのCPUリソースを消費してしまいます。そのため、もし5.9以前のバージョンを使っているのであればアップグレードが最善策です。

AbortSlowAckConsumerStrategyについて

その名の通り、AbortSlowAckConsumerStrategyはより正確なチェック方法としてコンシューマがブローカーへメッセージの受信通知を返すまでにかかった時間を使います。多くの場合こちらのやり方のほうがはるかに正確です。AbortSlowConsumerStrategyをオンにするのは先ほどのやりかたと同様です。

<destinationPolicy>
    <policyMap>
      <policyEntries>
        <policyEntry queue=">" >
          <slowConsumerStrategy>
            <abortSlowAckConsumerStrategy />
          </slowConsumerStrategy>
        </policyEntry>
      </policyEntries>
    </policyMap>
  </destinationPolicy>

このプラグインには多くのオプションがあります。

  • maxTimeSinceLastAck - デフォルトは30000で、最後のメッセージ通知が送られてからコンシューマが遅くなっていると判定されるまでの時間
  • ignoreIdleConsumers - デフォルトはtrueで、遅くなっているかどうかのチェックを、ディスパッチされたメッセージを所有していないコンシューマにも適用するかどうかを指定
  • maxSlowCount - デフォルトは-1(つまり無限)。コネクションを切断する前にコンシューマが遅くなっていると判定されるかどうか
  • maxSlowDuration - コンシューマがコネクションをアボートするまえに遅くなっていると判定されるまでの最大時間
  • checkPeriod - デフォルト30000。コンシューマが遅くなっているかどうかをチェックするサンプリングレート
  • abortConnection - デフォルトはfalse、ブローカーが切断する際にコンシューマにメッセージを送って礼儀正しく可否を問うもの。TCPコネクションなら単に切断

このうち重要なものがいくつかあります。まず、ignoreIdleConsumers はいかなるメッセージもディスパッチされていないコンシューマがチェックを免れるかどうかを決めるパラメータです。長時間アイドル状態にあるシステムならそのような指定をお望みでしょう。

abortConnection パラメータも同様に理解できます。ブローカーが切断のリクエストをコンシューマに送りますが、もしそのコンシューマがハングしてレスポンスできなかったらどうでしょうか?もしコンシューマがロック問題に陥りやすいならこの値をtrueにして積極的にコネクションを切断してみましょう。

遅いコンシューマは終了させるのが一番よい方法ですし、こうしたディスパッチのポリシーはメッセージングシステムのスループットを最適化し、クライアントをフォルトトレランスにするためにとても役に立ちます。そうは言っても、多くの場合オリジナルのAbortSlowConsumerStrategy は単純に不正確で有害です。したがって、ActiveMQ 5.9以上を使用しているのならAbortSlowAckConsumerStrategy を使うべきです。もしアップグレードできないのならAbortSlowConsumerStrategyでパラメータcheckPeriod を適切な値に設定してください。

Justin Reock

編集後記

いかがだったでしょうか、技術的にやや詳細な話になりましたが、システムを運用する際には不具合や脆弱性対策だけでなく、よりよいパフォーマンスのための細かい設定や背後の技術に対する理解が不可欠です。そうした情報を自前で調達するのか、ローグウェーブのOpenLogicサービスのような外部の専門家にアウトソーシングするのがよいのか、考える材料になれば幸いです。

roguewave.jp

ところで、上記のJIRA AMQ-6231を見ると、レポートしているのは執筆者Justin本人です。ActiveMQのコミッタとのやりとりも含め、OSS活動の息遣いが伝わって興味深いです。

ローグウェーブ セールスエンジニア 柄澤(からさわ)