tencent cloud

Data Transfer Service

ProtoBufデモの説明

ダウンロード
フォーカスモード
フォントサイズ
最終更新日: 2026-10-16 19:45:51
AI翻訳

デモの主要ロジック解説

メッセージ生成ロジック

以下では、まずメッセージ生成ロジックについて簡単に説明します。これはユーザーが消費ロジックを理解するのに役立ちます。 私たちは Protobuf を使用してシリアル化を行い、各言語の Demo には Protobuf 定義ファイルが付属しています。ファイルにはいくつかの重要な構造が定義されています:Envelope は最終的に送信される Kafka メッセージ構造です。Entry は単一のサブスクリプションイベント構造です。Entries は Entry の集合です。主要なデータ構造の関係は以下の通りです:



生産プロセスは以下の通りです:
1. Binlogメッセージを取得し、各Binlog Eventを1つのEntry構造体にエンコードします。
message Entry { //Entryは単一のサブスクリプションイベント構造です。1つのイベントはMySQLの1つのbinlog eventに相当します。
Header header = 1; //イベントヘッダー
Event event = 2; //イベントボディ
}


message Header {
int32 version = 1; //Entryプロトコルバージョン
SourceType sourceType = 2; //ソースデータベースのタイプ情報。MySQL、Oracleなどのタイプが含まれます。
MessageType messageType = 3; //メッセージのタイプ、つまりEventのタイプです。BEGIN、COMMIT、DMLなどが含まれます。
uint32 timestamp = 4; //Eventの元のbinlogにおけるタイムスタンプ
int64 serverId = 5; //ソースのserverId
string fileName = 6; //ソースbinlogのファイル名
uint64 position = 7; //ソースbinlogファイル内のイベントのオフセット
string gtid = 8; //現在のトランザクションのgtid
string schemaName = 9; //変更の影響を受けるスキーマ
string tableName = 10; //変更の影響を受けるテーブル
uint64 seqId = 11; //グローバル増分シーケンス番号
uint64 eventIndex = 12; //大きなeventをシャード化する場合、各シャードは0から番号が振られます。現在のバージョンでは意味がなく、今後の拡張用に予約されています。
bool isLast = 13; //現在のeventがeventシャードの最後のブロックであるかどうか。最後のブロックである場合はtrueです。現在のバージョンでは意味がなく、今後の拡張用に予約されています。
repeated KVPair properties = 15;
}


message Event {
BeginEvent beginEvent = 1; //binlog内のbeginイベント
DMLEvent dmlEvent = 2; //binlog内のdmlイベント
CommitEvent commitEvent = 3; //binlog内のcommitイベント
DDLEvent ddlEvent = 4; //binlog内のddlイベント
RollbackEvent rollbackEvent = 5; //rollbackイベント。現在のバージョンでは意味がありません。
HeartbeatEvent heartbeatEvent = 6; //ソースデータベースが定期的に送信するハートビートイベント
CheckpointEvent checkpointEvent = 7; //購読バックエンドが追加するcheckpointイベントです。10秒ごとに1つ自動生成され、Kafkaの生産および消費場所の管理に使用されます。
repeated KVPair properties = 15;
}
2. メッセージ量を削減するために、複数の Entry をマージします。マージ後の構造は Entries であり、Entries.items フィールドは Entry の順序リストです。マージの数は、マージ後に Kafka の単一メッセージサイズ制限を超えないことを基準とします。単一の Event がすでにサイズ制限を超えている場合は、マージせず、Entries には唯一の Entry のみが含まれます。
message Entries {
repeated Entry items = 1; //entry list
}
3. Entries に対して Protobuf エンコードを行い、バイナリシーケンスを取得します。
4. Entries のバイナリシーケンスを Envelope の data フィールドに格納します。単一の Binlog Event が大きすぎる場合、バイナリシーケンスが Kafka の単一メッセージサイズ制限を超える可能性があります。その場合、複数のセグメントに分割し、各セグメントを1つの Envelope に格納します。 Envelope.total と Envelope.index は、それぞれ総セグメント数と現在の Envelope のシーケンス番号(0から開始)を記録します。
message Envelope {
int32 version = 1; //プロトコルバージョン。data内容のデコード方法を決定します。
uint32 total = 2;
uint32 index = 3;
bytes data = 4; //現在のversionが1の場合、data内のデータはEntriesがPBシリアル化された結果であることを示します。
repeated KVPair properties = 15;
}
5. 前のステップで生成された1つまたは複数の Envelope に対して順次 Protobuf エンコードを行い、Kafka パーティションに配信します。同じ Entries から分割された複数の Envelope は、順番に同じパーティションに配信されます。

メッセージ消費ロジック

以下では、消費ロジックについて簡単に説明します。弊社が提供する3種類の言語のDemoは、いずれも同じフローに従います。
1. Kafkaコンシューマーを作成します。
2. 消費を開始します。
3. 元のメッセージを順次消費し、メッセージ内のパーティションに基づいて、そのパーティションに対応する partitionMsgConsumer オブジェクトを見つけ、そのオブジェクトがメッセージを処理します。
4. partitionMsgConsumer は元のメッセージを Envelope 構造にデシリアライズします。
// Kafka メッセージの Value 値を Envelope に変換します。
envelope := subscribe.Envelope{}
err := proto.Unmarshal(msg.Value, &envelope)
5. partitionMsgConsumer は、Envelope に記録された index と total に基づいて、1つまたは複数のメッセージを連続して消費します。Envelope.index が Envelope.total-1 と等しくなるまで続けます(上記の消費・生成ロジックを参照。これは完全な Entries を受信したことを示します)。
6. 受信した連続する複数の Envelope の data フィールドを順番に結合します。結合されたバイナリシーケンスを Protobuf で Entries にデコードします。
if envelope.Index == 0 {
pmc.completeMsg = envelope
} else {
// 分割された Entries のバイナリシーケンスを結合します。
pmc.completeMsg.Data = append(pmc.completeMsg.Data, envelope.Data...)
}
if envelope.Index < envelope.Total-1 {
return nil
}
// Envelope.Data を Entries にデシリアライズします。
entries := subscribe.Entries{}
err = proto.Unmarshal(pmc.completeMsg.Data, &entries)

