Todos los productos
Search
Centro de documentos

Hologres:Consumo de Binlog mediante JDBC

Última actualización: Sep 05, 2026

Binlog de Hologres registra las operaciones INSERT, UPDATE, DELETE y TRUNCATE como un flujo de eventos de cambio. Esta página explica cómo consumir dicho flujo mediante Java Database Connectivity (JDBC) directamente o a través de Holo-Client, el SDK de Java para Hologres.

Requisitos previos

Antes de empezar, asegúrese de cumplir con lo siguiente:

  • Binlog habilitado en la tabla destino. Consulte Subscribe to Hologres Binlog data.

  • La extensión hg_binlog creada (solo para Hologres V1.x). A partir de la versión V2.0, la extensión viene integrada y no requiere configuración manual. En versiones anteriores a V2.0, un superusuario debe ejecutar la siguiente sentencia una vez por base de datos. Si crea una nueva base de datos, ejecútela nuevamente.

    Importante

    Nunca utilice DROP EXTENSION <extension_name> CASCADE. La opción CASCADE elimina todos los datos de la extensión, incluidos PostGIS, RoaringBitmap, Proxima, Binlog y BSI, además de borrar todos los objetos dependientes como tablas, vistas, metadatos y datos del servidor.

    -- Create the extension.
    CREATE EXTENSION hg_binlog;
    
    -- Remove the extension.
    DROP EXTENSION hg_binlog;
  • Acceso configurado según su versión de Hologres: para crear una publicación y un slot de replicación (obligatorio en todas las versiones que usan este método), el usuario debe contar con uno de los siguientes conjuntos de permisos:

    • Permisos de superusuario en la instancia

    • Permisos de propietario en la tabla destino, permisos CREATE DATABASE y el rol de replicación (Replication Role) en la instancia

    Nota

    A partir de la versión V2.0, el modo Holohub ya no es compatible. Antes de actualizar a V2.0 o superior, actualice primero Flink a la versión 8.0.5. Después de la actualización, se utiliza automáticamente el modo JDBC.

    Versión de Hologres

    Versión del motor de Flink

    Requisitos

    V2.1 y posteriores

    8.0.5 y posteriores

    Permisos de lectura en la tabla destino. No se requiere slot de replicación.

    V2.0

    8.0.5 y anteriores

    Una publicación y un slot de replicación. Consulte Create a publication and a replication slot.

    V1.3 y anteriores

    8.0.5 y anteriores

    Permisos de lectura en la tabla destino. Se utiliza automáticamente el modo Holohub.

Limitaciones

  • El consumo de Binlog basado en JDBC requiere Hologres V1.1 o posterior.

  • Tipos de datos de columna compatibles: INTEGER, BIGINT, SMALLINT, TEXT, CHAR(n), VARCHAR(n), REAL, DOUBLE PRECISION, BOOLEAN, NUMERIC(38.8), DATE, TIME, TIMETZ, TIMESTAMP, TIMESTAMPTZ, BYTEA, JSON, SERIAL, OID, int4[], int8[], float4[], float8[], boolean[] y text[]. Si una tabla contiene columnas de tipos no compatibles, el consumo fallará. A partir de la versión V1.3.36, también se admiten columnas JSONB. Habilite el siguiente parámetro de Grand Unified Configuration (GUC) antes de iniciar el consumo:

    -- Enable at the session level.
    SET hg_experimental_enable_binlog_jsonb = ON;
    
    -- Enable at the database level.
    ALTER DATABASE <db_name> SET hg_experimental_enable_binlog_jsonb = ON;
  • Cada shard de cada tabla consumida utiliza una conexión Walsender. Las conexiones Walsender son independientes de las conexiones regulares.

  • El número máximo de Walsenders por nodo frontend varía según la versión. Para comprobar el límite actual, ejecute:

    1. Identifique los trabajos activos de consumo de Binlog por JDBC y detenga aquellos que no sean necesarios.

    2. Revise si la configuración del grupo de tablas y el recuento de shards son adecuados. Consulte Best practices for setting table groups.

    3. Si aun así se supera el límite, escale horizontalmente la instancia.

    Versión

    Máximo de Walsenders por nodo frontend

    V2.2 y posteriores

    600

    V2.0 y V2.1

    1,000

    V1.1.26 a V2.0

    100

    SHOW max_wal_senders;

    Valores predeterminados: El límite total es max_wal_senders × número de nodos frontend. Para conocer el número de nodos frontend correspondiente a una especificación de instancia determinada, consulte Instance management. Utilice esta fórmula para estimar cuántas tablas puede consumir simultáneamente:

    Number of tables ≤ (max_wal_senders × number of frontend nodes) / table shard count

    Ejemplo: Una instancia con dos nodos frontend que ejecuta V2.2 tiene un total de 600 × 2 = 1,200 Walsenders. Para tablas con un recuento de shards de 20, puede soportar hasta 60 consumos concurrentes de tablas. Si dos trabajos consumen de la misma tabla simultáneamente, cada uno utiliza 20 Walsenders, lo que suma 40 al total. Si se alcanza el límite de Walsenders, verá el siguiente mensaje:

    FATAL: sorry, too many wal senders already

    Para resolver esto:

  • Instancias secundarias de solo lectura: El consumo de Binlog mediante JDBC no es compatible antes de la versión V2.0.18. A partir de V2.0.18, las instancias secundarias admiten el consumo de Binlog, pero no registran el progreso del consumo.

