イベント駆動型アプリケーションアーキテクチャをテストする: 非同期的アプローチ

この記事はBob Reselmanによるゲスト投稿です。

イベント駆動型アプリケーションアーキテクチャでは、さまざまなコンポーネントが非常に大規模な分散システム内で非同期的に通信し、連携します。イベント駆動型アーキテクチャは、一体となってシステムを構成するさまざまなサービスやコンポーネントを結合する接着剤です。

KafkaRabbitMQなどの一般的なメッセージブローカーを使用してコンポーネント間でメッセージを渡すことによって、コンポーネントが独立して大きなスケールで動作することが可能になります。イベント駆動型アーキテクチャをサポートするシステムでは、1秒間に2万件以上のメッセージを処理することも珍しくありません。

このようなスケールのテストを設計するには、テスト技術者がイベント駆動型アーキテクチャの動作をよく理解していなければなりません。この記事では、イベント駆動型アーキテクチャのさまざまなコンポーネントが大きなスケールで期待どおりに動いていることを確認するには、どのようにテストを設計すればよいかを説明します。

同期型アプリケーションとイベント駆動型アプリケーションの比較

イベント駆動型アプリケーションアーキテクチャの一般的なテスト方法を詳しく説明する前に、イベント駆動型アプリケーションアーキテクチャとは何かを理解しておくのがよいでしょう。

基本的に、イベント駆動型アプリケーションアーキテクチャとは、アプリケーション内のサービス(関数とも呼ばれます)が、メッセージキューに格納されるメッセージを通じてデータを入出力するアーキテクチャのことです。同期型アーキテクチャでは、直接的な呼び出しによってサービスに直接データが渡されるので、その点が異なります。

典型的な同期通信の例は、Webサーバーとの間の標準的なリクエスト-レスポンス通信です。呼び出し側は、Webサーバーにリクエストを出し、レスポンスを受信するまで待機します。レスポンスが返ってくるまで、呼び出し側は通信中のまま「ロック」されます。レスポンスは1ミリ秒で返ってくることも、数秒かかることもありますが、呼び出し側は通信が完了するまで何もできません。

次の図 1 は同期型通信を表しています。

図1: 同期トランザクション

次の図 2 はイベント駆動型アーキテクチャの概念を表しています。

図2: イベント駆動型非同期トランザクション

イベント駆動型アプリケーションアーキテクチャの利点は、処理の間でブロックされないことです。クライアントはレスポンスを待つ必要がありません。ただ、メッセージブローカーのあらかじめ定義されたソースでレスポンスをListenしていればいいだけです。

イベント駆動型アーキテクチャは、証券取引所での高速トレーディングなどのほか、ライドシェアアプリケーションにも適しています。たとえば、一連のHTTPリクエストとレスポンスによって携帯電話からライドシェアサーバーに車の位置を照会し続ける代わりに、クライアントアプリケーションはメッセージブローカー上のトピックに接続し、車が移動するに従って位置情報を含むメッセージを受信します。

イベント駆動型アーキテクチャには利点があるいっぽうで、テスト上の課題もあります。パフォーマンステストに関して言えば、単にリクエストとレスポンスのあいだの時間を計測するだけとはいきません。メッセージが送信された後、後続のメッセージがいつ利用可能になるかはわかりません。

また、ブローカーとの入出力が行われるネットワーク、ブローカーの効率性、イベントデータを処理するアルゴリズムの効率性、そしてイベントメッセージの構造さえもシステムのパフォーマンスに影響を与える可能性があります。多くの要因を考慮する必要があります。

それに加えて、イベント駆動型アプリケーションは、妥当な方法でテストする必要があるだけでなく、徹底的にテストする必要もあります。その出発点になるのがログ記録です。

ログ記録がすべて

有効なログ記録は、どんなアプリケーションアーキテクチャでも重要ですが、イベント駆動型アプリケーションアーキテクチャとなると、ログ記録が必須です。

