一、整体架构与 Demo 思路
本 Demo 里会启动 4 个容器:
- observer:OceanBase CE 单机 mini 集群;
- oblogproxy:OceanBase 日志代理,用于提供日志流;
- elasticsearch:7.6.0 版本,用来存储 Flink 下游数据;
- kibana:可视化 Elasticsearch 的数据。
然后步骤大致是:
- 用 Docker Compose 一键拉起环境;
- 在 OceanBase 里建库建表,插入一点订单 / 商品示例数据;
- 启动 Flink 集群,引入 OceanBase CDC + Elasticsearch 连接器;
- 用 Flink SQL 建立 OceanBase 源表、ES 结果表,并做一次 订单表 + 商品表的实时 Join;
- 在 Kibana 里创建 index pattern,查看实时同步的数据;
- 在 OceanBase 里再做几条 INSERT / UPDATE / DELETE,观察 Kibana 中的实时变化;
- 清理环境。
二、用 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 并建两张表:products 和 orders:
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 集群节点上,把以下两个 JAR 放进 <FLINK_HOME>/lib:
flink-sql-connector-elasticsearch7-3.0.1-1.17.jarflink-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
五、用 Flink SQL 打通 OceanBase → Elasticsearch
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:
- 访问:
http://localhost:5601/app/kibana#/management/kibana/index_pattern - 创建一个 index pattern:
enriched_orders; - 然后打开:
http://localhost:5601/app/kibana#/discover
选择刚创建的 index pattern,就能看到同步过来的订单数据了(包含 product_name / product_description)。
七、在 OceanBase 中修改数据,观察 ES 实时变化
现在我们来验证"实时"两个字。
仍然在 root@test 的 ob 库下执行:
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 环境里。