O Tablestore oferece diversos métodos para migrar ou sincronizar dados entre tabelas. Use o Tunnel Service, o DataWorks, o DataX ou a interface de linha de comando para sincronizar dados de uma tabela para outra.
Pré-requisitos
Obtenha os nomes das instâncias, os endpoints e os IDs de região das tabelas de origem e de destino.
Crie uma AccessKey para sua conta Alibaba Cloud ou um usuário RAM com permissões no Tablestore.
Sincronizar dados usando um SDK
Use o Tunnel Service para sincronizar dados entre tabelas. Esse método permite a sincronização de dados na mesma região, entre regiões diferentes e entre contas distintas. O Tunnel Service captura e sincroniza alterações de dados para a tabela de destino em tempo real. O exemplo a seguir demonstra como usar o Java SDK para implementar essa sincronização.
Antes de executar o código, substitua os espaços reservados dos nomes das tabelas de origem e de destino, dos nomes das instâncias e dos endpoints pelos valores reais. Defina também o AccessKey ID e o AccessKey Secret como variáveis de ambiente.
import com.alicloud.openservices.tablestore.*;
import com.alicloud.openservices.tablestore.core.auth.DefaultCredentials;
import com.alicloud.openservices.tablestore.core.auth.ServiceCredentials;
import com.alicloud.openservices.tablestore.model.*;
import com.alicloud.openservices.tablestore.model.tunnel.*;
import com.alicloud.openservices.tablestore.tunnel.worker.IChannelProcessor;
import com.alicloud.openservices.tablestore.tunnel.worker.ProcessRecordsInput;
import com.alicloud.openservices.tablestore.tunnel.worker.TunnelWorker;
import com.alicloud.openservices.tablestore.tunnel.worker.TunnelWorkerConfig;
import com.alicloud.openservices.tablestore.writer.RowWriteResult;
import com.alicloud.openservices.tablestore.writer.WriterConfig;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
public class TableSynchronization {
// Source table configurations: table name, instance name, endpoint, AccessKey ID, AccessKey Secret
final static String sourceTableName = "sourceTableName";
final static String sourceInstanceName = "sourceInstanceName";
final static String sourceEndpoint = "sourceEndpoint";
final static String sourceAccessKeyId = System.getenv("SOURCE_TABLESTORE_ACCESS_KEY_ID");
final static String sourceKeySecret = System.getenv("SOURCE_TABLESTORE_ACCESS_KEY_SECRET");
// Target table configurations: table name, instance name, endpoint, AccessKey ID, AccessKey Secret
final static String targetTableName = "targetTableName";
final static String targetInstanceName = "targetInstanceName";
final static String targetEndpoint = "targetEndpoint";
final static String targetAccessKeyId = System.getenv("TARGET_TABLESTORE_ACCESS_KEY_ID");
final static String targetKeySecret = System.getenv("TARGET_TABLESTORE_ACCESS_KEY_SECRET");
// Tunnel name
static String tunnelName = "source_table_tunnel";
// TablestoreWriter: a tool for high-concurrency data writes.
static TableStoreWriter tableStoreWriter;
// Statistics for successful and failed rows
static AtomicLong succeedRows = new AtomicLong();
static AtomicLong failedRows = new AtomicLong();
public static void main(String[] args) {
// Create the target table.
createTargetTable();
System.out.println("Create target table Done.");
// Initialize TunnelClient.
TunnelClient tunnelClient = new TunnelClient(sourceEndpoint, sourceAccessKeyId, sourceKeySecret, sourceInstanceName);
// Create a data tunnel.
String tunnelId = createTunnel(tunnelClient);
System.out.println("Create tunnel Done.");
// Initialize TablestoreWriter.
tableStoreWriter = createTablesStoreWriter();
// Synchronize data through the data tunnel.
TunnelWorkerConfig config = new TunnelWorkerConfig(new SimpleProcessor());
TunnelWorker worker = new TunnelWorker(tunnelId, tunnelClient, config);
try {
System.out.println("Connect tunnel and working ...");
worker.connectAndWorking();
// Monitor the tunnel status. The data synchronization is complete when the tunnel status changes from full data synchronization to incremental data synchronization.
while (true) {
if (tunnelClient.describeTunnel(new DescribeTunnelRequest(sourceTableName, tunnelName)).getTunnelInfo().getStage().equals(TunnelStage.ProcessStream)) {
break;
}
Thread.sleep(5000);
}
// Synchronization result
System.out.println("Data Synchronization Completed.");
System.out.println("* Succeed Rows Count: " + succeedRows.get());
System.out.println("* Failed Rows Count: " + failedRows.get());
// Delete the tunnel.
tunnelClient.deleteTunnel(new DeleteTunnelRequest(sourceTableName, tunnelName));
// Shut down resources.
worker.shutdown();
config.shutdown();
tunnelClient.shutdown();
tableStoreWriter.close();
}catch(Exception e){
e.printStackTrace();
worker.shutdown();
config.shutdown();
tunnelClient.shutdown();
tableStoreWriter.close();
}
}
private static void createTargetTable() throws ClientException {
// Query the source table information.
SyncClient sourceClient = new SyncClient(sourceEndpoint, sourceAccessKeyId, sourceKeySecret, sourceInstanceName);
DescribeTableResponse response = sourceClient.describeTable(new DescribeTableRequest(sourceTableName));
// Create the target table.
SyncClient targetClient = new SyncClient(targetEndpoint, targetAccessKeyId, targetKeySecret, targetInstanceName);
TableMeta tableMeta = new TableMeta(targetTableName);
response.getTableMeta().getPrimaryKeyList().forEach(
item -> tableMeta.addPrimaryKeyColumn(new PrimaryKeySchema(item.getName(), item.getType()))
);
TableOptions tableOptions = new TableOptions(-1, 1);
CreateTableRequest request = new CreateTableRequest(tableMeta, tableOptions);
targetClient.createTable(request);
// Shut down resources.
sourceClient.shutdown();
targetClient.shutdown();
}
private static String createTunnel(TunnelClient client) {
// Create a data tunnel and return the tunnel ID.
CreateTunnelRequest request = new CreateTunnelRequest(sourceTableName, tunnelName, TunnelType.BaseAndStream);
CreateTunnelResponse response = client.createTunnel(request);
return response.getTunnelId();
}
private static class SimpleProcessor implements IChannelProcessor {
@Override
public void process(ProcessRecordsInput input) {
if(input.getRecords().isEmpty())
return;
System.out.print("* Begin consume " + input.getRecords().size() + " records ... ");
for (StreamRecord record : input.getRecords()) {
switch (record.getRecordType()) {
// Write row data.
case PUT:
RowPutChange putChange = new RowPutChange(targetTableName, record.getPrimaryKey());
putChange.addColumns(getColumnsFromRecord(record));
tableStoreWriter.addRowChange(putChange);
break;
// Update row data.
case UPDATE:
RowUpdateChange updateChange = new RowUpdateChange(targetTableName, record.getPrimaryKey());
for (RecordColumn column : record.getColumns()) {
switch (column.getColumnType()) {
// Add an attribute column.
case PUT:
updateChange.put(column.getColumn().getName(), column.getColumn().getValue(), System.currentTimeMillis());
break;
// Delete a version of an attribute column.
case DELETE_ONE_VERSION:
updateChange.deleteColumn(column.getColumn().getName(),
column.getColumn().getTimestamp());
break;
// Delete an attribute column.
case DELETE_ALL_VERSION:
updateChange.deleteColumns(column.getColumn().getName());
break;
default:
break;
}
}
tableStoreWriter.addRowChange(updateChange);
break;
// Delete row data.
case DELETE:
RowDeleteChange deleteChange = new RowDeleteChange(targetTableName, record.getPrimaryKey());
tableStoreWriter.addRowChange(deleteChange);
break;
}
}
// Flush data from the buffer.
tableStoreWriter.flush();
System.out.println("Done");
}
@Override
public void shutdown() {
}
}
public static List<Column> getColumnsFromRecord(StreamRecord record) {
List<Column> retColumns = new ArrayList<>();
for (RecordColumn recordColumn : record.getColumns()) {
// Replace the data version with the current timestamp to prevent the maximum version deviation from being exceeded.
Column column = new Column(recordColumn.getColumn().getName(), recordColumn.getColumn().getValue(), System.currentTimeMillis());
retColumns.add(column);
}
return retColumns;
}
private static TableStoreWriter createTablesStoreWriter() {
WriterConfig config = new WriterConfig();
// A row-level callback to count the number of successful and failed rows and print information about the rows that failed to be synchronized.
TableStoreCallback<RowChange, RowWriteResult> resultCallback = new TableStoreCallback<RowChange, RowWriteResult>() {
@Override
public void onCompleted(RowChange rowChange, RowWriteResult rowWriteResult) {
succeedRows.incrementAndGet();
}
@Override
public void onFailed(RowChange rowChange, Exception exception) {
failedRows.incrementAndGet();
System.out.println("* Failed Rows: " + rowChange.getTableName() + " | " + rowChange.getPrimaryKey() + " | " + exception.getMessage());
}
};
ServiceCredentials credentials = new DefaultCredentials(targetAccessKeyId, targetKeySecret);
return new DefaultTableStoreWriter(targetEndpoint, credentials, targetInstanceName,
targetTableName, config, resultCallback);
}
}
Sincronizar dados usando o DataWorks
O DataWorks fornece um service visual de Integração de Dados que permite configurar tarefas de sincronização entre tabelas do Tablestore por meio de uma interface gráfica. Também é possível usar outras ferramentas, como o DataX, para sincronizar dados entre tabelas do Tablestore.
Etapa 1: Preparações
Crie a tabela de destino. Certifique-se de que a estrutura da chave primária, incluindo os tipos de dados e a ordem das colunas de chave primária, seja idêntica à da tabela de origem.
Ative o DataWorks e crie um workspace na região onde a tabela de origem ou de destino está localizada.
Crie um grupo de recursos serverless e vincule-o ao workspace. Para informações sobre faturamento, consulte Faturamento de grupos de recursos serverless.
Se as tabelas de origem e de destino estiverem em regiões diferentes, crie uma conexão peering VPC para estabelecer conectividade de rede entre regiões.
Etapa 2: Adicionar uma source de dados do Tablestore
Adicione uma source de dados do Tablestore tanto para a instância da tabela de origem quanto para a instância da tabela de destino.
Faça login no console do DataWorks. Mude para a região de destino. No painel de navegação à esquerda, escolha . Na lista suspensa, selecione o workspace desejado e clique em Go to Data Integration.
No painel de navegação à esquerda, clique em Data Source.
Na página Data Sources, clique em Add Data Source.
Na caixa de diálogo Add Data Source, pesquise e selecione Tablestore como o tipo de source de dados.
-
Na caixa de diálogo Add OTS Data Source, configure os parâmetros da source de dados conforme descrito na tabela a seguir.
Parâmetro
Descrição
Data source name
Nome da source de dados. O nome pode conter letras, dígitos e sublinhados (_), mas não pode começar com um dígito ou sublinhado (_).
Data source description
Breve descrição da source de dados. A descrição pode ter até 80 caracteres.
Region
Selecione a região onde a instância do Tablestore está localizada.
Tablestore Instance Name
Nome da instância do Tablestore.
Endpoint
Endpoint da instância do Tablestore. Recomendamos o uso do VPC Address.
AccessKey ID
AccessKey ID e AccessKey Secret da sua conta Alibaba Cloud ou usuário RAM.
AccessKey Secret
-
Teste a conectividade do grupo de recursos.
Teste a conectividade do grupo de recursos com a source de dados. A tarefa de sincronização não será executada se o grupo de recursos não conseguir se conectar à source de dados.
Na seção Connection Configuration, clique em Test Network Connectivity na coluna Connection Status do grupo de recursos.
-
Após a aprovação no teste de conectividade, o Connection Status mudará para Connected. Clique em Complete. A nova source de dados estará visível na lista de sources de dados.
Se o resultado do teste de conectividade for Failed, utilize a Network Connectivity Diagnostic Tool para resolver o problema.
Etapa 3: Configurar e executar a tarefa de sincronização
Criar um nó de tarefa
-
Acesse a página Data Development.
Faça login no console do DataWorks.
Na barra de navegação superior, selecione o grupo de recursos e a região.
No painel de navegação à esquerda, escolha .
Selecione o workspace desejado e clique em Go To Data Studio.
Na página Data Development do console Data Studio, passe o ponteiro sobre o ícone
ao lado de Workspace Directory e escolha .Na caixa de diálogo Create Node, selecione um Path. Tanto para a source de dados quanto para o destino, selecione Tablestore. Insira um nome e clique em OK.
Configurar a tarefa de sincronização
Em Workspace Directory, clique para abrir o nó Batch Synchronization criado. Configure a tarefa de sincronização na UI sem código ou no editor de código.
Codeless UI (default)
Configure os seguintes itens:
Data source: Selecione as sources de dados de origem e de destino.
Runtime Resource: Selecione um grupo de recursos. Após selecionar um grupo de recursos, a conectividade da source de dados é testada automaticamente.
-
Data Source:
Table: Na lista suspensa, selecione a tabela de origem.
-
Primary Key Range Start: Chave primária inicial para leitura de dados, especificada como um array JSON.
inf_minrepresenta infinito negativo.Quando a chave primária consiste em uma coluna
intchamadaide uma colunastringchamadaname, um exemplo de configuração é:Faixa específica de chave primária
Dados completos
[ { "type": "int", "value": "000" }, { "type": "string", "value": "aaa" } ][ { "type": "inf_min" }, { "type": "inf_min" } ] -
Primary key range (end): Chave primária final para leitura de dados, especificada como um array JSON onde
inf_maxrepresenta infinito.Quando a chave primária consiste em uma coluna
intchamadaide uma colunastringchamadaname, um exemplo de configuração é:Faixa específica de chave primária
Dados completos
[ { "type": "int", "value": "999" }, { "type": "string", "value": "zzz" } ][ { "type": "inf_max" }, { "type": "inf_max" } ] -
Splitting Configuration: Configuração de divisão personalizada, especificada como um array JSON. Recomendamos não configurar este parâmetro em circunstâncias normais (defina como
[]).Se existirem partições quentes no Tablestore e a política de divisão automática do Tablestore Reader não surtir efeito, recomenda-se o uso de regras de divisão personalizadas. Uma regra de divisão especifica os pontos de divisão dentro da faixa das chaves primárias inicial e final. É necessário configurar apenas a chave de divisão, não todas as chaves primárias.
-
Destination:
Table: Na lista suspensa, selecione a tabela de destino.
-
Primary Key Information: Informações da chave primária da tabela de destino. O valor deve estar no formato de array JSON.
Quando a chave primária contém uma coluna de chave primária
intchamadaide uma coluna de chave primáriastringchamadaname, o exemplo de configuração é:[ { "name": "id", "type": "int" }, { "name": "name", "type": "string" } ] -
Write Mode: Modo de gravação de dados no Tablestore. Os seguintes modos são suportados:
PutRow: Grava dados de linha. Se a linha de destino não existir, uma nova linha será adicionada. Caso exista, a linha existente será sobrescrita.
UpdateRow: Atualiza dados de linha. Se a linha não existir, uma nova linha será adicionada. Se existir, os valores das colunas especificadas nesta linha serão adicionados, modificados ou excluídos conforme a solicitação.
-
Destination Field Mapping: Configure o mapeamento de campos da tabela de origem para a tabela de destino. Cada linha representa um campo, especificado no formato JSON.
-
Source Field: O valor deve incluir as informações da chave primária da tabela de origem.
Quando a chave primária contém uma coluna de chave primária
intchamadaide uma coluna de chave primáriastringchamadaname, e a coluna de atributo contém um campointchamadoage, o exemplo de configuração é:{"name":"id","type":"int"} {"name":"name","type":"string"} {"name":"age","type":"int"} -
Target Field: O valor não precisa incluir as informações da chave primária da tabela de destino.
Se a chave primária consistir em uma coluna
intchamadaide uma colunastringchamadaname, e a coluna de atributo contiver um campointchamadoage, o exemplo de configuração é:{"name":"age","type":"int"}
-
-
Verifique o status e o resultado da execução da tarefa na parte inferior da página. As informações de log a seguir indicam que a tarefa de sincronização foi bem-sucedida.
2025-11-18 11:16:23 INFO Shell run successfully! 2025-11-18 11:16:23 INFO Current task status: FINISH 2025-11-18 11:16:23 INFO Cost time is: 77.208s -
Visualize os dados na tabela de destino.
Acesse o console do Tablestore. Na barra de navegação superior, selecione o grupo de recursos e a região.
Clique no alias da instância. Na página Tables, clique na tabela de destino.
Clique em Query Data para visualizar os dados na tabela de destino.
Crie a tabela de destino. Certifique-se de que a estrutura da chave primária, incluindo nomes, tipos de dados e ordem das colunas de chave primária, seja idêntica à da tabela de origem.
-
Inicie a interface de linha de comando e execute o comando config para configurar as informações de acesso da instância onde a tabela de origem está localizada. Para mais informações, consulte Iniciar a ferramenta e configurar informações de acesso.
Antes de executar o comando, substitua endpoint, instance, id e key pelo endpoint, nome da instância, AccessKey ID e AccessKey Secret da instância onde a tabela de origem está localizada.
config --endpoint https://myinstance.cn-hangzhou.ots.aliyuncs.com --instance myinstance --id NTSVL******************** --key 7NR2**************************************** -
Exporte os dados.
-
Execute o comando
usepara utilizar a tabela de origem. Este tópico usasource_tablecomo exemplo.use --wc -t source_table -
Exporte os dados da tabela de origem para um arquivo JSON local. Para mais informações, consulte Exportar dados.
scan -o /tmp/sourceData.json
-
-
Execute o comando config para configurar as informações de acesso da instância onde a tabela de destino está localizada.
Antes de executar o comando, substitua endpoint, instance, id e key pelo endpoint, nome da instância, AccessKey ID e AccessKey Secret da instância onde a tabela de destino está localizada.
config --endpoint https://myinstance.cn-hangzhou.ots.aliyuncs.com --instance myinstance --id NTSVL******************** --key 7NR2**************************************** -
Importe os dados.
-
Execute o comando
usepara utilizar a tabela de destino. Este exemplo usatarget_table.use --wc -t target_table -
Importe os dados do arquivo JSON local para a tabela de destino. Para mais informações, consulte Importar dados.
import -i /tmp/sourceData.json
-
Após concluir a configuração, clique em Save na parte superior da página.
Code editor
Clique em Code Editor na parte superior da página. Na página exibida, edite o script.
O exemplo a seguir mostra a configuração para uma tabela cuja chave primária consiste em uma colunaintchamadaide uma colunastringchamadaname, e as colunas de atributo incluem um campointchamadoage. Ao definir as configurações, substitua o nome dadatasourcee datableno script de exemplo.
Full data
{
"type": "job",
"version": "2.0",
"steps": [
{
"stepType": "ots",
"parameter": {
"datasource": "source_data",
"column": [
{
"name": "id",
"type": "int"
},
{
"name": "name",
"type": "string"
},
{
"name": "age",
"type": "int"
}
],
"range": {
"begin": [
{
"type": "inf_min"
},
{
"type": "inf_min"
}
],
"end": [
{
"type": "inf_max"
},
{
"type": "inf_max"
}
],
"split": []
},
"table": "source_table",
"newVersion": "true"
},
"name": "Reader",
"category": "reader"
},
{
"stepType": "ots",
"parameter": {
"datasource": "target_data",
"column": [
{
"name": "age",
"type": "int"
}
],
"writeMode": "UpdateRow",
"table": "target_table",
"newVersion": "true",
"primaryKey": [
{
"name": "id",
"type": "int"
},
{
"name": "name",
"type": "string"
}
]
},
"name": "Writer",
"category": "writer"
}
],
"setting": {
"errorLimit": {
"record": "0"
},
"speed": {
"concurrent": 2,
"throttle": false
}
},
"order": {
"hops": [
{
"from": "Reader",
"to": "Writer"
}
]
}
}
Specific primary key range
{
"type": "job",
"version": "2.0",
"steps": [
{
"stepType": "ots",
"parameter": {
"datasource": "source_data",
"column": [
{
"name": "id",
"type": "int"
},
{
"name": "name",
"type": "string"
},
{
"name": "age",
"type": "int"
}
],
"range": {
"begin": [
{
"type": "int",
"value": "000"
},
{
"type": "string",
"value": "aaa"
}
],
"end": [
{
"type": "int",
"value": "999"
},
{
"type": "string",
"value": "zzz"
}
],
"split": []
},
"table": "source_table",
"newVersion": "true"
},
"name": "Reader",
"category": "reader"
},
{
"stepType": "ots",
"parameter": {
"datasource": "target_data",
"column": [
{
"name": "age",
"type": "int"
}
],
"writeMode": "UpdateRow",
"table": "target_table",
"newVersion": "true",
"primaryKey": [
{
"name": "id",
"type": "int"
},
{
"name": "name",
"type": "string"
}
]
},
"name": "Writer",
"category": "writer"
}
],
"setting": {
"errorLimit": {
"record": "0"
},
"speed": {
"concurrent": 2,
"throttle": false
}
},
"order": {
"hops": [
{
"from": "Reader",
"to": "Writer"
}
]
}
}
Após editar o script, clique em Save na parte superior da página.
Executar a tarefa de sincronização
Clique em Run na parte superior da página para iniciar a tarefa de sincronização. Ao executar a tarefa pela primeira vez, confirme a Debug Configuration.
Etapa 4: Visualizar o resultado da sincronização
Após a execução da tarefa, verifique o status nos logs e visualize os dados sincronizados no console do Tablestore.
Sincronizar dados usando a CLI
O uso da interface de linha de comando exige a exportação manual dos dados da tabela de origem para um arquivo JSON local e, em seguida, a importação desse arquivo para a tabela de destino. Este método é adequado apenas para migração de dados em pequena escala.