Este apêndice descreve as operações compatíveis, estratégias de sharding, formatos de dados e exemplos de mensagens para os diferentes tipos de dados do DataHub.
Operações compatíveis com diferentes tipos de dados
O tópico é a unidade básica para assinatura e publicação de dados no DataHub e representa uma coleção de dados em streaming. O DataHub oferece suporte a dois tipos de dados: TUPLE e BLOB.
|
Tipo do DataHub |
Gravar mensagens DML |
Gravar mensagens de heartbeat upstream |
Gravar mensagens DDL |
Mapeamento de source para tópico |
Tipo |
|
TUPLE |
Compatível |
Não compatível |
Não compatível |
Uma tabela para um tópico |
Tipos compatíveis com o DataHub |
|
BLOB |
Compatível |
Compatível |
Compatível |
Um banco de dados (várias tabelas) para um tópico |
Dados binários BLOB |
Os tópicos TUPLE possuem um schema fixo, impossível de alterar após a criação. Eles são adequados para cenários em que o schema da tabela de origem é estável e não envolve operações DDL como
ADD COLUMNouDROP COLUMN. Tópicos TUPLE não encaminham mensagens DDL ou de heartbeat da origem para consumidores downstream. Esse mapeamento um para um pode ser inconveniente para o consumo downstream se houver muitas tabelas de origem, pois exige a criação de um tópico correspondente para cada uma.Os tópicos BLOB não possuem um schema predefinido e armazenam apenas dados binários brutos, o que oferece maior flexibilidade. Eles encaminham mensagens DDL e de heartbeat da origem para consumidores downstream. Além disso, mapeiam várias tabelas de um único banco de dados para um único tópico. Isso permite usar um único tópico para todas as tabelas de origem, simplificando o consumo downstream. Esse tipo é ideal para cenários em que o DataHub atua como fila de mensagens intermediária para migração completa de banco de dados.
Estratégias de sharding para diferentes tipos de dados
Um shard é um canal concorrente para transmissão de dados dentro de um tópico do DataHub. Embora um único shard tenha throughput de gravação limitado, você pode usar vários shards para aumentá-lo. O DataHub garante o consumo ordenado apenas dentro de um único shard, e não entre múltiplos shards. Para melhorar o desempenho de gravação com vários shards, mantendo a ordem das mensagens e evitando skew de dados, o DataHub oferece as seguintes estratégias de sharding para os tipos de dados TUPLE e BLOB.
|
Cenário |
TUPLE |
BLOB |
|
Com chave primária (incluindo chaves primárias personalizadas) |
Shard por chave primária |
Shard por chave primária |
|
Garantia de ordenação |
Mensagens com a mesma chave primária são processadas em ordem |
Mensagens com a mesma chave primária são processadas em ordem |
|
Sem chave primária |
Sharding aleatório |
Shard por nome da tabela |
|
Garantia de ordenação |
A ordenação não é garantida |
Mensagens da mesma tabela são processadas em ordem |
Formatos de dados
-
TUPLE
O formato TUPLE utiliza tipos de dados nativos do DataHub. O Data Integration adiciona várias colunas de metadados quando você cria um tópico. O schema do formato TUPLE contém tanto colunas de metadados quanto colunas de dados de negócios. Campos iniciados com underscore, como
_sequence_id_e_operation_type_, são colunas de metadados. Os demais campos são colunas de dados de negócios. As colunas de metadados incluem_sequence_id_,_excute_time_,_source_table_,_before_image_e_after_image_.Parâmetro
Descrição
_sequence_id_
ID de mensagem exclusivo do tipo STRING, composto por dígitos. As operações UPDATE_BEFOR e UPDATE_AFTER da mesma atualização compartilham um sequence ID.
_excute_time_
Momento em que os dados foram gerados.
_source_table_
Nome da tabela de origem.
_before_image_
Pré-imagem. O valor é
Ypara uma operação UPDATE_BEFOR ou DELETE eNpara uma operação UPDATE_AFTER ou INSERT._after_image_
Pós-imagem. O valor é
Npara uma operação UPDATE_BEFOR ou DELETE eYpara uma operação UPDATE_AFTER ou INSERT.Exemplo: A tabela a seguir mostra os dados sincronizados com o DataHub após a execução de instruções INSERT, UPDATE e 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
Uma mensagem BLOB consiste em dados binários gerados pela conversão de uma string JSON. O formato JSON correspondente é o seguinte:
{ "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" }-
Campos BLOB
ImportanteO StreamX define os tipos de dados para todos os campos na mensagem, incluindo
BOOLEAN,DOUBLE,DATE,BYTES,LONGeSTRING.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)Elemento de nível superior
Elemento de segundo nível
Descrição
schema
dataColumn
JSONArray com informações de tipo das colunas de dados. dataColumn registra todas as colunas e seus tipos em um registro de alteração de dados upstream. Uma operação de alteração pode ser uma modificação de dados (como insert, delete ou update) ou uma modificação na estrutura da tabela.
name: Nome da coluna.
type: Tipo de dados da coluna.
primaryKey
Lista de strings que representam os nomes das colunas de chave primária.
pk: Nome da chave primária.
source
Objeto com informações sobre o banco de dados ou tabela de origem.
dbType: String que representa o tipo de banco de dados.
dbVersion: String que representa a versão do banco de dados.
dbName: String que representa o nome do banco de dados.
schemaName: String que representa o nome do schema, obrigatória para bancos de dados como PostgreSQL e SQL Server.
tableName: String que representa o nome da tabela.
payload
before
JSONObject com a pré-imagem dos dados. Para uma operação
UPDATEem uma origem MySQL, o campobeforearmazena o conteúdo do registro antes da atualização.Este campo é preenchido ao ler uma mensagem de atualização ou exclusão da origem.
dataColumn: Parâmetro do tipo JSONObject que representa as informações dos dados. O formato é nome da coluna: valor da coluna. O nome da coluna é uma string, e o valor depende do seu tipo de dados: valores BYTES aparecem como strings Base64, valores DATE como timestamps long de 13 dígitos e valores de outros tipos usam seus tipos nativos.
after
Pós-imagem dos dados. O formato é igual ao do campo
before.NotaCampo obrigatório para operações
UPDATEeINSERT.op
Tipo de operação. Valores válidos:
INSERT: Inserção de dados.
UPDATE_BEFOR: Pré-imagem de uma atualização.
UPDATE_AFTER: Pós-imagem de uma atualização.
DELETE: Exclusão de dados.
TRANSACTION_BEGIN: Início de uma transação de banco de dados.
TRANSACTION_END: Fim de uma transação de banco de dados.
CREATE: Criação de tabela.
ALTER: Alteração de tabela.
QUERY: SQL original da alteração no banco de dados.
TRUNCATE: Truncamento de tabela.
RENAME: Renomeação de tabela.
CINDEX: Criação de índice.
DINDEX: Exclusão de índice.
MHEARTBEAT: Mensagem de heartbeat indicando que a tarefa de sincronização executa normalmente, mesmo sem novos dados da origem.
timestamp
JSONObject com timestamps relacionados a este registro de dados.
eventTime: Valor Long representando o momento da alteração no banco de dados de origem. É um timestamp de 13 dígitos com precisão de milissegundos.
systemTime: Valor Long representando o momento em que a tarefa de sincronização processou esta mensagem de alteração. É um timestamp de 13 dígitos com precisão de milissegundos.
checkpointTime: Valor Long representando o tempo usado para redefinir o offset de sincronização. Geralmente igual a
eventTime. É um timestamp de 13 dígitos com precisão de milissegundos.
ddl
Campo preenchido apenas para operações DDL que alteram a estrutura da tabela. Para operações DML, como inserção, exclusão e modificação de dados, o campo ddl é nulo.
text: String com o texto da instrução DDL do banco de dados.
ddlMeta: String com a representação binária de um objeto SQLStatement, codificada em Base64. O objeto SQLStatement é gerado ao analisar a instrução DDL com FastSQL.
Ao ativar o suporte a DDL, o sistema transmite o objeto SQLStatement serializado. O componente downstream pode desserializar esse objeto para reconstruir a instrução DDL no banco de dados de destino e aplicar a alteração.
version
N/A
Número da versão do formato.
-
Serialização BLOB
Neste formato JSON, cada mensagem corresponde a um único JSONObject. A estrutura desse JSONObject, que pode incluir objetos e arrays aninhados, define o formato da mensagem.
Para serializar a mensagem, converta o JSONObject em uma string (por exemplo, usando o método
toJSONStringdo fastjson) e, em seguida, converta a string em um array de bytes usando o métodoString.getBytes(Charsets.UTF_8).
-
Exemplos de mensagens JSON
-
Insert:
{ "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" } -
Update before:
{ "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" } -
Update after:
{ "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" } -
Delete:
{ "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" }