Import data with Flink

Updated at:

ApsaraDB for SelectDB is fully compatible with Apache Doris. Use the Flink Doris Connector to import historical data from data sources such as MySQL, Oracle, PostgreSQL, SQL Server, and Kafka to SelectDB. After you start a change data capture (CDC) task in Flink, it also synchronizes incremental data from the data source to SelectDB.

Overview

Note

The Flink Doris Connector currently only supports writing data to SelectDB. If you need to use the Flink Doris Connector to connect directly to the backend nodes of SelectDB to read data efficiently, contact the SelectDB technical support team to request access.

You can also use the Flink JDBC Connector to read data from SelectDB.

The Flink Doris Connector enables Flink to read from and write to Apache Doris for real-time data processing and analytics. Since SelectDB is fully compatible with Apache Doris, this connector is a common method for streaming data into SelectDB.

Each component functions as follows:

  • Source

    • Purpose: A source reads data from external systems into a Flink data stream. These systems can include a message queue (such as Apache Kafka), a database, or a file system.

    • Example: Use Kafka as a source to read real-time messages, or read data from a file.

  • Transform

    • Purpose: The transform stage processes the incoming data stream. These operations can include filtering, mapping, aggregation, and windowing.

    • Example: Map an input stream to convert its data structure, or aggregate data to calculate a metric per minute.

  • Sink

    • Purpose: A sink writes the processed data from a Flink data stream to an external system, such as a database, a file, or a message queue.

    • Example: Write the processed results to a MySQL database or send the data to another Kafka topic.

The following figure shows how data is imported into SelectDB using the Flink Doris Connector.

image

Prerequisites

  • Ensure network connectivity between your data source, Flink, and SelectDB.

    1. Apply for a public endpoint for your ApsaraDB for SelectDB instance. For more information, see Apply for or release a public endpoint.

      Skip this step if your Flink environment and data source are in the same virtual private cloud (VPC) as your ApsaraDB for SelectDB instance. This is typical when they are Alibaba Cloud products or deployed on Elastic Compute Service (ECS) instances in the same VPC.

    2. Add the IP addresses of your Flink environment and data source to the whitelist of your ApsaraDB for SelectDB instance. For more information, see Configure an IP address whitelist.

  • Ensure the Flink Doris Connector is installed.

    The following table lists the version requirements for Flink and Flink Doris Connector.

    Flink version

    Flink Doris Connector version

    Download link

    Realtime Compute for Apache Flink: 1.17 or later

    Open source Flink: 1.15 or later

    1.5.2 or later. We recommend downloading the latest version.

    Flink Doris Connector

    For installation instructions, see Install Flink Doris Connector.

Add Flink Doris Connector

Add the Flink Doris Connector based on your environment.

  • If you use Realtime Compute for Apache Flink to import data into SelectDB, you can manage the Flink Doris Connector as a custom connector. For details, see Manage custom connectors.

  • If you use a self-managed Flink cluster, download the corresponding Flink Doris Connector JAR package and place it in the lib directory of your Flink installation. For the download link, see JAR Package.

  • To add the Flink Doris Connector as a Maven dependency, add the following code to your project's dependency configuration file. For more versions, see Maven Repository.

    <!-- flink-doris-connector -->
    <dependency>
      <groupId>org.apache.doris</groupId>
      <artifactId>flink-doris-connector-1.16</artifactId>
      <version>1.5.2</version>
    </dependency>  

Examples

Example environment

This example uses Flink SQL, Flink CDC, and the DataStream API to migrate data from the employees table in the test database of an ApsaraDB RDS for MySQL instance to the employees table in the test database of an SelectDB instance. Modify the parameters in these examples to fit your scenario. The example environment is as follows:

  • Flink 1.16 standalone environment

  • Java

  • Target database: test

  • Target table: employees

  • Source database: test

  • Source table: employees

Prepare the environment

