A look at how Tencent Games built service architecture based on CQRS and event sourcing patterns with Pulsar and ScyllaDB. テンセント・インタラクティブ・エンターテイメント・グループ・グローバル(IEG Global)の一員として、プロキシマ・ベータはチームやスタジオを支援し、世界中の何百万ものプレイヤーにユニークでエキサイティングなゲームを提供することにコミットしています。 Level Infinite(グローバルな出版社のブランド)の当社のチームは、ビジネスにおけるリスクの幅広い範囲を管理する責任を負っています - 例えば、詐欺活動や有害なコンテンツ。 このブログでは、このリアルタイムのイベント駆動分析システムを構築するための私たちの経験を共有します。最初に、私たちはなぜ私たちのサービスアーキテクチャをコマンドとクエリ責任分離に基づいて構築したのかを探索します( ) and event sourcing patterns with 次に、ScyllaDB を使用して、さまざまなゲームセッションにイベントを配信する問題を解決する方法について見ていきます。 CQRS Apache パルサー A Peek at the Use Case: Addressing Risks in Tencent Games(Tencentゲームにおけるリスクに対処する) 私たちが取り組んでいることと私たちが直面している課題の現実世界の例から始めましょう。 プレイヤーはこのダイアログを使用して、さまざまな理由で別のプレイヤーに対してレポートを提出することができます。 あなたが典型的なCRUDシステムを使用するなら、どのようにしてフォローアップのためにそのレコードを保持しますか? そして潜在的な問題は何ですか? 最初の課題は、どのチームがこのフォームを保存するためにデータベースを所有するかを決定することです。レポートを作成する理由はさまざまです(「他者」と呼ばれるオプションを含む)、したがってケースは異なる機能チームによって処理される可能性があります。 したがって、「事例を報告する」など、イベントとしてこのケースをキャプチャすることは、私たちにとって自然な選択です. すべての機能チームは、このイベントにサブスクリプトし、独自のフィルタリングを行う必要があります. もし彼らがこのケースが彼らのドメインに含まれていると思うなら、彼らはそれをキャプチャし、さらなるアクションを引き起こすことができます。 CQRSとイベントソーシング この例の背後にあるサービスアーキテクチャは、CQRSおよびイベントソーシングパターンに基づいています。これらの条件があなたにとって新しい場合は、心配しないでください! この概要の終わりまでに、あなたはこれらの概念を十分に理解すべきです。 . このテーマに捧げられたブログ ここで理解する最初のコンセプトは、イベントソーシングです。イベントソーシングの背後にあるコアアイデアは、システムの状態へのすべての変更がイベントオブジェクトでキャプチャされ、これらのイベントオブジェクトは、システムの状態に適用された順序で保存されているということです。言い換えれば、現在の状態を単に保存する代わりに、我々は、この状態で行われたすべてのアクションのシリーズを記録するための添付だけのストアを使用します。 次のコンセプトはCQRSであり、コマンドクエリ責任分離を意味します。CQRSは10年以上前にグレッグ・ヤングによって発明され、コマンドとクエリの分離原理から生まれたものです。基本的なアイデアは、両方の目的のために同じモデルを使用するのではなく、読み込みと書き込みのための別々のデータモデルを作成することです。CQRSパターンに従って、各APIはアクションを実行するコマンドであるか、または呼び出し者にデータを返すクエリであるべきです。 この分離はいくつかの利点を提供します。たとえば、コスト効率を最適化するために、書き込みおよび読み込み容量を独立してスケールできます。 書き方側の高レベルのワークフローは、次のように概要することができます: 多くのゲームセッションで発生するイベントは、イベントプロセッサの限られた数に送信されます。 実装は、通常、Pulsar、Kafkaなどのメッセージバス、またはイベントストアとして機能するより単純な列のシステムを含む、簡単です。 クライアントからのイベントは、イベントストアでトピックによって継続し、イベントプロセッサは、トピックにサブスクリプションしてイベントを消費します。 . 以前引用したブログ 列のようなシステムは、通常、1方向に流れるトラフィック(たとえばファンイン)を処理するのに効率的であるが、反対方向に流れるトラフィック(たとえばファンアウト)を処理するのに効率的ではない可能性があります。当社のシナリオでは、ゲームセッションの数は大きくなり、典型的な列のシステムは、イベントファンアウトのために最適化されている別の列のようなイベントストアを構築するためにScyllaDBを使用する理由です。 進む前に、以下は当社のサービスアーキテクチャの概要です。 書き方から始めて、ゲームサーバーはコマンドエンドポイントを通じてイベントをシステムに送信し続け、各イベントはゲームセッション中に発生した特定の種類の活動を表しています。イベントプロセッサは、各ゲームセッションのイベントストリームに対して結果やメトリクスを生成し、両サイド間の橋として機能します。 Distributed Queue-Like Event Store for Time Series イベント ちなみに、「Cassandra」と「queue」を Google で検索すると、10 年前の記事で、Cassandra を列として使用することは反パターンであると述べているかもしれないが、当時これは事実だったかもしれないが、今日では部分的にしかないと主張する。 各ゲームセッションへのイベントの配信をサポートするには、セッションIDをパーティションキーとして使用し、各ゲームセッションには独自のパーティションがあり、特定のゲームセッションに属するイベントがセッションIDによって効率的に位置づけられるようにします。 それぞれのイベントには、クラスターキーとして、時間 UUID というユニークなイベント id も含まれています。同じパーティション内のレコードがクラスターキーによって分類されているため、イベント id は列の位置 id として使用できます。 このアプローチを使用する際には、一貫性の問題を考慮すべき1つの注意事項があります。最新のイベント ID を追跡することで新しいイベントを取得することは、将来に小さな ID を持つイベントが発生しないという仮定に基づいています。 この問題は、私が「ファントムリーディング」と呼ぶもので、同じクエリを繰り返すことで、別の取引によって行われる未承諾された変更によって異なる結果が得られる SQL 世界の現象に似ています。 この問題を解決する方法はいくつかあります。ひとつの解決策は、すべてのイベントプロセッサの間で移動するタイムスタンプの最小値に基づいてクラスター全体の状態を維持することです。 TimeWindowCompactionStrategyは、TempleWindowCompactionStrategyが利用可能になる前にCassandraを列車として使用することを妨げた大きな問題であった。 次に、ScyllaDB を配信列として使用する以外の他の利点について話し合おう。 複雑なグローバルデータ配布の課題の簡素化 私たちは世界中の顧客にサービスを提供するための複数のテナンスシステムを構築しているので、さまざまな地域のクラスターで顧客の構成が一貫していることを確保することが不可欠です。 この問題は、すべてのデータセンターでキースペースでデータの複製を可能にするだけで解決しました. これは、あるデータセンターで行われた変更が、最終的に他のデータセンターに広がることを意味します. ScyllaDB、DynamoDB、Cassandra は、この困難な問題を微妙に思わせるような重いリハビリに感謝しています. 一般的な RDBMS を使用すると、ほとんどのデータベースもデータの複製をサポートしているため、同じ結果を達成する可能性があると考えているかもしれません。 特定の地域で実行されているコントロール パネルのインスタンスが 1 つしかない場合、これは事実です。 典型的なメイン/レプリカ アーキテクチャでは、メイン ノードだけが読み書きをサポートし、レプリカ ノードは読み書きのみです。 しかし、異なる地域間でコントロール パネルの複数のインスタンスを実行する必要がある場合、たとえば、各レンジャーは自宅地域で実行されているコントロール パネルを持っているか、あるいは各地域でローカル チームのために実行されているコントロール パネルを持っている場合、典型的なメイン/ AWS DynamoDB を使用している場合は、アプリケーションがローカルに読み書きし、データにグローバルにアクセスできる「グローバルテーブル」という機能をご存知かもしれません。ScyllaDB を使用してキースペースのレプリケーションを有効にすることは、同様の機能を提供しますが、ベンダーのロックインなしで、複数のクラウド環境でグローバルテーブルを簡単に拡張できます。 Keyspaces as Data Containers (データコンテナ) 次に、世界的なデータ配布の透明性を向上させるために、キースペースをデータコンテナとして使用する方法について見ていきましょう。 例えば、リージョンAは、オリジナルコピーがそのリージョンに保管されている限り、その国境外で特定のタイプのデータが処理されることを許可していると仮定します。 ♪♪♪ ♪♪♪ 可能な解決策の一つは、アプリケーションが正しいデータを正しいリージョンに正しく送信することを保証するためのエンド・トゥー・エンド(E2E)テストを実行することです。このアプローチでは、アプリケーション開発者が正しいデータ配布を実行することに全責任を負う必要があります。 キースペースでデータを複製することを可能にすることにより、データを正しく配布する責任を、2つのタスクに分けることができます: 1)データの種類を識別し、目的地を宣言し、 2)データをコピーまたは予想される場所に移動します。 これらの2つの任務を分離することで、複雑な構成や規制をアプリケーションから抽象化することができます。これは、データを別の地域に転送するプロセスが、ネットワークの境界を越え、トラフィックを正しく暗号化し、中断を処理するなどの最も複雑な部分であるためです。 これらの2つのタスクを分離した後、アプリケーションは最初のステップを正しく実行する必要があるだけで、開発サイクルの早期段階でのテストを通じて検証しやすくなります。 他の人が同じ道を歩むためのヒント 結論として、私たちが学んだ重要な教訓を残し、あなたが私たちに似た道を進む場合に適用することをお勧めします。 ScyllaDB を使用して、イベント配信列として使用するなど、タイム シリーズ データを処理する場合は、タイム ウィンドウ コンパクション 戦略を使用することを覚えておきましょう。 キースペースをデータコンテナとして使用して、データ配布の責任を分離することを検討してください. This can make complex data distribution problems much easier to manage. テクノロジー・トーク On-Demand This article is based on a tech talk presented at ScyllaDB Summit 2023. You watch this talk – as well as talks by engineers from Discord, Epic Games, Disney, Strava, ShareChat and more – on-demand. この記事は、ScyllaDB Summit2023で紹介されたテクノロジーのスピーチに基づいています。 テクノロジー テクノロジー テクノロジー Talks On Demand