Canal 采集MySQL binlog日志

Canal 采集MySQL binlog日志

1、Canal 数据同步之MySQL binlog日志

​ Canal是阿里巴巴开发数据实时同步框架,原理与OGG基本类似,都是捕获数据库日志数据,进行解析,将其发送到目标端(比如Kafka 消息队列)。新版Canal 1.1版本

针对MySQL数据库来说,日志数据:binlog日志,二进制日志。

binlog中存储四种类型日志数据:插入insert、更新update、删除delete和清空truncate

1612326012096

默认情况下,MySQL数据库没有开启binlog日志,向表中CUDT操作时,不会记录日志到文件中。

1615781586606

[root@node1 ~]# docker exec -it mysql /bin/bash
root@8b5cd2152ed9:/# 
root@8b5cd2152ed9:/# more /etc/mysql/my.cnf
## 相关配置解析:
## [mysqld]
## log-bin=mysql-bin #添加这一行就ok
## binlog-format=ROW #选择row模式
## server_id=1 #配置mysql replaction需要定义,不能和canal的slaveId重复
## expire_logs_days=7 # binlog文件保存7天
## max_binlog_size=500m # 每个binlog日志文件大小

1615781688969

root@8b5cd2152ed9:/# mysql -uroot -p123456
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 6
Server version: 5.7.30-log MySQL Community Server (GPL)

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 

1615781803587

可以查看MySQL数据库binlog日志文件存储目录

root@8b5cd2152ed9: ~# cd /var/lib/mysql
root@8b5cd2152ed9:/var/lib/mysql# ls -l
total 205364
-rw-r-----. 1 mysql mysql       56 May 29  2020 auto.cnf
-rw-------. 1 mysql mysql     1676 May 29  2020 ca-key.pem
-rw-r--r--. 1 mysql mysql     1112 May 29  2020 ca.pem
drwxr-x---. 2 mysql mysql       20 Jul  4  2020 canal_tsdb
-rw-r--r--. 1 mysql mysql     1112 May 29  2020 client-cert.pem
-rw-------. 1 mysql mysql     1676 May 29  2020 client-key.pem
drwxr-x---. 2 mysql mysql      186 Jul  4  2020 crm
-rw-r-----. 1 mysql mysql      576 Mar 13 08:50 ib_buffer_pool
-rw-r-----. 1 mysql mysql 50331648 Mar 15 02:18 ib_logfile0
-rw-r-----. 1 mysql mysql 50331648 Mar 15 02:18 ib_logfile1
-rw-r-----. 1 mysql mysql 79691776 Mar 15 02:18 ibdata1
-rw-r-----. 1 mysql mysql 12582912 Mar 15 02:22 ibtmp1
drwxr-x---. 2 mysql mysql     4096 May 29  2020 mysql
-rw-r-----. 1 mysql mysql 17271182 Mar 13 16:47 mysql-bin.000004
-rw-r-----. 1 mysql mysql      177 Mar 13 08:50 mysql-bin.000005
-rw-r-----. 1 mysql mysql      154 Mar 15 02:18 mysql-bin.000006
-rw-r-----. 1 mysql mysql       57 Mar 15 02:18 mysql-bin.index
drwxr-x---. 2 mysql mysql     8192 May 29  2020 performance_schema
-rw-------. 1 mysql mysql     1680 May 29  2020 private_key.pem
-rw-r--r--. 1 mysql mysql      452 May 29  2020 public_key.pem
-rw-r--r--. 1 mysql mysql     1112 May 29  2020 server-cert.pem
-rw-------. 1 mysql mysql     1676 May 29  2020 server-key.pem
drwxr-x---. 2 mysql mysql     8192 May 29  2020 sys
drwxr-x---. 2 mysql mysql       60 May 29  2020 test

2、Canal 数据同步之工作原理

Canal [kə’næl],译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据订阅和消费

1612334014005

Canal起源于,阿里巴巴杭州和美国机房数据同步备份,衍生框架,目前支持功能与版本如下:

1615790940107

Canal框架原理,参考MySQL数据主从复制原理

1612334597112

  • 1)、MySQL master 将数据变更写入二进制日志( binary log, 其中记录叫做二进制日志事件binary log events,可以通过 show binlog events 进行查看);变更数据,记录日志:biglog
  • 2)、MySQL slave 将 master 的 binary log events 拷贝到它的中继日志(relay log);IO 线程,获取binlog
  • 3)、MySQL slave 重放 relay log 中事件,将数据变更反映它自己的数据;SQL线程,执行语句

