Flink CDC 用 OceanBase CDC 实时同步数据到 Elasticsearch

一、整体架构与 Demo 思路

本 Demo 里会启动 4 个容器:

  • observer:OceanBase CE 单机 mini 集群;
  • oblogproxy:OceanBase 日志代理,用于提供日志流;
  • elasticsearch:7.6.0 版本,用来存储 Flink 下游数据;
  • kibana:可视化 Elasticsearch 的数据。

然后步骤大致是:

  1. 用 Docker Compose 一键拉起环境;
  2. 在 OceanBase 里建库建表,插入一点订单 / 商品示例数据;
  3. 启动 Flink 集群,引入 OceanBase CDC + Elasticsearch 连接器;
  4. 用 Flink SQL 建立 OceanBase 源表、ES 结果表,并做一次 订单表 + 商品表的实时 Join
  5. 在 Kibana 里创建 index pattern,查看实时同步的数据;
  6. 在 OceanBase 里再做几条 INSERT / UPDATE / DELETE,观察 Kibana 中的实时变化;
  7. 清理环境。

二、用 Docker Compose 启动 OceanBase + ES + Kibana

先在一个空目录下创建 docker-compose.yml

yaml 复制代码
version: '2.1'
services:
  observer:
    image: 'oceanbase/oceanbase-ce:4.2.1.6-106000012024042515'
    container_name: observer
    environment:
      - 'MODE=mini'
      - 'OB_SYS_PASSWORD=123456'
      - 'OB_TENANT_PASSWORD=654321'
    ports:
      - '2881:2881'
      - '2882:2882'

  oblogproxy:
    image: 'oceanbase/oblogproxy-ce:latest'
    container_name: oblogproxy
    environment:
      - 'OB_SYS_USERNAME=root'
      - 'OB_SYS_PASSWORD=123456'
    ports:
      - '2983:2983'

  elasticsearch:
    image: 'elastic/elasticsearch:7.6.0'
    container_name: elasticsearch
    environment:
      - cluster.name=docker-cluster
      - bootstrap.memory_lock=true
      - ES_JAVA_OPTS=-Xms512m -Xmx512m
      - discovery.type=single-node
    ports:
      - '9200:9200'
      - '9300:9300'
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65536
        hard: 65536

  kibana:
    image: 'elastic/kibana:7.6.0'
    container_name: kibana
    ports:
      - '5601:5601'
    volumes:
      - '/var/run/docker.sock:/var/run/docker.sock'

启动:

bash 复制代码
docker-compose up -d

检查:

bash 复制代码
docker ps

浏览器打开:http://localhost:5601,看到 Kibana 正常启动即可(首次加载会稍微慢一点)。

三、在 OceanBase 里准备业务数据

1. 查询 Root Service List

OceanBase CDC 这条链路里,需要用到 rootserver-list 参数,它来自 Root Service 列表。

sys 租户登录:

bash 复制代码
docker-compose exec observer \
  obclient -h127.0.0.1 -P2881 -uroot@sys -p123456

查询 RootService 列表(记下结果,后面要填进 Flink DDL):

sql 复制代码
SHOW PARAMETERS LIKE 'rootservice_list';

假设返回类似:

text 复制代码
xxx.xxx.xxx.xxx:2881;yyy.yyy.yyy.yyy:2881

后面我们就在 Flink SQL 里用这个字符串替换 ${root_service_list}

2. 在 test 租户下建库建表并插入数据

切到 test 租户(默认已经创建好了):

bash 复制代码
docker-compose exec observer \
  obclient -h127.0.0.1 -P2881 -uroot@test -p654321

建库 ob 并建两张表:productsorders

sql 复制代码
CREATE DATABASE ob;
USE ob;

CREATE TABLE products (
  id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(255) NOT NULL,
  description VARCHAR(512)
);
ALTER TABLE products AUTO_INCREMENT = 101;

INSERT INTO products
VALUES (default,"scooter","Small 2-wheel scooter"),
       (default,"car battery","12V car battery"),
       (default,"12-pack drill bits","12-pack of drill bits with sizes ranging from #40 to #3"),
       (default,"hammer","12oz carpenter's hammer"),
       (default,"hammer","14oz carpenter's hammer"),
       (default,"hammer","16oz carpenter's hammer"),
       (default,"rocks","box of assorted rocks"),
       (default,"jacket","water resistent black wind breaker"),
       (default,"spare tire","24 inch spare tire");