Flink environment

  1. Prepare a Java environment.

    Flink requires a Java environment to run. You must install a Java Development Kit (JDK) and configure the JAVA_HOME environment variable.

    For a list of supported Java versions, see Java Compatibility. This example uses Java 8. For installation instructions, see Install JDK.

  2. Download the Flink installation package flink-1.16.3-bin-scala_2.12.tgz. If this version is outdated, you can download another version from Apache Flink.

    wget https://www.apache.si/flink/flink-1.16.3/flink-1.16.3-bin-scala_2.12.tgz
  3. Decompress the installation package.

    tar -zxvf flink-1.16.3-bin-scala_2.12.tgz
  4. Navigate to the lib directory in the Flink installation directory and add the required connectors for the following steps.

    • Add the Flink Doris Connector.

      wget https://repo.maven.apache.org/maven2/org/apache/doris/flink-doris-connector-1.16/1.5.2/flink-doris-connector-1.16-1.5.2.jar
    • Add the Flink MySQL Connector.

      wget https://repo1.maven.org/maven2/com/ververica/flink-sql-connector-mysql-cdc/2.4.2/flink-sql-connector-mysql-cdc-2.4.2.jar
  5. Start the Flink cluster.

    In the bin directory of your Flink installation, run the following command:

    ./start-cluster.sh 

Target SelectDB

  1. Create an ApsaraDB for SelectDB instance. For more information, see Create an instance.

  2. Connect to the instance. For more information, see Connect to an instance.

  3. Create a test database named test.

    CREATE DATABASE test;
  4. Create a test table named employees.

    USE test;
    
    -- Create table
    CREATE TABLE employees (
        emp_no       int NOT NULL,
        birth_date   date,
        first_name   varchar(20),
        last_name    varchar(20),
        gender       char(2),
        hire_date    date
    )
    UNIQUE KEY(`emp_no`)
    DISTRIBUTED BY HASH(`emp_no`) BUCKETS 1;

Source MySQL

  1. Create an ApsaraDB RDS for MySQL instance.

  2. Create a test database named test.

    CREATE DATABASE test;
  3. Create a test table named employees.

    USE test;
    
    CREATE TABLE employees (
        emp_no INT NOT NULL PRIMARY KEY,
        birth_date DATE,
        first_name VARCHAR(20),
        last_name VARCHAR(20),
        gender CHAR(2),
        hire_date DATE
    );
  4. Insert data.

    INSERT INTO employees (emp_no, birth_date, first_name, last_name, gender, hire_date) VALUES
    (1001, '1985-05-15', 'John', 'Doe', 'M', '2010-06-20'),
    (1002, '1990-08-22', 'Jane', 'Smith', 'F', '2012-03-15'),
    (1003, '1987-11-02', 'Robert', 'Johnson', 'M', '2015-07-30'),
    (1004, '1992-01-18', 'Emily', 'Davis', 'F', '2018-01-05'),
    (1005, '1980-12-09', 'Michael', 'Brown', 'M', '2008-11-21');

Import with Flink SQL

  1. Start the Flink SQL Client.

    In the bin directory of your Flink installation, run the following command:

    ./sql-client.sh
  2. In the Flink SQL Client, submit a Flink job.

    1. Create a MySQL source table.

      The WITH clause in the following statement specifies the configuration for the MySQL CDC Source. For more information about the parameters, see MySQL | Apache Flink CDC.

      CREATE TABLE employees_source (
          emp_no INT,
          birth_date DATE,
          first_name STRING,
          last_name STRING,
          gender STRING,
          hire_date DATE,
          PRIMARY KEY (`emp_no`) NOT ENFORCED
      ) WITH (
          'connector' = 'mysql-cdc',
          'hostname' = '127.0.0.1', 
          'port' = '3306',
          'username' = 'root',
          'password' = '****',
          'database-name' = 'test',
          'table-name' = 'employees'
      );
    2. Create an SelectDB sink table.

      The WITH clause in the following statement specifies the configuration for SelectDB. For more information about the parameters, see Sink parameters.

      CREATE TABLE employees_sink (
          emp_no       INT ,
          birth_date   DATE,
          first_name   STRING,
          last_name    STRING,
          gender       STRING,
          hire_date    DATE
      ) 
      WITH (
        'connector' = 'doris',
        'fenodes' = 'selectdb-cn-****.selectdbfe.rds.aliyuncs.com:8080',
        'table.identifier' = 'test.employees',
        'username' = 'admin',
        'password' = '****'
      );
    3. Synchronize data from the MySQL source table to the SelectDB sink table.

      INSERT INTO employees_sink SELECT * FROM employees_source;
  3. Verify the data import.

    Connect to SelectDB and run the following statement to view the imported data.

    SELECT * FROM test.employees;

