CDCとは何か — データ変更をリアルタイムに捉える技術
CDC(Change Data Capture)とは、データベース上で発生したINSERT・UPDATE・DELETEといった変更操作を検知し、その差分をリアルタイムあるいは準リアルタイムでダウンストリームシステムに伝播する技術です。バッチETLが「全量スナップショットを定期的に転送」するのに対し、CDCは「変更差分のみをイベントとして連続的に転送」するアプローチをとります。この方式により、データウェアハウスやストリーミング基盤へのデータ反映遅延を数秒〜数分に抑えることが実現します。
CDCが近年急速に普及している背景には、データ活用のリアルタイム化要求があります。ECサイトの在庫残数リアルタイム表示、金融系システムの不正検知、SaaSプロダクトのマルチテナントデータ同期、マイクロサービス間のイベント駆動連携——これらのユースケースでは「昨夜のバッチで十分」という前提が崩壊しています。
一方で、CDCはバッチETLを完全に置き換える技術ではありません。重いトランスフォーム処理や月次レポート生成にはバッチが依然として適しており、両者の特性を理解したうえで使い分けることが重要です。データパイプラインやELT vs ETLの基礎を押さえたうえで本記事を読むと理解が深まります。
CDCの基本フロー
ソースDB CDCエンジン ターゲット
┌─────────────────┐ ┌────────────────┐ ┌──────────────────┐
│ テーブル: orders │ │ │ │ DWH(BigQuery/ │
│ │──変更検知─▶ 変更イベント生成 │──転送──▶ Snowflake等) │
│ INSERT id=5001 │ │ │ │ │
│ UPDATE id=4999 │ │ [before/after] │ │ Kafkaトピック / │
│ DELETE id=4980 │ │ │ │ データレイク │
└─────────────────┘ └────────────────┘ └──────────────────┘
CDCエンジンは変更イベントとして「変更前の値(before)」と「変更後の値(after)」、操作種別(INSERT/UPDATE/DELETE)、タイムスタンプ、トランザクションIDをセットにして送信します。このリッチなイベント形式により、ダウンストリームでの詳細な変更追跡が可能です。
CDCの3つの実装方式
CDCには実装アプローチが3つあります。DB負荷・実装難易度・機能制約がそれぞれ異なるため、システム要件に応じた選択が求められます。
ログベースCDC(WAL/binlog方式)
データベースが内部的に保持するトランザクションログを直接読み取る方式です。PostgreSQLではWAL(Write-Ahead Log)、MySQLではbinlogと呼ばれます。アプリケーションDBへの追加負荷が極めて低く、INSERT/UPDATE/DELETEすべてを検知でき、スキーマ変更の追跡も可能なため、本番環境での採用実績が最も多い方式です。
ただし、DBの管理者権限(レプリケーション権限)が必要であり、マネージドDBサービス(AWS RDS等)では設定に制約がある場合があります。
ログベースCDCの動作フロー
MySQL / PostgreSQL のトランザクションログ
┌────────────────────────────────────────────────────────┐
│ [LSN:1001] INSERT orders (id=5001, amount=980) │
│ [LSN:1002] UPDATE orders (id=4999, status=completed) │
│ [LSN:1003] DELETE orders (id=4980) │
└────────────────────────┬───────────────────────────────┘
│ ログ読み取り(レプリカ接続)
▼
┌──────────────┐
│ CDCエンジン │
│ (Debezium等) │
└──────┬───────┘
│ JSON イベント発行
▼
┌──────────────┐
│ Kafkaトピック │
│ mydb.orders │
└──────────────┘
トリガーベースCDC
データベースのトリガー機能を使い、テーブルへのINSERT/UPDATE/DELETE発生時にシャドウテーブル(変更ログテーブル)へ変更内容を書き込む方式です。実装がシンプルで、トランザクションログへの直接アクセスが難しい環境でも利用できます。ただし、トリガーはDB側の書き込み処理と同一トランザクション内で動作するため、高トラフィック環境ではDBの書き込み負荷を増大させるリスクがあります。バルクINSERTやDDL操作に対応できないケースもあります。
タイムスタンプベースCDC
テーブルにupdated_atのようなタイムスタンプカラムを持たせ、前回チェック時刻以降に更新された行をSELECTクエリで定期抽出する方式です。実装が最もシンプルで特別な権限も不要なため、小規模システムや開発初期段階でよく利用されます。ただし、DELETEした行は取得できない(レコードが消えるため)、更新間隔によっては分単位の反映遅延が発生するという制約があります。
3方式の比較
| 方式 | 仕組み | DB負荷 | DELETE検知 | 反映遅延 | 実装難易度 |
|---|---|---|---|---|---|
| ログベース(WAL/binlog) | トランザクションログ読み取り | 低 | 可 | 数秒 | 中 |
| トリガーベース | DBトリガー+シャドウテーブル | 中〜高 | 可 | 数秒〜分 | 低〜中 |
| タイムスタンプベース | updated_atカラムによる差分取得 | 低〜中 | 不可 | 分単位 | 低 |
CDCの主要ユースケース
- リアルタイムDWH同期: 本番DB(MySQL/PostgreSQL)のトランザクションデータをBigQuery・Snowflake・Redshiftへ数秒以内に反映し、常に最新状態のダッシュボードを実現します。夜間バッチによる「昨日時点のデータ」から脱却できます。
- マイクロサービス間のイベント駆動連携: サービスAのDB変更をKafkaトピック経由でサービスBに通知するTransactional Outboxパターンを実現します。サービス間の直接API呼び出しを排除し、疎結合アーキテクチャを構築できます。
- 検索インデックスのリアルタイム更新: 商品マスターDBへの変更をElasticsearchやSolrのインデックスにリアルタイム反映します。在庫状況や価格変更が即座に検索結果に反映されるECサイトで特に有効です。
- 不正検知・リアルタイムアラート: 金融系トランザクションDBの変更イベントをリアルタイム分析パイプラインへ流し込み、異常パターン(短時間の大量送金・地理的に離れた連続利用等)を即座に検知します。
主要CDCツールの比較
| ツール | 方式 | 対応DB | ホスティング | 特徴 | コスト感 |
|---|---|---|---|---|---|
| Debezium | ログベース | MySQL, PostgreSQL, MongoDB, Oracle等 | OSS(Kafka Connector) | 最も広いDB対応、Kafkaと緊密統合 | 無料(インフラコストのみ) |
| AWS DMS | ログベース+全量 | RDS/Aurora全般、Oracle、SQL Server等 | AWSマネージド | AWSエコシステムとの親和性が高い | 従量課金 |
| Fivetran | ログベース/タイムスタンプ | 200以上のコネクタ | SaaS | ノーコード、ETL機能一体型 | MAR課金(高め) |
| Oracle GoldenGate | ログベース | Oracle, DB2, SQL Server等 | エンタープライズ/クラウド | 高機能・高信頼性、エンタープライズ向け | 高価 |
| Striim | ログベース | MySQL, Oracle, SQL Server等 | SaaS/オンプレ | ストリーム処理機能内蔵、変換も可能 | 中〜高 |
OSSで始めるならDebezium+Kafka Connectが事実上の標準構成です。クラウドネイティブ環境でAWSが中心ならAWS DMS、ETLまで含めてSaaSでノーコード運用したいならFivetranが選択肢になります。
DebeziumによるMySQL CDC設定例
DebeziumはKafka Connectプラグインとして動作するOSSのCDCエンジンです。以下はMySQL向けConnector設定の例です。
{
"name": "mysql-connector",
"config": {
"connector.class": "io.debezium.connector.mysql.MySqlConnector",
"database.hostname": "mysql-db",
"database.port": "3306",
"database.user": "debezium",
"database.password": "****",
"database.server.id": "1",
"database.server.name": "mydb",
"database.include.list": "production",
"table.include.list": "production.orders,production.customers",
"database.history.kafka.bootstrap.servers": "kafka:9092",
"database.history.kafka.topic": "schema-changes"
}
}
database.server.nameはKafkaトピック名のプレフィックスになります(例: mydb.production.ordersというトピックが自動生成されます)。database.history.kafka.topicはスキーマ変更履歴を保存する専用トピックで、カラム追加・削除などのDDL変更もDebeziumが自動追跡します。table.include.listでCDC対象テーブルを絞り込み、不要なイベント発生を防ぐことを推奨します。
CDC設計の5つの考慮点
- 初期ロード(Initial Load)の設計: CDC開始前に既存データの全量スナップショットをターゲットへ投入する初期同期フェーズが必要です。Debeziumは
snapshot.modeをConnector設定で制御でき、initial(初回のみ全量)・always(毎回全量)・never(差分のみ)から選択できます。 - スキーマ変化(Schema Evolution)への対応: ソーステーブルへのカラム追加・型変更が発生した際のダウンストリームへの影響を事前設計します。Confluent Schema RegistryとAvroフォーマットを組み合わせることで、スキーマバージョン管理と互換性チェックを自動化できます。
- べき等性(Idempotency)の確保: ネットワーク障害によるイベント重複配信(at-least-once)に備え、ターゲット側でUPSERT処理を実装します。主キーをべき等キーとして利用し、同じイベントが複数回届いても結果が同一になるよう設計します。
- CDC遅延の監視: ソースDBでの変更からターゲットへの反映までのレイテンシをメトリクス化し、SLAを設定します。Debeziumのheartbeat機能を活用し、変更がない時間帯でもコネクターの生存確認ができます。
- 大量DELETE・TRUNCATE時の挙動確認:
TRUNCATE TABLEなどのバルク操作はbinlogに個別行として記録されないケースがあります。CDCエンジンごとの挙動を事前確認し、必要に応じてアプリケーション側での対応(削除フラグカラムの使用等)を検討します。
CDCを運用する際の3つの課題
CDCは強力な技術ですが、本番環境での運用では以下の3点が典型的な課題となります。
課題1: トランザクションログの保持期間管理
MySQLのbinlogはデフォルトで数日間しか保持されません。CDCエンジンがダウンした状態が続き、復旧前にログが消えた場合、データ欠損が発生します。binlog_expire_logs_secondsを十分長く設定(最低7日間推奨)し、CDCエンジンの監視アラートを整備することが重要です。PostgreSQLのWALも同様にwal_keep_sizeの適切な設定が必要です。
課題2: DB側の追加権限要求
ログベースCDCはbinlogまたはWALの読み取り権限(MySQLではREPLICATION SLAVE・REPLICATION CLIENT権限)を要求します。セキュリティポリシーとの調整が必要であり、特に外部SaaSのCDCツールを利用する場合はDB接続情報の提供範囲について慎重な検討が求められます。
課題3: ダウンストリームの処理能力とバックプレッシャー
月末バッチ処理や大規模データ移行時など、ソースDBへの大量書き込みが発生するとCDCイベントが急増します。Kafkaのパーティション設計やコンシューマーのスケーリング計画を事前に立て、バックプレッシャー(処理詰まり)時の挙動を設計しておくことが重要です。KafkaのConsumer Lag監視をSLAと紐付けて管理することを推奨します。
まとめ
CDCはバッチETLでは実現できないリアルタイムデータ連携の基盤技術として、DWH同期・イベント駆動連携・検索インデックス更新など幅広いユースケースを支えます。
- ログベースCDC(WAL/binlog)がDB負荷・信頼性・機能の面でもっともバランスが良い
- 初期ロード → CDC開始の2フェーズ設計が基本パターン
- OSSではKafka + Debeziumが標準構成
- スキーマ変化・べき等性・ログ保持期間の3点を設計時に必ず検討する
- バッチETLとの使い分けが重要で、重いトランスフォームはバッチに任せるハイブリッド構成も有効
関連記事: データパイプラインとは / ELT vs ETL / Apache Kafka入門
よくある質問(FAQ)
Q. CDCとバッチETLはどう使い分けますか?
A. リアルタイム性が必要な用途(在庫同期・不正検知・イベント駆動連携)にはCDC、夜間バッチで十分な重いトランスフォーム処理にはETLを使うのが基本です。CDCでリアルタイムレイヤーを、バッチでバッチレイヤーを担当させるLambdaアーキテクチャも有効な構成です。
Q. RDSやAuroraでCDCを使えますか?
A. はい。Aurora MySQLはbinlogを有効化(パラメータグループでbinlog_format=ROW設定)、Aurora PostgreSQLはwal_levelをlogicalに設定することでCDCに対応できます。AWS DMSをマネージドCDCエンジンとして利用する選択肢もあり、AWSエコシステムとの親和性が高い構成を取れます。
Q. CDCイベントが重複した場合の対策は?
A. ターゲット側でUPSERT(BigQueryではMERGE文、PostgreSQLではINSERT ... ON CONFLICT DO UPDATE)を実装し、主キーをべき等キーとして利用するのが標準的な対策です。Kafkaを使う場合はat-least-once配信を前提に設計し、ダウンストリームでの重複処理に耐えるべき等な処理を実装します。