docker+canal+canal-admin监听mysql增删改操作-初体验(window版本)

操作系统:window10
Docker Server Version: 20.10.12
canal-serve:1.1.15
canal-admin:1.1.15
C# 目标框架:.NET 5 (这个应该低版本也没啥问题)
官方文档:https://www.bookstack.cn/read/canal-v1.1.4/e015ba3570152b7a.md


canal安装

此处跳过一般环境安装

# 安装canal-admin
# 管理地址是:127.0.0.1:8089 帐号密码:admin/123456。 如下命令中的密码应该是加入admin的帐号密码(猜测)
docker run -d -it -p 8089:8089  -e server.port=8089 -e canal.adminUser=admin -e canal.adminPasswd=admin --name=canal-admin -m 1024m canal/canal-admin:v1.1.5

# 安装canal-server
# 11111端口是canal客户端连接的端口; 下面canal.admin.manager的ip换成你局域网的ip
docker run -d -it -p 11111:11111 -e canal.admin.manager=10.8.0.5:8089 -e canal.admin.port=11110 -e canal.admin.user=admin -e canal.admin.passwd=4ACFE3202A5FF5CF467898FC58AAB1D615029441 --name=canal-server -m 2048m canal/canal-server:v1.1.5

完成上面步骤后,看下效果,看到server有一条记录,代表canal-server已经成功加入到了canal-admin
在这里插入图片描述

C# 代码

C#代码我直接粘贴了,有点丑,大家先别管,自己跑起来感受下然后自己修改把
参考: https://github.com/dotnetcore/CanalSharp

using CanalSharp.Connections;
using Microsoft.Extensions.Logging;
using System;
using System.Threading;
using System.Threading.Tasks;


using System.Collections.Generic;
using System.Linq;
using CanalSharp.Protocol;

namespace CanalTest
{
    class Program
    {
        static ILogger<SimpleCanalConnection> logger;
        static ILogger<SimpleCanalConnection> _logger;

        static async Task Main(string[] args)
        {
            var loggerFactory = LoggerFactory.Create(builder =>
            {
                builder
                    .AddFilter("Microsoft", LogLevel.Debug)
                    .AddFilter("System", LogLevel.Information);
                //builder.AddConsole();

            });
            logger = loggerFactory.CreateLogger<SimpleCanalConnection>();


            var conn = new SimpleCanalConnection(new SimpleCanalOptions("127.0.0.1", 11111, "22"), logger);
            //连接到 Canal Server
            await conn.ConnectAsync();


            //订阅
            await conn.SubscribeAsync();



            do
            {
                try
                {
                    var msg = await conn.GetAsync(1024);
                    PrintEntry(msg.Entries);
                    await Task.Delay(300);
                }
                catch (Exception ex)
                {
                    Thread.Sleep(5000);
                    Console.WriteLine(ex.Message);
                    //logger.LogError(ex, "异常");
                }
            } while (true);
        }



        private static void PrintEntry(List<Entry> entries)
        {
            foreach (var entry in entries)
            {
                if (entry.EntryType == EntryType.Transactionbegin || entry.EntryType == EntryType.Transactionend)
                {
                    continue;
                }

                RowChange rowChange = null;

                try
                {
                    rowChange = RowChange.Parser.ParseFrom(entry.StoreValue);
                }
                catch (Exception e)
                {
                    logger.LogError(e.ToString());
                }

                if (rowChange != null)
                {
                    EventType eventType = rowChange.EventType;

                    logger.LogInformation(
                        $"================> binlog[{entry.Header.LogfileName}:{entry.Header.LogfileOffset}] , name[{entry.Header.SchemaName},{entry.Header.TableName}] , eventType :{eventType}");

                    foreach (var rowData in rowChange.RowDatas)
                    {
                        if (eventType == EventType.Delete)
                        {
                            PrintColumn(rowData.BeforeColumns.ToList());
                        }
                        else if (eventType == EventType.Insert)
                        {
                            PrintColumn(rowData.AfterColumns.ToList());
                        }
                        else
                        {
                            logger.LogInformation("-------> before");
                            PrintColumn(rowData.BeforeColumns.ToList());
                            logger.LogInformation("-------> after");
                            PrintColumn(rowData.AfterColumns.ToList());
                        }
                    }
                }
            }
            static void PrintColumn(List<Column> columns)
            {
                foreach (var column in columns)
                {
                    Console.WriteLine($"{column.Name}{column.Value}  update=  {column.Updated}");
                }
            }
        }
    }
}

遇到的问题

CanalSharp.CanalConnectionException:“Received an error returned by the server: something goes wrong with channel:[id: 0x47ae2285, /172.17.0.1:56572 => /172.17.0.3:11111], exception=com.alibaba.otter.canal.server.exception.CanalServerException: destination:example should start first

这个问题是真的狗,canal概念也多,找了很多才知道要添加一个名为example的instance,其他名字不好使,修改canal.destinations都不好使
如图,保证example为启动状态,在连接就ok了
在这里插入图片描述

我体验到现在比较晚了,还有一个坑,tm的断开一下后不会自动重连,无语!

场景使用

前几天我在研究我两个库的数据如何放到一个查询页面,并且都能够搜索他,还能分页。找到个词语叫做聚合查询
第一个就是redis,发现我第一步就失败了,能分页不能搜索条件,能搜索条件玩不好分页,最后放弃了
然后就自己封装了一套规则,把变化数据传到mq,然后在每个缓存数据订阅变化,并且增量更新,但这个有一个地方就是每个cur的时候需要发送变化数据到mq,这可不得了,那个混蛋没有写这行代码,就要被客户叼了。
后面和就Java大佬聊了下,他果断给出了canal这个工具,经过两天研究发现挺好的,正好解决了我聚合查询缓存的增量更新问题,还不用太担心混蛋漏写代码

同步数据,这个老掉牙了,canal还有其他生态,可以直接同步数据到es,其他库啥的,不用编码

视频

canal演示

canal-补充

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值