Import with Flink CDC

Important

Realtime Compute for Apache Flink does not support JAR-based jobs. Use YAML-based jobs with CDC 3.0 instead.

Use Flink CDC to import data into SelectDB.

To run a Flink CDC job, use the flink program in your Flink installation directory. The syntax is as follows:

<FLINK_HOME>/bin/flink run \
    -Dexecution.checkpointing.interval=10s \
    -Dparallelism.default=1 \
    -c org.apache.doris.flink.tools.cdc.CdcTools \
    lib/flink-doris-connector-1.16-1.5.2.jar \
    <mysql-sync-database|oracle-sync-database|postgres-sync-database|sqlserver-sync-database> \
    --database <selectdb-database-name> \
    [--job-name <flink-job-name>] \
    [--table-prefix <selectdb-table-prefix>] \
    [--table-suffix <selectdb-table-suffix>] \
    [--including-tables <mysql-table-name|name-regular-expr>] \
    [--excluding-tables <mysql-table-name|name-regular-expr>] \
    --mysql-conf <mysql-cdc-source-conf> [--mysql-conf <mysql-cdc-source-conf> ...] \
    --oracle-conf <oracle-cdc-source-conf> [--oracle-conf <oracle-cdc-source-conf> ...] \
    --sink-conf <doris-sink-conf> [--table-conf <doris-sink-conf> ...] \
    [--table-conf <selectdb-table-conf> [--table-conf <selectdb-table-conf> ...]]

Parameters

Parameter

Description

execution.checkpointing.interval

The Flink checkpoint interval. This setting affects the data synchronization frequency. A value of 10s is recommended.

parallelism.default

The parallelism of the Flink job. Increasing the parallelism can improve data synchronization speed.

job-name

The name of the Flink job.

database

The name of the target database in SelectDB.

table-prefix

The prefix for the target table name in SelectDB. For example, --table-prefix ods_.

table-suffix

The suffix for the target table name in SelectDB.

including-tables

The tables to synchronize. Use a vertical bar | to separate multiple tables. Regular expressions are supported. For example, --including-tables table1|tbl.* synchronizes table1 and all tables that start with tbl.

excluding-tables

The tables to exclude from synchronization. The format is the same as for including-tables.

mysql-conf

The configuration for the MySQL CDC Source. For more information, see MySQL CDC Connector. The hostname, username, password, and database-name parameters are required.

oracle-conf

The configuration for the Oracle CDC Source. For more information, see Oracle CDC Connector. The hostname, username, password, database-name, and schema-name parameters are required.

sink-conf

Configuration parameters for the Doris Sink. For more information, see Sink parameters.

table-conf

Configuration parameters for the SelectDB table. These correspond to the contents of the PROPERTIES clause when you create a table in SelectDB.

Note
  1. For data synchronization, add the required Flink CDC dependency, such as flink-sql-connector-mysql-cdc-${version}.jar or flink-sql-connector-oracle-cdc-${version}.jar, to the $FLINK_HOME/lib directory.

  2. Full database synchronization is supported in Flink 1.15 and later. To download different versions of the Flink Doris Connector, see Flink Doris Connector.

Sink parameters

Parameter

Default

Required

Description

fenodes

None

Yes

The endpoint and HTTP port of your ApsaraDB for SelectDB instance.

You can obtain the VPC Endpoint (or Public Endpoint) and HTTP Port from the Instance Details > Network Information page in the ApsaraDB for SelectDB console.

