アーキテクチャ (IT)システムアーキテクト

リアルタイム異常検知システムのアーキテクチャを設計してください。このシステムは、数百万のデバイスからの高速度IoTテレメトリを処理し、正確に一度だけのセマンティクスを確保し、イベント時間処理を用いて順序の狂ったイベントを処理し、履歴トレンド分析のためにコスト効果的にデータをアーカイブしながら、サブ秒のアラート遅延を維持します。

Hintsage AIアシスタントで面接を突破

質問への回答

IoTテレメトリ向けの現代のストリーミングアーキテクチャは、Apache Kafkaを分散イベントバックボーンとして利用し、耐久性のある永続性と水平方向のスケーラビリティを持ち、毎秒数百万のメッセージを処理します。Apache Flinkはストリーム処理エンジンとして機能し、洗練されたイベント時間処理機能を持ち、パイプライン全体で正確に一度だけの配信セマンティクスを保証するためにKafkaのトランザクションと調整します。状態管理は、インクリメンタル非同期スナップショットをAmazon S3に送信するRocksDB埋め込みバックエンドを利用し、JVMヒープメモリを使い果たすことなくテラバイト規模の状態操作を可能にします。即時警告のために、ホット集約結果はRedisにマテリアライズされ、履歴データはコスト効果の高い分析クエリ用にApache Icebergテーブルを介してS3 Glacierに流れます。

実生活の状況

スマートエネルギー公益事業は、毎秒1万のイベントを生成する200万のスマートメーターを監視し、連鎖的障害を防ぐために500ミリ秒以内に電力網の異常検出を要求します。核心的な課題は、セルラーネットワークのパーティションによって最大5分遅れて到着するイベントを処理し、メーターの再試行ロジックからの重複を排除し、高速度テレメトリとデバイスキャリブレーションメタデータを含むゆっくり変化する参照データを結合することです。エンジニアは以前、順序の狂ったイベントやピーク負荷時のデータ損失によって引き起こされる偽陽性に苦労し、リアルタイムの応答性を損なうことなく正確さを維持する堅牢なアーキテクチャが必要でした。

解決策1: Spark Streamingとバッチを用いたラムダアーキテクチャ

最初の提案は、ラムダアーキテクチャパターンを採用しました。Apache Spark Streamingは、約リアルタイムビューのためのスピードレイヤーを提供し、夜間のSpark SQLバッチジョブは、過去24時間の正確な結果を再計算しました。

利点: 広範なツールを持つ成熟したエコシステム、HDFS複製による明確なフォールトトレランス、スピードとバッチレイヤー間の明確な関心の分離。

欠点: ストリーミングとバッチロジックの間のコード重複は、重大なメンテナンスオーバーヘッドと同期バグを引き起こします。毎日テラバイトを再処理することは、禁止的な計算コストを伴い、バッチのレイテンシによってサブ秒の異常修正要件を満たさなくなります。

解決策2: 埋め込みストアを用いたKafka Streams

第二の設計は、アプリケーションポッド上で直接動作する埋め込みRocksDB状態ストアを持つKafka Streamsを考慮しました。

利点: 別々の処理クラスタなしの簡素化された運用トポロジー、Kafkaのコンシューマーグループとの密接なネイティブ統合、そして自動的なパーティション割り当ての処理。

欠点: 状態のある操作をスケーリングするには、すべてのパーティションの高額な再バランスがトリガーされ、重大なレイテンシースパイクを引き起こします。順序の狂ったイベントを処理するには、デフォルトのウィンドウ処理がイベント時間ではなく処理時間に依存しているため、複雑なカスタムタイムスタンプ抽出ロジックが必要です。アプリケーションサーバーのメモリ制約が、総状態サイズを厳しく制限し、大きなウィンドウ集計を妨げます。

解決策3: イベント時間セマンティクスを持つApache Flink

選択されたアーキテクチャは、Kubernetes上にApache Flinkをデプロイし、ウォーターマークと外部化されたインクリメンタルチェックポイントをAmazon S3へ利用しました。

利点: ウォーターマークとallowedLateness設定を通じてネイティブなイベント時間処理が行われ、カスタムロジックなしで順序の狂ったデータを処理します。正確に一度だけのセマンティクスは、FlinkのチェックポイントとKafkaのトランザクションを調整する二相コミットを通じて達成されます。RocksDBのインクリメンタルスナップショットは、メモリプレッシャーなしでテラバイト規模のキー付きウィンドウの独立したスケーリングを支援します。

