一、整体架构与 Demo 思路
本 Demo 会启动 3 个容器:
- Oracle 19c:作为上游业务库;
- Elasticsearch 7.6.0:存储 Flink 处理后的结果;
- Kibana 7.6.0:可视化 Elasticsearch 数据。
数据流非常简单直观:
Oracle PRODUCTS & ORDERS → Flink Oracle CDC → Flink SQL 中做 Join → 写入 ES 索引
enriched_orders_1→ Kibana 展示。
二、用 Docker Compose 一键拉起 Oracle + ES + Kibana
先在一个目录中创建 docker-compose.yml:
yaml
version: '2.1'
services:
oracle:
image: goodboy008/oracle-19.3.0-ee:non-cdb
ports:
- "1521:1521"
elasticsearch:
image: elastic/elasticsearch:7.6.0
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
ports:
- "5601:5601"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
启动所有容器:
bash
docker-compose up -d
验证一下:
bash
docker ps
浏览器访问:http://localhost:5601,能打开 Kibana 就说明 ES + Kibana 正常。
实验结束后记得:
bash
docker-compose down
三、准备 Flink 所需的 Connector JAR
在 Flink 集群所在机器,将以下 JAR 拷贝到 <FLINK_HOME>/lib/ 目录:
flink-sql-connector-elasticsearch7-3.0.1-1.17.jarflink-sql-connector-oracle-cdc-3.0-SNAPSHOT.jar
注意:3.0-SNAPSHOT 版本通常需要你从对应分支自己构建,只有稳定版本才会提供直接下载链接。
然后启动 Flink 集群(Standalone 示例):
bash
cd $FLINK_HOME
./bin/start-cluster.sh
打开 Flink SQL CLI:
bash
./bin/sql-client.sh
四、在 Oracle 中准备源表和测试数据
1. 连接到 Oracle 容器
使用预置的用户登录(文档示例是 debezium/dbz):
bash
docker-compose exec oracle \
sqlplus debezium/dbz@localhost:1521/ORCLCDB
注意:Flink DDL 里用的是
username = 'dbzuser',如果你数据库中实际用户是debezium,记得把 Flink 里的username配置改成debezium,保持一致。
2. 创建 PRODUCTS 表
先删后建,保证环境干净可重复:
sql
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE DEBEZIUM.PRODUCTS';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN
RAISE;
END IF;
END;
/
CREATE TABLE DEBEZIUM.PRODUCTS (
ID NUMBER(9, 0) NOT NULL,
NAME VARCHAR2(255) NOT NULL,
DESCRIPTION VARCHAR2(512),
WEIGHT FLOAT,
PRIMARY KEY(ID)
);
3. 创建 ORDERS 表
同样方式:
sql
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE DEBEZIUM.ORDERS';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN
RAISE;
END IF;
END;
/
CREATE TABLE DEBEZIUM.ORDERS (
ID NUMBER(9, 0) NOT NULL,
ORDER_DATE TIMESTAMP(3) NOT NULL,
PURCHASER VARCHAR2(255) NOT NULL,
QUANTITY NUMBER(9, 0) NOT NULL,
PRODUCT_ID NUMBER(9, 0) NOT NULL,
PRIMARY KEY(ID)
);
4. 为 CDC 开启补充日志(SUPPLEMENTAL LOG)
Oracle CDC 要依赖 Redo Log + Supplemental Log,否则变更记录里没有足够的信息。这里我们给表级别加上补充日志:
sql
ALTER TABLE DEBEZIUM.PRODUCTS ADD SUPPLEMENTAL LOG DATA (ALL) COLUMNS;
ALTER TABLE DEBEZIUM.ORDERS ADD SUPPLEMENTAL LOG DATA (ALL) COLUMNS;
实际生产环境通常还会开启 database 级别的 supplemental logging,这里 Demo 只展示表级配置。
5. 插入测试数据
插入一些商品和订单数据做演示:
sql
INSERT INTO DEBEZIUM.PRODUCTS VALUES (101, 'scooter', 'Small 2-wheel scooter', 3.14);
INSERT INTO DEBEZIUM.PRODUCTS VALUES (102, 'car battery', '12V car battery', 8.1);
INSERT INTO DEBEZIUM.PRODUCTS VALUES (103, '12-pack drill bits', '12-pack of drill bits with sizes ranging from #40 to #3', 0.8);
INSERT INTO DEBEZIUM.PRODUCTS VALUES (104, 'hammer', '12oz carpenter''s hammer', 0.75);
INSERT INTO DEBEZIUM.PRODUCTS VALUES (105, 'hammer', '14oz carpenter''s hammer', 0.875);
INSERT INTO DEBEZIUM.PRODUCTS VALUES (106, 'hammer', '16oz carpenter''s hammer', 1.0);
INSERT INTO DEBEZIUM.PRODUCTS VALUES (107, 'rocks', 'box of assorted rocks', 5.3);
INSERT INTO DEBEZIUM.PRODUCTS VALUES (108, 'jacket', 'water resistent black wind breaker', 0.1);
INSERT INTO DEBEZIUM.PRODUCTS VALUES (109, 'spare tire', '24 inch spare tire', 22.2);
INSERT INTO DEBEZIUM.ORDERS VALUES (1001, TO_TIMESTAMP('2020-07-30 10:08:22.001000', 'YYYY-MM-DD HH24:MI:SS.FF'), 'Jark', 1, 101);
INSERT INTO DEBEZIUM.ORDERS VALUES (1002, TO_TIMESTAMP('2020-07-30 10:11:09.001000', 'YYYY-MM-DD HH24:MI:SS.FF'), 'Sally', 2, 102);
INSERT INTO DEBEZIUM.ORDERS VALUES (1003, TO_TIMESTAMP('2020-07-30 12:00:30.001000', 'YYYY-MM-DD HH24:MI:SS.FF'), 'Edward', 2, 103);
INSERT INTO DEBEZIUM.ORDERS VALUES (1004, TO_TIMESTAMP('2020-07-30 15:22:00.001000', 'YYYY-MM-DD HH24:MI:SS.FF'), 'Jark', 1, 104);
至此,Oracle 侧准备完毕:一个商品表 + 一个订单表,后续会用 Flink CDC 将其 Join 后写入 ES。
五、在 Flink SQL 中配置 Oracle CDC 与 Elasticsearch Sink
回到 Flink SQL CLI,先打开 checkpoint(CDC 必备):
sql
-- 每 3 秒做一次 checkpoint
SET execution.checkpointing.interval = 3s;
1. 定义 Oracle CDC 源表:products
sql
CREATE TABLE products (
ID INT,
NAME STRING,
DESCRIPTION STRING,
PRIMARY KEY (ID) NOT ENFORCED
) WITH (
'connector' = 'oracle-cdc',
'hostname' = 'localhost',
'port' = '1521',
'username' = 'dbzuser',
'password' = 'dbz',
'database-name' = 'ORCLCDB',
'schema-name' = 'DEBEZIUM',
'table-name' = 'products'
);
参数说明要点:
connector = 'oracle-cdc':使用 Oracle CDC 源连接器;database-name = 'ORCLCDB':CDB 名;schema-name = 'DEBEZIUM':模式名;table-name = 'products':表名,不区分大小写(实际映射到DEBEZIUM.PRODUCTS);username/password:CDC 用户(Demo 中是 dbzuser/dbz,若你实际用 debezium/dbz,要同步修改)。
2. 定义 Oracle CDC 源表:orders
sql
CREATE TABLE orders (
ID INT,
ORDER_DATE TIMESTAMP(3),
PURCHASER STRING,
QUANTITY INT,
PRODUCT_ID INT,
ORDER_STATUS BOOLEAN
) WITH (
'connector' = 'oracle-cdc',
'hostname' = 'localhost',
'port' = '1521',
'username' = 'dbzuser',
'password' = 'dbz',
'database-name' = 'ORCLCDB',
'schema-name' = 'DEBEZIUM',
'table-name' = 'orders'
);
这里多了个 ORDER_STATUS 字段,Demo 里先空着不写入 Oracle,主要是为了展示 Flink 侧 schema 可以比源库宽一些(也可以不定义)。
3. 定义 Elasticsearch 结果表:enriched_orders
我们要在 ES 里存一张"订单 + 商品信息"的宽表:
sql
CREATE TABLE enriched_orders (
ORDER_ID INT,
ORDER_DATE TIMESTAMP(3),
PURCHASER STRING,
QUANTITY INT,
PRODUCT_NAME STRING,
PRODUCT_DESCRIPTION STRING,
PRIMARY KEY (ORDER_ID) NOT ENFORCED
) WITH (
'connector' = 'elasticsearch-7',
'hosts' = 'http://localhost:9200',
'index' = 'enriched_orders_1'
);
这会在 ES 里创建/使用索引 enriched_orders_1,主键字段为 ORDER_ID(用于 upsert)。
4. 启动实时 Join 任务:Oracle → ES
核心 SQL 就一条 INSERT ... SELECT:
sql
INSERT INTO enriched_orders
SELECT
o.ID AS ORDER_ID,
o.ORDER_DATE,
o.PURCHASER,
o.QUANTITY,
p.NAME AS PRODUCT_NAME,
p.DESCRIPTION AS PRODUCT_DESCRIPTION
FROM orders AS o
LEFT JOIN products AS p
ON o.PRODUCT_ID = p.ID;
任务一旦提交,Flink 会做几件事:
- 读取
PRODUCTS与ORDERS的表快照; - 持续订阅 redo 日志,捕获后续 INSERT/UPDATE/DELETE;
- 在流上按
PRODUCT_ID = ID做实时 Join; - 将 Join 后的结果 Upsert 到 Elasticsearch 索引
enriched_orders_1中。
六、在 Kibana 中查看同步结果
打开 Kibana:
-
访问:
http://localhost:5601/app/kibana#/management/kibana/index_pattern -
创建一个 index pattern:
enriched_orders_1; -
然后到:
http://localhost:5601/app/kibana#/discover选择刚才的 index pattern,即可看到:
ORDER_ID / ORDER_DATE / PURCHASER / QUANTITY- 以及 Join 后补充的
PRODUCT_NAME / PRODUCT_DESCRIPTION。
如果你更习惯 curl,也可以:
bash
curl -X GET "localhost:9200/enriched_orders_1/_search?pretty"
七、在 Oracle 中修改数据,观察 Elasticsearch 实时变化
现在来验证 CDC 是否生效。
重新进入 Oracle 容器(这次直接用 Debezium 用户即可):
bash
docker-compose exec oracle \
sqlplus debezium/dbz@localhost:1521/ORCLCDB
依次执行几条 DML:
sql
-- 1)插入一条新订单
INSERT INTO DEBEZIUM.ORDERS
VALUES (
1005,
TO_TIMESTAMP('2020-07-30 15:22:00.001000', 'YYYY-MM-DD HH24:MI:SS.FF'),
'Jark',
5,
105
);
-- 2)修改一条订单数量
UPDATE DEBEZIUM.ORDERS
SET QUANTITY = 10
WHERE ID = 1002;
-- 3)删除一条订单
DELETE FROM DEBEZIUM.ORDERS
WHERE ID = 1004;
每执行完一条语句:
-
Oracle 会产生 redo 日志;
-
Flink Oracle CDC Connector 通过 LogMiner/XStream(取决于模式)捕获到这些变更;
-
实时 Join 逻辑重新计算对应订单的宽表数据;
-
ES 索引
enriched_orders_1中的文档被插入 / 更新 / 删除; -
Kibana Discover 刷新页面即可看到:
- 新增:多了一条
ORDER_ID = 1005的记录,商品名称来自 Products 表中 ID=105; - 更新:
ORDER_ID = 1002的QUANTITY字段变为 10; - 删除:
ORDER_ID = 1004的文档从索引中消失(或被标记删除,视 connector 模式而定)。
- 新增:多了一条
这就是典型的 Oracle → Flink CDC → 实时宽表 → Elasticsearch 实战闭环。
八、清理环境
实验完成后记得清理资源。
关闭 Docker 中的 Oracle / ES / Kibana:
bash
docker-compose down
停止 Flink 集群:
bash
cd $FLINK_HOME
./bin/stop-cluster.sh
九、小结与扩展思路
通过这个 Demo,我们搭建并验证了一条简单但完整的链路:
Oracle(CDB = ORCLCDB,schema = DEBEZIUM)
→ Flink Oracle CDC Connector 捕获 PRODUCTS/ORDERS 的快照与变更
→ Flink SQL 中做实时 Join,构建"订单 + 商品信息"宽表
→ Elasticsearch enriched_orders_1 索引
→ Kibana 实时查询与展示