Example: selectdb-cn-4xl3jv1****.selectdbfe.rds.aliyuncs.com:8080.

table.identifier

None

Yes

The database and table name. Example: test_db.test_table.

username

None

Yes

The database username for your ApsaraDB for SelectDB instance.

password

None

Yes

The password for the database user of your ApsaraDB for SelectDB instance.

jdbc-url

None

No

The JDBC connection information for your ApsaraDB for SelectDB instance.

You can obtain the VPC Endpoint (or Public Endpoint) and MySQL Port from the Instance Details > Network Information page in the ApsaraDB for SelectDB console.

Example: jdbc:mysql://selectdb-cn-4xl3jv1****.selectdbfe.rds.aliyuncs.com:9030.

auto-redirect

true

No

Specifies whether to redirect Stream Load requests. If enabled, Stream Load writes data through the frontends (FEs), and backend (BE) information is not retrieved.

doris.request.retries

3

No

The number of times to retry sending a request to SelectDB.

doris.request.connect.timeout

30s

No

The timeout for connecting to SelectDB.

doris.request.read.timeout

30s

No

The timeout for reading data from SelectDB.

sink.label-prefix

""

Yes

The label prefix for Stream Load imports. In a two-phase commit (2PC) scenario, this prefix must be globally unique to ensure Flink's exactly-once semantics (EOS).

sink.properties

None

No

The import parameters for Stream Load. Configure the properties as follows:

  • For CSV format:

    sink.properties.format='csv' 
    sink.properties.column_separator=','
    sink.properties.line_delimiter='\n' 
  • For JSON format:

    sink.properties.format='json' 

For more parameters, see Stream Load.

sink.buffer-size

1048576

No

The size of the write buffer, in bytes. The default value of 1 MB is recommended.

sink.buffer-count

3

No

The number of write buffers. The default value is recommended.

sink.max-retries

3

No

The maximum number of retries after a failed commit. The default is 3.

sink.use-cache

false

No

Specifies whether to use an in-memory cache for recovery upon exceptions. If enabled, data from the checkpoint period is retained in the cache.

sink.enable-delete

true

No

Specifies whether to synchronize delete events. This option is only supported for tables that use the Unique Key model.

sink.enable-2pc

true

No

Specifies whether to enable two-phase commit (2PC). This is enabled by default (true) to ensure exactly-once semantics (EOS).

sink.enable.batch-mode

false

No

Specifies whether to use batch mode to write data to SelectDB. When enabled, the write operation is triggered by buffer size or time, as defined by sink.buffer-flush.max-rows, sink.buffer-flush.max-bytes, and sink.buffer-flush.interval, rather than by Flink checkpoints.

When batch mode is enabled, exactly-once semantics (EOS) is not guaranteed. You can use the Unique Key model to achieve idempotence.

sink.flush.queue-size

2

No

The size of the buffer queue in batch mode.

sink.buffer-flush.max-rows

50000

No

The maximum number of rows per batch write in batch mode.

sink.buffer-flush.max-bytes

10MB

No

The maximum size in bytes per batch write in batch mode.

sink.buffer-flush.interval

10s

No

The asynchronous buffer flush interval in batch mode. The minimum value is 1 second.

sink.ignore.update-before

true

No

Specifies whether to ignore update-before events. By default, they are ignored.

Synchronization examples

MySQL sync

<FLINK_HOME>/bin/flink run \
    -Dexecution.checkpointing.interval=10s \
    -Dparallelism.default=1 \
    -c org.apache.doris.flink.tools.cdc.CdcTools \
    lib/flink-doris-connector-1.16-1.5.2.jar \
    mysql-sync-database \
    --database test \
    --mysql-conf hostname=127.0.0.1 \
    --mysql-conf port=3306 \
    --mysql-conf username=root \
    --mysql-conf password="password" \
    --mysql-conf database-name=test \
    --including-tables "employees" \
    --sink-conf fenodes=selectdb-cn-****.selectdbfe.rds.aliyuncs.com:8080 \
    --sink-conf username=admin \
    --sink-conf password=****

