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

一、整体架构与 Demo 思路

本 Demo 中我们会用 Docker 启动 3 个容器:

  • SqlServer 2019 :存放源表 productsorders
  • Elasticsearch 7.6.0:作为 Flink CDC 的 sink;
  • Kibana 7.6.0:用来查看 ES 中的数据。

数据流向非常简单:

SqlServer → Flink SqlServer CDC → Flink SQL 中 Join → Elasticsearch 索引 enriched_orders_1 → Kibana 实时查看

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

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

yaml 复制代码
version: '2.1'
services:
   sqlserver:
     image: mcr.microsoft.com/mssql/server:2019-latest
     container_name: sqlserver
     ports:
       - "1433:1433"
     environment:
       - "MSSQL_AGENT_ENABLED=true"
       - "MSSQL_PID=Standard"
       - "ACCEPT_EULA=Y"
       - "SA_PASSWORD=Password!"
   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 正常启动,就说明 ES + Kibana 环境 OK。

实验结束后记得用:

bash 复制代码
docker-compose down

来关闭并移除所有容器。

在 Flink 集群所在机器,将以下两个 JAR 复制到 <FLINK_HOME>/lib

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

注意:3.0-SNAPSHOT 一般需要从对应分支源码自行构建,稳定版本才有直接下载地址。

接着启动 Flink 集群(以 Standalone 为例):

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

浏览器打开 Flink UI:http://localhost:8081,看到界面说明集群正常。

启动 Flink SQL CLI:

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

四、在 SqlServer 中准备业务表和 CDC 配置

连接 SqlServer 容器,你可以用本机的 SQL Server 客户端(例如 SQL Server Management Studio / sqlcmd)直接连:

  • hostname = localhost
  • port = 1433
  • user = sa
  • password = Password!

下面的 SQL 在 SqlServer 中执行即可。

1. 创建数据库并开启 CDC

sql 复制代码
-- 创建数据库
CREATE DATABASE inventory;
GO

-- 切库
USE inventory;
GO

-- 在数据库级开启 CDC
EXEC sys.sp_cdc_enable_db;
GO

2. 创建并初始化 products 表

sql 复制代码
-- 创建产品表
CREATE TABLE products (
  id INTEGER IDENTITY(101,1) NOT NULL PRIMARY KEY,
  name VARCHAR(255) NOT NULL,
  description VARCHAR(512),
  weight FLOAT
);

-- 插入测试数据
INSERT INTO products(name,description,weight)
VALUES ('scooter','Small 2-wheel scooter',3.14);
INSERT INTO products(name,description,weight)
VALUES ('car battery','12V car battery',8.1);
INSERT INTO products(name,description,weight)
VALUES ('12-pack drill bits','12-pack of drill bits with sizes ranging from #40 to #3',0.8);
INSERT INTO products(name,description,weight)
VALUES ('hammer','12oz carpenter''s hammer',0.75);
INSERT INTO products(name,description,weight)
VALUES ('hammer','14oz carpenter''s hammer',0.875);
INSERT INTO products(name,description,weight)
VALUES ('hammer','16oz carpenter''s hammer',1.0);
INSERT INTO products(name,description,weight)
VALUES ('rocks','box of assorted rocks',5.3);
INSERT INTO products(name,description,weight)
VALUES ('jacket','water resistent black wind breaker',0.1);
INSERT INTO products(name,description,weight)
VALUES ('spare tire','24 inch spare tire',22.2);

-- 为 products 表开启 CDC
EXEC sys.sp_cdc_enable_table
  @source_schema = 'dbo',
  @source_name   = 'products',
  @role_name     = NULL,
  @supports_net_changes = 0;
GO

3. 创建并初始化 orders 表

