flink实时计算实例(保姆级操作)

对于交易数据写到mysql数据库,使用Canal监听数据库binlog日志,然后将监听到的日志信息发送到kafka,flink消费Kafka数据,整个流程的场景。以国内最常用的 Canal(MySQL CDC) + Kafka 为例,从环境部署、配置、完整流程、代码、联调全链路落地,同时补充 Flink CDC 直连方案(无中间Kafka),覆盖两种主流工业实现。

一、整体架构(Canal + MySQL + Kafka)

复制代码
业务系统 → MySQL(开启binlog) → Canal 监听binlog → Canal转发数据到Kafka → Flink消费Kafka计算大屏指标

核心:Canal 伪装成 MySQL 从库,同步 binlog 日志,解析后推送 Kafka,零业务代码侵入


二、前置环境准备

1. MySQL 开启 Binlog(必做)

1.1 修改 MySQL 配置 my.cnf / my.ini

ini 复制代码
[mysqld]
# 开启binlog
log-bin=mysql-bin
# binlog 格式,CDC 必须用 ROW 模式
binlog-format=ROW
# 服务器ID,集群内唯一
server-id=1
# 只同步指定库(可选,过滤无关库)
binlog-do-db=trade_db

重启 MySQL:

bash 复制代码
# Linux
systemctl restart mysqld
# Windows 重启MySQL服务

1.2 创建 Canal 专属账号(最小权限)

登录 MySQL 执行:

sql 复制代码
-- 创建账号
CREATE USER 'canal'@'%' IDENTIFIED BY 'Canal@123456';
-- 授予复制权限
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';
FLUSH PRIVILEGES;

1.3 验证 Binlog 开启

sql 复制代码
SHOW VARIABLES LIKE 'log_bin';
SHOW VARIABLES LIKE 'binlog_format';

结果均为 ON / ROW 即正常。

2. 部署 Canal

2.1 下载&解压

下载地址:https://github.com/alibaba/canal/releases

选用稳定版 canal.deployer-1.1.7.tar.gz

bash 复制代码
tar -zxvf canal.deployer-1.1.7.tar.gz -C /usr/local/
cd /usr/local/canal

2.2 核心配置文件

① 全局配置 conf/canal.properties

配置 Canal 服务、对接 Kafka:

properties 复制代码
# canal 服务端口
canal.port = 11111
# 模式:kafka 代表数据投递到Kafka
canal.serverMode = kafka

# ========== Kafka 集群地址 ==========
kafka.bootstrap.servers = 127.0.0.1:9092
# 消息分区策略
kafka.partition.number = 1
② 实例配置 conf/example/instance.properties

example 是默认实例,负责监听指定 MySQL 库表:

properties 复制代码
# ========== MySQL 连接信息 ==========
canal.instance.master.address=127.0.0.1:3306
canal.instance.master.journal.name=
canal.instance.master.position=
canal.instance.master.timestamp=

# MySQL 账号密码(上面创建的canal账号)
canal.instance.dbUsername=canal
canal.instance.dbPassword=Canal@123456
canal.instance.defaultDatabaseName=trade_db

# 字符集
canal.instance.connectionCharset = UTF-8

# ========== 过滤规则:只监听交易表 trade_record ==========
# 格式:库名.表名,正则匹配
canal.instance.filter.regex=trade_db\\.trade_record

# ========== 投递到Kafka的主题名 ==========
canal.mq.topic=ods_trade_cdc_topic
# 单分区
canal.mq.partition=0

2.3 启动 Canal

bash 复制代码
# Linux
bin/startup.sh
# 查看日志,验证启动
tail -f logs/canal/canal.log

无报错、正常监听即部署完成。

3. 准备测试表 & 测试数据

在 MySQL trade_db 创建交易表:

sql 复制代码
USE trade_db;
CREATE TABLE trade_record (
    trade_id VARCHAR(32) PRIMARY KEY COMMENT '交易ID',
    cust_id VARCHAR(20) COMMENT '客户ID',
    trade_type VARCHAR(10) COMMENT '交易类型',
    trade_amount DECIMAL(16,2) COMMENT '交易金额',
    trade_time DATETIME COMMENT '交易时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='交易流水表';

三、链路验证:MySQL 增数据 → Canal → Kafka

  1. 打开 Kafka 控制台消费者,监听 ods_trade_cdc_topic
bash 复制代码
kafka-console-consumer.sh --topic ods_trade_cdc_topic --bootstrap-server 127.0.0.1:9092
  1. MySQL 插入一条交易数据:
sql 复制代码
INSERT INTO trade_record(trade_id,cust_id,trade_type,trade_amount,trade_time)
VALUES('T001','cust001','买入',5200.00,NOW());
  1. 观察 Kafka 控制台,会收到 Canal 标准 JSON 格式 CDC 数据,示例:
json 复制代码
{
  "data": [
    {
      "trade_id": "T001",
      "cust_id": "cust001",
      "trade_type": "买入",
      "trade_amount": "5200.00",
      "trade_time": "2026-06-10 16:20:00"
    }
  ],
  "database": "trade_db",
  "es": 1718026800000,
  "id": 1,
  "isDdl": false,
  "mysqlType": {
    "trade_id": "varchar(32)",
    "cust_id": "varchar(20)",
    "trade_type": "varchar(10)",
    "trade_amount": "decimal(16,2)",
    "trade_time": "datetime"
  },
  "old": null,
  "sql": "",
  "table": "trade_record",
  "ts": 1718026800123,
  "type": "INSERT"
}

字段说明:

  • type:操作类型 INSERT/UPDATE/DELETE
  • data:变更后的行数据数组
  • database/table:库表名

到这里:MySQL → Canal → Kafka 链路完全通了


承接上面的 CDC 数据,Flink 消费、解析、窗口聚合、输出大屏指标,完整可运行代码。

4.1 补充 Maven 依赖(沿用之前项目)

xml 复制代码
<!-- Flink Kafka 连接器 -->
<dependency>
    <groupId>org.apache.flink</groupId>
    <artifactId>flink-connector-kafka</artifactId>
    <version>1.17.0</version>
    <scope>provided</scope>
</dependency>
<!-- JSON 解析 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.83</version>
</dependency>
java 复制代码
package com.sec.flink.cdc;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.serialization.SimpleStringSchema;
import org.apache.flink.connector.kafka.source.KafkaSource;
import org.apache.flink.connector.kafka.source.enumerator.initializer.OffsetsInitializer;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.windowing.WindowFunction;
import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.api.windowing.windows.TimeWindow;
import org.apache.flink.util.Collector;

import java.time.Duration;

/**
 * 链路:MySQL Binlog -> Canal -> Kafka -> Flink 实时计算交易总额(大屏使用)
 */
public class CanalCdcKafkaJob {
    public static void main(String[] args) throws Exception {
        // 1. 初始化流环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);
        // 生产环境开启Checkpoint,保证数据不丢不重
        // env.enableCheckpointing(30000);

        // 2. 构建Kafka Source,消费Canal投递的CDC数据
        KafkaSource<String> kafkaSource = KafkaSource.<String>builder()
                .setBootstrapServers("127.0.0.1:9092")
                .setTopics("ods_trade_cdc_topic") // Canal 对应的Kafka主题
                .setGroupId("flink-cdc-group")
                .setStartingOffsets(OffsetsInitializer.latest())
                .setValueDeserializer(new SimpleStringSchema())
                .build();

        DataStream<String> kafkaStream = env.fromSource(
                kafkaSource,
                WatermarkStrategy.forBoundedOutOfOrderness(Duration.ofSeconds(2)),
                "Canal-CDC-Source"
        );

        // 3. 解析Canal JSON,提取交易金额(只处理INSERT新增交易)
        DataStream<Double> amountStream = kafkaStream.map(line -> {
            JSONObject root = JSONObject.parseObject(line);
            // 只处理新增交易,UPDATE/DELETE 过滤
            String opType = root.getString("type");
            if (!"INSERT".equalsIgnoreCase(opType)) {
                return 0.0;
            }
            // 获取行数据数组
            JSONArray dataArray = root.getJSONArray("data");
            if (dataArray == null || dataArray.isEmpty()) {
                return 0.0;
            }
            // 取出单条交易数据
            JSONObject tradeData = dataArray.getJSONObject(0);
            String amountStr = tradeData.getString("trade_amount");
            return Double.parseDouble(amountStr);
        }).filter(amount -> amount > 0); // 过滤无效0值

        // 4. 5秒滚动窗口:计算实时交易总额(大屏核心指标)
        DataStream<String> resultStream = amountStream
                .window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
                .apply(new WindowFunction<Double, String, String, TimeWindow>() {
                    @Override
                    public void apply(String key, TimeWindow window,
                                      Iterable<Double> values, Collector<String> out) {
                        double total = 0.0;
                        for (Double val : values) {
                            total += val;
                        }
                        String windowTime = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
                                .format(window.getEnd());
                        String result = String.format("窗口时间:%s , 实时交易总额:%.2f 元", windowTime, total);
                        out.collect(result);
                    }
                });

        // 本地控制台输出,调试用
        resultStream.print("【CDC实时交易总额】");

        // 生产环境:此处添加 Doris Sink,写入结果库供大屏查询
        // resultStream.sinkTo(dorisSink);

        env.execute("Canal-CDC-Trade-Total-Job");
    }
}

4.3 联调测试全流程

  1. 确保 MySQL、Canal、Kafka 全部启动;
  2. 启动上述 Flink 程序;
  3. 在 MySQL 执行 INSERT 新增交易记录;
  4. Flink 控制台每5秒输出当前窗口交易总额
  5. 生产环境开启 Doris Sink,结果入库后,前端大屏轮询查询展示。

如果想精简架构 ,不用独立 Canal 服务,直接使用 Flink CDC 连接器 监听 MySQL binlog,一步到位,也是当下主流方案。

5.1 新增 Maven 依赖

xml 复制代码
<!-- Flink CDC MySQL 连接器 -->
<dependency>
    <groupId>com.ververica</groupId>
    <artifactId>flink-connector-mysql-cdc</artifactId>
    <version>2.4.0</version>
    <scope>provided</scope>
</dependency>
java 复制代码
package com.sec.flink.cdc;

import com.alibaba.fastjson.JSONObject;
import com.ververica.cdc.connectors.mysql.source.MySqlSource;
import com.ververica.cdc.connectors.mysql.table.StartupOptions;
import com.ververica.cdc.debezium.JsonDebeziumDeserializationSchema;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.windowing.WindowFunction;
import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.streaming.api.windowing.windows.TimeWindow;
import org.apache.flink.util.Collector;

public class FlinkCdcDirectJob {
    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);

        // 1. 构建 Flink MySQL CDC Source
        MySqlSource<String> mysqlSource = MySqlSource.<String>builder()
                .hostname("127.0.0.1")
                .port(3306)
                .databaseList("trade_db")       // 监听库
                .tableList("trade_db.trade_record") // 监听表
                .username("canal")
                .password("Canal@123456")
                // 启动策略:latest 从当前最新binlog开始读取
                .startupOptions(StartupOptions.latest())
                // 序列化:转为JSON字符串
                .deserializer(new JsonDebeziumDeserializationSchema())
                .build();

        // 2. 读取CDC流
        DataStream<String> cdcStream = env.fromSource(
                mysqlSource,
                WatermarkStrategy.noWatermarks(),
                "Flink-MySQL-CDC"
        );

        // 3. 解析Debezium格式JSON,提取交易金额
        DataStream<Double> amountStream = cdcStream.map(line -> {
            JSONObject json = JSONObject.parseObject(line);
            // 操作类型:c=新增, u=更新, d=删除
            String op = json.getString("op");
            if (!"c".equals(op)) {
                return 0.0;
            }
            // after 字段:变更后的数据
            JSONObject after = json.getJSONObject("after");
            String amountStr = after.getString("trade_amount");
            return Double.parseDouble(amountStr);
        }).filter(amt -> amt > 0);

        // 4. 窗口聚合计算总额
        DataStream<String> resultStream = amountStream
                .window(TumblingProcessingTimeWindows.of(Time.seconds(5)))
                .apply(new WindowFunction<Double, String, String, TimeWindow>() {
                    @Override
                    public void apply(String key, TimeWindow window,
                                      Iterable<Double> values, Collector<String> out) {
                        double total = 0;
                        for (Double v : values) total += v;
                        String time = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
                                .format(window.getEnd());
                        out.collect(time + " | 实时交易总额:" + String.format("%.2f", total));
                    }
                });

        resultStream.print("【Flink-CDC直连 交易总额】");
        env.execute("Flink-CDC-Direct-Job");
    }
}