Oracle sync

<FLINK_HOME>/bin/flink run \
    -Dexecution.checkpointing.interval=10s \
    -Dparallelism.default=1 \
    -c org.apache.doris.flink.tools.cdc.CdcTools \
    lib/flink-doris-connector-1.16-1.5.2.jar \
    oracle-sync-database \
    --database test_db \
    --oracle-conf hostname=127.0.0.1 \
    --oracle-conf port=1521 \
    --oracle-conf username=admin \
    --oracle-conf password="password" \
    --oracle-conf database-name=XE \
    --oracle-conf schema-name=ADMIN \
    --including-tables "tbl1|test.*" \
    --sink-conf fenodes=selectdb-cn-****.selectdbfe.rds.aliyuncs.com:8080 \
    --sink-conf username=admin \
    --sink-conf password=****

PostgreSQL sync

<FLINK_HOME>/bin/flink run \
    -Dexecution.checkpointing.interval=10s \
    -Dparallelism.default=1 \
    -c org.apache.doris.flink.tools.cdc.CdcTools \
    lib/flink-doris-connector-1.16-1.5.2.jar \
    postgres-sync-database \
    --database db1\
    --postgres-conf hostname=127.0.0.1 \
    --postgres-conf port=5432 \
    --postgres-conf username=postgres \
    --postgres-conf password="123456" \
    --postgres-conf database-name=postgres \
    --postgres-conf schema-name=public \
    --postgres-conf slot.name=test \
    --postgres-conf decoding.plugin.name=pgoutput \
    --including-tables "tbl1|test.*" \
    --sink-conf fenodes=selectdb-cn-****.selectdbfe.rds.aliyuncs.com:8080 \
    --sink-conf username=admin \
    --sink-conf password=****

SQL Server sync

<FLINK_HOME>/bin/flink run \
    -Dexecution.checkpointing.interval=10s \
    -Dparallelism.default=1 \
    -c org.apache.doris.flink.tools.cdc.CdcTools \
    lib/flink-doris-connector-1.16-1.5.2.jar \
    sqlserver-sync-database \
    --database db1\
    --sqlserver-conf hostname=127.0.0.1 \
    --sqlserver-conf port=1433 \
    --sqlserver-conf username=sa \
    --sqlserver-conf password="123456" \
    --sqlserver-conf database-name=CDC_DB \
    --sqlserver-conf schema-name=dbo \
    --including-tables "tbl1|test.*" \
    --sink-conf fenodes=selectdb-cn-****.selectdbfe.rds.aliyuncs.com:8080 \
    --sink-conf username=admin \
    --sink-conf password=****

