OpenCTIにおけるRedisクラスタサポートへの設計と開発の歩み
この記事は、通常と異なり、当社のオープンソース脅威インテリジェンスプラットフォームであるOpenCTIの新しい脅威インテリジェンス機能に焦点を当てるのではなく、Redisクラスタ環境をサポートするための製品適応の経験(OpenCTI 5.7.X以降)に焦点を当てています。
OpenCTIの開発初期において、残念ながらクラスタ版と互換性のないRedis機能を使用していました。本記事では、シングルノードデプロイメントとの互換性を維持しながら、最終的にRedisクラスタのサポートを実装するために何を変更したかについて説明します。
OpenCTIのRedis使用方法
課題をより理解するために、まずOpenCTIのコンテキストでRedisを使用する理由を説明しましょう。以下に示すように、Redisデータベースはプラットフォームの技術スタックの中心的な要素です。

OpenCTIの技術スタック
共有セッション
OpenCTIはプラットフォームのクラスタデプロイメントをサポートしているため、ユーザーセッションはRedisに保存されます。ElasticSearch/OpenSearchではなくRedisにセッションを保存することを選択した理由は、このデータベースにはセッション処理に不可欠な自動タイムアウトなどの機能があるためですが、メモリにセッションを保存することで、短時間に複数回オブジェクトを取得する際により優れたパフォーマンスが得られるためでもあります。
クラスタ管理
最適なパフォーマンスと高可用性のための推奨事項は、複数のOpenCTIプラットフォームインスタンスをクラスタとしてデプロイし、これらのインスタンス間でワーカーとジョブを負荷分散することです。各インスタンスは特定のキーに自身を登録し、リアルタイムで情報を共有します。その内容は以下の通りです:
- クォーラム、バージョン、稼働シグナル
- 起動およびロックされたバックグラウンドプロセス
- クラスタの一貫性を保つためのその他の有用な情報

クラスタステータス
ロック
OpenCTIは、ナレッジ(エンティティとリレーションシップの両方)を保存するためにElasticSearch/OpenSearchに依存しています。このデータベースシステムを選択したのは、データ量、インジェストパフォーマンス、全文検索、集計/相関といった当社のユースケースを最もよくカバーしているためです。しかし、このデータベースはトランザクショナルではありません。並行性の問題を防ぐために、Redisを内部で利用する高速ロックシステム(Redlockを使用)を実装しました。ロックシステムは設計上、有効期限が短いため、この種の用途にはRedisが完璧に適しています(セッションの自動タイムアウトと同じシステムです)。

ロックと解決を伴う作成ワークフロー
インジェストの可観測性
OpenCTIでは、さまざまなコネクタのインジェストメカニズムをユーザーインターフェイス上で直接監視できます。このユースケースを処理するため、コネクタは「ワーク」(通常はSTIXバンドル1つ)を宣言し、各ワークは一定数のオペレーション(通常はSTIXバンドルのチャンク)で構成されます。ワーカーがチャンクを処理すると、処理されたオペレーションの数がインクリメントされます。

ワーク内のオペレーション数のカウント
この継続的な監視はIO集約的になる可能性があるため、Redisを使用してすべての処理済みオペレーションのカウントを維持します。ワークの最後に、最終的な数値がElasticSearch/OpenSearchに保存されます。
ユーザーとキャッシングのためのパブリッシュ・サブスクライブ
Redisは、Pub/Subシステムとして使用され、ユーザーに通知します(作成、変更、削除など)。また、OpenCTIの内部キャッシュに、一部のデータを更新する必要があることを通知します(無効化)。
ストリーム
最後に、Redisはプラットフォーム内のすべてのナレッジオペレーション(作成、変更、削除)を表す脅威インテリジェンス情報ストリーム全体を保存するためにも使用されます。OpenCTIの複数の組み込み機能がこのストリームに依存して、リアルタイムで意思決定と反応を行っています(通知、同期、ルールエンジンなど)。

