Cette annexe décrit les opérations prises en charge, les stratégies de partitionnement, les formats de données et des exemples de messages pour les différents types de données DataHub.
Opérations prises en charge selon le type de données
Un topic constitue l'unité de base pour l'abonnement et la publication de données dans DataHub ; il représente une collection de données en continu. DataHub prend en charge deux types de données : TUPLE et BLOB.
|
Type DataHub |
Écriture de messages DML |
Écriture de messages de heartbeat amont |
Écriture de messages DDL |
Mappage source vers topic |
Type |
|
TUPLE |
Pris en charge |
Non pris en charge |
Non pris en charge |
Une table vers un topic |
Types pris en charge par DataHub |
|
BLOB |
Pris en charge |
Pris en charge |
Pris en charge |
Une base de données (plusieurs tables) vers un topic |
Données binaires BLOB |
Les topics TUPLE disposent d'un schéma fixe que vous ne pouvez pas modifier après leur création. Ils conviennent aux scénarios où le schéma de la table source est stable et n'implique pas d'opérations DDL telles que
ADD COLUMNouDROP COLUMN. Les topics TUPLE ne permettent pas de transférer les messages DDL ni les messages de heartbeat de la source vers les consommateurs en aval. Ce mappage un-à-un peut s'avérer contraignant pour la consommation en aval si vous disposez de nombreuses tables sources, car vous devez créer un topic correspondant pour chacune d'elles.Les topics BLOB ne possèdent pas de schéma prédéfini et stockent uniquement des données binaires brutes, ce qui les rend plus flexibles. Ils prennent en charge le transfert des messages DDL et des messages de heartbeat de la source vers les consommateurs en aval. Ils permettent de mapper plusieurs tables d'une même base de données vers un seul topic. Cette approche vous permet d'utiliser un unique topic pour toutes les tables sources, simplifiant ainsi la consommation en aval. Ce type de topic est idéal lorsque DataHub sert de file d'attente intermédiaire pour la migration complète d'une base de données.
Stratégies de partitionnement selon le type de données
Un shard représente un canal de transmission de données concurrent au sein d'un topic DataHub. Bien qu'un shard unique offre un débit d'écriture limité, vous pouvez augmenter ce débit en utilisant plusieurs shards. DataHub garantit la consommation dans l'ordre uniquement au sein d'un même shard, et non entre plusieurs shards. Pour améliorer les performances d'écriture avec plusieurs shards tout en maintenant l'ordre des messages et en évitant le déséquilibre des données, DataHub propose les stratégies de partitionnement suivantes pour les types de données TUPLE et BLOB.
|
Scénario |
TUPLE |
BLOB |
|
Avec une clé primaire (y compris les clés primaires personnalisées) |
Partitionnement par clé primaire |
Partitionnement par clé primaire |
|
Garantie d'ordre |
Les messages partageant la même clé primaire sont traités dans l'ordre |
Les messages partageant la même clé primaire sont traités dans l'ordre |
|
Sans clé primaire |
Partitionnement aléatoire |
Partitionnement par nom de table |
|
Garantie d'ordre |
L'ordre n'est pas garanti |
Les messages provenant de la même table sont traités dans l'ordre |
Formats de données
-
TUPLE
Le format TUPLE utilise les types de données nativement pris en charge par DataHub. Data Integration ajoute plusieurs colonnes de métadonnées lors de la création d'un topic. Le schéma du format TUPLE contient à la fois des colonnes de métadonnées et des colonnes de données métier. Les champs commençant par un trait de soulignement, tels que
_sequence_id_et_operation_type_, sont des colonnes de métadonnées. Les autres champs correspondent aux données métier. Les colonnes de métadonnées incluent_sequence_id_,_excute_time_,_source_table_,_before_image_et_after_image_.Paramètre
Description
_sequence_id_
ID de message unique de type STRING, composé de chiffres. Les opérations UPDATE_BEFOR et UPDATE_AFTER pour une même mise à jour partagent le même ID de séquence.
_excute_time_
Date et heure de génération des données.
_source_table_
Nom de la table source.
_before_image_
Image avant. La valeur est
Ypour une opération UPDATE_BEFOR ou DELETE, etNpour une opération UPDATE_AFTER ou INSERT._after_image_
Image après. La valeur est
Npour une opération UPDATE_BEFOR ou DELETE, etYpour une opération UPDATE_AFTER ou INSERT.Exemple : le tableau suivant présente les données synchronisées vers DataHub après l'exécution d'instructions INSERT, UPDATE et DELETE.
_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
Un message BLOB correspond à des données binaires créées à partir de la conversion d'une chaîne JSON. Le format JSON associé est le suivant :
{ "schema": { // Metadata about the change, specifying only column names and types. "dataColumn": [ // Information about the changed data columns, used to update records in the destination table. { "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, // A string used for data ordering when merging full and incremental data. "op": "INSERT/UPDATE/DELETE/TRANSACTION_BEGIN/TRANSACTION_END/CREATE/ALTER/ERASE/QUERY/TRUNCATE/RENAME/CINDEX/DINDEX/GTID/XACOMMIT/XAROLLBACK/MHEARTBEAT...", // Case-sensitive. "timestamp": { "eventTime": 1, // Required. The time of the record change. A 13-digit timestamp with millisecond precision. "systemTime": 2, // Optional. Exists for some data sources like Oracle CDC. "checkpointTime": 3 // Optional. Included for some data sources like OceanBase. }, "ddl": { "text": "ADD COLUMN ...", "ddlMeta": "[SQLStatement serialized binary, expressed in base64 string]" } }, "version":"1.0.0" }-
Champs BLOB
ImportantLes types de données pour tous les champs du message sont définis par StreamX et incluent
BOOLEAN,DOUBLE,DATE,BYTES,LONGetSTRING.BOOLEAN: The value is `true` or `false`. DATE: The value is a 13-digit integer representing a timestamp with millisecond precision. BYTES: Stores byte arrays as a Base64-encoded string. Use the `java.util.Base64` APIs for Base64 encoding and decoding: String text = "text123"; // Encode Base64.getEncoder().encodeToString(text.getBytes("UTF-8")) // Decode Base64.getDecoder().decode(encodedText)Élément de premier niveau
Élément de second niveau
Description
schema
dataColumn
Tableau JSONArray contenant les informations de type pour les colonnes de données. dataColumn recense toutes les colonnes et leurs types présents dans un enregistrement de modification de données amont. Une opération de modification peut être une modification de données (insertion, suppression ou mise à jour) ou une modification de la structure de la table.
name : nom de la colonne.
type : type de données de la colonne.
primaryKey
Liste de chaînes représentant les noms des colonnes de clé primaire.
pk : nom de la clé primaire.
source
Objet contenant les informations relatives à la base de données ou à la table source.
dbType : chaîne représentant le type de base de données.
dbVersion : chaîne représentant la version de la base de données.
dbName : chaîne représentant le nom de la base de données.
schemaName : chaîne représentant le nom du schéma, requis pour les bases de données telles que PostgreSQL et SQL Server.
tableName : chaîne représentant le nom de la table.
payload
before
Objet JSONObject contenant l'image avant des données. Pour une opération
UPDATEsur une source MySQL, le champbeforestocke le contenu de l'enregistrement avant la mise à jour.Ce champ est renseigné lorsqu'un message de mise à jour ou de suppression est lu depuis la source.
dataColumn : paramètre de type JSONObject représentant les informations de données. Le format est nom_colonne : valeur_colonne. Le nom de la colonne est une chaîne, et la valeur de la colonne dépend de son type de données : les valeurs de type BYTES sont représentées sous forme de chaînes Base64, les valeurs de type DATE sont représentées par des horodatages à 13 chiffres de type long, et les valeurs des autres types sont représentées par leurs types natifs.
after
Image après des données. Le format est identique à celui du champ
before.RemarqueCe champ est obligatoire pour les opérations
UPDATEetINSERT.op
Type d'opération. Valeurs valides :
INSERT : insertion de données.
UPDATE_BEFOR : image avant d'une mise à jour.
UPDATE_AFTER : image après d'une mise à jour.
DELETE : suppression de données.
TRANSACTION_BEGIN : début d'une transaction de base de données.
TRANSACTION_END : fin d'une transaction de base de données.
CREATE : création de table.
ALTER : modification de table.
QUERY : instruction SQL d'origine pour la modification de la base de données.
TRUNCATE : troncature de table.
RENAME : renommage de table.
CINDEX : création d'index.
DINDEX : suppression d'index.
MHEARTBEAT : message de heartbeat indiquant que la tâche de synchronisation fonctionne normalement, même en l'absence de nouvelles données provenant de la source.
timestamp
Objet JSONObject contenant les horodatages liés à cet enregistrement de données.
eventTime : valeur Long représentant l'heure à laquelle la modification s'est produite dans la base de données source. Il s'agit d'un horodatage à 13 chiffres avec une précision à la milliseconde.
systemTime : valeur Long représentant l'heure à laquelle la tâche de synchronisation a traité ce message de modification. Il s'agit d'un horodatage à 13 chiffres avec une précision à la milliseconde.
checkpointTime : valeur Long représentant l'heure utilisée pour réinitialiser le décalage de synchronisation. Cette valeur est généralement identique à
eventTime. Il s'agit d'un horodatage à 13 chiffres avec une précision à la milliseconde.
ddl
Ce champ est renseigné uniquement pour les opérations DDL qui modifient la structure de la table. Pour les opérations DML telles que l'insertion, la suppression et la modification de données, le champ ddl est nul.
text : chaîne contenant le texte de l'instruction DDL de la base de données.
ddlMeta : chaîne contenant la représentation binaire d'un objet SQLStatement, encodée en Base64. L'objet SQLStatement est généré en analysant l'instruction DDL avec FastSQL.
Si vous activez la prise en charge des DDL, le système transmet l'objet SQLStatement sérialisé. Le composant en aval peut ensuite désérialiser cet objet pour reconstruire l'instruction DDL pour la source de données de destination et appliquer la modification.
version
N/A
Numéro de version du format.
-
Sérialisation BLOB
Dans ce format JSON, chaque message correspond à un seul objet JSONObject. La structure de cet objet JSONObject, qui peut inclure des objets et des tableaux imbriqués, définit le format du message.
Pour sérialiser le message, convertissez l'objet JSONObject en chaîne (par exemple, en utilisant la méthode
toJSONStringde fastjson), puis convertissez cette chaîne en tableau d'octets à l'aide de la méthodeString.getBytes(Charsets.UTF_8).
-
Exemples de messages JSON
-
Insertion :
{ "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" } -
Mise à jour avant :
{ "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_BEFOR", "before": { "dataColumn": { "name": "joe", "comment": "comment", "id": 1 } }, "sequenceId": "1605339516000000005", "timestamp": { "eventTime": 1605339934000, "systemTime": 1605339934951, "checkpointTime": 1605339934000 } }, "version": "0.0.1" } -
Mise à jour après :
{ "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" } -
Suppression :
{ "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" } -
Heartbeat :
{ "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" }