メッセージングシステムの構築方法

私たちのチームは、モバイルデバイスからのメッセージを処理するためのバックエンドシステムを開発しています。 デバイスは、複雑な機器の操作に関する情報を収集し、メッセージを処理センターに送信します。 この記事では、そのようなシステムを構築するためのアプローチを共有したいと思います。 アイデアは非常に一般的であり、次のアーキテクチャを持つ任意のシステムに適用できます。







デバイスの通信チャネルを介して、アプリケーションのエントリポイントであるゲートウェイにメッセージを送信します。 アプリケーションのタスクは、正確に何が来たかを理解し、必要なアクションを実行し、さらに分析するためにデータベースに情報を保存することです。 ベースを処理の終点と見なします。 簡単に聞こえますが、メッセージの数と種類が増えるにつれて、いくつかのニュアンスを話し合いたいと思います。



負荷レベルについて少し。 私たちのシステムは数万のデバイスからのメッセージを処理しますが、平均して数百から千のメッセージを受信します。 数字が1方向または2方向で数桁異なる場合、問題のセットとそれらを解決するためのアプローチが異なる可能性があります。



1秒あたりの実際のメッセージ数に加えて、不均等な受信の問題があります。 アプリケーションは、平均の数十倍の短い負荷ピークに対応できる必要があります。 この問題を解決するために、システムは一連のキューとそのハンドラーとして構成されています。



受信ゲートウェイは実際の作業を行いません-クライアントからメッセージを受信し、それをキューに入れるだけです。 これは非常に安価な操作なので、ゲートウェイは毎秒膨大な数のメッセージを受信できます。 次に、キューからいくつかのメッセージを受信する別のプロセスがあります-彼が望み、そしてできる限り正確に-そしてハードワークを行います。 処理は非同期であり、負荷は安定して制限されます。 おそらく、ピーク時には、メッセージのキューで費やされる時間がわずかに増加するでしょう。それだけです。



多くの場合、メッセージ処理は自明ではなく、いくつかのアクションで構成されています。 次の論理ステップは、作業をいくつかの段階に分割することです:いくつかのキューとハンドラー。 この場合、物理的に異なるキューとハンドラーを異なるサーバーに配置し、それぞれを特定のタスクに合わせて構成およびスケーリングできます。







最初のステージには、デバイスから到着した形式のメッセージが含まれます。 ハンドラーはそれらをデコードし、2番目に配置します。 たとえば、2番目のプロセッサは、ある種の集約を作成し、ビジネスにとって興味深い情報を作成できます。3番目のプロセッサは、それをデータベースに保存できます。



これは基本的なレイアウトですが、他に考えるべきことはありますか?



値の定義



1.作成、変更、および保守が簡単


非同期分散メッセージ処理は、ソフトウェア製品にさらなる複雑さをもたらします。 この価格の削減に常に取り組んでいます。 コードは、まず読みやすさ、すべてのチームメンバーの理解度、変更の容易さ、およびサポートの方向に最適化されています。 結局、作者以外はコードを理解できない場合、チームを幸せにするのに役立つ優れたアーキテクチャはありません。



論文は単純に思えますが、この原則を表明するだけでなく、日常業務で安定して絶えず適用するようになるまでに多くの時間がかかりました。 コードを少し改善し、簡単にすることができると感じたら、常にリファクタリングを試みます。 すべてのソースがレビューされ、最も重要な部分は通常ペアで開発されます。



2.耐障害性


機器やサブシステムに障害が発生した場合にシステムが機能し続けるための要件をすぐに判断することは理にかなっています。 それらはすべて異なります。 おそらく誰かが、サーバーの1つがリブートする5分間のメッセージをすべて破棄する準備ができているのかもしれません。



このシステムでは、メッセージを失いたくありません。 一部のサービスが利用できない場合、データベースへの呼び出しがタイムアウトで終了する場合、または処理中にランダムエラーが発生する場合、デバイスからの情報が失われることはありません。 依存メッセージは、問題が修正された直後にキューに入れて処理する必要があります。



あるサーバー上のコードが別のサーバー上のWebサービスを同期的に呼び出すとします。 2番目のサーバーが使用できない場合、処理は失敗し、セキュリティのみを確保できます。 非同期処理では、メッセージは2番目のサーバーが動作状態に戻るまで待機します。



3.パフォーマンス


単位時間、遅延、サーバー負荷ごとに処理されるメッセージの数-これらはすべて、システムパフォーマンスの重要なパラメーターです。 そのため、プロジェクトに柔軟なアーキテクチャを採用しています。



ただし、最初から最適化に焦点を合わせないでください。 通常、パフォーマンスの問題の大部分は、比較的小さなコードによって発生します。 残念ながら、これらの問題がどこにあるかを正確に予測することはできません。 これは、人々が時期尚早の最適化に関する本を書く場所です。 最初の負荷テストの前に、システムでシステムを迅速に構成し、最適化を忘れることができるアーキテクチャであることを確認してください。



