Tablestore ofrece varios métodos para migrar o sincronizar datos entre tablas. Para sincronizar datos de una tabla a otra, puede utilizar Tunnel Service, DataWorks, DataX o la interfaz de línea de comandos (CLI).
Requisitos previos
Obtenga los nombres de las instancias, los endpoints y los identificadores region de las tablas de origen y destino.
Create an AccessKey para su cuenta de Alibaba Cloud o para un usuario de RAM con permisos en Tablestore.
Sincronización de datos mediante un SDK
Puede usar Tunnel Service para sincronizar datos entre tablas. Este método admite la sincronización dentro de la misma región, entre distintas regiones y entre diferentes cuentas. Tunnel Service captura los cambios de datos y los sincroniza hacia la tabla de destino en tiempo real. A continuación se muestra cómo implementar esta sincronización con el SDK de Java.
Antes de ejecutar el código, reemplace los marcadores de posición de los nombres de las tablas de origen y destino, los nombres de las instancias y los endpoints con sus valores reales. También debe establecer el AccessKey ID y el AccessKey Secret como variables de entorno.
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);
}
}
Sincronización de datos mediante DataWorks
DataWorks proporciona un servicio visual de integración de datos que le permite configurar tareas de sincronización entre tablas de Tablestore desde una interfaz gráfica. También puede usar otras herramientas, como DataX, para sincronizar datos entre tablas de Tablestore.
Paso 1: Preparativos
Create the target table. Compruebe que la estructura de su clave primaria, incluidos los tipos de datos y el orden de las columnas de clave primaria, sea idéntica a la de la tabla de origen.
Activate DataWorks y create a workspace en la región donde se encuentra la tabla de origen o de destino.
Create a serverless resource group and bind it to the workspace. Para obtener información sobre la facturación, consulte Serverless resource group billing.
Si las tablas de origen y destino están en regiones distintas, debe crear una conexión de emparejamiento VPC para establecer la conectividad de red entre regiones.
Paso 2: Agregar un origen de datos de Tablestore
Agregue un origen de datos de Tablestore tanto para la instancia de la tabla de origen como para la de la tabla de destino.
Inicie sesión en la consola de DataWorks. Cambie a la región de destino. En el panel de navegación izquierdo, elija . En la lista desplegable, seleccione el espacio de trabajo deseado y haga clic en Go to Data Integration.
En el panel de navegación izquierdo, haga clic en Data Source.
En la página Data Sources, haga clic en Add Data Source.
En el cuadro de diálogo Add Data Source, busque y seleccione Tablestore como tipo de origen de datos.
-
En el cuadro de diálogo Add OTS Data Source, configure los parámetros del origen de datos tal como se indica en la siguiente tabla.
Parámetro
Descripción
Data source name
Nombre del origen de datos. Puede contener letras, dígitos y guiones bajos (_), pero no puede comenzar con un dígito ni con un guion bajo (_).
Data source description
Descripción breve del origen de datos. La longitud máxima es de 80 caracteres.
Region
Seleccione la región donde se encuentra la instancia de Tablestore.
Tablestore Instance Name
Nombre de la instancia de Tablestore.
Endpoint
Endpoint de la instancia de Tablestore. Se recomienda usar la VPC Address.
AccessKey ID
El AccessKey ID y el AccessKey Secret de su cuenta de Alibaba Cloud o del usuario de RAM.
AccessKey Secret
-
Compruebe la conectividad del resource group.
Debe comprobar la conectividad del resource group con el origen de datos. Si el resource group no logra conectarse, la tarea de sincronización no se ejecutará.
En la sección Connection Configuration, haga clic en Test Network Connectivity en la columna Connection Status correspondiente al resource group.
-
Una vez superada la prueba de conectividad, el estado Connection Status cambia a Connected. Haga clic en Complete. El nuevo origen de datos aparecerá en la lista de orígenes de datos.
Si el resultado de la prueba de conectividad es Failed, utilice la herramienta Network Connectivity Diagnostic Tool para resolver el problema por su cuenta.
Paso 3: Configurar y ejecutar la tarea de sincronización
Crear un nodo de tarea
-
Vaya a la página Data Development.
Inicie sesión en la consola de DataWorks.
En la barra de navegación superior, seleccione el resource group y la región.
En el panel de navegación izquierdo, elija .
Seleccione el espacio de trabajo deseado y haga clic en Go To Data Studio.
En la página Data Development de la consola Data Studio, pase el puntero sobre el icono
situado junto a Workspace Directory y elija .En el cuadro de diálogo Create Node, seleccione una Path. Tanto para el origen como para el destino de datos, seleccione Tablestore. Introduzca un nombre y haga clic en OK.
Configurar la tarea de sincronización
En Workspace Directory, haga clic para abrir el nodo Batch Synchronization creado. Puede configurar la tarea de sincronización en Codeless UI o en el editor de código.
Codeless UI (predeterminado)
Configure los siguientes elementos:
Data source: Seleccione los orígenes de datos de origen y destino.
Runtime Resource: Seleccione un resource group. Tras seleccionarlo, la conectividad del origen de datos se comprueba automáticamente.
-
Data Source:
Table: En la lista desplegable, seleccione la tabla de origen.
-
Primary Key Range Start: Clave primaria inicial para la lectura de datos, especificada como una matriz JSON.
inf_minrepresenta infinito negativo.Cuando la clave primaria consta de una columna
intllamadaidy una columnastringllamadaname, la configuración de ejemplo es la siguiente:Rango específico de clave primaria
Datos completos
[ { "type": "int", "value": "000" }, { "type": "string", "value": "aaa" } ][ { "type": "inf_min" }, { "type": "inf_min" } ] -
Primary key range (end): Clave primaria final para la lectura de datos, especificada como una matriz JSON donde
inf_maxrepresenta infinito.Cuando la clave primaria consta de una columna
intllamadaidy una columnastringllamadaname, la configuración de ejemplo es la siguiente:Rango específico de clave primaria
Datos completos
[ { "type": "int", "value": "999" }, { "type": "string", "value": "zzz" } ][ { "type": "inf_max" }, { "type": "inf_max" } ] -
Splitting Configuration: Configuración de división personalizada, especificada como una matriz JSON. Se recomienda no configurar este parámetro en condiciones normales (déjelo como
[]).Si existen particiones calientes en Tablestore y la política de división automática de Tablestore Reader no surte efecto, se recomienda usar reglas de división personalizadas. Una regla de división define los puntos de corte dentro del rango de las claves primarias inicial y final. Solo necesita configurar la clave de división, no todas las claves primarias.
-
Destination:
Table: En la lista desplegable, seleccione la tabla de destino.
-
Primary Key Information: Información de la clave primaria de la tabla de destino. El valor debe tener formato de matriz JSON.
Cuando la clave primaria contiene una columna de clave primaria
intllamadaidy una columna de clave primariastringllamadaname, la configuración de ejemplo es la siguiente:[ { "name": "id", "type": "int" }, { "name": "name", "type": "string" } ] -
Write Mode: Modo en el que se escriben los datos en Tablestore. Se admiten los siguientes modos:
PutRow: Escribe datos de fila. Si la fila de destino no existe, se agrega una nueva. Si ya existe, se sobrescribe la fila existente.
UpdateRow: Actualiza datos de fila. Si la fila no existe, se agrega una nueva. Si existe, se agregan, modifican o eliminan los valores de las columnas especificadas según la solicitud.
-
Destination Field Mapping: Configure la asignación de campos de la tabla de origen a la de destino. Cada línea representa un campo y se especifica en formato JSON.
-
Source Field: El valor debe incluir la información de la clave primaria de la tabla de origen.
Cuando la clave primaria contiene una columna de clave primaria
intllamadaidy una columna de clave primariastringllamadaname, y la columna de atributos contiene un campointllamadoage, la configuración de ejemplo es la siguiente:{"name":"id","type":"int"} {"name":"name","type":"string"} {"name":"age","type":"int"} -
Target Field: No es necesario que el valor incluya la información de la clave primaria de la tabla de destino.
Si la clave primaria consta de una columna
intllamadaidy una columnastringllamadaname, y la columna de atributos contiene un campointllamadoage, la configuración de ejemplo es la siguiente:{"name":"age","type":"int"}
-
Una vez completada la configuración, haga clic en Save en la parte superior de la página.
Editor de código
Haga clic en Code Editor en la parte superior de la página. En la página que aparece, edite el script.
El siguiente ejemplo muestra la configuración para una tabla cuya clave primaria consta de una columnaintllamadaidy una columnastringllamadaname, y cuyas columnas de atributos incluyen un campointllamadoage. Al configurar los ajustes, reemplace los nombresdatasourceytableen el script de ejemplo.
Datos 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"
}
]
}
}
Rango específico de clave primaria
{
"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"
}
]
}
}
Después de editar el script, haga clic en Save en la parte superior de la página.
Ejecutar la tarea de sincronización
Haga clic en Run en la parte superior de la página para iniciar la tarea de sincronización. La primera vez que ejecute la tarea, deberá confirmar la Debug Configuration.
Paso 4: Consultar el resultado de la sincronización
Una vez ejecutada la tarea, consulte su estado de ejecución en los registros y los datos sincronizados en la consola de Tablestore.
-
Consulte el estado y el resultado de ejecución de la tarea en la parte inferior de la página. La siguiente información de registro indica que la tarea de sincronización finalizó correctamente.
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 -
Consulte los datos en la tabla de destino.
Vaya a la consola de Tablestore. En la barra de navegación superior, seleccione el resource group y la región.
Haga clic en el alias de la instancia. En la página Tables, haga clic en la tabla de destino.
Haga clic en Query Data para consultar los datos de la tabla de destino.
Sincronización de datos mediante la CLI
El uso de la interfaz de línea de comandos requiere exportar manualmente los datos de la tabla de origen a un archivo JSON local y, después, importar ese archivo en la tabla de destino. Este método solo es adecuado para migraciones de datos a pequeña escala.
Paso 1: Preparativos
Create the target table. Compruebe que la estructura de su clave primaria, incluidos los nombres, los tipos de datos y el orden de las columnas de clave primaria, sea idéntica a la de la tabla de origen.
Paso 2: Exportar datos de la tabla de origen
-
Inicie la interfaz de línea de comandos y ejecute el comando config para configurar la información de acceso de la instancia donde se encuentra la tabla de origen. Para más información, consulte Start the tool and configure access information.
Antes de ejecutar el comando, reemplace endpoint, instance, id y key con el endpoint, el nombre de la instancia, el AccessKey ID y el AccessKey Secret de la instancia donde se ubica la tabla de origen.
config --endpoint https://myinstance.cn-hangzhou.ots.aliyuncs.com --instance myinstance --id NTSVL******************** --key 7NR2**************************************** -
Exporte los datos.
-
Ejecute el comando
usepara trabajar con la tabla de origen. Este documento utilizasource_tablecomo ejemplo.use --wc -t source_table -
Exporte los datos de la tabla de origen a un archivo JSON local. Para más información, consulte Export data.
scan -o /tmp/sourceData.json
-
Paso 3: Importar datos a la tabla de destino
-
Ejecute el comando config para configurar la información de acceso de la instancia donde se encuentra la tabla de destino.
Antes de ejecutar el comando, reemplace endpoint, instance, id y key con el endpoint, el nombre de la instancia, el AccessKey ID y el AccessKey Secret de la instancia donde se encuentra la tabla de destino.
config --endpoint https://myinstance.cn-hangzhou.ots.aliyuncs.com --instance myinstance --id NTSVL******************** --key 7NR2**************************************** -
Importe los datos.
-
Ejecute el comando
usepara usar la tabla de destino. En este ejemplo se utilizatarget_table.use --wc -t target_table -
Importe los datos del archivo JSON local a la tabla de destino. Para obtener más información, consulte Import data.
import -i /tmp/sourceData.json
-