1612334674650

  • 1)、canal 模拟 MySQL slave 的交互协议,伪装自己为 MySQL slave ,向 MySQL master 发送dump 协议
  • 2)、MySQL master 收到 dump 请求,开始推送 binary log 给 slave (即 canal )
  • 3)、canal 解析 binary log 对象(原始为 byte 流);

1612334913065

上图中功能,属于Canal新版才有的(解析binlog日志,发送到Kafka消息队列)。

1615791603097

3-Canal 数据同步之Canal 架构

Canal框架使用Java语言编写,启动服务Server,每个服务配置多个实例Instance,如下结构所示:

1615791782074

  • 1)、Canal Server 代表一个 Canal 运行实例,对应于一个 JVM;
  • 2)、Instance 对应于一个数据队列 (1个 Canal Server 对应 1…n 个 Instance)
    • 监控某个数据库database binlog日志,需要将数据,发送到Kafka消息队列和Es索引index
    • 发送到Kafka,称为1个实例:instance(binlog -> instance -> kafka)
    • 发送到Es,称为1个实例:instance(binlog -> instance -> es)
  • 3)、Instance下的子模块
    • eventParser: 数据源接入,模拟 slave 协议和 master 进行交互,协议解析
    • eventSink: ParserStore 链接器,进行数据过滤,加工,分发的工作
    • eventStore:数据存储
    • metaManager:增量订阅 & 消费信息管理器

1612335671638

​ 总结:CanalServer来说,启动1个服务,运行多个instance实例(每个实例对应一个sink),每个实例instance包含四个部分:eventParse、eventSink、eventStore、metaManager

EventParser在向MySQL发送dump命令之前会先从Log Position中获取上次解析成功的位置(如果是第一次启动,则获取初始指定位置或者当前数据段binlog位点)。

canal架构图.png

  • 1)、EventSink起到一个类似channel的功能,可以对数据进行过滤、分发/路由(1:n)、归并(n:1)和加
    工。EventSink是连接EventParser和EventStore的桥梁
  • 2)、EventStore实现模式是内存模式,内存结构为环形队列,由三个指针(Put、Get和Ack)标识数据
    存储和读取的位置。

4-Canal 数据同步之Docker 安装部署

​ Canal 1.1.x版本开始,支持Docker容器部署,所以本项目中,采用Docker容器部署CanallServer。

在node1.itcast.cn机器上安装部署CanalServer,首先搜索获取canal镜像,然后pull拉取镜像,最后创建容器

文档:https://github.com/alibaba/canal/wiki/Docker-QuickStart、
1615792713761

​ Canal的好处在于对业务代码没有侵入,因为是基于监听binlog日志去进行同步数据的。实时性也能做到准实时,其实是很多企业一种比较常见的数据同步的方案。

1612336004227

​ 具体安装部署,已经完成,只需要启动CanalServer容器即可,再启动Server服务,但是需要掌握如何配置,以及一些参数含义。

# 拉取镜像
docker pull canal/canal-server:v1.1.2

# 创建容器
docker run -d --name canal-server \
-e canal.instance.master.address=192.168.88.10:3306 \
-e canal.instance.dbUsername=root \
-e canal.instance.dbPassword=123456 \
-p 11111:11111 \
canal/canal-server:v1.1.2

# 进入容器
docker exec -it canal-server /bin/bash

# 切换到canal-server安装目录bin下,重启服务
[root@28888fad98c9 admin]# cd canal-server/bin/
[root@28888fad98c9 bin]# ./restart.sh 
[root@28888fad98c9 bin]# jps
305 CanalLauncher
321 Jps

1615793128774

接下来,查看CanalServer配置:

  • 1)、CanalServer配置文件:canal-server/conf/canal.properties

1615793313924

  • 2)、Instance实例配置文件:canal-server/conf/example/instance.properties

1615793419104

启动node2.itcast.cn中Kafka消息队列,准备测试,看是否将MySQL表数据实时同步到Kafka中。

5-Canal 数据同步之CRM数据同步Kafka

​ 测试Canal功能,首先启动MySQL数据库,然后启动Kafka消息队列,最后启动CanalServer服务。

同步MySQL数据库表的数据。

  • 1)、插入数据测试