欠点: 重要な運用の複雑さにより、チェックポイント調整、ウォーターマーク整合、バックプレッシャー管理に関する深い専門知識が必要です。Flinkのジョブマネージャーは、Kubernetesの高可用性設定を必要とする潜在的な単一障害点を表します。

選択された解決策と結果

私たちは解決策3を採用し、FlinkBoundedOutOfOrdernessWatermarksを5分の許容範囲で設定し、30秒ごとにRocksDBのインクリメンタルチェックポイントを設定しました。重複排除は、Kafkaの冪等プロデューサーと、Flinkの二相コミットプロトコルと調整されたトランザクションライティングを有効にすることで達成されました。S3 Glacierへのデータティアリングは、過剰なストレージコストなしでクエリ可能な履歴データセットを維持するために、Apache Icebergのコンパクション戦略を利用しました。

このアーキテクチャは、製品テスト中に300ms p99アラート遅延と99.99%の処理精度を達成しました。このシステムは、チェックポイント復元後にKafkaのオフセットから再生することで、3時間のセルラーネットワークパーティションをスムーズに処理し、データ損失はゼロでした。ストレージコストは以前のHDFSソリューションに比べて60%減少し、GrafanaダッシュボードはFlinkのウォーターマーク遅延とチェックポイント期間メトリクスにリアルタイムの可視性を提供しました。

候補者が見落としがちなこと

質問: Apache Flinkは、Kafkaに書き込むときにどのように正確に一度だけのセマンティクスを維持し、ジョブ再起動中に重複書き込みを防ぎますか?

Flinkは、チェックポイントバリアとKafkaトランザクションの間の二相コミットプロトコルを通じて正確に一度だけを実装しています。プレコミットフェーズ中に、データはユニークなtransactional.idを使用してKafkaにフラッシュされますが、チェックポイントが正常に完了するまでコミットされません。チェックポイントが失敗した場合、Flinkはトランザクションを中止し、Kafkaはデータを破棄します。再起動時、Flinkは最後の成功したチェックポイントからプロデューサー状態を復元し、不完全な書き込みからのゾンビトランザクションを防ぎます。候補者は、transactional.idが再起動間での冪等性を保証するためにチェックポイントIDを埋め込む必要があること、そしてFlinkがマルチテナントのKafkaクラスタでの衝突を避けるためにsetTransactionalIdPrefix構成が必要であることを見落としがちです。

質問: なぜイベント時間ウィンドウがキー付き操作で状態の爆発を引き起こし、無制限のデバイスIDストリームを処理する際にこれをどのように緩和しますか?

イベント時間ウィンドウは、Flinkが各キーのすべてのイベントをウィンドウ終了時間を超え、設定されたallowedLateness期間を加えた時間までバッファリングする必要があるため、状態の爆発を引き起こします。ユニークなデバイス識別子のような高カーディナリティキーの場合、これはRocksDBに何百万もの同時ウィンドウ状態を蓄積し、最終的にすべての利用可能なディスクとメモリ資源を消費します。緩和には、古いウィンドウを自動的に期限切れにするためにState TTL(生存時間)設定を実装し、オフヒープ使用を制限するためにRocksDBのメモリ管理バッファを設定し、スナップショットオーバーヘッドを減少させるためにインクリメンタルチェックポイントを使用する必要があります。候補者は、明示的なウィンドウ排除またはTTL設定がない限り、タスクマネージャーがOut-Of-Memoryエラーに遭遇するまで状態バックエンドが無限に成長することを見落としがちです。特に、遅れて到着した履歴データを処理する場合にはそうです。

質問: 単一の故障するIoTデバイスが通常のイベント量の100倍を生成し、特定のFlinkサブタスクを圧倒する場合、ホットキーの偏りをどのように解決しますか?

ホットキーの偏りは、パーティションハッシュが高ボリュームキーを単一のタスクインスタンスに集中させ、パイプライン全体にバックプレッシャーとレイテンシースパイクを引き起こすときに発生します。解決策は、キーソルトを用いること—初期のシャッフル中にホットキーにランダムサフィックス(例:0-9)を追加して、複数のサブタスクに処理を分散させ、その後サフィックスを取り除いて結果を再集約します。あるいは、シャッフル前にFlinkAggregateFunctionを用いたローカルキー付きの事前集約を実装してネットワークトラフィックを削減するか、特定のプロデューサーを制限するためにKafkaのスティッキーパーティショニングを利用します。候補者は、ソルトがネットワークシャッフルのボリュームと状態サイズを増加させるため、並列性の向上とRocksDBにおける合成キーの管理のオーバーヘッドの間の慎重なバランスを要求することを見落としがちです。