Flink通过Maxwell读取mysql的binlog发送到kafka再写入mysql

1.准备环境

JDK1.8

MySQL

Zookeeper

Kakfa

Maxweill

IDEA

2.实操

2.1开启mysql的binlog

查看binlog 状态,是否开启

show variables like 'log_%'

如果log_bin显示为ON,则代表已开启。如果是OFF 说明还没开启。

[Linux] 编辑 /etc/my.cnf 文件,在[mysqld]后面增加

server-id=1
log-bin=mysql-bin
binlog_format=row
#如果不加此参数,默认所有库开启binlog
binlog-do-db=gmall_20230424 

重启mysql 服务

service mysqld restart

再次查看binlog 状态

[Windows] 编辑 mysql安装目录 下 my.ini 文件,在[mysqld]后面增加 如上 linux 一样

2.2 Zookeeper 、 Kafka

2.2.1启动 ZK

bin/zkServer.sh start

2.2.2启动 Kakfa

#常规模式启动 

bin/kafka-server-start.sh config/server.properties 

#进程守护模式启动

nohup bin/kafka-server-start.sh config/server.properties >/dev/null 2>&1 &

2.2.3创建 kafka-topic

bin/kafka-topics.sh --bootstrap-server 192.168.221.100:9092 --create --topic flink_test01 --partitions 1 --replication-factor 1

测试kafka-topic

#消费 

bin/kafka-console-consumer.sh --bootstrap-server 192.168.221.100:9092 --topic flink_test01 --from-beginning 

#生产

bin/kafka-console-producer.sh --broker-list 192.168.221.100:9092 --topic flink_t

2.3配置Maxwell

2.3.1创建Maxwell 所需要的 数据库 和 用户

1)创建数据库

CREATE DATABASE maxwell;

2)调整MySQL数据库密码级别

set global validate_password_policy=0; 

set global validate_password_length=4;

3)创建Maxwell用户并赋予其必要权限

CREATE USER 'maxwell'@'%' IDENTIFIED BY 'maxwell'; 

GRANT ALL ON maxwell.* TO 'maxwell'@'%'; 

GRANT SELECT, REPLICATION CLIENT, REPLICATION SLAVE ON *.* TO 'maxwell'@'%';

2.3.2配置Maxwell

在Maxwell安装包解压目录下,复制 并 编辑 config.properties.example

mv config.properties.example config.properties
vim config.properties
producer=kafka 

kafka.bootstrap.servers=192.168.221.100:9092 

#目标Kafka topic,可静态配置,例如:maxwell,也可动态配置,例如:%{database}_%{table} kafka_topic=flink_test01 

# mysql login info host=192.168.221.100 

user=maxwell 

password=maxwell

2.3.3 启动Maxwell

1)启动Maxwell

bin/maxwell --config config.properties

2)停止Maxwell

ps -ef | grep maxwell | grep -v grep | grep maxwell | awk '{print $2}' | xargs kill -9

2.4测试maxwell、mysql、kafka 正常使用

2.4.1查看Maxwell、kafka、zookeeper 进程

jps

2.4.2 mysql添加、修改、删除数据

查看 kafka 消费者

有消费 说明 流程是通畅 的

2.5 idea 编写程序

2.5.1 idea 创建 maven 项目

2.5.2 pom.xml 依赖

<dependencies>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.21</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.21</version>
    </dependency>

    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-streaming-java_2.11</artifactId>
        <version>1.13.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-java</artifactId>
        <version>1.13.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-clients_2.11</artifactId>
        <version>1.13.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-client</artifactId>
        <version>3.1.3</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.13</version>
    </dependency>
    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-table-planner-blink_2.11</artifactId>
        <version>1.13.0</version>
    </dependency>
    <!--mysql cdc -->
    <dependency>
        <groupId>com.ververica</groupId>
        <artifactId>flink-connector-mysql-cdc</artifactId>
        <version>2.2.0</version>
        <!--            <scope>provided</scope>-->
    </dependency>
    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-connector-kafka_2.12</artifactId>
        <version>1.12.7</version>
    </dependency>

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>2.0.29</version>
    </dependency>

    <!--kafka-->
    <dependency>
        <groupId>org.apache.kafka</groupId>
        <artifactId>kafka-clients</artifactId>
        <version>2.1.1</version>
    </dependency>

    <!--本地调试flink ui-->
    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-runtime-web_2.11</artifactId>
        <version>1.13.0</version>
        <scope>compile</scope>
    </dependency>

    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-connector-jdbc_2.11</artifactId>
        <version>1.12.0</version>
    </dependency>

    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-jdbc_2.11</artifactId>
        <version>1.9.1</version>
    </dependency>

    <dependency>
        <groupId>org.apache.kafka</groupId>
        <artifactId>kafka-clients</artifactId>
        <version>3.0.0</version>
    </dependency>

    <dependency>
        <groupId>org.apache.flink</groupId>
        <artifactId>flink-table-planner_2.11</artifactId>
        <version>1.10.1</version>
    </dependency>