覚えておくべきこととして、イベント駆動型アプリケーションアーキテクチャでは、メッセージはほぼ瞬時に送受信されます。さらに、多くの場合、順番は保証されていません。たとえば図3に示すように、メッセージA、B、Cの順でメッセージキューに送信されたとしても、プロセッサーはB、C、Aの順で処理済みのメッセージを送出するかもしれません。

図3: イベント駆動型アプリケーションアーキテクチャでは、メッセージの順序は必ずしも保証されていない

したがって、アプリケーションの動作という点で、実際に何が起こっているかを解明する唯一の方法は、アプリケーションのパフォーマンスに関連するすべての情報を確実にログに記録することであり、その際、タイムスタンプの取得は言うまでもなく必須です。

また、すべてのソースからログ情報を収集するため、ログ集約フレームワークも必要です。そのようなフレームワークの例として、FluentdLogstashが挙げられます。クラウドプロバイダーを利用している場合、Amazon CloudWatchまたはGoogle Cloud Stackdriverなどの製品があります。ログ収集が重要なだけでなく、収集した後にログの情報を解析し、参照する手段も必要です。そこで、KibanaSplunkGrafanaなどの製品を利用できます。

どこへ向かうにしても、イベント駆動型アプリケーションをテストしたときに生成されるデータを取得するには、包括的なログ記録によって情報をキャプチャし、集約フレームワークによって情報を収集する必要があることを覚えておくのが重要です。

ここで分散トレーシングが役に立ちます。

分散トレーシングは必須

イベント駆動型アプリケーションの非同期的な性質を考慮に入れると、特定のワークフローの論理的な実行パスを明確に把握するのは非常に困難です。

たとえば、下の図4は旅行予約システムのイベント駆動型アプリケーションアーキテクチャを示しています。さまざまなキューの間でメッセージがやりとりされ、航空券の取得、ホテルの部屋の予約、レンタカーの予約が行われます。サービス間でさまざまなメッセージが非同期的に生成されるいっぽう、航空券、ホテルの予約、レンタカーという旅行トランザクションを構成する論理的な流れがあります。

図4: 分散トレーシングにより、分散環境での一連のメッセージを明確に参照できる

それでも、任意のメッセージが任意のタイミングで発生するのであれば、やりとり全体で何が起こっているかを理解するには、どうしたらよいのでしょうか?そこで分散トレーシングの出番です。
分散トレーシングは、システム全体でトランザクションの完全なアクティビティパスをモニターするためのものです。トレーシングクライアントは、サービスをホストする演算リソースごとにインストールされます。クライアントがアクティビティをモニターして情報を送り返すと、特定のワークフローインスタンスとしてまとめられます。

トレーシングツールは、すべてをインスタンスベースで追跡する能力があります。最新のトレーシングツールは、たとえば数秒程度の短い実行時間でも、1週間単位の長い実行時間でも処理できます。

理解しておくべきことは、分散トレーシングツールを利用することで、テスト技術者は複数のイベントとメッセージが絡むトランザクションのメトリクスを収集できるということです。非同期環境での分散トレーシングをサポートする製品やプロジェクトは、WavefrontJaegerなど多数あります。

以前は、非同期通信はまさにブラックボックスだったことを考えれば、分散トレーシングは非常に重要です。現在では、分散トレーシングツールを利用して通信を可視化できます。エンタープライズレベルでテストを行うということになると、この機能が重要です。

そこで、どのようにイベント駆動型アプリケーションアーキテクチャをテストするかという点が問題になります。

テストピラミッドは依然として有効

同期型アプリケーションをテストする場合と、イベント駆動型アーキテクチャベースのアプリケーションをテストする場合の一番大きな違いは、通信の非同期的な性質を考慮する必要があるという点です。開発者は依然としてユニットテストを行う必要があります。統合テスト、パフォーマンステスト、デプロイメントテストも依然として行う必要があります。