Creación de una publicación y un slot de replicación

Obligatorio para Hologres V2.0 y anteriores. A partir de V2.1, los usuarios con solo permisos de lectura en la tabla destino pueden consumir datos de Binlog sin necesidad de un slot de replicación; omita esta sección si utiliza V2.1 o posterior.

Publicación

Una publicación define qué cambios de tabla están disponibles para la replicación lógica. En Hologres, una publicación se vincula exactamente a una tabla física, y dicha tabla debe tener Binlog habilitado.

Crear una publicación

CREATE PUBLICATION <name> FOR TABLE <table_name>;

Parámetro

Descripción

name

Nombre personalizado para la publicación.

table_name

Nombre de la tabla destino.

Ejemplo:

CREATE PUBLICATION hg_publication_test_1 FOR TABLE test_message_src;

Consultar publicaciones

SELECT * FROM pg_publication;

Salida de ejemplo:

         pubname        | pubowner | puballtables | pubinsert | pubupdate | pubdelete | pubtruncate
------------------------+----------+--------------+-----------+-----------+-----------+-------------
 hg_publication_test_1  |    16728 | f            | t         | t         | t         | t
(1 row)

Campo

Descripción

pubname

Nombre de la publicación.

pubowner

Propietario de la publicación.

puballtables

Indica si se incluyen todas las tablas. Siempre es false, ya que no se admite la vinculación de varias tablas físicas.

pubinsert

Indica si se publican los eventos INSERT. Valor predeterminado: true.

pubupdate

Indica si se publican los eventos UPDATE. Valor predeterminado: true.

pubdelete

Indica si se publican los eventos DELETE. Valor predeterminado: true.

pubtruncate

Indica si se publican los eventos TRUNCATE. Valor predeterminado: true.

Para obtener más información sobre los tipos de eventos de Binlog, consulte Binlog format and principles.

Consultar tablas en una publicación

SELECT * FROM pg_publication_tables;

Salida de ejemplo:

         pubname        | schemaname |    tablename
------------------------+------------+------------------
 hg_publication_test_1  | public     | test_message_src
(1 row)

Eliminar una publicación

DROP PUBLICATION <name>;

Ejemplo:

DROP PUBLICATION hg_publication_test_1;

Slot de replicación

Importante

Un slot de replicación inactivo continúa reteniendo datos WAL en el servidor. Si un slot no se consume, los datos WAL se acumulan y pueden agotar el almacenamiento. Elimine cualquier slot que ya no necesite.

Un slot de replicación rastrea el progreso del consumo de una publicación y permite reanudar la transmisión. Tras un failover, un consumidor puede recuperarse desde el último punto de control confirmado registrado en el slot.

Solo los superusuarios y los usuarios con el rol de replicación (Replication Role) pueden crear y utilizar slots de replicación. Para otorgar o revocar este rol:

-- Grant the Replication Role to a user.
ALTER ROLE <user_name> REPLICATION;

-- Revoke the Replication Role from a user.
ALTER ROLE <user_name> NOREPLICATION;