</dependencies>

2.5.3 编写测试代码

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.qiyu.dim.KafkaUtil;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.api.java.io.jdbc.JDBCOutputFormat;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.types.Row;
import org.apache.flink.util.Collector;

/**
 * @Author liujian
 * @Date 2023/4/24 9:40
 * @Version 1.0
 */
public class Flink_kafka {
    public static void main(String[] args) throws Exception {
        // todo 1.获取执行环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        // todo 2.将并行度设为1, (生产环境中,kafka中 topic有几个分区 设为几)
        env.setParallelism(1);
        // todo 3.读取 maxwell kafka 数据流
        DataStream dataStreamSource=
                env.addSource(KafkaUtil.getKafkaConsumer("flink_test01","192.168.221.100:9092"));
        // todo 4.取kafka中的数据流 有效数据,获取 emp_user 表中的 新增、修改、初始化数据 。脏数据直接打印控制台,不处理
        DataStream<JSONObject> data = dataStreamSource.flatMap(new FlatMapFunction<String, JSONObject>() {
            @Override
            public void flatMap(String s, Collector<JSONObject> collector) throws Exception {
                try {
                    // 将 数据流中 类型 转换 String >> JsonObject
                    JSONObject json = JSON.parseObject(s);
                    //取 emp_user 表数据
                    if (json.getString("table").equals("emp_user")) {
                        //取新增、修改数据
                        if (json.getString("type").equals("insert") || json.getString("type").equals("update")) {
                            System.out.println(json.getJSONObject("data"));
                            collector.collect(json.getJSONObject("data"));
                        }
                    }
                } catch (Exception e) {
                    System.out.println("脏数据:" + s);
                }

            }
        });

        // todo 5. 将 有效数据转换 为 Row 类型 。JDBCOutputFormat只能处理Row,而Row是对prepared statement的参数的一个包装类
        DataStream<Row> map = data.map(new MapFunction<JSONObject, Row>() {
            @Override
            public Row map(JSONObject jsonObject) throws Exception {
                Row row = new Row(4);
                row.setField(0, jsonObject.getString("id"));
                row.setField(1, jsonObject.getString("name"));
                row.setField(2, jsonObject.getString("age"));
                row.setField(3, jsonObject.getString("sex"));
                return row;
            }
        });

        // todo 6.  将 数据存储 到 mysql 当中,同主键 数据 就修改, 无 就新增
        String query =
                "INSERT  INTO gmall_20230424.emp_user_copy (id,name,age,sex) " +
                        "VALUES (?, ?,?,?) " +
                        "ON DUPLICATE KEY UPDATE name = VALUES(name) , age = VALUES(age)  , sex = VALUES(sex)";
        JDBCOutputFormat finish = JDBCOutputFormat.buildJDBCOutputFormat()
                .setDrivername("com.mysql.jdbc.Driver")
                .setDBUrl("jdbc:mysql://192.168.221.100:3306/gmall_20230424?user=root&password=000000")
                .setQuery(query)
                .setBatchInterval(1)
                .finish();

        //todo 7.提交存储任务
        map.writeUsingOutputFormat(finish);

        //todo 8.提交flink 任务
        env.execute();

    }
}

2.5.4 启动测试代码

2.5.5 测试

如 2.4.2 一样 ,在测试表 emp_user 中 进行 新增 、修改

查看 是否写入 emp_user_copy表中

INSERT into emp_user VALUES ("1","zhangsan",22,"F"); 

INSERT into emp_user VALUES ("2","lisi",22,"M"); 

INSERT into emp_user VALUES ("3","wangwu",22,"F"); 

INSERT into emp_user VALUES ("4","jia",22,"M"); 

INSERT into emp_user VALUES ("5","yi",22,"F"); 

UPDATE emp_user set age=23 where id ="4"; 

INSERT into emp_user VALUES ("6","666",22,"F");

新增 id为 4的数据时:age=22,但后面做了次 update age=23