sql 复制代码
-- 创建订单表
CREATE TABLE orders (
  id INTEGER IDENTITY(10001,1) NOT NULL PRIMARY KEY,
  order_date DATE NOT NULL,
  purchaser INTEGER NOT NULL,
  quantity INTEGER NOT NULL,
  product_id INTEGER NOT NULL,
  FOREIGN KEY (product_id) REFERENCES products(id)
);

-- 插入订单数据
INSERT INTO orders(order_date,purchaser,quantity,product_id)
VALUES ('16-JAN-2016', 1001, 1, 102);
INSERT INTO orders(order_date,purchaser,quantity,product_id)
VALUES ('17-JAN-2016', 1002, 2, 105);
INSERT INTO orders(order_date,purchaser,quantity,product_id)
VALUES ('19-FEB-2016', 1002, 2, 106);
INSERT INTO orders(order_date,purchaser,quantity,product_id)
VALUES ('21-FEB-2016', 1003, 1, 107);

-- 为 orders 表开启 CDC
EXEC sys.sp_cdc_enable_table
  @source_schema = 'dbo',
  @source_name   = 'orders',
  @role_name     = NULL,
  @supports_net_changes = 0;
GO

到这里,SqlServer 侧准备好了:

  • 一个 inventory 库;
  • 两张表:dbo.productsdbo.orders
  • 在数据库和表级都开启了 CDC,Flink 就可以读取变更日志了。

回到 Flink SQL CLI。

1. 开启 checkpoint

sql 复制代码
-- Flink SQL
SET execution.checkpointing.interval = 3s;

2. 创建 SqlServer CDC 源表:products

sql 复制代码
CREATE TABLE products (
    id INT,
    name STRING,
    description STRING,
    PRIMARY KEY (id) NOT ENFORCED
) WITH (
    'connector' = 'sqlserver-cdc',
    'hostname' = 'localhost',
    'port' = '1433',
    'username' = 'sa',
    'password' = 'Password!',
    'database-name' = 'inventory',
    'table-name' = 'dbo.products'
);

关键点:

  • connector = 'sqlserver-cdc':使用 SqlServer 专用 CDC 连接器;
  • database-name = 'inventory'
  • table-name = 'dbo.products':带 schema 限定;
  • PRIMARY KEY (id) NOT ENFORCED:提供 Flink 语义上的主键,便于下游 Upsert。

3. 创建 SqlServer CDC 源表:orders

sql 复制代码
CREATE TABLE orders (
   id INT,
   order_date DATE,
   purchaser INT,
   quantity INT,
   product_id INT,
   PRIMARY KEY (id) NOT ENFORCED
) WITH (
    'connector' = 'sqlserver-cdc',
    'hostname' = 'localhost',
    'port' = '1433',
    'username' = 'sa',
    'password' = 'Password!',
    'database-name' = 'inventory',
    'table-name' = 'dbo.orders'
);

这两张表定义好之后,Flink 会:

  • 启动任务时读取 productsorders 的当前快照;
  • 后续订阅 SQL Server CDC 数据表,实时捕获 INSERT / UPDATE / DELETE。

4. 创建 Elasticsearch Sink 表:enriched_orders

sql 复制代码
CREATE TABLE enriched_orders (
   order_id INT,
   order_date DATE,
   purchaser INT,
   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。

核心逻辑是一条 INSERT INTO ... SELECT,把订单和商品 Join 成一张"宽表":

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 Job 会一直运行:

  1. 通过 sqlserver-cdc 源持续消费 SqlServer CDC 数据;
  2. 在流上完成 ordersproducts 的 Join;
  3. 将 Join 后的结果 Upsert 到 ES 索引 enriched_orders_1 中。

七、在 Kibana 中查看 enriched_orders 数据

1. 创建 Index Pattern

打开 Kibana:

  • 访问:
    http://localhost:5601/app/kibana#/management/kibana/index_pattern
  • 新建一个 index pattern:enriched_orders_1

2. 查看数据

切换到 Discover 页面:

  • 访问:
    http://localhost:5601/app/kibana#/discover

选择 enriched_orders_1 索引模式,你应该能看到类似这样的字段:

  • 订单信息:order_id / order_date / purchaser / quantity
  • 商品信息:product_name / product_description

这就说明 Flink CDC 已经把 SqlServer 的数据成功同步并 Join 到 ES 里了。

八、在 SqlServer 中修改数据,验证实时同步效果

接下来在 SqlServer 中执行几条 DML,看一下 Kibana 是否能实时反映变更。

inventory 数据库中执行:

sql 复制代码
-- 1)插入一条新订单
INSERT INTO orders(order_date,purchaser,quantity,product_id)
VALUES ('22-FEB-2016', 1006, 22, 107);
GO