同時に、負荷テストを早期に開始し、標準のテスト手順の一部にする必要があります。 そして、テストで特定の問題が示された場合にのみ、最適化を行います。



脳をカスタマイズする



1.キューと非同期ハンドラーを操作する


これについてはすでに上で書いた。 主なツールは、キューとそのハンドラーです。 「リモートコードと呼ばれる要求を受信し、応答を待機し、応答を返す」というコードを整理する古典的なスタイルに加えて、「キューからメッセージを受信し、機能し、メッセージを別のキューに送信する」というアプローチがあります。 システム開発のスケーラビリティとシンプルさの両方は、2つのアプローチの組み合わせでどの程度バランスを取るかによって決まります。



2.処理をいくつかの段階に分けます


メッセージの処理が非常に複雑で、複数の段階に分割できる場合は、いくつかのキューとハンドラーを検討してください。 過度の断片化は、システムの理解をより困難にする可能性があることに留意してください。 ここにはバランスが必要です。 多くの場合、開発者にとって自然で理解しやすいパーティションがあります。 そうでない場合は、障害点について考えてください。 ハンドラーがいくつかの独立した理由で失敗する可能性がある場合、それを分割することを検討するかもしれません。



3.デコードと処理を混在させないでください


通常、メッセージは、ネットワーク上のデバイスの相互作用のための何らかのプロトコルの形式で提供されます:バイナリ、xml、jsonなど。 できるだけ早くデコードして、内部形式に変換します。 これにより、少なくとも2つの問題が解決されます。 まず、いくつかのプロトコルがあります。 デコード後、さらにメッセージの形式を統一できます。 第二に、ロギングとデバッグが簡素化されます。



4.キュー構成を簡単にする


キューの構成を簡単に変更できるように、処理コードを構造化します。 ハンドラーを2つに分割しても、リファクタリングのクラウドにつながるべきではありません。 コードがキューの特定の実装に依存しすぎないようにしてください。明日、変更したい場合があります。



5.グループ内のメッセージを処理する


多くの場合、キューからメッセージを1つずつではなく、グループで一度に受信するのが理にかなっています。 使用するサービスは、バッチ処理のために一連のデータを受け取ることができます。この場合、通常、1つの大きな呼び出しは、100個の小さな呼び出しよりもはるかに効率的です。 一度に何百ものレコードをデータベースに貼り付けると、100回の削除された呼び出しよりも速くなります。



ツールを作成します



1.完全な観察を実施する


最初から監視に投資します。 帯域幅、平均処理時間、現在のキューサイズ、最後のメッセージからの時間、キューごとのグラフを簡単かつ明確に表示する必要があります。







戦闘環境だけでなく、テスト、さらには開発者のマシンでも監視を使用します。 適切に構成されたグラフと通知は、デバッグと事前ロードテストに非常に役立ちます。



2.すべてをテストする


メッセージ処理システムは、自動テストの理想的なテストの場です。 入力プロトコルは定義および制限されており、生きている人との相互作用はありません。 コードを単体テストでカバーします。 バトルキューをローカルメモリ内のテストキューに置き換えることを検討し、ハンドラーインタラクションテストをすばやく実行します。 最後に、ベータ(ステージング)環境で実行できる(および本番環境で実行できる)本格的な統合テストを行います。



3.誤ったメッセージのサンプを挿入します。


ほとんどの場合、1つのメッセージの処理でエラーが発生してキュー全体が停止することは望ましくありません。 同様に重要なのは、エラーを診断する能力です。 そのようなメッセージを特別なリポジトリに置き、すべてのスポットライトをこのリポジトリに向けます。 エラーの原因が解決されたらすぐに、メッセージを処理キューに簡単に戻すことを検討してください。



同じまたは類似のメカニズムを使用して、将来のある時点よりも早く処理する必要のあるメッセージを格納できます。 私たちはそれらをサンプに入れて、定期的にCh。



4.展開を自動化する


システムのインストールと更新は、1回または数回のクリックで実行する必要があります。 頻繁に製品を更新し、理想的にはマスターブランチにコミットするたびに自動展開するようにします。 インストールスクリプトは、開発者が個人環境と最新のテスト環境を維持するのに役立ちます。



結論の代わりに



優れた、理解可能なアーキテクチャは、開発者のコ​​ミュニケーション、彼らの共通のビジョン、および一連の概念を簡素化する方法でもあります。 この意味で、システムのメタファーを絵の形で定式化するのに非常に役立ちました。これを使用して、プロジェクトで多くの議論を始めることができます。



私たちの比phorは、 ボブおじさんの記事The Clean Architectureのこの写真に似ています:







この図では、システムの本質とその依存関係を示しています。これは、正しい設計へのアプローチ、エラーの発見、またはリファクタリングの計画に関する議論に役立ちます。



All Articles