このトピックでは、DataHub の各データ型でサポートされる操作、シャーディングポリシー、データ形式、およびメッセージのサンプルについて説明します。
データ型ごとのサポート操作
Topic は、DataHub におけるデータの購読および公開の最小単位です。Topic は、ストリーミングデータのクラスまたは種類を表すことができます。DataHub では、Tuple および Blob の 2 種類の Topic をサポートしています。
DataHub のデータ型 | DML メッセージの書き込み | 上流ハートビートメッセージの書き込み | DDL メッセージの書き込み | ソーステーブルから宛先 Topic へのマッピング | データの型 |
Tuple | サポート | 非サポート | 非サポート | 1 つのテーブル → 1 つの Topic | DataHub でサポートされるデータ型 |
Blob | サポート | サポート | サポート | 1 つのデータベース(複数のテーブル)→ 1 つの Topic | BLOB バイナリデータ |
Tuple Topic の場合、Topic 作成後にスキーマフィールドを変更することはできません。これは、ソーステーブルに `add column` や `drop column` などのデータ定義言語 (DDL) 操作によるスキーマ変更が発生しない固定スキーマのシナリオに適しています。Tuple Topic では、上流ソースからの DDL メッセージおよびハートビートメッセージの保存はサポートされていません。つまり、これらのメッセージをダウンストリームのコンシューマーに渡すことはできません。マッピングは「1 つのソーステーブル → 1 つの Topic」です。ソーステーブルが多数ある場合、対応する Topic を多数作成する必要があり、これによりダウンストリームでの消費が複雑化する可能性があります。
Blob Topic にはスキーマがなく、BLOB バイナリデータのみを格納します。そのため、柔軟性が高くなります。また、ソースからの DDL メッセージおよびハートビートメッセージの保存をサポートしており、これらをダウンストリームのコンシューマーに渡すことができます。マッピングは「1 つのデータベース(複数のテーブル)→ 1 つの Topic」です。ソーステーブルの数に関係なく、1 つの Topic のみを作成すればよいので、ダウンストリームでの消費が簡素化されます。このため、Blob Topic は、DataHub を完全データ移行のための中間メッセージキューとして使用するシナリオに特に適しています。
データ型ごとのシャーディングポリシー
シャードは、DataHub Topic へのデータ送信を行う同時チャネルです。各シャードには最大書き込み速度が設定されています。複数のシャードを使用することで、書き込みパフォーマンスを向上させることができます。ただし、DataHub では、単一のシャード内でのみメッセージ順序が保証され、複数のシャード間では順序は保証されません。シャード数を増加させて書き込みパフォーマンスを向上させる一方で、メッセージ順序を確保し、データスキューを回避するため、Blob Topic および Tuple Topic に対して以下のシャーディングポリシーが提供されています。
シナリオ | Tuple | Blob |
プライマリキーあり(カスタムプライマリキーを含む) | プライマリキーによるシャーディング | プライマリキーによるシャーディング |
注文保証 | 同一プライマリキーを持つメッセージは順序付けられます | 同一プライマリキーを持つメッセージは順序付けられます |
プライマリキーなし | ランダムシャーディング | テーブル名によるシャーディング |
注文保証 | 順序は保証されません | 同一テーブルのメッセージは順序付けられます |
同期データ形式
Tuple
データ形式は、DataHub Tuple Topic でサポートされるデータ型を使用します。Data Integration で Topic を作成すると、特定のメタデータ列が自動的に追加されます。
追加されるメタデータ列は、
_sequence_id_、_execute_time_、_source_table_、_before_image_、および_after_image_です。パラメーター
説明
_sequence_id_
文字列型。各メッセージに割り当てられる一意の数値 ID です。「update before」と「update after」の操作では、同じ sequence ID を共有します。
_excute_time_
データが生成された時刻です。
_source_table_
ソーステーブルの名称です。
_before_image_
「before image」です。「update before」と「delete」操作では Y、「update after」と「insert」操作では N になります。
_after_image_
「after image」です。「update before」と「delete」操作では N、「update after」と「insert」操作では Y になります。
例:以下の表は、Insert、Update、Delete 文を DataHub に同期した結果を示しています。
_sequence_id_
_operation_type_
_excute_time_
_before_image_
_after_image_
1649991610688000000
I
1649991726000
N
Y
1649991610688000001
U
1649991756000
Y
N
1649991610688000001
U
1649991756000
N
Y
1649991610688000002
D
1649991774000
Y
N
Blob
Blob Topic のメッセージ形式は、JSON 文字列から変換されたバイナリデータです。対応する JSON 形式は以下のとおりです:
{ "schema": { // 変更に関するメタデータ情報。カラム名とその型のみを指定 "dataColumn": [// 変更されたデータカラムに関する情報。宛先テーブルのレコード更新に使用 { "name": "id", "type": "LONG" }, { "name": "name", "type": "STRING" }, { "name": "binData", "type": "BYTES" }, { "name": "ts", "type": "DATE" } ], "primaryKey": [ "pkName1", "pkName2" ], "source": { "dbType": "mysql", "dbVersion": "1.0.0", "dbName": "myDatabase", "schemaName": "mySchema", "tableName": "tableName" } }, "payload": { "before": { "dataColumn":{ "id": 111, "name":"scooter", "binData": "[base64 string]", "ts": 1590315269000 } }, "after": { "dataColumn":{ "id": 222, "name":"donald", "binData": "[base64 string]", "ts": 1590315269000 } }, "sequenceId":XXX, // 文字列型。増分データと完全データをマージする際のデータ並べ替えに使用 "op": "INSERT/UPDATE/DELETE/TRANSACTION_BEGIN/TRANSACTION_END/CREATE/ALTER/ERASE/QUERY/TRUNCATE/RENAME/CINDEX/DINDEX/GTID/XACOMMIT/XAROLLBACK/MHEARTBEAT...", // 大文字小文字を区別 "timestamp": { "eventTime": 1, // 必須。レコード変更時の時刻。ミリ秒精度の 13 桁タイムスタンプ。 "systemTime": 2, // 任意。Oracle CDC などの一部のデータソースで存在。 "checkpointTime": 3 // 任意。OceanBase Database などの一部のデータソースで含まれる。 }, "ddl": { "text": "ADD COLUMN ...", "ddlMeta": "[SQLStatement のシリアル化バイナリ。Base64 文字列で表現]" } }, "version":"1.0.0" }Blob フィールドの説明
重要メッセージ内のすべてのフィールド型は、StreamX で定義された 6 種類のいずれかである必要があります:BOOLEAN、DOUBLE、DATE、BYTES、LONG、STRING。
BOOLEAN: 値は true または false。 DATE: 値はミリ秒精度の 13 桁整数(タイムスタンプ)。 BYTES: bytes 型を格納。フォーマットは Base64 エンコード済み文字列。 Base64 のエンコーディングおよびデコードは、java.util.Base64 のインターフェイスを使用して実装: String text = "test_text123"; // エンコード Base64.getEncoder().encodeToString(text.getBytes("UTF-8")) // デコード Base64.getDecoder().decode(encodedText)1 次要素
2 次要素
説明
schema
dataColumn
JSONArray 型。データカラムの型に関する情報。dataColumn は、上流のデータ変更におけるすべてのカラムおよび対応する型情報を記録します。変更操作には、データの変更(挿入、削除、更新)およびデータベース内のテーブルスキーマ変更が含まれます。
name:カラム名
type:カラムの型
primaryKey
List 型。プライマリキーに関する情報。
pk:プライマリキーの名称
source
Object 型。ソースデータベースまたはテーブルに関する情報。
dbType:文字列型。データベースの種類
dbVersion:文字列型。データベースのバージョン
dbName:文字列型。データベース名
schemaName:文字列型。スキーマ名(PostgreSQL や SQL Server などのデータベース用)
tableName:文字列型。テーブル名
payload
before
JSONObject 型。変更前のデータです。たとえば、MySQL データソースのレコードに対する更新操作の場合、before フィールドには更新前のレコード内容が格納されます。
更新または削除操作のメッセージをソースから読み取った際に、書き込まれたレコードにこのフィールドが設定されます。
dataColumn:JSONObject 型。データ情報。フォーマットは column_name: column_value です。カラム名は文字列、カラム値はその型に依存します。BYTES 型は Base64 文字列で表現、DATE 型は長整数で表現されるミリ秒精度の 13 桁タイムスタンプ、その他の型はそれぞれ固有の値型を使用します。
after
変更後のデータです。フォーマットは before と同じです。
説明更新および挿入操作では必須です。
op
操作タイプ。有効な値は以下のとおりです:
INSERT:データの挿入
UPDATE_BEFOR:データ更新前
UPDATE_AFTER:データ更新後
DELETE:データの削除
TRANSACTION_BEGIN:データベーストランザクションの開始
TRANSACTION_END:データベーストランザクションの終了
CREATE:データベース内でのテーブル作成
ALTER:データベース内でのテーブル変更
QUERY:データベース変更元のオリジナル SQL
TRUNCATE:データベース内でのテーブルの切り捨て
RENAME:データベース内でのテーブル名変更
CINDEX:インデックスの作成
DINDEX:インデックスの削除
MHEARTBEAT:新規データがない場合でも同期が正常であることを示すハートビートメッセージ
timestamp
JSONObject 型。このデータレコードに関連するタイムスタンプです。
eventTime:long 型。ソースデータベースで変更が発生した時刻。ミリ秒精度の 13 桁タイムスタンプ。
systemTime:long 型。同期タスクがこの変更メッセージを処理した時刻。ミリ秒精度の 13 桁タイムスタンプ。
checkpointTime:long 型。同期オフセットをリセットしたときに設定される時刻。ミリ秒精度の 13 桁タイムスタンプで、通常は eventTime と同じ値です。
ddl
このフィールドは、データベースのテーブルスキーマが変更された場合にのみ設定されます。データ変更(挿入、削除、更新を含む)では、ddl フィールドは null に設定されます。
text:文字列型。データベース DDL 文のテキスト
ddlMeta:文字列型。FastSQL を使用して DDL 文を解析した結果得られる SQLStatement オブジェクトのバイナリ表現。このバイナリ表現はシリアル化され、Base64 エンコードされた文字列として格納されます。
DDL サポートが有効な場合、シリアル化された SQLStatement オブジェクトを必ず渡す必要があります。ダウンストリーム側のリンクでは、このオブジェクトを逆シリアル化・解析し、宛先データソースで変更を実行できる DDL 文へ復元します。
version
なし
フォーマットのバージョン番号です。
Blob のシリアル化の説明
本トピックで定義される JSON 形式では、1 つのメッセージが 1 つの JSONObject に対応します。JSONObject 内のコンテンツは、メッセージ形式に従って、JSONObject、JSONArray、または特定の型の値など、対応する形式へレベルごとにマップされます。
JSONObject 内の各フィールドのストレージ型は、前述のフィールド説明と一致します。シリアル化では、JSONObject を文字列(fastJSON の toJSONString メソッドなど)に変換し、その後、その文字列を UTF-8 文字セットでバイト配列(getBytes(Charsets.UTF_8) メソッド)に変換します。
関連メッセージの JSON サンプル
挿入(Insert):
{ "schema": { "dataColumn": [ { "name": "id", "type": "LONG" }, { "name": "name", "type": "STRING" }, { "name": "comment", "type": "STRING" } ], "source": { "dbName": "yunshi_db", "dbType": "MySQL", "tableName": "t_shiyu_pk" }, "primaryKey": [ "id", "name" ] }, "payload": { "op": "INSERT", "after": { "dataColumn": { "name": "joe", "comment": "comment", "id": 1 } }, "sequenceId": "1605339516000000004", "timestamp": { "eventTime": 1605339932000, "systemTime": 1605339932736, "checkpointTime": 1605339932000 } }, "version": "0.0.1" }更新前(Update before):
{ "schema": { "dataColumn": [ { "name": "id", "type": "LONG" }, { "name": "name", "type": "STRING" }, { "name": "comment", "type": "STRING" } ], "source": { "dbName": "yunshi_db", "dbType": "MySQL", "tableName": "t_shiyu_pk" }, "primaryKey": [ "id", "name" ] }, "payload": { "op": "UPDATE_BEFOR", "before": { "dataColumn": { "name": "joe", "comment": "comment", "id": 1 } }, "sequenceId": "1605339516000000005", "timestamp": { "eventTime": 1605339934000, "systemTime": 1605339934951, "checkpointTime": 1605339934000 } }, "version": "0.0.1" }更新後(Update after):
{ "schema": { "dataColumn": [ { "name": "id", "type": "LONG" }, { "name": "name", "type": "STRING" }, { "name": "comment", "type": "STRING" } ], "source": { "dbName": "yunshi_db", "dbType": "MySQL", "tableName": "t_shiyu_pk" }, "primaryKey": [ "id", "name" ] }, "payload": { "op": "UPDATE_AFTER", "after": { "dataColumn": { "name": "joe", "comment": "com1", "id": 1 } }, "sequenceId": "1605339516000000005", "timestamp": { "eventTime": 1605339934000, "systemTime": 1605339934951, "checkpointTime": 1605339934000 } }, "version": "0.0.1" }削除(Delete):
{ "schema": { "dataColumn": [ { "name": "id", "type": "LONG" }, { "name": "name", "type": "STRING" }, { "name": "comment", "type": "STRING" } ], "source": { "dbName": "yunshi_db", "dbType": "MySQL", "tableName": "t_shiyu_pk" }, "primaryKey": [ "id", "name" ] }, "payload": { "op": "DELETE", "before": { "dataColumn": { "name": "joe", "comment": "com1", "id": 1 } }, "sequenceId": "1605339516000000006", "timestamp": { "eventTime": 1605339937000, "systemTime": 1605339937671, "checkpointTime": 1605339937000 } }, "version": "0.0.1" }ハートビート(Heartbeat):
{ "schema": {}, "payload": { "op": "MHEARTBEAT", "timestamp": { "eventTime": 1605339953629, "checkpointTime": 1605339953629 } }, "version": "0.0.1" }DDL:
{ "schema": { "source": { "dbName": "test_db", "dbType": "MySQL", "tableName": "t_test_nopk" } }, "payload": { "op": "ALTER", "sequenceId": "1605339516000000035", "ddl": { "text": "alter table t_test_nopk add column holo text", "ddlMeta": "rO0ABXNyACljb20uYWxpYmFiYS5kaS5wbHVnaW4uY2VudGVyLm1ldGEuRERMTWV0YQLb5Cx/YWXtAgACTAAHZGRsVGV4dHQAEkxqYXZhL2xhbmcvU3RyaW5nO0wACXN0YXRlbWVudHQAKkxjb20vYWxpYmFiYS9mYXN0c3FsL3NxbC9hc3QvU1FMU3RhdGVtZW50O3hwdAAtYWx0ZXIgdGFibGUgdF9zaGl5dV9ub3BrIGFkZCBjb2x1bW4gaG9sbyB0ZXh0c3IAPGNvbS5hbGliYWJhLmZhc3RzcWwuc3FsLmFzdC5zdGF0ZW1lbnQuU1FMQWx0ZXJUYWJsZVN0YXRlbWVudBQPP3vMUl2cAgAPSQAHYnVja2V0c1oABmlnbm9yZVoAF2ludmFsaWRhdGVHbG9iYWxJbmRleGVzWgAPbWVyZ2VTbWFsbEZpbGVzWgAHb2ZmbGluZVoABm9ubGluZVoADnJlbW92ZVBhdGl0aW5nWgATdXBkYXRlR2xvYmFsSW5kZXhlc1oAD3VwZ3JhZGVQYXRpdGluZ0wAC2NsdXN0ZXJlZEJ5dAAQTGphdmEvdXRpbC9MaXN0O0wABWl0ZW1zcQB+AAZMAAlwYXJ0aXRpb250ACxMY29tL2FsaWJhYmEvZmFzdHNxbC9zcWwvYXN0L1NRTFBhcnRpdGlvbkJ5O0wACHNvcnRlZEJ5cQB+AAZMAAx0YWJsZU9wdGlvbnNxAH4ABkwAC3RhYmxlU291cmNldAA6TGNvbS9hbGliYWJhL2Zhc3RzcWwvc3FsL2FzdC9zdGF0ZW1lbnQvU1FMRXhwclRhYmxlU291cmNlO3hyACxjb20uYWxpYmFiYS5mYXN0c3FsLnNxbC5hc3QuU1FMU3RhdGVtZW50SW1wbEOxUUDVCJMGAgADWgAJYWZ0ZXJTZW1pTAAGZGJUeXBldAAcTGNvbS9hbGliYWJhL2Zhc3RzcWwvRGJUeXBlO0wACWhlYWRIaW50c3EAfgAGeHIAKWNvbS5hbGliYWJhLmZhc3RzcWwuc3FsLmFzdC5TUUxPYmplY3RJbXBs5LvqLFggFVECAAVJAAxzb3VyY2VDb2x1bW5JAApzb3VyY2VMaW5lTAAKYXR0cmlidXRlc3QAD0xqYXZhL3V0aWwvTWFwO0wABGhpbnR0ACxMY29tL2FsaWJhYmEvZmFzdHNxbC9zcWwvYXN0L1NRTENvbW1lbnRIaW50O0wABnBhcmVudHQAJ0xjb20vYWxpYmFiYS9mYXN0c3FsL3NxbC9hc3QvU1FMT2JqZWN0O3hwAAAAAAAAAABwcHAAfnIAGmNvbS5hbGliYWJhLmZhc3RzcWwuRGJUeXBlAAAAAAAAAAASAAB4cgAOamF2YS5sYW5nLkVudW0AAAAAAAAAABIAAHhwdAAFbXlzcWxwAAAAAAAAAAAAAAAAc3IAE2phdmEudXRpbC5BcnJheUxpc3R4gdIdmcdhnQMAAUkABHNpemV4cAAAAAB3BAAAAAB4c3EAfgAUAAAAAXcEAAAAAXNyADxjb20uYWxpYmFiYS5mYXN0c3FsLnNxbC5hc3Quc3RhdGVtZW50LlNRTEFsdGVyVGFibGVBZGRDb2x1bW4l5T6CFe//BAIABloAB2Nhc2NhZGVaAAVmaXJzdEwAC2FmdGVyQ29sdW1udAAlTGNvbS9hbGliYWJhL2Zhc3RzcWwvc3FsL2FzdC9TUUxOYW1lO0wAB2NvbHVtbnNxAH4ABkwAC2ZpcnN0Q29sdW1ucQB+ABhMAAhyZXN0cmljdHQAE0xqYXZhL2xhbmcvQm9vbGVhbjt4cQB+AAsAAAAAAAAAAHBwcQB+AA8AAHBzcQB+ABQAAAABdwQAAAABc3IAOWNvbS5hbGliYWJhLmZhc3RzcWwuc3FsLmFzdC5zdGF0ZW1lbnQuU1FMQ29sdW1uRGVmaW5pdGlvbst0gLKZ0qAtAgAmWgANYXV0b0luY3JlbWVudFoADGRpc2FibGVJbmRleFoAB3ByZVNvcnRJAAxwcmVTb3J0T3JkZXJaAAZzdG9yZWRaAAd2aXJ0dWFsWgAHdmlzaWJsZUwACGFubkluZGV4dAApTGNvbS9hbGliYWJhL2Zhc3RzcWwvc3FsL2FzdC9TUUxBbm5JbmRleDtMAAZhc0V4cHJ0ACVMY29tL2FsaWJhYmEvZmFzdHNxbC9zcWwvYXN0L1NRTEV4cHI7TAALY2hhcnNldEV4cHJxAH4AHkwADWNvbFByb3BlcnRpZXNxAH4ABkwAC2NvbGxhdGVFeHBycQB+AB5MAAdjb21tZW50cQB+AB5MAAtjb21wcmVzc2lvbnQALkxjb20vYWxpYmFiYS9mYXN0c3FsL3NxbC9hc3QvZXhwci9TUUxDaGFyRXhwcjtMAANkYnQAcQB+AApMAALkZWZhdWx0RXhwcXEAfgAfTAAGZm9ybWF0cQB+AB5MABBnZW5lcmF0ZWRBbGF3c0FzcQB+AB5MAAhpZGVudGl0eXQARExjb20vYWxpYmFiYS9mYXN0c3FsL3NxbC9hc3Qvc3RhdGVtZW50L1NRTENvbHVtbkRlZmluaXRpb24kSWRlbnRpdHk7TAASam9zbkluZGV4QXR0cnNFeHBycQB+AB5MAAhtYXBwZWRCeXEAfgAGTAAEbmFtZXEAfgAYTAAMbmxwVG9rZW5pemVycQB+AB5MAAhvblVwZGF0ZXEAfgAeTAAEcmVseXEAfgAZTAAMc2VxdWVuY2VUeXBldAAvTGNvbS9hbGliYWJhL2Zhc3RzcWwvc3FsL2FzdC9BdXRvSW5jcmVtZW50VHlwZTtMAARzdGVwcQB+AB5MAAdzdG9yYWdlcQB+AB5MAAl1bml0Q291bnRxAH4AHkwACXVuaXRJbmRleHEAfgAeTAAIdmFsaWRhdGVxAH4AGUwACXZhbHVlVHlwZXEAfgAeeHEAfgALAAAAAAAAAABwcHEAfgAaAAAAAAAAAAAAAHBwcHBwcHBzcQB+ABQAAAAAdwQAAAAAeHNyADpjb20uYWxpYmFiYS5mYXN0c3FsLnNxbC5hc3Quc3RhdGVtZW50LlNRTENoYXJhY3RlckRhdGFUeXBlqtJac/d+04cCAAVaAAloYXNCaW5hcnlMAAtjaGFyU2V0TmFtZXEAfgABTAAIY2hhclR5cGVxAH4AAUwAB2NvbGxhdGVxAH4AAUwABWhpbnRzcQB+AAZ4cgArY29tLmFsaWJhYmEuZmFzdHNxbC5zcWwuYXN0LlNRTERhdGFUeXBlSW1wbEWL29pc1gZFAgAJSgAObmFtZUhhc2hDb2RlNjRaAAh1bnNpZ25lZFoAEXdpdGhMb2NhbFRpbWVab25lWgAIemVyb2ZpbGxMAAlhcmd1bWVudHNxAH4ABkwABmRiVHlwZXEAfgAKTAAHaW5kZXhCeXEAfgAeTAAEbmFtZXEAfgABTAAMd2l0aFRpbWVab25lcQB+ABl4cQB+AAsAAAAAAAAAAHBwcQB+ACP6BPTvGZVAfgAAAHNxAH4AFAAAAAB3BAAAAAB4cHB0AAR0ZXh0cABwcHBwcQB+ABJwcHBwcHBwcHBwc3IAMmNvbS5hbGliYWJhLmZhc3RzcWwuc3FsLmFzdC5leHByLlNRTElkZW50aWZpZXJFeHBy3DXH1zvWbgkCAARKAApoYXNoQ29kZTY0TAAEbmFtZXEAfgABTAAOcmVzb2x2ZWRDb2x1bW5xAH4ADkwAE3Jlc29sdmVkT3duZXJPYmplY3RxAH4ADnhyACdjb20uYWxpYmFiYS5mYXN0c3FsLnNxbC5hc3QuU1FMRXhwckltcGxs2ypmFJxWrQIAAHhxAH4ACwAAAAAAAAAAcHBwQCnxzH5tIDl0AARob2xvcHBwcHBwcHBwcHBweHBweHBzcQB+ABQAAAAAdwQAAAAAeHNxAH4AFAAAAAB3BAAAAAB4c3IAOGNvbS5hbGliYWJhLmZhc3RzcWwuc3FsLmFzdC5zdGF0ZW1lbnQuU1FMRXhwclRhYmxlU291cmNlRHD7eYJ4eswCAAVMAAdjb2x1bW5zcQB+AAZMAARleHBycQB+AB5MAApwYXJ0aXRpb25zcQB+AAZMAAhzYW1wbGluZ3QAOExjb20vYWxpYmFiYS9mYXN0c3FsL3NxbC9hc3Qvc3RhdGVtZW50L1NRTFRhYmxlU2FtcGxpbmc7TAAMc2NoZW1hT2JqZWN0dAAxTGNvbS9hbGliYWJhL2Zhc3RzcWwvc3FsL3JlcG9zaXRvcnkvU2NoZW1hT2JqZWN0O3hyADhjb20uYWxpYmFiYS5mYXN0c3FsLnNxbC5hc3Quc3RhdGVtZW50LlNRTFRhYmxlU291cmNlSW1wbAqEMenTm5zUAgAESgAPYWxpYXNIYXNoQ29kZTY0TAAFYWxpYXNxAH4AAUwACWZsYXNoYmFja3EAfgAeTAAFaGludHNxAH4ABnhxAH4ACwAAAAAAAAAAcHBwAAAAAAAAAABwcHBwc3EAfgAqAAAAAAAAAABwcHEAfgA0NH7o4UvP9Dt0AAx0X3NoaXl1X25vcGtwcHBwcA==" }, "timestamp": { "eventTime": 1605342109000, "systemTime": 1605342109259, "checkpointTime": 1605342109000 } }, "version": "0.0.1" }