O DataHub introduziu serialização em lote e compressão zstd para reduzir significativamente o consumo de recursos no servidor, melhorar o desempenho e diminuir os custos dos usuários.
Detalhes da atualização
Suporte à compressão zstd
O DataHub agora oferece suporte à compressão Zstandard (zstd). Em comparação com LZ4 e Deflate, o zstd proporciona melhores taxas de compressão e desempenho superior.
O zstd é um algoritmo de compressão de alto desempenho desenvolvido pelo Facebook e disponibilizado como open source em 2016. Ele se destaca tanto na velocidade quanto na taxa de compressão, sendo ideal para cargas de trabalho do DataHub.
Transformação de serialização
A serialização em lote é um método de organização de dados no DataHub. Mais do que um formato específico de serialização, ela envolve um encapsulamento secundário dos dados já serializados. Por exemplo, para enviar 100 registros de dados em um lote, o sistema primeiro serializa os registros em um buffer, depois os comprime e, por fim, os encapsula com um cabeçalho. Esse cabeçalho armazena o tamanho do buffer, a contagem de registros, o algoritmo de compressão, a soma de verificação CRC e outros metadados. O buffer resultante com o cabeçalho representa um lote completo.
A serialização em lote oferece os seguintes benefícios:
Mitiga eficazmente dados corrompidos.
Reduz a sobrecarga de CPU nos servidores de back-end e melhora o desempenho do processamento de dados.
Diminui a latência nas operações de leitura e gravação.
Após o envio de um buffer em lote ao servidor, basta verifique a soma de verificação CRC para confirme a integridade do buffer, pois o cliente já realizou verificações rigorosas de validade dos dados. Uma vez verificado, o servidor pode persistir o buffer diretamente no disco sem necessidade de serialização, desserialização, compressão, descompressão ou validação adicionais. Essa otimização aumenta o desempenho do servidor em mais de 80%. Além disso, comprimir múltiplas entradas de dados juntas melhora a taxa de compressão e reduz os custos de armazenamento.
Comparação de custos
Para comprovar os benefícios da serialização em lote, utilizamos os seguintes dados e condições de teste:
O teste utiliza aproximadamente 200 colunas de dados relacionados a publicidade. A proporção de valores nulos nos dados de teste varia entre 20% e 30%.
Cada lote contém 1.000 entradas de dados.
Utiliza-se Apache Avro para a serialização em lote.
Antes da atualização, o LZ4 era o padrão para compressão de dados. Após a atualização, o zstd passou a ser o algoritmo de compressão padrão.
A tabela a seguir apresenta os resultados dos testes.
|
Tamanho original dos dados (unidade: bytes) |
Tamanho dos dados comprimidos com LZ4 (unidade: bytes) |
Tamanho dos dados comprimidos com zstd (unidade: bytes) |
|
|
Serialização Protobuf |
11.506.677 |
3.050.640 |
1.158.868 |
|
Serialização em lote |
11.154.596 |
2.931.729 |
1.112.693 |
A redução de custos é comparada nas duas principais dimensões de faturamento do DataHub: armazenamento e tráfego. Outros itens faturáveis servem para evitar abusos e podem ser ignorados em condições normais de uso.
Custos de armazenamento: quando o DataHub utiliza serialização Protobuf, os dados armazenados não são comprimidos; a compressão ocorre apenas durante a transmissão via HTTP. Com a adoção do modo serialização em lote + zstd, o tamanho de armazenamento cai de 11.506 KB para 1.112 KB. Isso representa uma redução de aproximadamente 90% nos custos de armazenamento.
Custos de tráfego: no modo Protobuf + LZ4, o tamanho dos dados é de 3.050 KB. Já no modo serialização em lote + zstd, o volume cai para 1.112 KB. Consequentemente, os custos de tráfego diminuem em cerca de 60%.
Os resultados acima baseiam-se em dados de amostra. Os resultados reais variam conforme seus dados específicos. Recomendamos execute seus próprios testes alinhados aos requisitos do seu negócio.
Usar serialização em lote
Observações de uso
A principal vantagem da gravação em lote é a capacidade de agrupar registros de dados em lotes. Se o cliente não conseguir agrupar os registros ou se o número de registros por lote for pequeno, as melhorias podem não atender às expectativas.
Para facilitar a transição, o modo em lote é compatível com os métodos originais de leitura e gravação. Dados gravados em modo de lote ainda podem ser lidos no modo original e vice-versa. No entanto, se você gravar dados em lotes, recomendamos consumi-los também em lotes. Otherwise, the performance may be deteriorated.
Pré-requisitos
O recurso multi-version schema deve estar ativado.
É necessário utilizar a biblioteca Client versão 1.4 ou posterior.
Há suporte apenas para o DataHub SDK for Java.
Ative o recurso multi-version schema
Ative o recurso multi-version schema no console
Não é possível modifique tópicos existentes no console. Para usar a serialização em lote, ative Enable Multi-version ao crie um tópico. Para mais informações sobre como crie um tópico, consulte Criar e configure tópicos.