user_name es un ID de cuenta de Alibaba Cloud o un usuario de Resource Access Management (RAM). Consulte Account overview.

Crear un slot de replicación

CALL hg_create_logical_replication_slot('<replication_slot_name>', 'hgoutput', '<publication_name>');

Parámetro

Descripción

replication_slot_name

Nombre personalizado para el slot de replicación.

hgoutput

Plugin de salida para el formato Binlog. Solo se admite hgoutput.

publication_name

Nombre de la publicación a la que se vinculará.

Ejemplo:

CALL hg_create_logical_replication_slot('hg_replication_slot_1', 'hgoutput', 'hg_publication_test_1');

Consultar slots de replicación

SELECT * FROM hologres.hg_replication_slot_properties;

Salida de ejemplo:

        slot_name       | property_key |      property_value
------------------------+--------------+------------------------
 hg_replication_slot_1  | plugin       | hgoutput
 hg_replication_slot_1  | publication  | hg_publication_test_1
 hg_replication_slot_1  | parallelism  | 1
(3 rows)

Campo

Descripción

slot_name

Nombre del slot de replicación.

property_key

Uno de los siguientes: plugin (plugin de salida), publication (publicación vinculada) o parallelism (número de conexiones concurrentes necesarias para consumir la tabla completa, equivalente al recuento de shards del grupo de tablas).

property_value

Valor de la propiedad correspondiente.

Consultar el paralelismo requerido

Dado que Hologres es una base de datos distribuida, los datos de cada tabla se distribuyen en varios shards. Se requiere una conexión por shard para consumir la tabla completa. Para comprobar cuántas conexiones concurrentes requiere hg_replication_slot_1:

SELECT hg_get_logical_replication_slot_parallelism('hg_replication_slot_1');

Salida de ejemplo:

 hg_get_logical_replication_slot_parallelism
---------------------------------------------
                                          20

Consultar el progreso del consumo

La tabla hologres.hg_replication_progress registra el desplazamiento del consumidor que usted confirma explícitamente.

SELECT * FROM hologres.hg_replication_progress;

Salida de ejemplo:

        slot_name       | parallel_index | lsn
------------------------+----------------+-----
 hg_replication_slot_1  |              0 |  66
 hg_replication_slot_1  |              1 | 122
 hg_replication_slot_1  |              2 | 119
(3 rows)

Campo

Descripción

slot_name

Nombre del slot de replicación.

parallel_index

Índice de la conexión concurrente (una por shard).

lsn

Número de secuencia de registro (LSN) del último registro de Binlog consumido que se confirmó.

Importante
  • La tabla hologres.hg_replication_progress se crea únicamente después del primer consumo de Binlog.

  • La tabla solo registra los desplazamientos que usted confirma explícitamente al llamar a la función de confirmación de LSN en su código. Es posible que el valor registrado no coincida con la posición real del consumidor. Rastree el LSN en el lado del cliente y utilícelo como punto de recuperación.

  • Las confirmaciones de puntos de control solo son efectivas cuando se consume mediante un slot de replicación. Al consumir solo por nombre de tabla (sin withSlotName), no se registra el progreso.

Eliminar un slot de replicación

Elimine un slot cuando ya no lo necesite para evitar la acumulación de WAL. Los slots no se cierran automáticamente cuando se detiene un trabajo de consumo; debe eliminarlos manualmente.

CALL hg_drop_logical_replication_slot('<replication_slot_name>');

Ejemplo:

CALL hg_drop_logical_replication_slot('hg_replication_slot_1');

Consumo de datos de Binlog mediante JDBC

El consumo basado en JDBC le ofrece un control detallado sobre cada shard. Debe crear un PGReplicationStream por shard y gestionar el paralelismo por su cuenta.

Paso 1: Agregar dependencias

Utilice JDBC 42.2.18 o posterior. Agregue las siguientes dependencias a su archivo pom.xml:

<dependency>
    <groupId>org.postgresql</groupId>
    <artifactId>postgresql</artifactId>
    <version>42.3.8</version>
</dependency>
<!-- Used to get the table schema and decode Binlog records -->
<dependency>
    <groupId>com.alibaba.hologres</groupId>
    <artifactId>holo-client</artifactId>
    <version>2.2.10</version>
