
みなさん、こんにちは。オンラインサロン開発部 開発グループ アーキテクトチームの赤石です。
DMMオンラインサロンでは現行のシステムにおける課題を解決し、ビジネス的な課題を抽出しつつリプレース・リアーキテクトを進めるプロジェクト「neon」を中期的に取り組んでいます。
今回はそんな私達DMMオンラインサロンがシステムをリプレースする上で行っている、現行データベースから継続的にマイグレーションする仕組みについてご紹介します。
経緯と背景
DMMオンラインサロンではシステムのリプレースを行ない、新たなビジネス基盤を構築しています。neonプロジェクトの詳細は以前の記事で紹介していますので、ご覧ください。
記事の一部で触れましたが、DMMオンラインサロンには、サービス立ち上げ時に構築された入会・オーナー管理画面と、その後リリースされた専用コミュニティサービスが存在しています。これらは別の時期に構築されたため、それぞれが独自のデータベースを保有し、必要なデータを管理するためにアカウント情報やオンラインサロンのデータを重複して管理していました。その結果、データの整合性を保つためにバッチ処理などで同期を行い、APIによる連携や直接お互いのデータベースを読み取るようなフローが混在していました。このため、システムのデータフローが分かりづらく、課題となっていました。

neonプロジェクトではこれらの課題に対処するため、新たな基盤構築の中でDatebase per ServiceまたはDatabase per Moduleという形でデータベースの再設計および移行を行っています。
データ移行が単純な作業であれば問題はなかったのですが、本プロジェクトでは既存のシステムが使用しているデータベースと新基盤上のデータベースを稼働させながら、ストラングラーフィグパターンを用いて段階的に移行を進めているため、継続的なデータ同期が必要でした。
この課題に対応するため、私たちはCDC(Change Data Capture)の手法を採用し、Debeziumを活用してデータの継続的同期を行うシステムを構築しました。
CDCとは
CDC(Change Data Capture)とは、リアルタイムでデータベースの変更(Insert、Update、Deleteなど)を検出し、それらの変更を他のシステムへ即座に伝播させる技術です。データパイプラインなどでよく利用される手法です。CDCにはデータベースの変更点を検出するいくつかの方法がありますので、ここで紹介します。
Trigger-Based CDC
データベースのトリガー機能を使用して変更を検出します。変更があるごとにトリガーが発火し、ログテーブルなどに変更情報を記録します。しかし、これにはクエリ実行時にトリガーによるオーバーヘッドが伴いアプリケーションのパフォーマンスに影響を与えてしまいます。
Log-Based CDC
データベースのトランザクションログやレプリケーションログを直接読み取ることで変更を検出します。トランザクションログとはデータベースが行う変更を記録する内部ログファイルです。この方法はログ情報を利用するため追加負荷が少なく、実際のデータベース操作に影響を与えることなく変更を捕捉できるため、高いスループットを実現可能です。
Query-Based CDC
データベース内の作成日時や更新日時などのAuditカラムから日時情報をクエリで絞り込み、定期的にデータベースをポーリングし、変更があったかを調べる方法です。シンプルですが、データのボリュームが大きい場合や更新頻度が高い場合はパフォーマンスに悪影響を与える恐れがあり、削除されたレコードの検出が困難という課題も持ち合わせています
Debeziumについて
Debeziumは、Apache Kafkaを活用したオープンソースのCDCプラットフォームでKafka Connect互換のコネクタを提供します。MySQL、PostgreSQL、MongoDB、Cassandraなどの様々なデータベースシステムに対応しており、Log-Based CDCを採用しています。
これにより、データベースのトランザクションログをリアルタイムで監視し、発生したデータ変更情報を抽出してKafkaトピックへと送信する機能を持ちます。特にMySQLやPostgreSQLの場合は、変更をミリ秒単位で検出し、伝播することが可能です。これにより、データベースに起きた変更を迅速に他システムやサービスに伝え、リアルタイムのデータ共有を実現することができます。
画像
技術選定
技術選定に際しては、AWS環境でのシームレスな連携とコスト効率の観点から、調査と評価を進めました。AWSでの統合がスムーズであることは重要でした。なぜなら、現行のシステムも新たに構築を進めている基盤もAWS上で運用する予定であり、ネットワーク接続の複雑化を避け、それに伴う時間的なコストを削減したかったからです。
また、金銭的コストについても重要な判断基準の一つでした。現行システムでは多数のレコードに対する追加や変更を頻繁に行うテーブルが存在するため、変更量に応じて従量課金されるサービスを使用するとコストが膨大になるリスクがありました。そこで、インスタンスの利用時間に応じて課金されるサービスに焦点を当てて選定を行いました。
その中で、Debeziumの他にもAWS Database Migration Service(以下、DMS) も候補にあがりました。
DMSは、異なるデータベース間のマイグレーションを容易にし、高い可用性を維持したまま、データストア間でのデータ複製を持続的に実行できるAWSのマネージドサービスです。DMSは多様なデータベースエンジンに対応し、同一のデータベースタイプ間の移行はもちろん、異種データベース間の移行も可能という柔軟性を有しています。
しかし今回の要件では移行元となるデータベースが分散しており、複数のデータソースにまたがるお互いのデータから正しい値を判断するような複雑なワークロードを処理する必要がありました。
DMSではこのような複雑な条件での移行が実現できなかったため、今回はDebeziumでの移行を行うことを決定しました。
アーキテクチャ
今回構築したデータ同期アーキテクチャは、ユースケースに応じてイベントベースの同期とバッチベースの同期の2種類を実装しました。
イベントベースの同期
イベントベースの同期アーキテクチャでは、上述のDebeziumを利用したCDCを活用しています。
DebeziumはApache Kafka/Kafka Connect上で動作するため、運用の負担を軽減する目的でApache KafkaのフルマネージドサービスであるAmazon MSKを採用しました。
DebeziumがキャプチャしたイベントはMSKを経由してLambda関数をトリガーし、ニアリアルタイムでの同期処理を行います。なお、Debeziumはデータ変更の前後の状態をイベントとして取得しますが、今回複数のデータソースから移行先データベースへ同期が必要とされたため、現行データベースへの読み取りも発生しています。
バッチベースの同期
バッチベースの同期では、イベントベースの同期だけでは対処できない特定のケースを考慮しています。例えば、新たに作成されず更新もされない既存データや、何かしらの障害で移行先のデータベースからデータがロストしてしまった場合などです。こうした場合に備えて、データの全体移行とデータ整合性チェックを、冪等性を担保した形でバッチ処理として定期的に実施しています。
バッチ処理はAWS Step Functionsを使用してワークフローを管理し、リトライやタイムアウトのハンドリングだけでなく、テーブル間に依存関係がある場合は並列で同期を実行することができないため、それを考慮して順番に実行する制御も行っています。

これら2つの同期処理はアプリケーションの観点から見ると、コードベースを共通にしています。プレゼンテーション層に相当する部分ではLambda関数とバッチ処理に分岐していますが、その先のレイヤーでは同一のデータ同期ロジックを共有しており、システム全体として一貫した動作を保証する設計になっています。
おわりに
DMMオンラインサロンが取り組む「neon」プロジェクトの一環としてのデータ同期プロセスについて紹介させていただきました。今回は特にデータ同期におけるアーキテクチャを中心に解説しましたが、実際の運用ではさまざまな課題に直面することもあります。これらの経験に基づいた学びを、また記事にして共有できればと考えています。
既存のシステムをリプレースしていくことは複合的な課題に直面しながら、それを解決するアーキテクチャを考えていく難しい仕事ではありますが、そこから得られる成長は、私たちにとっても大きな魅力の一つです。
DMMオンラインサロンでは、今後も開発グループの一員として共に働く新たなメンバーを募集しています。この記事を読んで「neon」プロジェクトに関心をお持ちいただいた方や、さらに深く知りたいと感じた方は、ぜひ気軽にご連絡ください。