5.3 架构对比

  1. Canal + Kafka + Flink

    • 优点:解耦强、缓冲流量、可多消费端复用Kafka数据(大屏、风控、数仓共用)、运维成熟;
    • 适用:中大型交易集群、多业务复用数据流(生产主流)。
  2. Flink CDC 直连 MySQL

    • 优点:架构极简、组件少、部署简单、延迟更低;
    • 缺点:数据流无法复用,Flink 挂掉则数据断流;
    • 适用:单一实时任务、小型系统、快速落地

六、生产环境关键优化 & 可靠性(必看)

  1. 断点续传
    • Canal 自动记录 binlog 偏移量,重启不丢数据;
    • Flink 开启 Checkpoint,消费 Kafka/CDC 均支持状态恢复。
  2. 幂等性
    利用 trade_id 交易唯一ID做去重,防止重复计算。
  3. 过滤无用操作
    交易场景只处理 INSERT,过滤 UPDATE/DELETE,减少计算压力。
  4. 并行度匹配
    Canal 分区数 = Kafka 分区数 = Flink 并行度,避免数据倾斜。
  5. 权限最小化
    MySQL 账号只授予复制、查询权限,禁止高权限。

七、总结

  1. Canal 方案 :部署独立 Canal 服务监听 MySQL binlog,转发到 Kafka,Flink 消费 Kafka,企业金融交易首选,多业务复用数据流
  2. Flink CDC 直连 :无需中间组件,Flink 直接监听 binlog,架构简单,适合单一任务
  3. 核心本质:两种方案都是基于 MySQL binlog 日志实现变更数据捕获,不侵入业务代码、数据库压力极小,是实时交易大屏标准接入方式。