</dependency>

Paso 2: Conectar y consumir

El siguiente ejemplo se conecta a un slot de replicación, lee registros de Binlog de un shard e imprime cada registro.

import com.alibaba.hologres.client.HoloClient;
import com.alibaba.hologres.client.HoloConfig;
import com.alibaba.hologres.client.impl.binlog.HoloBinlogDecoder;
import com.alibaba.hologres.client.model.Record;
import com.alibaba.hologres.client.model.TableSchema;

import org.postgresql.PGConnection;
import org.postgresql.PGProperty;
import org.postgresql.replication.LogSequenceNumber;
import org.postgresql.replication.PGReplicationStream;

import java.nio.ByteBuffer;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

public class Test {

    public static void main(String[] args) throws Exception {

        String username = "";
        String password = "";
        String url = "jdbc:postgresql://Endpoint:Port/db_test";

        // Set up the JDBC connection for replication.
        Properties properties = new Properties();
        PGProperty.USER.set(properties, username);
        PGProperty.PASSWORD.set(properties, password);
        PGProperty.ASSUME_MIN_SERVER_VERSION.set(properties, "9.4");
        // Required for Binlog consumption.
        PGProperty.REPLICATION.set(properties, "database");

        try (Connection connection = DriverManager.getConnection(url, properties)) {

            // Each PGReplicationStream consumes one shard. Set shardId for each stream.
            int shardId = 0;
            PGConnection pgConnection = connection.unwrap(PGConnection.class);
            PGReplicationStream pgReplicationStream = pgConnection.getReplicationAPI()
                    .replicationStream()
                    .logical()
                    // V2.1+: two options
                    // Option 1: specify the replication slot name. table_name is ignored.
                    // Option 2: omit withSlotName and set table_name in withSlotOption instead.
                    .withSlotName("slot_name")
                    .withSlotOption("table_name", "public.test_message_src")
                    .withSlotOption("parallel_index", shardId)
                    .withSlotOption("batch_size", "1024")
                    .withSlotOption("start_time", "2021-01-01 00:00:00")
                    .withSlotOption("start_lsn", "0")
                    .start();

            // HoloClient is needed to get the table schema for decoding.
            HoloConfig holoConfig = new HoloConfig();
            holoConfig.setJdbcUrl(url);
            holoConfig.setUsername(username);
            holoConfig.setPassword(password);
            HoloClient client = new HoloClient(holoConfig);

            // Decode raw binary Binlog data into BinlogRecord objects.
            TableSchema schema = client.getTableSchema("test_message_src", true);
            HoloBinlogDecoder decoder = new HoloBinlogDecoder(schema);

            // Track the last consumed LSN for checkpoint recovery.
            Long currentLsn = 0L;

            ByteBuffer byteBuffer = pgReplicationStream.readPending();
            while (true) {
                if (byteBuffer != null) {
                    List<BinlogRecord> records = decoder.decode(shardId, byteBuffer);
                    Long latestLsn = 0L;
                    for (BinlogRecord record : records) {
                        latestLsn = record.getBinlogLsn();
                        // Process the record here.
                        System.out.println("lsn: " + latestLsn + ", record: " + Arrays.toString(record.getValues()));
                    }
                    // Save the latest LSN as the recovery point.
                    currentLsn = latestLsn;
                    pgReplicationStream.forceUpdateStatus();
                }
                byteBuffer = pgReplicationStream.readPending();
            }
        }
    }
}

Parámetros

Comportamiento de withSlotName según la versión:

Versión

Comportamiento

Anterior a V2.1

Especifique el nombre de un slot de replicación existente. Obligatorio.

V2.1 y posteriores

Opcional. Omita withSlotName y establezca table_name en withSlotOption para consumir sin un slot de replicación.

Parámetros de withSlotOption:

Parámetro

Obligatorio

Descripción

table_name

Sí, cuando no se establece withSlotName

Tabla destino a consumir. Formato: schema_name.table_name o table_name. Se ignora si se establece withSlotName.

parallel_index

Sí

Índice del shard a consumir. Un PGReplicationStream gestiona un shard. Para una tabla con tres shards, cree tres flujos con parallel_index 0, 1 y 2.

start_time

No

Inicia el consumo desde esta marca de tiempo. Ejemplo: 2021-01-01 12:00:00+08.