7. Entries.items を順次処理し、元の Entry 構造を出力するか、SQL 文に変換します。
8. Checkpoint メッセージを消費したときに、Kafka のオフセットを1回コミットします。Checkpoint メッセージは、サブスクリプションバックエンドが定期的に Kafka に書き込む特殊なメッセージで、10秒ごとに1つ生成されます。

データベースフィールドマッピングとストレージ

本节では、データベースのフィールドタイプとシリアライゼーションプロトコルで定義されたデータタイプとの間のマッピング関係を説明します。 ソースデータベース(MySQLなど)のフィールド値は、Protobuf プロトコルにおいて以下の Data 構造で保存されます。
message Data {
DataType dataType = 1;
string charset = 2; //DataType_STRING のエンコーディングタイプ。値は bv に格納されます。
string sv = 3; //DataType_INT8/16/32/64/UINT8/16/32/64/Float32/64/DataType_DECIMAL の文字列値。
bytes bv = 4; //DataType_STRING/DataType_BYTES の値。
}
DataType フィールドは保存されるフィールドタイプを表し、取り得る列挙値は以下の図の通りです。
enum DataType {
NIL = 0; //値は NULL です。
INT8 = 1;
INT16 = 2;
INT32 = 3;
INT64 = 4;
UINT8 = 5;
UINT16 = 6;
UINT32 = 7;
UINT64 = 8;
FLOAT32 = 9;
FLOAT64 = 10;
BYTES = 11;
DECIMAL = 12;
STRING = 13;
NA = 14; //値は存在しません (N/A)
}
このうち、bv フィールドは STRING および BYTES タイプのバイナリ表現を格納し、sv フィールドは INT8/16/32/64/UINT8/16/32/64/DECIMAL タイプの文字列表現を格納し、charset フィールドは STRING のエンコーディングタイプを格納します。
MySQL/TDSQL の元のタイプと DataType のマッピング関係は以下の通りです(UNSIGNED で修飾された MYSQL_TYPE_INT8/16/24/32/64 は、それぞれ UINT8/16/32/32/64 にマッピングされます):
説明
DATE、TIME、DATETIME タイプはタイムゾーンをサポートしていません。
TIMESTAMP タイプはタイムゾーンをサポートします。このタイプのフィールドは、保存時にシステムが現在のタイムゾーンから UTC(Universal Time Coordinated)に変換して保存し、クエリ時にシステムが UTC から現在のタイムゾーンに変換してクエリすることを示します。
以上をまとめると、以下の表の「MYSQL_TYPE_TIMESTAMP」および「MYSQL_TYPE_TIMESTAMP_NEW」フィールドにはタイムゾーン情報が含まれます。ユーザーはデータを消費する際に自身で変換できます。(例えば、DTS が出力する時刻形式はタイムゾーン付きの文字列「2021-05-17 07:22:42 +00:00」です。このうち、「+00:00」は UTC 時間を表し、ユーザーは解析および変換の際にタイムゾーン情報を考慮する必要があります。)
MySQLフィールドタイプ(TDSQLはMySQLと同じタイプをサポート)
対応する Protobuf DataType 列挙値
MYSQL_TYPE_NULL
NIL
MYSQL_TYPE_INT8
INT8
MYSQL_TYPE_INT16
INT16
MYSQL_TYPE_INT24
INT32
MYSQL_TYPE_INT32
INT32
MYSQL_TYPE_INT64
INT64
MYSQL_TYPE_BIT
INT64
MYSQL_TYPE_YEAR
INT64
MYSQL_TYPE_FLOAT
FLOAT32
MYSQL_TYPE_DOUBLE
FLOAT64
MYSQL_TYPE_VARCHAR
STRING
MYSQL_TYPE_STRING
STRING
MYSQL_TYPE_VAR_STRING
STRING
MYSQL_TYPE_TIMESTAMP
STRING
MYSQL_TYPE_DATE
STRING
MYSQL_TYPE_TIME
STRING
MYSQL_TYPE_DATETIME
STRING
MYSQL_TYPE_TIMESTAMP_NEW
STRING
MYSQL_TYPE_DATE_NEW
STRING
MYSQL_TYPE_TIME_NEW
STRING
MYSQL_TYPE_DATETIME_NEW
STRING
MYSQL_TYPE_ENUM
STRING
MYSQL_TYPE_SET
STRING
MYSQL_TYPE_DECIMAL
DECIMAL
MYSQL_TYPE_DECIMAL_NEW
DECIMAL
MYSQL_TYPE_JSON
BYTES
MYSQL_TYPE_BLOB
BYTES
MYSQL_TYPE_TINY_BLOB
BYTES
MYSQL_TYPE_MEDIUM_BLOB
BYTES
MYSQL_TYPE_LONG_BLOB
BYTES
MYSQL_TYPE_GEOMETRY
BYTES



ヘルプとサポート

この記事はお役に立ちましたか?

フィードバック