-- 插入数据INSERT
INSERT INTO `crm_address` VALUES (10001, '葛秋红', null, '17*******47', '恒大影城南侧小金庄', '130903', null, '2020-02-02 18:51:39', '2020-02-02 18:51:39', null);

插入数据到MySQL数据库表,Kafka中数据:

{
  "data": [
    {
      "id": "10001",
      "name": "葛秋红",
      "tel": null,
      "mobile": "17*******47",
      "detail_addr": "恒大影城南侧小金庄",
      "area_id": "130903",
      "gis_addr": null,
      "cdt": "2020-02-02 18:51:39",
      "udt": "2020-02-02 18:51:39",
      "remark": null
    }
  ],
  "database": "crm",
  "es": 1615794443000,
  "id": 2,
  "isDdl": false,
  "mysqlType": {
    "id": "bigint(20)",
    "name": "varchar(50)",
    "tel": "varchar(20)",
    "mobile": "varchar(20)",
    "detail_addr": "varchar(100)",
    "area_id": "bigint(20)",
    "gis_addr": "varchar(20)",
    "cdt": "datetime",
    "udt": "datetime",
    "remark": "varchar(100)"
  },
  "old": null,
  "sql": "",
  "sqlType": {
    "id": -5,
    "name": 12,
    "tel": 12,
    "mobile": 12,
    "detail_addr": 12,
    "area_id": -5,
    "gis_addr": 12,
    "cdt": 93,
    "udt": 93,
    "remark": 12
  },
  "table": "crm_address",
  "ts": 1615794443644,
  "type": "INSERT"
}
  • 2)、更新数据

更新MySQL数据库表的数据,查看Kafka中数据格式:

{
  "data": [
    {
      "id": "10001",
      "name": "葛红红",
      "tel": null,
      "mobile": "17*******47",
      "detail_addr": "恒大影城南侧小金庄",
      "area_id": "130903",
      "gis_addr": null,
      "cdt": "2020-02-02 18:51:39",
      "udt": "2020-02-02 18:51:39",
      "remark": null
    }
  ],
  "database": "crm",
  "es": 1615794537000,
  "id": 3,
  "isDdl": false,
  "mysqlType": {
    "id": "bigint(20)",
    "name": "varchar(50)",
    "tel": "varchar(20)",
    "mobile": "varchar(20)",
    "detail_addr": "varchar(100)",
    "area_id": "bigint(20)",
    "gis_addr": "varchar(20)",
    "cdt": "datetime",
    "udt": "datetime",
    "remark": "varchar(100)"
  },
  "old": [
    {
      "name": "葛秋红"
    }
  ],
  "sql": "",
  "sqlType": {
    "id": -5,
    "name": 12,
    "tel": 12,
    "mobile": 12,
    "detail_addr": 12,
    "area_id": -5,
    "gis_addr": 12,
    "cdt": 93,
    "udt": 93,
    "remark": 12
  },
  "table": "crm_address",
  "ts": 1615794537264,
  "type": "UPDATE"
}
  • 3)、删除数据测试

删除MySQL数据库表的数据,查看Kafka中数据:

{
  "data": [
    {
      "id": "10001",
      "name": "葛红红",
      "tel": null,
      "mobile": "17*******47",
      "detail_addr": "恒大影城南侧小金庄",
      "area_id": "130903",
      "gis_addr": null,
      "cdt": "2020-02-02 18:51:39",
      "udt": "2020-02-02 18:51:39",
      "remark": null
    }
  ],
  "database": "crm",
  "es": 1615794586000,
  "id": 4,
  "isDdl": false,
  "mysqlType": {
    "id": "bigint(20)",
    "name": "varchar(50)",
    "tel": "varchar(20)",
    "mobile": "varchar(20)",
    "detail_addr": "varchar(100)",
    "area_id": "bigint(20)",
    "gis_addr": "varchar(20)",
    "cdt": "datetime",
    "udt": "datetime",
    "remark": "varchar(100)"
  },
  "old": null,
  "sql": "",
  "sqlType": {
    "id": -5,
    "name": 12,
    "tel": 12,
    "mobile": 12,
    "detail_addr": 12,
    "area_id": -5,
    "gis_addr": 12,
    "cdt": 93,
    "udt": 93,
    "remark": 12
  },
  "table": "crm_address",
  "ts": 1615794586746,
  "type": "DELETE"
}