start_lsn

No

Inicia el consumo desde el registro posterior a este LSN. Tiene prioridad sobre start_time.

batch_size

No

Máximo de registros por recuperación. Valor predeterminado: 1,024.

Comportamiento de inicio predeterminado (cuando no se establece ni start_lsn ni start_time):

Escenario

Comportamiento

Primer consumo desde un slot de replicación

Comienza desde el inicio, similar al desplazamiento más temprano (earliest offset) de Kafka.

Consumos subsiguientes desde un slot de replicación

Se reanuda desde el último punto de control confirmado.

Consumo solo por nombre de tabla (sin withSlotName)

Siempre comienza desde el inicio.

Campos de BinlogRecord

BinlogRecord expone los siguientes campos del sistema de Binlog:

Método

Retorna

getBinlogLsn()

El LSN del registro de Binlog.

getBinlogTimestamp()

La marca de tiempo del sistema cuando ocurrió el evento.

getBinlogEventType()

El tipo de evento: INSERT, UPDATE, DELETE o TRUNCATE.

Para consultar la referencia completa de campos, véase Subscribe to Hologres Binlog data.

Confirmar el punto de control

Después de consumir datos de Binlog, confirme el punto de control llamando a la función de confirmación de LSN. Esto cumple dos propósitos: permite que el servidor sepa qué segmentos WAL son seguros para archivar o descartar, y proporciona un punto de recuperación para que el consumo pueda reanudarse desde la posición correcta tras un failover.

El código de ejemplo anterior no incluye este paso; agréguelo según los requisitos de recuperación de su aplicación.

Consumo de datos de Binlog mediante Holo-Client

Holo-Client simplifica el consumo de Binlog al gestionar automáticamente las conexiones a nivel de shard. Especifique la tabla destino y Holo-Client se encargará del resto.

  • El número de conexiones es igual al recuento de shards de la tabla.

  • Guarde el punto de control por shard para que el consumo pueda reanudarse desde la posición correcta tras un fallo de red u otra interrupción.

Nota

Utilice Holo-Client 2.2.10 o posterior. Las versiones 2.2.9 y anteriores presentan una fuga de memoria.

Paso 1: Agregar dependencias

<dependency>
    <groupId>com.alibaba.hologres</groupId>
    <artifactId>holo-client</artifactId>
    <version>2.2.10</version>
</dependency>

Paso 2: Conectar y consumir

El siguiente ejemplo se suscribe a una tabla, procesa cada registro, guarda un punto de control por shard y reintenta en caso de error.

import com.alibaba.hologres.client.BinlogShardGroupReader;
import com.alibaba.hologres.client.Command;
import com.alibaba.hologres.client.HoloClient;
import com.alibaba.hologres.client.HoloConfig;
import com.alibaba.hologres.client.Subscribe;
import com.alibaba.hologres.client.exception.HoloClientException;
import com.alibaba.hologres.client.impl.binlog.BinlogOffset;
import com.alibaba.hologres.client.model.binlog.BinlogHeartBeatRecord;
import com.alibaba.hologres.client.model.binlog.BinlogRecord;

import java.util.HashMap;
import java.util.Map;

public class HoloBinlogExample {

    public static BinlogShardGroupReader reader;