非同期関数の単体テストを作成するには、従来とは異なるアプローチでテストを設計する必要があります。非同期環境では、メッセージへのレスポンスとして呼び出しが発生します。メッセージはメッセージキューにパブリッシュし、サービスがそれをプルして処理します。そして結果は、関係する他の処理のために別のキューにパブリッシュする必要があります。単に何らかのコードをメモリに投入し、関数を呼び出すだけでは済みません。1つのユニットテストを実行するのにも、メッセージングアーキテクチャ全体が機能している必要があります。

イベント駆動型アプリケーションアーキテクチャでは、開発者はより多くの作業を行わなければならなくなります。しかし、ユニットテスト環境の骨組みをセットアップするオートメーションプロセスを構築することで、この作業を軽減できます。プロセスを自動化したら、チームの開発者で共有し、それぞれのニーズに合わせることができます。

上位レベルのテストでも、メッセージング基盤のプロビジョニングにオートメーションを利用する必要があります。また、メッセージング基盤の一部として集約されたログと分散トレーシングが必要です。さもなければ、テスト技術者には作業の結果を観察し、測定する方法がありません。ログ記録とトレーシングは、アプリケーションモニタリングだけでなくシステムモニタリングの機能も備えている必要があります。先ほど述べたように、イベント駆動型アプリケーションアーキテクチャでは、何百万ものメッセージがほぼ瞬時にシステム内を動いています。不良ネットワークルーターや低速のディスクドライブが1つでもあれば、非効率的なデータ取得アルゴリズムと同様にアプリケーションのパフォーマンスに影響を与える可能性があります。

物理的環境が重要です。ハードウェアイベントは、集約されたログや分散トレーシングに反映されるアプリケーションイベントに関連付けられる必要があります。

結論

特に、アプリケーション内の1つのイベントがより幅広いサービスに消費されるようになるにつれて、イベント駆動型アプリケーションアーキテクチャはますます一般的になってきています。たとえば、Webページの1回のクリックで生成されたデータが、ヒートマップのレポートから購入を成功させるためのユーザープロファイル分析まで、特定の目的を持つさまざまなサービスによって消費される可能性があります。

イベント駆動型アプリケーションアーキテクチャには多大な力があります。いっぽうで、テスト技術者にとっては課題も生まれます。しかし、朗報として、そのような課題は十分認識されています。テスト駆動型アプリケーションのテストに成功している企業は、テスト駆動型パラダイムの非同期的な性質を理解しています。ユニットテストからシステムレベルでのパフォーマンステストに至るテストアクティビティのすべてのレベルに、集約されたログと分散トレーシングを織り込んでいます。

イベント駆動型アプリケーションが一般的になるにつれ、テスト技術者がサービス間の非同期通信をサポートするテスト技法を身に着ける必要が増していくでしょう。それは困難な仕事ですが、大きな困難に立ち向かうことですばらしいソフトウェアが生まれるのですから、やりがいのあることです。そしてすばらしいソフトウェアこそがすべてです。

Bob Reselmanは全国的に著名なソフトウェア開発者、システムアーキテクト、業界アナリスト、テクニカルライター/ジャーナリストです。コンピュータープログラミングに関する書籍のほか、ソフトウェア開発テクノロジーおよびテクニック、ソフトウェア開発カルチャーに関する記事を多数執筆。元Cap GeminiのPrincipal ConsultantおよびコンピューターメーカーGatewayのPlatform Architect。ロサンゼルス在住。現在は、ソフトウェア開発およびテスト活動のかたわら、自動化が雇用に与える影響に関する書籍を執筆中。連絡はLinkedInwww.linkedin.com/in/bobreselmanまで。

(この記事は、開発元Gurock社の Blog 「Testing Event-Driven Application Architectures: An Asynchronous Approach」2019年12月17日の翻訳記事です。)

eBook 公開中

Paul Gerrard著 効果的なテスト管理12の秘密 (日本語)

テスト計画やテスト管理に役立つ12のトピックを解説します。

詳細はこちら