Ative o recurso multi-version schema usando um SDK
public static void createTopicWithOption() {
try {RecordSchema recordSchema = new RecordSchema() {{
this.addField(new Field("field1", FieldType.STRING));
this.addField(new Field("field2", FieldType.BIGINT));
}};
TopicOption option = new TopicOption();
// Enable the multi-version schema feature.
option.setEnableSchemaRegistry(true);
option.setComment(Constant.TOPIC_COMMENT);
option.setExpandMode(ExpandMode.ONLY_EXTEND);
option.setLifeCycle(Constant.LIFE_CYCLE);
option.setRecordType(RecordType.TUPLE);
option.setRecordSchema(recordSchema);
option.setShardCount(Constant.SHARD_COUNT);
datahubClient.createTopic(Constant.PROJECT_NAME, Constant.TOPIC_NAME, option);
LOGGER.info("create topic successful");
} catch (ResourceAlreadyExistException e) {
LOGGER.info("topic already exists, please check if it is consistent");
} catch (ResourceNotFoundException e) {
// project not found
e.printStackTrace();
throw e;
} catch (DatahubClientException e) {
// other error
e.printStackTrace();
throw e;
}
}
Configure a serialização em lote
Se o servidor oferecer suporte ao protocolo de transmissão em lote, o DataHub usará a serialização em lote por padrão. Caso o servidor não suporte o protocolo — por exemplo, se não estiver executando a versão mais recente do Apsara Stack ou estiver em uma versão anterior ao Apsara Stack V3.16 — o DataHub reverterá automaticamente para o método de serialização original. Os clientes se adaptam automaticamente sem configuração adicional. O exemplo a seguir utiliza a biblioteca Client 1.4.1. O sistema seleciona automaticamente o algoritmo de compressão ideal. Para a biblioteca Client 1.4 ou posterior, o zstd é usado por padrão.
Adicionar dependências Maven
<dependency>
<groupId>com.aliyun.datahub</groupId>
<artifactId>aliyun-sdk-datahub</artifactId>
<version>2.25.3</version>
</dependency>
<dependency>
<groupId>com.aliyun.datahub</groupId>
<artifactId>datahub-client-library</artifactId>
<version>1.4.3</version>
</dependency>
Configure a serialização em lote
ProducerConfig config = new ProducerConfig(endpoint, accessId, accessKey);
DatahubProducer producer = new DatahubProducer(projectName, topicName, config);
RecordSchema schema = producer.getTopicSchema();
List<RecordEntry> recordList = new ArrayList<>();
// To achieve better performance, we recommend that you add as many records as possible to recordList.
// Set the size of recordList to be within the range of 512 KB to 1 MB if possible.
for (int i = 0; i < 1000; ++i) {
RecordEntry record = new RecordEntry();
TupleRecordData data = new TupleRecordData(schema);
// Assume that the following schema is used: {"fields":[{"name":"f1", "type":"STRING"},{"name":"f2", "type":"BIGINT"}]}
data.setField("f1", "value" + i);
data.setField("f2", i);
record.setRecordData(data);
// Optional. Add custom attributes.
record.addAttribute("key1", "value1");
recordList.add(record);
}
try {
// Write data repeatedly for 1,000 times.
for (int i = 0; i < 1000; ++i) {
try {
String shardId = datahubProducer.send(recordList);
LOGGER.info("Write shard {} success, record count:{}", shardId, recordList.size());
} catch (DatahubClientException e) {
if (!ExceptionChecker.isRetryableException(e)) {
LOGGER.info("Write data fail", e);
break;
}
// Execute the sleep statement to retry data writing.
Thread.sleep(1000);
}
}
} finally {
// Disable producer-related resources.
datahubProducer.close();
}
Próximos passos
Se tiver dúvidas ou encontrar problemas ao usar o DataHub, ticket de suporte ou participe do grupo DingTalk 33517130.