-- 2)更新一条订单的数量
UPDATE orders
SET quantity = 11
WHERE id = 10001;
GO

-- 3)删除一条订单
DELETE FROM orders
WHERE id = 10004;
GO

每执行一步:

  • SqlServer 侧会将变更写入 CDC 日志;

  • Flink SqlServer CDC Connector 会捕获这些变更;

  • Join 后的宽表结果被同步更新到 ES 索引;

  • Kibana 中的 enriched_orders_1 结果列表会实时发生变化:

    • Insert:多了一条新订单;
    • Update :对应订单的 quantity 数量被更新;
    • Delete :对应 order_id 的那条记录被删除。

整个过程不需要重启任务,也不需要人工干预。

九、清理环境

实验结束后,别忘了清理资源。

关闭并移除 Docker 中的 SqlServer / ES / Kibana:

bash 复制代码
docker-compose down

停止 Flink 集群(在 <FLINK_HOME> 目录下):

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

十、小结:SqlServer 也能"优雅地"进入实时世界

至此,我们完成了一条完整的链路:

SqlServer inventory 库(dbo.products / dbo.orders)

→ 数据库/表级开启 CDC

Flink SqlServer CDC Connector 捕获变更

Flink SQL 中实时 Join 成 enriched_orders

→ 写入 Elasticsearch enriched_orders_1 索引

→ 使用 Kibana 实时查看数据变化

如果你已经看完 / 实操过本系列里 MySQL、PolarDB-X、Oracle、OceanBase、Db2 等 CDC Demo,你会发现一件很舒服的事:

上游不管是啥库,

在 Flink 这边基本就是:
换一个 connector 名,改几行 WITH 参数,其余 SQL 模板几乎一模一样。

这也是 Flink CDC 真正的价值所在:

让各种"老系统 + 异构数据库"

在进入"实时数仓 / 实时搜索 / 实时分析"世界的路上,变得非常统一、可控、可复制。

相关推荐
合作小小程序员小小店4 小时前
网页开发,在线%宠物论坛管理%系统,基于eclipse,html,css,jquery,servlet,jsp,sql server数据库。
java·sqlserver·eclipse·jdk·html·intellij-idea
阿里云大数据AI技术4 小时前
阿里云 Elasticsearch 的 AI 革新:高性能、低成本、智能化的搜索新纪元
人工智能·elasticsearch·阿里云
w***4244 小时前
Springboot中使用Elasticsearch(部署+使用+讲解 最完整)
spring boot·elasticsearch·jenkins
利刃大大5 小时前
【c++中间件】Elasticsearch介绍与安装 && 核心概念 && Kibana && 二次封装
c++·elasticsearch·中间件
q***54756 小时前
springboot之集成Elasticsearch
spring boot·后端·elasticsearch
2501_9411467020 小时前
5G与物联网:智能城市的未来
elasticsearch
万山y1 天前
git remote add做了什么
大数据·git·elasticsearch
驾数者1 天前
DDL实战指南:如何定义和管理动态表
大数据·sql·flink
Hello.Reader1 天前
Flink CDC 用 OceanBase CDC 实时同步数据到 Elasticsearch
elasticsearch·flink·oceanbase