相关推荐
一切皆是因缘际会1 小时前
因果推理人工智能
大数据·数据结构·人工智能
AI原来如此1 小时前
Claude Opus与GPT-5激战,国内API中转站如何应对2026模型迭代潮?
大数据·人工智能·gpt·ai·大模型·ai编程
Taerge01101 小时前
Doris, StarRocks, ClickHouse, Hologres, ES 对比,选型建议
大数据·clickhouse·elasticsearch
极光代码工作室1 小时前
基于数据分析的电影票房预测系统
大数据·python·数据分析·spark·数据可视化
搞科研的小刘选手1 小时前
【智能计算方向专题研讨会】第三届智能计算与数据分析国际学术会议(ICDA 2026)
大数据·算法·机器学习·数据挖掘·数据分析·可视化·计算
量化君也1 小时前
桥水基金全天候策略拆解,构建中国ETF躺平版策略
大数据·人工智能·python·算法·金融·业界资讯
DataX_ruby822 小时前
2026年数据中台平台成熟度排名
大数据·人工智能·数据治理·数据中台
十六年开源服务商2 小时前
2026数字艺术展示网站策划全攻略
大数据·人工智能
YangYang9YangYan2 小时前
专科大数据技术学习数据分析的价值分析
大数据·学习·数据分析