OpenCTI内でのストリームの使用
開発の起点と制限事項
上記のすべての機能に基づいて、初期設計はシングルノードRedisデプロイメントを対象としていました。基本的に、OpenCTIのユースケースをサポートするために、主にRedisデータベースの3つの重要な機能を使用しましたが、これらはクラスタモードのサポートに直接影響を与えます。
複数の論理データベース
Redisの複数データベース機能を使用して、保存する必要のあるさまざまな種類のキーを分割することにしました。当初は、関心事を分離し、メインデータをデータベース0に、トラッキング/監視をデータベース1に保存することは良いアイデアに思えました。実際、悪い選択ではありませんでしたが、この機能はクラスタモードでは利用できません。
パターンキースキャン
OpenCTIでは、一部のAPI(およびユーザーインターフェイス画面)は、Redisデータベースに保存されているキーを一覧表示するために使用される関数に直接関連しています。たとえば、OpenCTI管理者がセッションを視覚化(および強制終了)できる設定セクションのセッション一覧などです。
これを実現するために、scanコマンドを使用して、session:*で始まるすべてのキーを取得しました。これは悪い方法ではありませんが、クラスタモードでは、すべてのノードを反復処理して、それぞれのノードでスキャンを開始する必要があります。実行可能ですが、シングルノードモードとクラスタモードの間でソースコードロジックが大きく変わります。
1回の呼び出しで複数のキーを取得
Redisは、mgetという強力なコマンドを提供しており、これにより同じクエリで複数のキーを取得できます。この機能は非常に強力ですが、Redisクラスタ内では常に使用できるわけではありません。このコマンドは、すべてのキーが同じノード上にある場合にのみクラスタで使用できます。これを実現するには、通常、使用方法に応じた戦略を確立し、ハッシュ計算を強制することで一部のキーを同じ場所に配置する必要があります。
ioredisを使用したRedisクライアント
OpenCTIプラットフォームはNodeJSで開発されているため、ioredisクライアントを使用することにしました。当初は、デフォルトのクライアントビルダーを使用していましたが、Redisクラスタに対して使用する場合とまったく同じではありません。使用するRedisに応じて、異なるクライアントが必要になる場合があります。私たちにとってのもう1つの課題は、2つの異なるクライアントを開発することなく、RedisシングルノードとRedisクラスタの両方をサポートする方法を見つけることでした。
実施した対応
Redisクラスタをサポートするために、すべての制限事項を解決し、設計アプローチとコードを変更するしか選択肢がありませんでした。さまざまな用途とその影響について見ていきましょう。
Redisクライアント
クライアント側では、シングルノードまたはクラスタを使用する場合に同じアプローチを使用する方法を見つけることにしました。そのために、両方のアプローチで利用可能な機能の使用に焦点を当てました。プラットフォームに宣言された構成に応じて、適切なクライアントをインスタンス化し、特定のコードなしで単に使用します。
可観測性、Pub-Sub、ストリーム
この部分については何も行っていません。現在の実装はRedisクラスタで完全にサポートされているためです。
複数の論理データベース
この機能の使用を単に削除しました。すべてのインスタンス化されたクライアントは、データ共有がクラスタによって直接処理されるため、データベース0に接続するだけになりました。
ロック
ロックの管理は、redlockライブラリの使用により少し特殊でした。このライブラリは、mgetコマンドといくつかのスクリプトを活用して、可能な限り迅速にロックを取得します。これは素晴らしいことですが、残念ながらクラスタ全体でロックをシャーディングする能力を妨げます。
ロックは短時間に頻繁に作成および取得されるため、これは強制的なコロケーションが意味をなすユースケースです。そこで、すべてのロックキーに{lock}というプレフィックスを付けて、Redisにキーを同じ場所に配置するよう強制し、redlockライブラリを問題なく引き続き使用できるようにしました。
セッションとクラスタ管理
scanコマンドの使用を避けるため、OpenCTIがキーを一覧表示する方法の設計を変更することにしました。したがって、同じニーズにリンクされたキーのリストを維持するために、Redis SETを使用した新しいアプローチを作成しました。この新しいアプローチは、セッションとクラスタ情報が限られた量のデータを表すため可能でした。
この新しい設計により、セッションとクラスタ情報のすべてのキーをシャーディングし、必要に応じてSETを使用して情報のリストを取得することが可能になりました。シャードのため、SET内のすべてのキーは、単純なgetコマンドで個別に取得する必要があります。
まとめ
この記事が、OpenCTIプラットフォーム内でのRedisの使用を理解する助けになれば幸いです。また、Redisクラスタへの移行を検討している開発者に関連情報と得られた教訓を提供するために書きました。Redisについての知識があり、より良い使い方をサポートしたい方は、ぜひコミュニティSlackチャンネルにご参加ください!
続きを読む
関連トピックとインサイトをご覧ください