CREATE TABLE orders (
  order_id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
  order_date DATETIME NOT NULL,
  customer_name VARCHAR(255) NOT NULL,
  price DECIMAL(10, 5) NOT NULL,
  product_id INTEGER NOT NULL,
  order_status BOOLEAN NOT NULL -- Whether order has been placed
) AUTO_INCREMENT = 10001;

INSERT INTO orders
VALUES (default, '2020-07-30 10:08:22', 'Jark', 50.50, 102, false),
       (default, '2020-07-30 10:11:09', 'Sally', 15.00, 105, false),
       (default, '2020-07-30 12:00:30', 'Edward', 25.25, 106, false);

到这里,源库数据就准备好了。

在你的 Flink 集群节点上,把以下两个 JAR 放进 <FLINK_HOME>/lib

  • flink-sql-connector-elasticsearch7-3.0.1-1.17.jar
  • flink-sql-connector-oceanbase-cdc-3.0-SNAPSHOT.jar

然后启动 Flink:

bash 复制代码
cd $FLINK_HOME
./bin/start-cluster.sh

再打开 Flink SQL CLI:

bash 复制代码
./bin/sql-client.sh

1. 基本配置

在 SQL CLI 里先打开 checkpoint、设置时区:

sql 复制代码
-- 每 3 秒 checkpoint 一次
SET execution.checkpointing.interval = 3s;

-- 本地时区设为上海
SET table.local-time-zone = Asia/Shanghai;

2. 定义 OceanBase CDC 源表(orders)

注意:rootserver-list 要用前面 SHOW PARAMETERS 查到的值替换 ${root_service_list}

sql 复制代码
CREATE TABLE orders (
   order_id INT,
   order_date TIMESTAMP(0),
   customer_name STRING,
   price DECIMAL(10, 5),
   product_id INT,
   order_status BOOLEAN,
   PRIMARY KEY (order_id) NOT ENFORCED
) WITH (
    'connector' = 'oceanbase-cdc',
    'scan.startup.mode' = 'initial',
    'username' = 'root@test',
    'password' = '654321',
    'tenant-name' = 'test',
    'database-name' = '^ob$',
    'table-name' = '^orders$',
    'hostname' = 'localhost',
    'port' = '2881',
    'rootserver-list' = '${root_service_list}', -- 这里替换成真实值
    'logproxy.host' = 'localhost',
    'logproxy.port' = '2983',
    'working-mode' = 'memory'
);

几个关键点:

  • scan.startup.mode = 'initial':先跑一遍快照,再接增量日志;
  • database-name / table-name 用的是正则匹配(这里正则是严格等于 ob / orders);
  • rootserver-list:OceanBase 集群 RootService 列表,决定从哪儿拿元信息;
  • logproxy.host/port:指向我们 docker-compose 里的 oblogproxy 服务。

3. 定义 OceanBase CDC 源表(products)

同理,再建一个产品表:

sql 复制代码
CREATE TABLE products (
    id INT,
    name STRING,
    description STRING,
    PRIMARY KEY (id) NOT ENFORCED
) WITH (
    'connector' = 'oceanbase-cdc',
    'scan.startup.mode' = 'initial',
    'username' = 'root@test',
    'password' = '654321',
    'tenant-name' = 'test',
    'database-name' = '^ob$',
    'table-name' = '^products$',
    'hostname' = 'localhost',
    'port' = '2881',
    'rootserver-list' = '${root_service_list}',
    'logproxy.host' = 'localhost',
    'logproxy.port' = '2983',
    'working-mode' = 'memory'
);

4. 定义 Elasticsearch 结果表 enriched_orders

我们希望在 ES 里看到一张"宽表":订单 + 商品信息一起平铺开。

sql 复制代码
CREATE TABLE enriched_orders (
   order_id INT,
   order_date TIMESTAMP(0),
   customer_name STRING,
   price DECIMAL(10, 5),
   product_id INT,
   order_status BOOLEAN,
   product_name STRING,
   product_description STRING,
   PRIMARY KEY (order_id) NOT ENFORCED
) WITH (
     'connector' = 'elasticsearch-7',
     'hosts' = 'http://localhost:9200',
     'index' = 'enriched_orders'
);