Import with the DataStream API

  1. Add the following dependencies to your Maven project.

    Maven dependencies

    <properties>
            <maven.compiler.source>8</maven.compiler.source>
            <maven.compiler.target>8</maven.compiler.target>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <scala.version>2.12</scala.version>
            <java.version>1.8</java.version>
            <flink.version>1.16.3</flink.version>
            <fastjson.version>1.2.62</fastjson.version>
            <scope.mode>compile</scope.mode>
        </properties>
        <dependencies>
            <!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
            <dependency>
                <groupId>com.google.guava</groupId>
                <artifactId>guava</artifactId>
                <version>28.1-jre</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-lang3</artifactId>
                <version>3.14.0</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.doris</groupId>
                <artifactId>flink-doris-connector-1.16</artifactId>
                <version>1.5.2</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.flink</groupId>
                <artifactId>flink-table-api-scala-bridge_${scala.version}</artifactId>
                <version>${flink.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.flink</groupId>
                <artifactId>flink-table-planner_${scala.version}</artifactId>
                <version>${flink.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.flink</groupId>
                <artifactId>flink-streaming-scala_${scala.version}</artifactId>
                <version>${flink.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.flink</groupId>
                <artifactId>flink-clients</artifactId>
                <version>${flink.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.flink</groupId>
                <artifactId>flink-connector-jdbc</artifactId>
                <version>${flink.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.flink</groupId>
                <artifactId>flink-connector-kafka</artifactId>
                <version>${flink.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.doris</groupId>
                <artifactId>flink-doris-connector-1.16</artifactId>
                <version>1.5.2</version>
            </dependency>
    
            <dependency>
                <groupId>com.ververica</groupId>
                <artifactId>flink-sql-connector-mysql-cdc</artifactId>
                <version>2.4.2</version>
                <exclusions>
                    <exclusion>
                        <artifactId>flink-shaded-guava</artifactId>
                        <groupId>org.apache.flink</groupId>
                    </exclusion>
                </exclusions>
            </dependency>
    
            <dependency>
                <groupId>org.apache.flink</groupId>
                <artifactId>flink-runtime-web</artifactId>
                <version>${flink.version}</version>
            </dependency>
    
        </dependencies>
  2. Core Java code.

    The following code configures the MySQL source table and the ApsaraDB for SelectDB sink table. The parameters correspond to those used in the Import data using Flink SQL section. For more information, see MySQL | Apache Flink CDC and Sink parameters.

    package org.example;
    
    import com.ververica.cdc.connectors.mysql.source.MySqlSource;
    import com.ververica.cdc.connectors.mysql.table.StartupOptions;
    import com.ververica.cdc.connectors.shaded.org.apache.kafka.connect.json.JsonConverterConfig;
    import com.ververica.cdc.debezium.JsonDebeziumDeserializationSchema;
    
    import org.apache.doris.flink.cfg.DorisExecutionOptions;
    import org.apache.doris.flink.cfg.DorisOptions;
    import org.apache.doris.flink.sink.DorisSink;
    import org.apache.doris.flink.sink.writer.serializer.JsonDebeziumSchemaSerializer;
    import org.apache.doris.flink.tools.cdc.mysql.DateToStringConverter;
    import org.apache.flink.api.common.eventtime.WatermarkStrategy;
    import org.apache.flink.streaming.api.datastream.DataStreamSource;
    import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
    
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Properties;
    
    public class Main {
        public static void main(String[] args) throws Exception {
            StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
            env.setParallelism(1);
            env.enableCheckpointing(10000);
    
            Map<String, Object> customConverterConfigs = new HashMap<>();
            customConverterConfigs.put(JsonConverterConfig.DECIMAL_FORMAT_CONFIG, "numeric");
            JsonDebeziumDeserializationSchema schema =
                    new JsonDebeziumDeserializationSchema(false, customConverterConfigs);
            
            // Configure the MySQL source table
            MySqlSource<String> mySqlSource = MySqlSource.<String>builder()
                    .hostname("rm-xxx.mysql.rds.aliyuncs***")
                    .port(3306)
                    .startupOptions(StartupOptions.initial())
                    .databaseList("db_test")
                    .tableList("db_test.employees")
                    .username("root")
                    .password("test_123")
                    .debeziumProperties(DateToStringConverter.DEFAULT_PROPS)
                    .deserializer(schema)
                    .serverTimeZone("Asia/Shanghai")
                    .build();
    
            // Configure the ApsaraDB for SelectDB sink table
            DorisSink.Builder<String> sinkBuilder = DorisSink.builder();
            DorisOptions.Builder dorisBuilder = DorisOptions.builder();
            dorisBuilder.setFenodes("selectdb-cn-xxx-public.selectdbfe.rds.aliyunc****:8080")
                    .setTableIdentifier("db_test.employees")
                    .setUsername("admin")
                    .setPassword("test_123");
            DorisOptions dorisOptions = dorisBuilder.build();
    
            // Configure Stream Load parameters with sink.properties
            Properties properties = new Properties();
            properties.setProperty("format", "json");
            properties.setProperty("read_json_by_line", "true");
            DorisExecutionOptions.Builder executionBuilder = DorisExecutionOptions.builder();
            executionBuilder.setStreamLoadProp(properties);
    
            sinkBuilder.setDorisExecutionOptions(executionBuilder.build())
                    .setSerializer(JsonDebeziumSchemaSerializer.builder().setDorisOptions(dorisOptions).build()) // Serialize the data stream.
                    .setDorisOptions(dorisOptions);
    
            DataStreamSource<String> dataStreamSource = env.fromSource(mySqlSource, WatermarkStrategy.noWatermarks(), "MySQL Source");
            dataStreamSource.sinkTo(sinkBuilder.build());
            env.execute("MySQL to SelectDB");
        }
    }

Advanced usage

Update partial columns with Flink SQL

-- enable checkpoint
SET 'execution.checkpointing.interval' = '10s';

CREATE TABLE cdc_mysql_source (
   id INT
  ,name STRING
  ,bank STRING
  ,age INT
  ,PRIMARY KEY (id) NOT ENFORCED
) WITH (
 'connector' = 'mysql-cdc',
 'hostname' = '127.0.0.1',
 'port' = '3306',
 'username' = 'root',
 'password' = 'password',
 'database-name' = 'database',
 'table-name' = 'table'
);

CREATE TABLE selectdb_sink (
    id INT,
    name STRING,
    bank STRING,
    age INT
) 
WITH (
  'connector' = 'doris',
  'fenodes' = 'selectdb-cn-****.selectdbfe.rds.aliyuncs.com:8080',
  'table.identifier' = 'database.table',
  'username' = 'admin',
  'password' = '****',
  'sink.properties.format' = 'json',
  'sink.properties.read_json_by_line' = 'true',
  'sink.properties.columns' = 'id,name,bank,age',
  'sink.properties.partial_columns' = 'true' -- Enable partial column updates.
);


INSERT INTO selectdb_sink SELECT id,name,bank,age FROM cdc_mysql_source;

Use Flink SQL to delete data by column

In CDC scenarios, the Doris sink identifies the event type from RowKind and assigns a value to the hidden column __DORIS_DELETE_SIGN__ to perform deletions. When the data source is Kafka messages, the sink cannot use RowKind to determine the operation type. Instead, it must rely on a specific field within the message, such as {"op_type":"delete",data:{...}}. To delete data where op_type is 'delete', you must explicitly pass a value to the hidden column based on your business logic. The following Flink SQL example shows how to delete data in Alibaba Cloud SelectDB based on a specific field in Kafka data.

-- Example message: {"op_type":"delete",data:{"id":1,"name":"zhangsan"}}
CREATE TABLE KAFKA_SOURCE(
  data STRING,
  op_type STRING
) WITH (
  'connector' = 'kafka',
  ...
);

CREATE TABLE SELECTDB_SINK(
  id INT,
  name STRING,
  __DORIS_DELETE_SIGN__ INT
) WITH (
  'connector' = 'doris',
  'fenodes' = 'selectdb-cn-****.selectdbfe.rds.aliyuncs.com:8080',
  'table.identifier' = 'db.table',
  'username' = 'admin',
  'password' = '****',
  'sink.enable-delete' = 'false',        -- A value of false indicates that the event type is not inferred from RowKind.
  'sink.properties.columns' = 'id, name, __DORIS_DELETE_SIGN__'  -- Explicitly specify the columns for the Stream Load import.
);

INSERT INTO SELECTDB_SINK
SELECT json_value(data,'$.id') as id,
json_value(data,'$.name') as name, 
if(op_type='delete',1,0) as __DORIS_DELETE_SIGN__ 
FROM KAFKA_SOURCE;

FAQ

  • Q: How do I write BITMAP data?

    A: See the example below:

    CREATE TABLE bitmap_sink (
      dt INT,
      page STRING,
      user_id INT 
    )
    WITH ( 
      'connector' = 'doris', 
      'fenodes' = 'selectdb-cn-****.selectdbfe.rds.aliyuncs.com:8080',
      'table.identifier' = 'test.bitmap_test', 
      'username' = 'admin', 
      'password' = '****', 
      'sink.label-prefix' = 'selectdb_label', 
      'sink.properties.columns' = 'dt,page,user_id,user_id=to_bitmap(user_id)'
    );
  • Q: How can I resolve the error errCode = 2, detailMessage = Label[label_0_1]has already been used, relate to txn[19650]?

    A: In an exactly-once scenario, a Flink job must be restarted from the latest checkpoint or savepoint. This error occurs if you restart the job from an older state. If exactly-once semantics are not required, you can disable two-phase commit (2PC) by setting sink.enable-2pc=false or use a different sink.label-prefix.

  • Q: How can I resolve the error errCode = 2, detailMessage = transaction[19650]not found?

    A: This error occurs during the commit phase. It indicates that the transaction ID recorded in the checkpoint has expired in ApsaraDB for SelectDB. When the connector tries to commit this expired transaction, the server reports that the transaction cannot be found. In this case, you cannot restart the job from the checkpoint. To prevent this issue, increase the streaming_label_keep_max_second parameter in ApsaraDB for SelectDB. The default value is 12 hours.

  • Q: How can I resolve the error errCode = 2, detailMessage = current running txns on db 10006 is 100, larger than limit 100?

    A: This error indicates that the number of concurrent import transactions for a single database has exceeded the system limit of 100. To resolve this, increase the max_running_txn_num_per_db parameter in ApsaraDB for SelectDB. For more information, see max_running_txn_num_per_db.

    This error can also occur if you frequently change the label and restart the job. In two-phase commit (2PC) scenarios (applicable to Duplicate Key and Aggregate Key models), each job requires a unique label. When a job restarts from a checkpoint, Flink aborts only the transactions that were precommitted but not yet committed. If you frequently change the label before restarting, many precommitted transactions are not aborted and continue to consume the transaction quota. For the Unique Key model, you can disable 2PC and design the sink operator for idempotent writes.

  • Q: How can I ensure data ordering within a batch when writing to a table that uses the Unique Key model?

    A: Add a sequence column configuration to ensure data ordering. For more information, see SEQUENCE.

  • Q: Why is no data being synchronized even though the Flink job reports no errors?

    A: This behavior depends on the connector version. In versions earlier than 1.1.0, writes are batched and data-driven, so you must verify that the upstream source is producing data. In version 1.1.0 and later, writes are triggered by checkpoints, which you must enable to write data.

  • Q: How can I resolve the error tablet writer write failed, tablet_id=190958, txn_id=3505530, err=-235?

    A: This error typically occurs in connector versions earlier than 1.1.0. This error is caused by an excessively high write frequency, which creates too many versions on the tablet. To resolve this issue, increase the sink.buffer-flush.max-bytes and sink.buffer-flush.interval parameters to reduce the Stream Load frequency.

  • Q: How can I skip dirty data during a Flink import?

    A: If the source data contains records that do not match the destination table's schema (for example, incorrect data type or length), the Stream Load job fails, and Flink continuously retries. To skip this dirty data, you can either disable the Stream Load strict mode by setting strict_mode=false,max_filter_ratio=1, or add a transformation step to filter out the invalid data before it reaches the sink operator.

  • Q: How should the source table map to the ApsaraDB for SelectDB table?

    A: When you import data using the Flink Doris Connector, ensure the following mappings are correct: (1) The columns and types in the source table must match those in Flink SQL. (2) The columns and types in Flink SQL must match those in the ApsaraDB for SelectDB table.

  • Q: How can I resolve the error TApplicationException: get_next failed: out of sequence response: expected 4 but got 3?

    A: This error indicates a concurrency bug within the underlying Thrift framework. To resolve this, upgrade to the latest version of the Flink Doris Connector and use a compatible Flink version.

  • Q: How can I resolve the error DorisRuntimeException: Fail to abort transaction 26153 with urlhttp://192.168.XX.XX?

    A: To diagnose this issue, search the TaskManager logs for the phrase abort transaction response. The HTTP status code in the log entry indicates whether the issue originates from the client or the server.