canal1.1.8+mysql8.0+jdk17+redis的使用

文章目录

一、Canal

在工作中,我们常常会遇到同步MySQL数据到Redis的需求,我们也会有很多种方式去解决,常见的方式有如下几种

  • 业务操作中同步
  • 使用消息队列
  • 基于binlog方式

基于binlog方式

其中Mysql主从工作原理:

Mysql主从,根据2/8原则,80%的性能问题都在读上面,当我们数据库的读并发较大的时候,我们可以使用Mysql主从来分担读的压力。它的原理是所有的写操作在主库上,读操作在从库上,当然主库也可以承担读请求,而从库的数据则通过主库复制而来。

  • MySQL master 将数据变更写入二进制日志( binary log, 其中记录叫做二进制日志事件binary log events,可以通过 show binlog events 进行查看)
  • MySQL slave 将 master 的 binary log events 拷贝到它的中继日志(relay log)
  • MySQL slave 重放 relay log 中事件,将数据变更反映它自己的数据

主从复制步骤:

  1. 将Master的binary-log日志文件打开,mysql会把所有的DDL,DML,TCL写入BinaryLog日志文件中
  2. Master会生成一个 log dump 线程,用来给从库的 i/o线程传binlog
  3. 从库的i/o线程去请求主库的binlog,并将得到的binlog日志写到中继日志(relaylog)中
  4. 从库的sql线程,会读取relaylog文件中的日志,并解析成具体操作,通过主从的操作一致,而达到最终数据一致
  5. 而Canal的工作原理就是伪装成mysql的从库去获取Binlog中SQL语句再更新到Redis。

二、前期准备

2.1 检查MySQL是否开启binlog

binlog是二进制日志文件,用于记录mysql的数据变更,数据在恢复的时候binlog日志起着至关重要的作用

sql 复制代码
#cmd打开命令提示符
#输入该代码登录mysql
mysql -u root -p
#执行命令查看 binlog 状态 Value 为 ON,则表示 binlog 已开启
SHOW VARIABLES LIKE 'log_bin';
#执行命令查看 binlog 格式 如果 Value 为 ROW,则表示 binlog 格式为 ROW,这是 Canal 正常工
作所必需的格式
SHOW VARIABLES LIKE 'binlog_format';

若没有开启binlog,则需要进行配置,配置步骤如下:

找到my.ini文件,默认位置: C:\ProgramData\MySQL\MySQL Server 8.0

如果在安装MySQL时使用的是自定义安装,请看你安装位置的文件中的my.ini文件

bash 复制代码
#在mysqld下面添加
server_id=1918
log_bin = mysql-bin
binlog_format = ROW

重启MySQL服务,并查看是否开启binlog,查看方式同上

创建用户,方便后续测试

bash 复制代码
# 使用命令登录:mysql -u root -p 或 在客户端软件操作
# 创建用户 用户名:canal 密码:canal
# 注意:myql8.0版本的密码加密方式为caching_sha2_password,如果不做处理在canal连接时会提示连接不上或没有权限
# 所以我们修改为mysql_native_password
create user 'canal'@'%' IDENTIFIED WITH mysql_native_password BY 'canal';
# 授权 *.*表示所有库
grant SELECT, REPLICATION SLAVE, REPLICATION CLIENT on *.* to 'canal'@'%';
#刷新权限
FLUSH PRIVILEGES;

执行完上面的语句后查看所有用户

bash 复制代码
select * from mysql.user;

2.2 下载canal

Canal仓库地址 : https://github.com/alibaba/canal/releases

解压后文件目录:

2.2 修改Canal的配置文件

修改instance.properties

修改instance 配置文件 : conf/example/instance.properties

bash 复制代码
# 按需修改成自己的数据库信息
#################################################
canal.instance.master.address=127.0.0.1:3380
# username/password,数据库的用户名和密码
...
#刚才开通的mysql的账户密码
canal.instance.dbUsername = canal
canal.instance.dbPassword = canal

.......
# table regex 将canal.instance.filter.regex=.*\\..* 改为 canal.instance.filter.regex=canaldb\\..*
canal.instance.filter.regex=canaldb\\..*

...
#################################################
# mq config 数据同步到MQ中的topic名字
canal.mq.topic=canal.exchange
# 添加账号密码
canal.mq.username=guest
canal.mq.password=guest
# 针对库名或者表名发送动态topic
#canal.mq.dynamicTopic=mytest,.*,mytest.user,mytest\..*,.*\..*
canal.mq.partition=0
# hash partition config
#canal.mq.partitionsNum=3
#库名.表名: 唯一主键,多个表之间用逗号分隔
#canal.mq.partitionHash=mytest.person:id,mytest.role:id

修改canal.properties

修改canal 配置文件 conf/canal.properties

bash 复制代码
canal.ip = 0.0.0.0
# register ip to zookeeper
canal.register.ip = 127.0.0.1
# 添加下面这一条 确保实例加载配置正确(默认加载 conf 目录下的所有实例文件夹)
canal.destinations = example  

# ...
# 可选项: tcp(默认) tcp, kafka, rocketMQ, rabbitMQ
# 这里使用rabbitMQ
canal.serverMode = tcp
##################################################
######### RabbitMQ #############
##################################################
# rabbitMQ所在主机地址
rabbitmq.host = 127.0.0.1:5672
rabbitmq.virtual.host = /
# 交换机
rabbitmq.exchange = canal.exchange
# 用户名
rabbitmq.username = guest
# 密码
rabbitmq.password = guest
rabbitmq.deliveryMode =

