本付録では、DataHub のさまざまなデータ型でサポートされる操作、シャーディング戦略、データフォーマット、メッセージの例について説明します。
データ型ごとにサポートされる操作
トピックは DataHub におけるデータサブスクリプションとパブリケーションの基本単位であり、ストリーミングデータのコレクションを表します。DataHub は、TUPLE と BLOB の 2 つのデータ型をサポートしています。
|
DataHub の型 |
DML メッセージの書き込み |
アップストリームのハートビートメッセージの書き込み |
DDL メッセージの書き込み |
ソースとトピックのマッピング |
型 |
|
TUPLE |
サポート |
非サポート |
非サポート |
1 つのテーブル対 1 つのトピック |
DataHub がサポートする型 |
|
BLOB |
サポート |
サポート |
サポート |
1 つのデータベース (複数のテーブル) 対 1 つのトピック |
BLOB バイナリデータ |
-
TUPLE トピックは固定スキーマを持ち、作成後に変更することはできません。これらは、ソーステーブルのスキーマが安定しており、
ADD COLUMNやDROP COLUMNなどの DDL 操作を伴わないシナリオに適しています。TUPLE トピックは、ソースからの DDL メッセージやハートビートメッセージのダウンストリームコンシューマーへの転送をサポートしていません。この 1 対 1 のマッピングは、ソーステーブルが多数ある場合、それぞれに対応するトピックを作成する必要があるため、ダウンストリームでのコンシュームには不便な場合があります。 -
BLOB トピックには事前定義されたスキーマがなく、raw バイナリデータのみを格納するため、より柔軟性があります。ソースからの DDL メッセージやハートビートメッセージのダウンストリームコンシューマーへの転送をサポートしています。単一のデータベースから複数のテーブルを 1 つのトピックにマッピングします。これにより、すべてのソーステーブルに対して 1 つのトピックを使用でき、ダウンストリームでのコンシュームが簡素化されます。この型は、DataHub がデータベース全体の移行のための中間メッセージキューとして機能するシナリオに最適です。
データ型ごとのシャーディング戦略
シャードは、DataHub トピック内のデータ転送のための同時実行チャネルです。単一のシャードの書き込みスループットは制限されていますが、複数のシャードを使用してそれを向上させることができます。DataHub は、単一のシャード内でのみ順序どおりのコンシュームを保証し、複数のシャード間では保証しません。メッセージの順序を維持し、データスキューを防ぎながら、複数のシャードで書き込みパフォーマンスを向上させるために、DataHub は TUPLE および BLOB データ型に対して次のシャーディング戦略を提供します。
|
シナリオ |
TUPLE |
BLOB |
|
プライマリキーあり (カスタムプライマリキーを含む) |
プライマリキーによるシャーディング |
プライマリキーによるシャーディング |
|
順序の保証 |
同じプライマリキーを持つメッセージは順序どおりに処理されます |
同じプライマリキーを持つメッセージは順序どおりに処理されます |
|
プライマリキーなし |
ランダムシャーディング |
テーブル名によるシャーディング |
|
順序の保証 |
順序は保証されません |
同じテーブルからのメッセージは順序どおりに処理されます |
データフォーマット
-
TUPLE
TUPLE フォーマットは、DataHub がネイティブにサポートするデータ型を使用します。Data Integration は、トピックを作成する際にいくつかのメタデータ列を追加します。TUPLE フォーマットのスキーマには、メタデータ列とビジネスデータ列の両方が含まれます。アンダースコアで始まるフィールド (例:
_sequence_id_、_operation_type_) はメタデータ列です。残りのフィールドはビジネスデータ列です。メタデータ列には、_sequence_id_、_excute_time_、_source_table_、_before_image_、_after_image_が含まれます。パラメーター
説明
_sequence_id_
STRING 型の一意のメッセージ ID で、数字で構成されます。同じ更新に対する UPDATE_BEFORE 操作と UPDATE_AFTER 操作は、同じシーケンス ID を共有します。
_excute_time_
データが生成された時刻。
_source_table_
ソーステーブルの名前。
_before_image_
更新前イメージ。UPDATE_BEFORE または DELETE 操作の値は
Y、UPDATE_AFTER または INSERT 操作の値はNです。_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 メッセージは、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_BEFORE/UPDATE_AFTER/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 などの一部のデータソースに含まれます。 }, "ddl": { "text": "ADD COLUMN ...", "ddlMeta": "[SQLStatement のシリアル化されたバイナリ。base64 文字列で表現]" } }, "version":"1.0.0" }-
BLOB フィールド
重要メッセージ内のすべてのフィールドのデータ型は StreamX によって定義され、
BOOLEAN、DOUBLE、DATE、BYTES、LONG、STRINGが含まれます。BOOLEAN:値は `true` または `false` です。 DATE:値は、ミリ秒精度のタイムスタンプを表す 13 桁の整数です。 BYTES:バイト配列を Base64 エンコードされた文字列として格納します。 Base64 のエンコードとデコードには `java.util.Base64` API を使用します: String text = "テスト text123"; // エンコード Base64.getEncoder().encodeToString(text.getBytes("UTF-8")) // デコード Base64.getDecoder().decode(encodedText)トップレベル要素
セカンドレベル要素
説明
schema
dataColumn
データ列の型情報を含む JSONArray です。dataColumn は、アップストリームのデータ変更レコード内のすべての列とその型を記録します。変更操作は、データ変更 (挿入、削除、更新など) またはテーブル構造の変更であることがあります。
-
name:列名。
-
type:列のデータ型。
primaryKey
プライマリキー列名を表す文字列のリストです。
pk: プライマリキーの名前。
source
ソースデータベースまたはテーブルに関する情報を含むオブジェクトです。
-
dbType:データベースのタイプを表す文字列。
-
dbVersion:データベースのバージョンを表す文字列。
-
dbName:データベース名を表す文字列。
-
schemaName:スキーマ名を表す文字列。PostgreSQL や SQL Server などのデータベースで必要です。
-
tableName:テーブル名を表す文字列。
payload
before
データの更新前イメージを含む JSONObject です。MySQL ソースに対する
UPDATE操作の場合、beforeフィールドには更新前のレコードのコンテンツが格納されます。-
このフィールドは、ソースから更新または削除メッセージが読み取られたときに設定されます。
-
dataColumn:データ情報を表す JSONObject 型のパラメーター。フォーマットは 列名:列値 です。列名は文字列で、列値はそのデータ型に依存します:BYTES 型の値は Base64 文字列として表され、DATE 型の値は long 型の 13 桁のタイムスタンプとして表され、その他の型の値はネイティブ型で表されます。
after
データの更新後イメージ。フォーマットは
beforeフィールドと同じです。説明UPDATEおよびINSERT操作では、このフィールドは必須です。op
操作のタイプ。有効な値:
-
INSERT:データ挿入。
-
UPDATE_BEFORE:更新の更新前イメージ。
-
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 値。この値は通常、
eventTimeと同じです。ミリ秒精度の 13 桁のタイムスタンプです。
ddl
このフィールドは、テーブル構造を変更する DDL 操作の場合にのみ設定されます。データ挿入、削除、変更などの DML 操作の場合、ddl フィールドは null です。
-
text:データベースの DDL ステートメントテキストを含む文字列。
-
ddlMeta:SQLStatement オブジェクトのバイナリ表現を含む文字列で、Base64 でエンコードされています。SQLStatement オブジェクトは、FastSQL で DDL ステートメントを解析して生成されます。
DDL サポートを有効にすると、システムはシリアル化された SQLStatement オブジェクトを渡します。その後、ダウンストリームコンポーネントはこのオブジェクトを逆シリアル化して、宛先データソースの DDL ステートメントを再構築し、変更を適用できます。
version
N/A
フォーマットのバージョン番号。
-
-
BLOB のシリアル化
この JSON フォーマットでは、各メッセージが単一の JSONObject に対応します。ネストされたオブジェクトや配列を含むことができるこの JSONObject の構造が、メッセージフォーマットを定義します。
メッセージをシリアル化するには、JSONObject を文字列に変換し (たとえば、fastjson の
toJSONStringメソッドを使用)、次にString.getBytes(Charsets.UTF_8)メソッドを使用して文字列をバイト配列に変換します。
-
JSON メッセージのサンプル
-
挿入:
{ "schema": { "dataColumn": [ { "name": "id", "type": "LONG" }, { "name": "name", "type": "STRING" }, { "name": "comment", "type": "STRING" } ], "source": { "dbName": "example_db", "dbType": "MySQL", "tableName": "example_table_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" } -
更新前:
{ "schema": { "dataColumn": [ { "name": "id", "type": "LONG" }, { "name": "name", "type": "STRING" }, { "name": "comment", "type": "STRING" } ], "source": { "dbName": "example_db", "dbType": "MySQL", "tableName": "example_table_pk" }, "primaryKey": [ "id", "name" ] }, "payload": { "op": "UPDATE_BEFORE", "before": { "dataColumn": { "name": "joe", "comment": "comment", "id": 1 } }, "sequenceId": "1605339516000000005", "timestamp": { "eventTime": 1605339934000, "systemTime": 1605339934951, "checkpointTime": 1605339934000 } }, "version": "0.0.1" } -
更新後:
{ "schema": { "dataColumn": [ { "name": "id", "type": "LONG" }, { "name": "name", "type": "STRING" }, { "name": "comment", "type": "STRING" } ], "source": { "dbName": "example_db", "dbType": "MySQL", "tableName": "example_table_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" } -
削除:
{ "schema": { "dataColumn": [ { "name": "id", "type": "LONG" }, { "name": "name", "type": "STRING" }, { "name": "comment", "type": "STRING" } ], "source": { "dbName": "example_db", "dbType": "MySQL", "tableName": "example_table_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" } -
ハートビート:
{ "schema": {}, "payload": { "op": "MHEARTBEAT", "timestamp": { "eventTime": 1605339953629, "checkpointTime": 1605339953629 } }, "version": "0.0.1" } -
DDL:
{ "schema": { "source": { "dbName": "example_db", "dbType": "MySQL", "tableName": "example_table_nopk" } }, "payload": { "op": "ALTER", "sequenceId": "1605339516000000035", "ddl": { "text": "alter table example_table_nopk add column holo text", "ddlMeta": "rO0ABXNyACljb20uYWxpYmFiYS5kaS5wbHVnaW4uY2VudGVyLm1ldGEuRERMTWV0YQLb5Cx/YWXtAgACTAAHZGRsVGV4dHQAEkxqYXZhL2xhbmcvU3RyaW5nO0wACXN0YXRlbWVudHQAKkxjb20vYWxpYmFiYS9mYXN0c3FsL3NxbC9hc3QvU1FMU3RhdGVtZW50O3hwdAAtYWx0ZXIgdGFibGUgdF9zaGl5dV9ub3BrIGFkZCBjb2x1bW4gaG9sbyB0ZXh0c3IAPGNvbS5hbGliYWJhLmZhc3RzcWwuc3FsLmFzdC5zdGF0ZW1lbnQuU1FMQWx0ZXJUYWJsZVN0YXRlbWVudBQPP3vMUl2cAgAPSQAHYnVja2V0c1oABmlnbm9yZVoAF2ludmFsaWRhdGVHbG9iYWxJbmRleGVzWgAPbWVyZ2VTbWFsbEZpbGVzWgAHb2ZmbGluZVoABm9ubGluZVoADnJlbW92ZVBhdGl0aW5nWgATdXBkYXRlR2xvYmFsSW5kZXhlc1oAD3VwZ3JhZGVQYXRpdGluZ0wAC2NsdXN0ZXJlZEJ5dAAQTGphdmEvdXRpbC9MaXN0O0wABWl0ZW1zcQB+AAZMAAlwYXJ0aXRpb250ACxMY29tL2FsaWJhYmEvZmFzdHNxbC9zcWwvYXN0L1NRTFBhcnRpdGlvbkJ5O0wACHNvcnRlZEJ5cQB+AAZMAAx0YWJsZU9wdGlvbnNxAH4ABkwAC3RhYmxlU291cmNldAA6TGNvbS9hbGliYWJhL2Zhc3RzcWwvc3FsL2FzdC9zdGF0ZW1lbnQvU1FMRXhwclRhYmxlU291cmNlO3hyACxjb20uYWxpYmFiYS5mYXN0c3FsLnNxbC5hc3QuU1FMU3RhdGVtZW50SW1wbEOxUUDVCJMGAgADWgAJYWZ0ZXJTZW1pTAAGZGJUeXBldAAcTGNvbS9hbGliYWJhL2Zhc3RzcWwvRGJUeXBlO0wACWhlYWRIaW50c3EAfgAGeHIAKWNvbS5hbGliYWJhLmZhc3RzcWwuc3FsLmFzdC5TUUxPYmplY3RJbXBs5LvqLFggFVECAAVJAAxzb3VyY2VDb2x1bW5JAApzb3VyY2VMaW5lTAAKYXR0cmlidXRlc3QAD0xqYXZhL3V0aWwvTWFwO0wABGhpbnR0ACxMY29tL2FsaWJhYmEvZmFzdHNxbC9zcWwvYXN0L1NRTENvbW1lbnRIaW50O0wABnBhcmVudHQAJ0xjb20vYWxpYmFiYS9mYXN0c3FsL3NxbC9hc3QvU1FMT2JqZWN0O3hwAAAAAAAAAABwcHAAfnIAGmNvbS5hbGliYWJhLmZhc3RzcWwuRGJUeXBlAAAAAAAAAAASAAB4cgAOamF2YS5sYW5nLkVudW0AAAAAAAAAABIAAHhwdAAFbXlzcWxwAAAAAAAAAAAAAAAAc3IAE2phdmEudXRpbC5BcnJheUxpc3R4gdIdmcdhnQMAAUkABHNpemV4cAAAAAB3BAAAAAB4c3EAfgAUAAAAAXcEAAAAAXNyADxjb20uYWxpYmFiYS5mYXN0c3FsLnNxbC5hc3Quc3RhdGVtZW50LlNRTEFsdGVyVGFibGVBZGRDb2x1bW4l5T6CFe//BAIABloAB2Nhc2NhZGVaAAVmaXJzdEwAC2FmdGVyQ29sdW1udAAlTGNvbS9hbGliYWJhL2Zhc3RzcWwvc3FsL2FzdC9TUUxOYW1lO0wAB2NvbHVtbnNxAH4ABkwAC2ZpcnN0Q29sdW1ucQB+ABhMAAhyZXN0cmljdHQAE0xqYXZhL2xhbmcvQm9vbGVhbjt4cQB+AAsAAAAAAAAAAHBwcQB+AA8AAHBzcQB+ABQAAAABdwQAAAABc3IAOWNvbS5hbGliYWJhLmZhc3RzcWwuc3FsLmFzdC5zdGF0ZW1lbnQuU1FMQ29sdW1uRGVmaW5pdGlvbst0gLKZ0qAtAgAmWgANYXV0b0luY3JlbWVudFoADGRpc2FibGVJbmRleFoAB3ByZVNvcnRJAAxwcmVTb3J0T3JkZXJaAAZzdG9yZWRaAAd2aXJ0dWFsWgAHdmlzaWJsZUwACGFubkluZGV4dAApTGNvbS9hbGliYWJhL2Zhc3RzcWwvc3FsL2FzdC9TUUxBbm5JbmRleDtMAAZhc0V4cHJ0ACVMY29tL2FsaWJhYmEvZmFzdHNxbC9zcWwvYXN0L1NRTEV4cHI7TAALY2hhcnNldEV4cHJxAH4AHkwADWNvbFByb3BlcnRpZXNxAH4ABkwAC2NvbGxhdGVFeHBycQB+AB5MAAdjb21tZW50cQB+AB5MAAtjb21wcmVzc2lvbnQALkxjb20vYWxpYmFiYS9mYXN0c3FsL3NxbC9hc3QvZXhwci9TUUxDaGFyRXhwcjtMAAtjb25zdHJhaW50c3EAfgAGTAAIZGF0YVR5cGV0AClMY29tL2FsaWJhYmEvZmFzdHNxbC9zcWwvYXN0L1NRTERhdGFUeXBlO0wABmRiVHlwZXEAfgAKTAALZGVmYXVsdEV4cHJxAH4AHkwACWRlbGltaXRlcnEAfgAeTAASZGVsaW1pdGVyVG9rZW5pemVycQB+AB5MAAZlbmFibGVxAH4AGUwABmVuY29kZXEAfgAfTAAGZm9ybWF0cQB+AB5MABBnZW5lcmF0ZWRBbGF3c0FzcQB+AB5MAAhpZGVudGl0eXQARExjb20vYWxpYmFiYS9mYXN0c3FsL3NxbC9hc3Qvc3RhdGVtZW50L1NRTENvbHVtbkRlZmluaXRpb24kSWRlbnRpdHk7TAASanNvbkluZGV4QXR0cnNFeHBycQB+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" }