​ 可以发现,Canal数据同步实时性很高,针对插入数据:INSERT、更新数据:UPDATE和删除数据:DELETE

  • 4)、清空表数据测试
    • 执行DDL语句:TRUNCATE TABLE crm_address ;
{
  "data": null,
  "database": "crm",
  "es": 1615794718000,
  "id": 5,
  "isDdl": true,
  "mysqlType": null,
  "old": null,
  "sql": "/* ApplicationName\u003dDBeaver 6.3.4 - SQLEditor \u003cScript-4.sql\u003e */ TRUNCATE TABLE crm_address",
  "sqlType": null,
  "table": "crm_address",
  "ts": 1615794719249,
  "type": "TRUNCATE"
}

16-Canal 数据同步之集群高可用HA

​ Canal 1.1.4版本开始,提供集群高可用HA,运行2个CanalServer服务,一个为Active,一个为Standby,当Active宕掉以后,Standby接收工作,继续进行数据实时同步功能。

  • 1)、首先,Canal集群同步数据数据流转示意图:

    业务系统 -> MySQL(业务主库) -> Canal 集群 -> Kafak Topic -> 实时应用程序 :统计分析 -> Redis

1612338707148

Canal 集群高可用如何实现的,如下图所示,核心点2个:

  • 1)、CanalServer服务启动2个:running(active)、Standby
  • 2)、依赖Zookeeper监控CanalServer状态,并且存储状态

1612338755220

比如CanalServer中有2个Instance实例时,高可用集群如何工作:

1612338926977

  • 6
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Java8新特性及实战视频教程完整版Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。 Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用Lambda 表达式可以使代码变的更加简洁紧凑。Java8实战视频-01让方法参数具备行为能力Java8实战视频-02Lambda表达式初探Java8实战视频-03Lambda语法精讲Java8实战视频-04Lambda使用深入解析Java8实战视频-05Lambda方法推导详细解析-上.wmvJava8实战视频-06Lambda方法推导详细解析-下Java8实战视频-07Stream入门及Stream在JVM中的线程表现Java8实战视频-08Stream知识点总结Stream源码阅读Java8实战视频-09如何创建Stream上集Java8实战视频-10如何创建Stream下集.wmvJava8实战视频-11Stream之filter,distinct,skip,limit,map,flatmap详细介绍Java8实战视频-12Stream之Find,Match,Reduce详细介绍Java8实战视频-13NumericStream的详细介绍以及和Stream之间的相互转换Java8实战视频-14Stream综合练习,熟练掌握API的用法Java8实战视频-15在Optional出现之前经常遇到的空指针异常.wmvJava8实战视频-16Optional的介绍以及API的详解Java8实战视频-17Optional之flatMap,综合练习,Optional源码剖析Java8实战视频-18初识Collector体会Collector的强大Java8实战视频-19Collector使用方法深入详细介绍-01Java8实战视频-20Collector使用方法深入详细介绍-02Java8实战视频-21Collector使用方法深入详细介绍-03.wmvJava8实战视频-22Collector使用方法深入详细介绍-04Java8实战视频-23Collector原理讲解,JDK自带Collector源码深度剖析Java8实战视频-24自定义Collector,结合Stream的使用详细介绍Java8实战视频-25Parallel Stream编程体验,充分利用多核机器加快计算速度Java8实战视频-26Fork Join框架实例深入讲解Java8实战视频-27Spliterator接口源码剖析以及自定义Spliterator实现一个Stream.wmvJava8实战视频-28Default方法的介绍和简单的例子Java8实战视频-29Default方法解决多重继承冲突的三大原则详细介绍Java8实战视频-30多线程Future设计模式原理详细介绍,并且实现一个Future程序Java8实战视频-31JDK自带Future,Callable,ExecutorService介绍Java8实战视频-32实现一个异步基于事件回调的Future程序.wmvJava8实战视频-33CompletableFuture用法入门介绍Java8实战视频-34CompletableFuture之supplyAsync详细介绍Java8实战视频-35CompletableFuture流水线工作,join多个异步任务详细讲解Java8实战视频-36CompletableFuture常用API的重点详解-上Java8实战视频-37CompletableFuture常用API的重点详解-下Java8实战视频-38JDK老DateAPI存在的问题,新的DateAPI之LocalDate用法及其介绍.wmvJava8实战视频-39New Date API之LocalTime,LocalDateTime,Instant,Duration,Period详细介绍Java8实战视频-40New Date API之format和parse介绍
好的,下面是一个基于 Canal、Kafka 和 PySpark Streaming 的实时案例,用于将 MySQL 数据库中的增量数据读取并发送到 Kafka,并通过 PySpark Streaming 进行实时计算。具体步骤如下: 1. 首先需要安装并启动 Canal 和 Kafka。 2. 创建一个 Python 脚本,使用 Canal 客户端连接到 Canal Server,并订阅指定的 MySQL 数据库和表。然后将解析出的增量数据发送到 Kafka。 ```python from canal.client import Client from kafka import KafkaProducer import json # 创建Canal客户端对象 client = Client() client.connect(host='127.0.0.1', port=11111) client.check_valid(username=b'', password=b'') # 创建Kafka生产者对象 producer = KafkaProducer(bootstrap_servers='127.0.0.1:9092') # 订阅指定的数据库和表 client.subscribe(client_id='1001', destination='example', filter='.*\\..*') try: while True: message = client.get(batch_size=100, timeout=100) for entry in message.get('entries'): if entry.entryType == 'ROWDATA': row_change = entry.rowChange event_type = row_change.eventType for row_data in row_change.rowDatas: row_dict = {} for column in row_data.afterColumns: row_dict[column.name] = column.value # 将解析出的增量数据发送到Kafka producer.send(topic='example', value=json.dumps(row_dict).encode('utf-8')) except Exception as e: print(e) finally: client.disconnect() ``` 上述代码中,首先创建了一个 Canal 客户端对象,并连接到 Canal Server。然后创建了一个 Kafka 生产者对象,用于将解析出的增量数据发送到 Kafka。接着,订阅了指定的 MySQL 数据库和表,并循环获取增量数据。对于每个增量数据,将其转换为字典格式,并使用 `json.dumps` 方法将字典编码为 JSON 字符串,并使用 Kafka 生产者将其发送到指定的 Kafka 主题中。 3. 创建一个 PySpark Streaming 应用程序,从 Kafka 主题中读取增量数据,并进行实时计算。例如,以下代码用于计算每隔5秒钟的单词计数: ```python from pyspark import SparkConf, SparkContext from pyspark.streaming import StreamingContext from pyspark.streaming.kafka import KafkaUtils import json # 创建SparkConf对象 conf = SparkConf().setAppName("Real-time Word Count") # 创建SparkContext对象 sc = SparkContext(conf=conf) # 创建StreamingContext对象,每隔5秒钟处理一次数据 ssc = StreamingContext(sc, 5) # 从Kafka读取数据 kafka_params = { "bootstrap.servers": "127.0.0.1:9092", "group.id": "example" } kafka_stream = KafkaUtils.createDirectStream( ssc, ["example"], kafka_params ) # 对Kafka中的每条消息进行解析并扁平化处理 messages = kafka_stream.map(lambda x: json.loads(x[1])) words = messages.flatMap(lambda x: x.values()) # 对每个单词进行计数 word_counts = words.map(lambda word: (word, 1)).reduceByKey(lambda a, b: a + b) # 打印计数结果 word_counts.pprint() # 启动StreamingContext并等待它完成 ssc.start() ssc.awaitTermination() ``` 上述代码中,首先创建了一个 `SparkConf` 对象,用于设置应用程序名称。然后创建了一个 `SparkContext` 对象,用于连接到 Spark 集群。接着,创建了一个 `StreamingContext` 对象,并设置每隔5秒钟处理一次数据。然后使用 `createDirectStream` 方法从 Kafka 主题中读取数据,并使用 `json.loads` 方法将 JSON 字符串转换为字典格式。接着,对字典中的值进行扁平化处理,并使用 `map` 和 `reduceByKey` 方法对每个单词进行计数。最后,使用 `pprint` 方法打印计数结果。最后启动 `StreamingContext` 并等待它完成。 运行上述代码后,您应该可以在终端看到类似以下的结果: ``` ------------------------------------------- Time: 2022-10-20 16:00:05 ------------------------------------------- (PySpark, 1) (Streaming, 1) (Hello, 1) (PySparkStreaming, 1) (World, 1) ------------------------------------------- Time: 2022-10-20 16:00:10 ------------------------------------------- (PySpark, 2) (Streaming, 1) (Hello, 2) (PySparkStreaming, 1) (World, 1) ``` 注意,以上代码仅提供了一个简单的示例,实际的 Canal 和 PySpark Streaming 应用程序可能需要更多的配置和代码来实现特定的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

章鱼哥TuNan&Z

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

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

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

打赏作者

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

抵扣说明:

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

余额充值