修改startup.bat

修改bin/startup.bat

因为我们使用的Java17 版本过高,不再支持 -XX:PermSize参数。这个参数在 Java 8 及以后版本已被移除。

修改完毕后,启动canal,找到bin/startup.bat 启动canal

2.3 查看canal是否启动

注意:下面三步必须全对才算启动canal成功

  1. 查看logs\canal\canal.log日志是否最近修改时间是你启动的时间。
  2. 查看logs\example\example.log查看是否报错,可以按住Ctrl+F搜一下是否有ERROR,如果没有说明启动成功。
  3. 新打开命令行窗口执行netstat -ano | findstr :11111指令查看是否启动,如果出现以下情况说明启动成功。

2.4 RabbitMQ队列创建

添加交换机 canal.exchange

添加队列 canal.queue

队列绑定交换机

点进去队列

输入canal.exchangecanal.routing.key

三、SpringBoot项目中集成 Canal + RabbitMQ

创建项目

pom文件中引入依赖

xml 复制代码
<!-- Canal 协议依赖 -->
<dependency>
    <groupId>com.alibaba.otter</groupId>
    <artifactId>canal.protocol</artifactId>
    <version>1.1.6</version>
</dependency>

<!-- Canal 公共组件 -->
<dependency>
    <groupId>com.alibaba.otter</groupId>
    <artifactId>canal.common</artifactId>
    <version>1.1.6</version>
</dependency>

<!-- Canal 客户端依赖 -->
<dependency>
    <groupId>com.alibaba.otter</groupId>
    <artifactId>canal.client</artifactId>
    <version>1.1.6</version>
</dependency>

<!-- Spring Boot 核心启动器 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>

<!-- Redis  -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<!-- MySQL  -->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

<!-- 消息队列 AMQP 支持(如 RabbitMQ) -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

<!-- 阿里巴巴 FastJSON2 (JSON处理) -->
<dependency>
    <groupId>com.alibaba.fastjson2</groupId>
    <artifactId>fastjson2</artifactId>
    <version>2.0.31</version>
</dependency>

<!-- 测试依赖(解决 JUnit 和 Spring Boot Test 缺失问题) -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

yml配置

yml 复制代码
spring:
    # 数据库连接配置(Canal需要连接数据库获取binlog)
    datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3380/smbms?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowPublicKeyRetrieval=true&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8
        username: root  # 数据库用户名(需要有binlog权限)
        password: root  # 数据库密码
    rabbitmq:
        host: 127.0.0.1
        port: 5672
        username: guest
        password: guest
        virtual-host: /
    redis:
        host: 127.0.0.1
        port: 6379
        database: 0
        password: 123456

# Canal客户端配置(监听数据库binlog)
canal:
    client:
        instances:
            example:  # 实例名,可自定义
                host: 192.168.108.13  # Canal Server地址(如果是本地部署的Canal服务)
                port: 11111      # Canal默认端口
                username: canal  # Canal默认用户名
                password: canal  # Canal默认密码
                filter: smbms.*  # 监听的数据库表(格式:库名.表名,*表示所有表)
# 日志配置
logging:
    level:
        com.yak: DEBUG
        org.springframework.amqp: INFO
        com.alibaba.otter.canal: INFO  # 开启Canal日志,方便调试

CanalRabbitMQConsumer

java 复制代码
package com.hsh.canal.listen;

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
@Component
public class CanalRabbitMQConsumer {
    @Autowired
    private StringRedisTemplate redisTemplate;
    /**
     * 直接监听Canal通过RabbitMQ发送的消息
     * Canal会直接将binlog数据发送到配置的exchange中
     */
    @RabbitListener(queues = "canal.queues")
    public void processCanalMessage(String message) {
        System.out.println("收到CALAL数据: " + message);
        // 存储到Redis
        redisTemplate.opsForValue().set("canal:lastChange", message);
        System.out.println("已同步到Redis: " + message);
        // 这里可以添加具体的业务处理逻辑
        // 比如解析JSON、更新缓存、同步到其他系统等
    }
}

RabbitConfig

java 复制代码
package com.hsh.canal.config;

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitConfig {
    @Bean
    public Queue canalSyncQueue() {
        return new Queue("canal.queues", true);
    }
    @Bean
    public DirectExchange canalExchange() {
        return new DirectExchange("canal.exchange", true, false);
    }

    // 修改绑定,使用空路由键
    @Bean
    public Binding bindingCanalQueue(Queue canalSyncQueue, DirectExchange
            canalExchange) {
        return BindingBuilder.bind(canalSyncQueue)
                .to(canalExchange)
                .with(""); // 改为空路由键,匹配所有消息
    }
}

我这demo只要运行起来不报错说明canal能用,但是没有说canal怎么用,我会在另一篇帖子说明。

相关推荐
阿巴斯甜2 天前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker2 天前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95272 天前
Andorid Google 登录接入文档
android
黄林晴2 天前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab2 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿3 天前
Android MediaPlayer 笔记
android
Jony_3 天前
Android 启动优化方案
android
阿巴斯甜3 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇3 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_3 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android