使用Maxwell 和 RabbitMQ监听MySQL BinLog
最近要做一个运营管理新系统,要求把原来的一些旧的子系统的数据(MySQL)抽取出来放到数据中心,并要求把子系统的增量数据实时同步到数据中心;一听这需求觉得一次性同步倒不是很难,难就是难在增量数据要实时同步;数据库这块本来就不是强项,加上是刚开始用MySQL所以一下子想不出什么好的解决方案。
经过Google一个上午终于找到了一个自己觉得可行的方案,使用Maxwell来监听MySQL的BinLog文件。Maxwell的具体介绍请参考 https://blog.csdn.net/wwwdc1012/article/details/88388552。这里主要记录下在本机搭建环境时遇到的一些问题。
先说下本机环境:
Docker Desktop: Linux Containers
MySQL: 安装在 Docker Desktop里面;
RabbitMQ: 安装在Docker Desktop里面;
同样的Maxwell也将安装在 Docker Desktop里
docker pull zendesk/maxwell
开启MySQL的 BinLog:
在Powershell 使用 docker ps 查看 mysql的容器ID或者容器名字
使用 docker exec -it 容器名/容器ID /bin/bash 进入到MySQL容器
登录 MySQL: mysql -u root -h 127.0.0.1 -p
执行以下命令开启MySQL的BinLog:
mysql> set global binlog_format=ROW; mysql> set global binlog_row_image=FULL;
将Maxwell连接到MySQL:
docker run -ti --rm zendesk/maxwell bin/maxwell --user='root' --password='123456' --host='172.17.0.2' --producer=stdout
--user: mysql 登录用户名
--password: mysql 登录密码
--host: mysql 服务IP
--producer: maxwell 输出方式, 默认为stdout:控制台输出
--port: mysql的端口, 默认为3306
这里特别强调下,因为我这里都是用docker 来安装的所以每个应用都会有一个独立的容器,刚开始的时候没有考虑到这点 --host 使用了 127.0.0.1 就一直失败;所以这里不能使用127.0.0.1或者localhost,只能使用容器IP,如果做了映射也可以用你本机的IP。
以下是连接成功
当我们对数据库做增、删、改时控制台输出如下
接下来将把这个输出,输出到RabbitMQ:
docker run -ti --rm zendesk/maxwell bin/maxwell --user='root' --password='123456' --host='172.17.0.2' --producer=rabbitmq --rabbitmq_user='guest' --rabbitmq_pass='guest' --rabbitmq_host='172.17.0.3' --rabbitmq_port='5672' --rabbitmq_exchange='databaselogs' --rabbitmq_exchange_type='fanout'
--producer改为 rabbitmq;
--rabbitmq_user: mq登录名;
--rabbitmq_pass: mq登录密码;
--rabbitmq_host: mq服务器地址,我这里的172.17.0.3 为mq的容器IP, 也可以写本机的IP, 也不能使用 localhost和127.0.0.1
--rabbitmq_port: mq端口;
--rabbitmq_exchange: mq交换器名称,这里可以自定义,只要跟后台的程序一致就行了;
--rabbitmq_exchange_type: mq交换类型;
后台接收代码:
var factory = new ConnectionFactory() { HostName = "localhost", UserName= "guest", Password= "guest" , Port= 5672 }; using (var connection = factory.CreateConnection()) using (var channel = connection.CreateModel()) {
// 这里的 exchange 要跟前面命令一致 channel.ExchangeDeclare(exchange: "databaselogs", type: "fanout"); channel.QueueBind(queue: "task_queue", exchange: "databaselogs", routingKey: ""); //channel.QueueDeclare(queue: "task_queue", // durable: true, // exclusive: false, // autoDelete: false, // arguments: null); channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false); Console.WriteLine(" [*] Waiting for messages."); var consumer = new EventingBasicConsumer(channel); consumer.Received += (model, ea) => { var body = ea.Body; var message = Encoding.UTF8.GetString(body); Console.WriteLine(" [x] Received {0}", message); Console.WriteLine(" [x] Done"); channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false); }; channel.BasicConsume(queue: "task_queue", autoAck: false, consumer: consumer); Console.WriteLine(" Press [enter] to exit."); Console.ReadLine();
控制台输出如下: