
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; //ソースの serverIdstring fileName = 6; //ソース binlog のファイル名uint64 position = 7; //イベントのソース binlog ファイルにおけるオフセットstring gtid = 8; //現在のトランザクションの gtidstring 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;}
message Entries {repeated Entry items = 1; //entry list}
message Envelope {int32 version = 1; //protocol version。data 内容のデコード方法を決定します。uint32 total = 2;uint32 index = 3;bytes data = 4; //現在の version は1です。これは data 内のデータが Entries を PB シリアル化した結果であることを示します。repeated KVPair properties = 15;}
// Flink-kafka コンシューマーを作成します。FlinkKafkaConsumer<RecordMsgObject> consumer =new FlinkKafkaConsumer<>(topic, new DeserializeProtobufToRecordMsgObject(), props);
// カスタムデシリアライザ。元のメッセージを RecordMsgObject オブジェクトにデシリアライズします。@Overridepublic RecordMsgObject deserialize(ConsumerRecord<byte[], byte[]> record) throws Exception {RecordMsgObject obj = new RecordMsgObject();obj.topic = record.topic();obj.partition = record.partition();obj.offset = record.offset();obj.partitionSeq = getPartitionSeq(record);obj.key = new String(record.key());obj.headers = record.headers();// ここで受信するのは Envelope のバイナリ値です。obj.value = record.value();return obj;}
//受信したメッセージを partition に従ってパーティション処理します。stream.keyBy(RecordMsgObject::getPartition).process(new SubscribeMsgProcess(trans2sql)).setParallelism(1);
// envelope をデシリアライズします。このデモでは、1つの envelope に binlog-event のデータ全体を格納できることがデフォルトです。SubscribeProtobufData.Envelope envelope = SubscribeProtobufData.Envelope.parseFrom(record.value);if (1 != envelope.getVersion()) {throw new IllegalStateException(String.format("unsupported version: %d", envelope.getVersion()));}
// デシリアライズして Entries を取得します。ByteString envelopeData = envelope.getData();SubscribeProtobufData.Entries entries;if (1 == envelope.getTotal()) {entries = SubscribeProtobufData.Entries.parseFrom(envelopeData.toByteArray());} else {entries = SubscribeProtobufData.Entries.parseFrom(shardMsgMap.get(shardId).toByteArray());shardMsgMap.remove(shardId);}
// 各 Entry を走査し、Entry タイプに応じて sql を出力します。for (SubscribeProtobufData.Entry entry : entries.getItemsList()) {onEntry(record.partition, record.offset, ps, entry, trans2sql);}
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 の値。}
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)}
DATE、TIME、DATETIME タイプはタイムゾーンをサポートしていません。TIMESTAMP タイプはタイムゾーンをサポートします。このタイプのフィールドは、次のことを示します:保存時、システムは現在のタイムゾーンから UTC(Universal Time Coordinated)に変換して保存します。クエリ時、システムは UTC から現在のタイムゾーンに変換してクエリを実行します。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 |
フィードバック