5. 启动实时 Join 任务

最后,一条 INSERT INTO 就把整个链路串起来了:

sql 复制代码
INSERT INTO enriched_orders
  SELECT o.order_id,
         o.order_date,
         o.customer_name,
         o.price,
         o.product_id,
         o.order_status,
         p.name,
         p.description
  FROM orders AS o
  LEFT JOIN products AS p
    ON o.product_id = p.id;
  • Flink 从 OceanBase orders / products 表读取快照;
  • 按 order.product_id = product.id 做流式 Join;
  • 把结果写入 Elasticsearch 的 enriched_orders 索引;
  • 后续任何变更都会一路传播到 ES。

六、在 Kibana 里查看 enriched_orders 数据

打开 Kibana:

  1. 访问:
    http://localhost:5601/app/kibana#/management/kibana/index_pattern
  2. 创建一个 index pattern:enriched_orders
  3. 然后打开:
    http://localhost:5601/app/kibana#/discover
    选择刚创建的 index pattern,就能看到同步过来的订单数据了(包含 product_name / product_description)。

七、在 OceanBase 中修改数据,观察 ES 实时变化

现在我们来验证"实时"两个字。

仍然在 root@testob 库下执行:

sql 复制代码
-- 1)插入一条新订单
INSERT INTO orders
VALUES (default, '2020-07-30 15:22:00', 'Jark', 29.71, 104, false);

-- 2)更新订单状态
UPDATE orders
SET order_status = true
WHERE order_id = 10004;

-- 3)删除订单
DELETE FROM orders
WHERE order_id = 10004;

每执行完一条 SQL:

  • Flink OceanBase CDC 会从日志中捕获这次变更;

  • Join 逻辑会按新的数据重新计算 enriched_orders 中对应记录;

  • Elasticsearch 索引会被更新;

  • Kibana 页面刷新一下,你就能看到:

    • INSERT:多了一行新的 order;
    • UPDATE:这一行的 order_status 变为 true
    • DELETE:这一行从索引中消失。

这就是典型的 数据库 → CDC → 实时宽表 → 搜索引擎 的闭环。

八、清理环境

Demo 玩完记得收尾。

关闭 Docker 中的组件:

bash 复制代码
docker-compose down

停止 Flink 集群:

bash 复制代码
cd $FLINK_HOME
./bin/stop-cluster.sh

九、小结与扩展方向

这个 Demo 帮你打通了一条完整的链路:

OceanBase(test 租户 ob 库)

→ oblogproxy 提供日志流

→ Flink OceanBase CDC Connector 捕获变更

→ Flink SQL 实时 Join + 写 Elasticsearch

→ Kibana 可视化实时数据

接下来你可以做的扩展包括:

  • 把 Demo 用到的 orders / products 换成你的业务表;
  • 在 Flink SQL 里加上更多字段清洗、过滤、聚合逻辑,做一张真正的"实时宽表";
  • 将 Elasticsearch 换成 Doris / StarRocks / Kafka 等下游组件;
  • 把 Mini 模式的 OceanBase 换成生产集群,把 logproxy + Flink 部署到 K8s 环境里。
相关推荐
小高学习java6 小时前
Canal、Elasticsearch、RabbitMq构建高可用、高性能的异构数据同步方案(亲测可用!!!!)
大数据·elasticsearch·rabbitmq·java-rabbitmq
2501_941144037 小时前
边缘计算重塑数字世界:智能化时代的新型技术架构
elasticsearch
一只会写代码的猫7 小时前
云计算与边缘计算的融合:推动数字化转型的核心力量
flink
Hello.Reader7 小时前
Flink CDC 用 Db2 CDC 实时同步数据到 Elasticsearch
大数据·elasticsearch·flink
Apache Flink20 小时前
Flink Forward Asia 2025 城市巡回 · 深圳站
大数据·flink
Hello.Reader20 小时前
Flink DataStream API 打包使用 MySQL CDC 连接器
大数据·mysql·flink
2021_fc20 小时前
Flink入门指南:使用Java构建第一个Flink应用
java·大数据·flink
Hello.Reader20 小时前
Streaming ELT with Flink CDC · Iceberg Sink
大数据·flink
2021_fc20 小时前
Flink快速入门--安装与示例运行
大数据·flink