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 da região das tabelas de origem e de destino.
Crie um AccessKey para sua conta Alibaba Cloud ou para um usuário RAM com permissões no Tablestore.
Sincronizar dados usando um SDK
Sincronize dados entre tabelas com o Tunnel Service. 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 alterações nos dados e as sincroniza com 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 nomes das tabelas, os nomes das instâncias e os endpoints pelos valores reais das tabelas de origem e de destino. Em seguida, configure 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 tunnel.
String tunnelId = createTunnel(tunnelClient);
System.out.println("Create tunnel: Done.");
// Initialize TablestoreWriter.
tableStoreWriter = createTablesStoreWriter();
// Synchronize data through the tunnel.
TunnelWorkerConfig config = new TunnelWorkerConfig(new SimpleProcessor());
TunnelWorker worker = new TunnelWorker(tunnelId, tunnelClient, config);
try {
System.out.println("Connecting to tunnel and working...");
worker.connectAndWorking();
// Monitor the tunnel status. When the status changes from full data synchronization to incremental synchronization, the data synchronization is complete.
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("* Succeeded rows: " + succeedRows.get());
System.out.println("* Failed rows: " + 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 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 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("* Start to 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 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 number with the current timestamp to prevent exceeding the maximum version drift.
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();
// Row-level callback to count successful and failed rows and print information about failed rows.
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 Row: " + 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 serviço 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 utilizar outras ferramentas, como o DataX, para sincronizar dados entre tabelas do Tablestore.
Etapa 1: Preparações
Crie uma tabela de dados de destino. Garanta que a estrutura de chave primária da tabela de destino, 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 anexe-o ao workspace. Para mais informações sobre faturamento, consulte Faturamento de grupo de recursos serverless.
Se as tabelas de origem e de destino estiverem em regiões diferentes, crie uma conexão de peering VPC para estabelecer conectividade de rede entre regiões.
Etapa 2: Adicionar uma fonte de dados do Tablestore
Adicione uma fonte 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 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 fonte de dados.
-
Na caixa de diálogo Add OTS Data Source, configure os parâmetros da fonte de dados conforme descrito na tabela a seguir.
Parâmetro
Descrição
Data Source Name
O nome da fonte de dados deve ser uma combinação de letras, dígitos e sublinhados (_). Não pode começar com um dígito ou um sublinhado (_).
Data Source Description
Uma breve descrição da fonte de dados. A descrição não pode exceder 80 caracteres.
Region
Selecione a região onde a instância do Tablestore reside.
Tablestore Instance Name
O nome da instância do Tablestore.
Endpoint
O endpoint da instância do Tablestore. Use o endereço da VPC.
AccessKey ID
O AccessKey ID e o AccessKey secret da conta Alibaba Cloud ou do usuário RAM.
AccessKey Secret
-
Teste a conectividade do grupo de recursos.
Ao criar uma fonte de dados, teste a conectividade do grupo de recursos para garantir que o grupo de recursos da tarefa de sincronização consiga se conectar à fonte de dados. Caso contrário, a tarefa de sincronização de dados não poderá ser executada.
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, clique em Complete. A nova fonte de dados aparecerá na lista de fontes de dados.
Se o teste de conectividade falhar, utilize a Network Connectivity Diagnostic Tool para solucionar 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 e clique em Go To Data Studio.
No console do Data Studio, clique no ícone
à direita de Workspace Directories e selecione .Na caixa de diálogo Create Node, selecione um Path, defina tanto a fonte de dados quanto o destino de dados como Tablestore, insira um nome e clique em OK.
Configurar a tarefa de sincronização
Em Workspace Directories, clique no nó da tarefa de sincronização em lote recém-criado. Configure a tarefa de sincronização na interface sem código ou no editor de código.
Interface sem código (padrão)
Configure os seguintes itens:
Data Source: Selecione as fontes de dados de origem e de destino.
Runtime Resource: Selecione um grupo de recursos. A conectividade da fonte de dados é testada automaticamente.
-
Data Source:
Table: Na lista suspensa, selecione a tabela de dados de origem.
-
Primary Key Range (Start): A chave primária inicial para operações de leitura de dados. O formato é um array JSON.
inf_minindica infinito negativo.Se a chave primária consistir em uma coluna de chave primária
intchamadaide uma coluna de chave primáriastringchamadaname, a configuração a seguir serve como exemplo: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): A chave primária final para operações de leitura de dados. O formato é um array JSON.
inf_maxindica infinito positivo.Se a chave primária consistir em uma coluna de chave primária
intchamadaide uma coluna de chave primáriastringchamadaname, a configuração a seguir serve como exemplo: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: A configuração personalizada de shard. O formato é um array JSON. Normalmente, não é necessário configurar este parâmetro. Defina-o como
[].Se ocorrerem hot spots no armazenamento de dados do Tablestore e a política de sharding automático do Tablestore Reader for ineficaz, utilize regras de sharding personalizadas. O sharding especifica os pontos de shard dentro da faixa de chave primária inicial e final. Configure apenas as chaves de shard, não todas as chaves primárias.
-
Destination:
Table: Na lista suspensa, selecione a tabela de dados de destino.
-
Primary Key Information: As informações de chave primária da tabela de dados de destino. O formato é um array JSON.
Se a chave primária consistir em uma coluna de chave primária
intchamadaide uma coluna de chave primáriastringchamadaname, a configuração a seguir serve como exemplo:[ { "name": "id", "type": "int" }, { "name": "name", "type": "string" } ] -
Write Mode: O 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. Se a linha de destino existir, a linha original será sobrescrita.
UpdateRow: Atualiza dados de linha. Se a linha não existir, uma nova linha será adicionada. Se a linha existir, os valores das colunas especificadas na linha serão adicionados, modificados ou excluídos com base na solicitação.
-
Destination Field Mapping: Configure o mapeamento de campos da tabela de dados de origem para a tabela de dados de destino. Cada linha representa um campo no formato JSON.
-
Source Field: Deve incluir as informações de chave primária da tabela de dados de origem.
Se a chave primária consistir em uma coluna de chave primária
intchamadaide uma coluna de chave primáriastringchamadaname, e as colunas de atributo incluírem um campointchamadoage, a configuração a seguir serve como exemplo:{"name":"id","type":"int"} {"name":"name","type":"string"} {"name":"age","type":"int"} -
Target Field: Não precisa incluir as informações de chave primária da tabela de dados de destino.
Se a chave primária consistir em uma coluna de chave primária
intchamadaide uma coluna de chave primáriastringchamadaname, e as colunas de atributo incluírem um campointchamadoage, a configuração a seguir serve como exemplo:{"name":"age","type":"int"}
-
-
Visualize 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 executada com sucesso.
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 lista de tabelas, clique na tabela de dados de destino.
Clique em Query Data para visualizar os dados na tabela de dados de destino.
Crie uma tabela de dados de destino. Garanta que sua estrutura de chave primária, incluindo o nome, o tipo de dados e a ordem das colunas, seja idêntica à da tabela de origem.
-
Inicie a interface de linha de comando e execute o comando
configpara configurar as informações de acesso da instância onde a tabela de origem está localizada. Para mais informações, consulte Iniciar e configurar informações de acesso.Antes de executar o comando, substitua
endpoint,instance,idekeypelo 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 selecionar a tabela de origem. O exemplo a seguir usasource_table.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
configpara configurar as informações de acesso da instância onde a tabela de destino está localizada.Antes de executar o comando, substitua
endpoint,instance,idekeypelo 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 selecionar a tabela de destino. O exemplo a seguir 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.
Editor de código
Clique em Code Editor na parte superior da página. Edite o script na página exibida.
O exemplo a seguir mostra a configuração para uma tabela cuja chave primária consiste em uma coluna de chave primáriaintchamadaide uma coluna de chave primáriastringchamadaname, e as colunas de atributo incluem um campointchamadoage. Ao configurar a tarefa, substitua os nomesdatasourceetableno script de exemplo pelos seus valores reais.
Dados completos
{
"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"
}
]
}
}
Faixa específica de chave primária
{
"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 terminar de 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. Na primeira execução da tarefa, confirme a configuração de depuração.
Etapa 4: Visualizar o resultado da sincronização
Após a execução da tarefa de sincronização, visualize o status de execução nos logs e verifique o resultado da sincronização no console do Tablestore.
Sincronizar dados usando a interface de linha de comando
Este método exige a exportação manual dos dados da tabela de origem para um arquivo JSON local e, em seguida, a importação do arquivo para a tabela de destino. Esta abordagem é adequada apenas para migrar pequenos volumes de dados e não é recomendada para migração de dados em grande escala.
