docker安装并使用阿里巴巴Canal(含安装MySQL、开启binlog、Java代码、填坑经验)

一、安装MySQL

MySQL的安装可参考本人博客:docker安装mysql

建议将配置文件挂载在本地,方便后续修改,请参考文中方式二。
在这里插入图片描述

二、开启MySQL binlog日志并注册账户

1、查看是否已经开启binlog

	show variables like 'log_bin';

在这里插入图片描述

2、开启binlog日志

通过第一步安装MySQL时,已经将配置文件挂载在了本地,在配置文件中新增以下内容,让重启MySQL

# server_id不重复即可,不要和canal的slaveId重复
server_id=1
# 开启binlog
log_bin = mysql-bin
# 选择row模式
binlog_format = ROW
# 可根据个人情况选择,可以指定数据库开启binlog 若不写默认所有数据库均开启
# binlog-do-db=
# 例如只开启test1、test2、test3数据库binlog
# binlog-do-db=test1
# binlog-do-db=test2
# binlog-do-db=test3

binlog三种模式说明

  • statement【语句级】
    binlog会记录每一次执行写操作的语句
    优点:节省空间 例:批量操作:通过性别批量更新姓名,只会记录一条语句
    缺点:有可能造成数据不一致 例如:语句中存在UUID() now() 随机数等函数,使用binlog恢复数据时,会产生不一样的数据
  • row【行级】
    binlog会记录每次操作后每行的变化
    优点:保证数据的绝对一致性
    缺点:占用空间大
  • mixed【混合日志记录】
    默认是【statement】模式,特殊情况时会使用row模式(包含UUID、自增[auto_increment]等)
    优点:节省空间,同时兼顾了一定的一致性
    缺点:还有极个别情况依旧会造成不一致

对于配置文件在本人博客【解决MySQL分组查询时SELECT list is not in GROUP BY。。。】中有过简单说明,发现配置文件在mysql.conf.d/mysqld.cnf,并非my.cnf,有可能是安装方式或MySQL版本不同配置文件地址应该不同,此处不做深层次研究。

在这里插入图片描述
重启MySQL后显示binlog已开启
在这里插入图片描述

3、注册账户

新建用户用于canal订阅binlog使用,可以进入docker容器操作 也可以直接在Navicat中操作

# 新建用户 用户名:canal  密码:canal 
CREATE USER canal IDENTIFIED by 'canal';
# 授权
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';
# 刷新MySQL的系统权限相关表
FLUSH PRIVILEGES;

方式一:在Navicat中操作
在这里插入图片描述

在这里插入图片描述
方式二:进入docker容器操作

# 8a069c3081f6为MySQL的容器ID
docker exec -it 8a069c3081f6 /bin/bash
# 已root权限进入 然后输入密码即可
mysql -u root -p

在这里插入图片描述

三、docker安装canal

1、 先在Docker Hub中下载canal-server镜像

	docker pull canal/canal-server:latest

2、 先启动Canal,用于复制properties配置文件

	docker run -p 11111:11111 --name canal -d canal/canal-server:latest

3、 初次启动Canal镜像后,将instance.properties文件复制到宿主机,用于后续挂载使用

	# de91f4226e27 容器ID
	# /home/admin/canal-server/conf/example/instance.properties 容器中properties配置文件地址
	# /mydata/canal/conf/ 宿主机的位置,按照个人配置即可
	docker cp de91f4226e27:/home/admin/canal-server/conf/example/instance.properties  /mydata/canal/conf/

4、 修改instance.properties

在这里插入图片描述

5、 删除旧的canal容器、再创建新容器(使用挂载)

删除旧的canal容器

	docker rm 旧的canal容器ID或者名称
	# -v 本地的instance.properties:容器的instance.properties  将容器的instance.properties配置文件挂载到宿主机,方便后续变更
	docker run -p 11111:11111 --name canal -v /mydata/canal/conf/instance.properties:/home/admin/canal-server/conf/example/instance.properties -d canal/canal-server:latest