    public static void main(String[] args) throws Exception {
        String username = "";
        String password = "";
        String url = "jdbc:postgresql://ip:port/database";
        String tableName = "test_message_src";
        String slotName = "hg_replication_slot_1";

        HoloConfig holoConfig = new HoloConfig();
        holoConfig.setJdbcUrl(url);
        holoConfig.setUsername(username);
        holoConfig.setPassword(password);
        holoConfig.setBinlogReadBatchSize(128);
        holoConfig.setBinlogIgnoreDelete(true);
        holoConfig.setBinlogIgnoreBeforeUpdate(true);
        holoConfig.setBinlogHeartBeatIntervalMs(5000L);
        HoloClient client = new HoloClient(holoConfig);

        // Get the shard count to initialize per-shard checkpoint tracking.
        int shardCount = Command.getShardCount(client, client.getTableSchema(tableName));

        // Initialize the checkpoint map with LSN 0 for each shard.
        Map<Integer, Long> shardIdToLsn = new HashMap<>(shardCount);
        for (int i = 0; i < shardCount; i++) {
            shardIdToLsn.put(i, 0L);
        }

        // Before V2.1: tableName and slotName are both required.
        // V2.1 and later: tableName is enough (slotName defaults to "hg_table_name_slot").
        Subscribe subscribe = Subscribe.newStartTimeBuilder(tableName, slotName)
                .setBinlogReadStartTime("2021-01-01 12:00:00")
                .build();

        reader = client.binlogSubscribe(subscribe);

        BinlogRecord record;
        int retryCount = 0;

        while (true) {
            try {
                if (reader.isCanceled()) {
                    // Re-create the reader using the last saved checkpoint.
                    reader = client.binlogSubscribe(subscribe);
                }
                while ((record = reader.getBinlogRecord()) != null) {
                    if (record instanceof BinlogHeartBeatRecord) {
                        // All data up to this heartbeat's timestamp has been consumed on this shard.
                        continue;
                    }

                    // Process the record here.
                    System.out.println(record);

                    // Save the checkpoint so consumption can resume from here on failure.
                    shardIdToLsn.put(record.getShardId(), record.getBinlogLsn());
                    retryCount = 0;
                }
            } catch (HoloClientException e) {
                if (++retryCount > 10) {
                    throw new RuntimeException(e);
                }
                System.out.println(String.format(
                        "Binlog read failed: %s. Retrying (%d/10)...", e.getMessage(), retryCount));

                // Wait before retrying, with increasing backoff.
                Thread.sleep(5000L * retryCount);

                // Resume from the saved per-shard checkpoint.
                Subscribe.OffsetBuilder subscribeBuilder = Subscribe.newOffsetBuilder(tableName, slotName);
                for (int i = 0; i < shardCount; i++) {
                    subscribeBuilder.addShardStartOffset(i,
                            new BinlogOffset().setSequence(shardIdToLsn.get(i)));
                }
                subscribe = subscribeBuilder.build();
                reader.cancel();
            }
        }
    }
}

Parámetros

Tipos de Subscribe:

Tipo

Cuándo utilizarlo

Subscribe.newStartTimeBuilder(tableName, slotName)

Para iniciar el consumo desde una marca de tiempo específica.

Subscribe.newOffsetBuilder(tableName, slotName)

Para iniciar el consumo desde un LSN específico por shard; utilícelo para la recuperación basada en puntos de control.

Nota sobre versiones: Antes de V2.1, tanto tableName como slotName son obligatorios. A partir de V2.1, solo se requiere tableName (equivalente a usar el nombre de slot fijo hg_table_name_slot).

Parámetros de Binlog en HoloConfig:

Parámetro

Valor predeterminado

Descripción

binlogReadBatchSize

1,024

Máximo de registros por recuperación por shard.

binlogHeartBeatIntervalMs

-1 (deshabilitado)

Intervalo en milisegundos entre mensajes BinlogHeartBeatRecord. Cuando no llegan datos nuevos, los registros de latido indican que se han consumido todos los datos hasta esa marca de tiempo en ese shard.

binlogIgnoreDelete

false

Omite los eventos DELETE.

binlogIgnoreBeforeUpdate

false

Omite los registros de imagen previa (before-image) para eventos UPDATE.

Solución de problemas

La tabla hologres.hg_replication_progress falta o está vacía

Si la tabla no existe o no muestra datos después de confirmar el progreso del consumo, compruebe lo siguiente:

Consumo por nombre de tabla sin slot de replicación. Si no estableció withSlotName (JDBC) o no especificó un slot (Holo-Client), el seguimiento de progreso no es compatible. La tabla no se creará ni se actualizará. Cambie al consumo basado en slots de replicación para habilitar el seguimiento de progreso.

Primer consumo en una instancia secundaria de solo lectura. En instancias secundarias que ejecutan versiones de Hologres anteriores a V2.0.18, la tabla hologres.hg_replication_progress no puede crearse durante el primer consumo de Binlog. Consuma desde la instancia principal una vez y luego vuelva a la instancia secundaria.

Si ninguna de estas situaciones aplica, contacte al soporte técnico a través del grupo de DingTalk de Hologres. Consulte How do I get more online support?.

Pasos siguientes