<think>好的,我现在需要处理用户的问题:“请使用中文回答我或者给我介绍一下: mysql同步binlog”。首先,我需要确定用户的具体需求是什么。用户之前询问了如何根据commit查询对应的log信息,现在又提到MySQL同步binlog,可能是在数据库复制或数据同步方面遇到了问题。 首先,我得回忆一下MySQLbinlog同步机制。用户可能想知道如何配置主从复制,或者使用binlog进行数据同步到其他系统,比如数据仓库或缓存。需要分步骤介绍同步的原理、配置方法、工具以及常见问题处理。 接下来,要确定用户的使用场景。是设置主从复制的高可用架构,还是进行数据迁移、分析?不同的场景可能需要不同的同步策略。比如主从复制注重实时性和一致性,而数据抽取可能更关注增量处理。 然后,需要解释binlog的三种格式:STATEMENT、ROW、MIXED,以及它们的优缺点。用户可能需要根据业务需求选择合适的格式,比如ROW格式更安全但日志量大,STATEMENT节省空间但有函数风险。 还要介绍常用的同步工具,比如MySQL自带的复制功能,或者第三方工具如Canal、Maxwell、Debezium。这些工具各有特点,适用于不同的技术栈,比如Java生态可能偏向Canal,而Kafka集成可能用Debezium。 配置步骤方面,需要详细说明如何开启binlog,配置主从服务器的my.cnf,创建复制账号,获取binlog位置,启动从库复制。这些步骤必须准确,尤其是server-id、log-bin等参数设置,避免配置错误导致同步失败。 另外,用户可能会遇到同步延迟、数据不一致等问题,需要给出排查方法,比如检查IO/SQL线程状态,查看错误日志,验证网络连接等。这部分需要简明扼要,帮助用户快速定位问题。 最后,注意事项部分要提醒用户权限问题,binlog保留策略,以及版本兼容性。特别是GTID的使用,现在很多生产环境都启用了GTID,需要强调其优势和使用方法。 需要确保语言通俗易懂,结构清晰,分步骤讲解,让用户能够按图索骥进行操作。同时,避免使用过于专业的术语,或者在必要时给出解释,比如GTID、位点等概念。可能还需要提供示例命令,如CHANGE MASTER TO的具体参数,方便用户复制使用。 总结下来,回答需要涵盖原理、配置步骤、工具选择、问题排查和注意事项,确保用户全面了解MySQLbinlog同步机制,并能够实际应用。同时,根据用户之前的提问历史,可能对数据库操作有一定基础,但需要详细而不冗余的说明。</think>--- MySQL 的二进制日志(Binlog)是数据库实现数据同步、主从复制的核心机制。通过解析 Binlog,可以将主库的数据变更实时同步到从库或其他数据系统(如数据仓库、缓存)。以下是 Binlog 同步的 **核心原理、配置方法及常见工具**: --- ### **一、Binlog 同步原理** 1. **Binlog 记录内容** - 所有更改数据库的 SQL 语句(`INSERT`/`UPDATE`/`DELETE`)或行变更(Row-based 格式)。 - 事务提交时间、执行线程 ID、日志位置(Position)等元信息。 2. **同步流程** - **主库(Master)**:将事务的 Binlog 事件写入日志文件。 - **从库(Slave)**:通过 `IO Thread` 拉取主库的 Binlog,`SQL Thread` 重放日志中的事件,实现数据同步。 - **外部系统**:使用工具(如 Canal、Debezium)监听 Binlog 流,将数据发送到 Kafka、Elasticsearch 等。 --- ### **二、配置 MySQL Binlog 同步(主从复制)** #### **步骤1:主库配置** 1. 修改主库配置文件 `my.cnf`,启用 Binlog 并设置唯一标识: ```ini [mysqld] server-id = 1 # 主库唯一ID(必须>0) log-bin = /var/log/mysql/mysql-bin.log # Binlog 存储路径 binlog-format = ROW # 推荐使用 ROW 格式(数据一致性更强) expire-logs-days= 7 # Binlog 保留天数 gtid-mode = ON # 启用 GTID(简化故障恢复) enforce-gtid-consistency = ON ``` 2. 重启 MySQL 服务: ```bash systemctl restart mysql ``` 3. 创建同步专用账号: ```sql CREATE USER 'repl'@'%' IDENTIFIED BY 'Repl_Password123!'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%'; ``` 4. 查看主库状态,记录 `File` 和 `Position`: ```sql SHOW MASTER STATUS; ``` ``` +------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+-------------------+ | mysql-bin.000003 | 785 | | | | +------------------+----------+--------------+------------------+-------------------+ ``` --- #### **步骤2:从库配置** 1. 修改从库配置文件 `my.cnf`: ```ini [mysqld] server-id = 2 # 从库唯一ID(与主库不同) relay-log = /var/log/mysql/mysql-relay.log read-only = ON # 从库设为只读 ``` 2. 重启 MySQL 服务: ```bash systemctl restart mysql ``` 3. 配置同步链路: ```sql CHANGE MASTER TO MASTER_HOST = '主库IP', MASTER_USER = 'repl', MASTER_PASSWORD = 'Repl_Password123!', MASTER_LOG_FILE = 'mysql-bin.000003', -- 替换为主库的 File 值 MASTER_LOG_POS = 785; -- 替换为主库的 Position 值 ``` 4. 启动同步: ```sql START SLAVE; ``` 5. 检查同步状态: ```sql SHOW SLAVE STATUS\G ``` - 确认 `Slave_IO_Running` 和 `Slave_SQL_Running` 均为 `Yes`。 - 若出现错误,检查 `Last_IO_Error` 或 `Last_SQL_Error`。 --- ### **三、Binlog 同步工具** #### **1. 官方方案:MySQL Replication** - **适用场景**:主从高可用、读写分离。 - **特点**:内置于 MySQL,支持 GTID 和自动故障转移。 #### **2. 第三方工具** | 工具 | 语言 | 输出目标 | 核心功能 | |--------------|--------|--------------------|---------------------------------------| | **Canal** | Java | Kafka/RocketMQ | 解析 Binlog,支持过滤和格式转换 | | **Maxwell** | Java | Kafka/RabbitMQ | 轻量级,支持全量+增量同步 | | **Debezium** | Java | Kafka | 基于 Kafka Connect,支持多种数据库 | | **Flink CDC**| Java | 实时计算引擎 | 结合 Flink 实现流式 ETL | --- #### **示例:使用 Canal 同步到 Kafka** 1. **Canal 服务端配置**: ```properties # canal.properties canal.destinations = test canal.instance.master.address = 主库IP:3306 canal.instance.dbUsername = canal canal.instance.dbPassword = Canal_Password123! ``` 2. **启动 Canal**: ```bash bin/startup.sh ``` 3. **消费 Binlog 事件**: ```java // Java 客户端监听示例 CanalConnector connector = CanalConnectors.newClusterConnector("canal-server:11111", "test", "", ""); connector.connect(); connector.subscribe(".*\\..*"); // 订阅所有表 while (true) { Message message = connector.getWithoutAck(100); for (CanalEntry.Entry entry : message.getEntries()) { if (entry.getEntryType() == EntryType.ROWDATA) { RowChange rowChange = RowChange.parseFrom(entry.getStoreValue()); System.out.println(rowChange); } } } ``` --- ### **四、常见问题排查** #### **1. 同步延迟** - **原因**:从库性能不足、大事务、网络延迟。 - **解决**: - 监控 `Seconds_Behind_Master`。 - 优化慢查询,避免主库大批量写入。 #### **2. 数据不一致** - **修复步骤**: ```sql STOP SLAVE; SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1; -- 跳过1个错误事件(谨慎使用) START SLAVE; ``` - 若需彻底修复,使用 `mysqldump` 重新全量同步。 #### **3. GTID 同步错误** - **错误示例**: ```sql Last_SQL_Error: Could not execute Write_rows event on table test.t1; Duplicate entry '2' for key 'PRIMARY' ``` - **解决**: ```sql STOP SLAVE; SET @@GLOBAL.GTID_PURGED = '+主库的GTID'; -- 重置 GTID 点位 START SLAVE; ``` --- ### **五、注意事项** 1. **Binlog 格式选择**: - `ROW`:记录行变更,安全但日志量大。 - `STATEMENT`:记录 SQL 语句,节省空间但可能因函数导致主从不一致。 - `MIXED`:混合模式,根据情况自动选择。 2. **权限控制**: - 同步账号需具备 `REPLICATION SLAVE` 权限。 - 禁止从库直接写入数据(配置 `read-only=ON`)。 3. **版本兼容性**: - 主从 MySQL 版本尽量一致,从库版本不低于主库。 --- 通过以上步骤,可实现 MySQL Binlog 的高效同步。若需同步到非 MySQL 系统(如 Elasticsearch),建议结合 Kafka 作为消息中间件,实现解耦和流量削峰。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

只爱大锅饭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值