至此,Canal就可以使用了,后续若需要更改instance.properties,只要在宿主机修改后重启docker容器即可。

四、Java测试代码

下载的canal为最新的版本(1.1.5),所以导包也采用(1.1.5)

 		<dependency>
            <groupId>com.alibaba.otter</groupId>
            <artifactId>canal.client</artifactId>
            <version>1.1.5</version>
        </dependency>

        <!-- Message、CanalEntry.Entry等来自此安装包 -->
        <dependency>
            <groupId>com.alibaba.otter</groupId>
            <artifactId>canal.protocol</artifactId>
            <version>1.1.5</version>
        </dependency>
import com.alibaba.otter.canal.client.CanalConnector;
import com.alibaba.otter.canal.client.CanalConnectors;
import com.alibaba.otter.canal.protocol.CanalEntry;
import com.alibaba.otter.canal.protocol.Message;
import com.google.protobuf.InvalidProtocolBufferException;

import java.net.InetSocketAddress;
import java.util.List;

public class PbsAssetMapTest {

    //Canal服务地址
    private static final String SERVER_ADDRESS = "172.16.234.150";

    //Canal Server 服务端口号
    private static final Integer PORT = 11111;

    //目的地,其实Canal Service内部有一个队列,和配置文件中一致即可,参考【修改instance.properties】图中
    private static final String DESTINATION = "example";

    //用户名和密码,但是目前不支持,只能为空
    private static final String USERNAME = "";

    //用户名和密码,但是目前不支持,只能为空
    private static final String PASSWORD= "";

    public static void main(String[] args){
        CanalConnector canalConnector = CanalConnectors.newSingleConnector(new InetSocketAddress(SERVER_ADDRESS, PORT), DESTINATION, USERNAME, PASSWORD);
        canalConnector.connect();
        //订阅所有消息
        canalConnector.subscribe(".*\\..*");
        // canalConnector.subscribe("test1.*"); 只订阅test1数据库下的所有表
        //恢复到之前同步的那个位置
        canalConnector.rollback();

        for(;;){
            //获取指定数量的数据,但是不做确认标记,下一次取还会取到这些信息。 注:不会阻塞,若不够100,则有多少返回多少
            Message message = canalConnector.getWithoutAck(100);
            //获取消息id
            long batchId = message.getId();
            if(batchId != -1){
                System.out.println("msgId -> " + batchId);
                printEnity(message.getEntries());
                //提交确认
                //canalConnector.ack(batchId);
                //处理失败,回滚数据
                //canalConnector.rollback(batchId);
            }
        }
    }

    private static void printEnity(List<CanalEntry.Entry> entries) {
        for (CanalEntry.Entry entry : entries) {
            if(entry.getEntryType() != CanalEntry.EntryType.ROWDATA){
                continue;
            }
            try{
            	// 序列化数据
                CanalEntry.RowChange rowChange = CanalEntry.RowChange.parseFrom(entry.getStoreValue());
                for (CanalEntry.RowData rowData : rowChange.getRowDatasList()) {
                    System.out.println(rowChange.getEventType());
                    switch (rowChange.getEventType()){
                        //如果希望监听多种事件,可以手动增加case
                        case INSERT:
                        	// 表名
                            String tableName = entry.getHeader().getTableName();
                            //System.out.println("表名:"+tableName);
                            //测试users表进行映射处
                            List<CanalEntry.Column> afterColumnsList = rowData.getAfterColumnsList();
							//for(CanalEntry.Column c:afterColumnsList){
							//	System.out.println("字段:"+c.getName()+"值:"+c.getValue());
							//}

                            System.out.println(afterColumnsList);
                            break;
                        case UPDATE:
                            List<CanalEntry.Column> afterColumnsList2 = rowData.getAfterColumnsList();
                            System.out.println("新插入的数据是:" + afterColumnsList2);
                            break;
                        case DELETE:
                            List<CanalEntry.Column> beforeColumnsList = rowData.getBeforeColumnsList();
                            System.out.println("被删除的数据是:" + beforeColumnsList);
                            break;
                        default:
                    }
                }
            } catch (InvalidProtocolBufferException e) {
                e.printStackTrace();
            }
        }
    }
}

截止此处,整个canal的搭建和使用就结束了。
启动Java程序,修改数据库的值即可看到日志。
在这里插入图片描述

五、填坑经验

运行Java程序后、修改数据库,并未发现有任何日志输出。只存在以下日志:
在这里插入图片描述
看到此日志说明Java程序已经连接上了canal,但是修改数据库后没有任何日志输出。
问题一: 是否为binlog问题
若按照文中配置,应该不会是binlog问题导致的

  1. 查询binlog是否开启
 show variables like 'log_bin';
  1. 查询是否生成binlog日志

查看当前正在写入的binlog文件

show master status;

查看指定binlog文件的内容

show binlog events in 'mysql-bin.000002';

更新数据库再次查询【查看指定binlog文件的内容】,即可看到刚才生成的binlog日志明细

其他命令:

查询binlog文件列表

show binary logs;

只查看第一个binlog文件的内容

show binlog events;

问题二: canal连接数据库问题

1、查看canal容器启动日志 docker logs -f 容器ID或名称
发现启动日志并没发现有啥问题
在这里插入图片描述
2、进入canal容器,查询日志
进入docker容器

# 29326e3b6c5d canal容器ID
docker exec -it 29326e3b6c5d /bin/bash
# 进入文件夹
cd canal-server/logs/example/
# 查看历史记录 实时记录可以使用【tail -f example.log】
tail -100 example.log

发现日志存在连接数据库异常【No route to host (Host unreachable)】
在这里插入图片描述
经查看应该是防火墙没有关闭导致的

# 查询防火墙
systemctl status firewalld
# 临时关闭
systemctl stop firewalld
#永久关闭,即设置开机的时候不自动启动
systemctl disable firewalld 

关闭防火墙后,发现日志请求就正常了,Java控制台也可以监听到日志了

  • 12
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
使用Docker安装MySQL5.7可以按照以下步骤进行操作。 1. 首先,拉取MySQL5.7镜像。你可以使用以下命令下载最新版本的MySQL5.7镜像: ``` docker pull mysql:5.7 ``` 如果你想下载指定版本的MySQL5.7,可以使用命令: ``` docker pull mysql:5.7.34 ``` 2. 创建宿主机的数据、配置和日志目录。你可以使用以下命令创建相应的目录: ``` mkdir -p /usr/local/docker_data/mysql/data mkdir -p /usr/local/docker_data/mysql/conf/conf.d mkdir -p /usr/local/docker_data/mysql/conf/mysql.conf.d mkdir -p /usr/local/docker_data/mysql/logs ``` 3. 运行MySQL容器。你可以使用以下命令来启动一个名为mysql5.7的容器,并将宿主机的目录挂载到容器中: ``` docker run --name mysql5.7 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d -v /usr/local/docker_data/mysql/data:/var/lib/mysql -v /usr/local/docker_data/mysql/conf:/etc/mysql/ -v /usr/local/docker_data/mysql/logs:/var/log/mysql mysql:5.7 ``` 在CentOS 7上,如果目录挂载失败,你可以添加`--privileged=true`参数给容器,让容器拥有真正的root权限: ``` docker run --privileged=true --name mysql5.7 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d -v /usr/local/docker_data/mysql/data:/var/lib/mysql -v /usr/local/docker_data/mysql/conf:/etc/mysql/ -v /usr/local/docker_data/mysql/logs:/var/log/mysql mysql:5.7 ``` 这样,你就成功地使用Docker安装并运行了MySQL5.7数据库。你可以使用Navicat或其他工具连接到MySQL数据库进行开发和管理。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Docker安装MySQL5.7和8](https://download.csdn.net/download/weixin_38627769/14886408)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Docker 安装MySQL 5.7(超详细文图说明及MySQL配置)](https://blog.csdn.net/weixin_43956484/article/details/116499061)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值