前言
在前面章节中,我们写了一个canal c#版的客户端用来接受canal服务端发送过来的数据,但目前的客户端不完善,比如:不能断线重连、多个客户端代码重复等,因此,我们首先封装一个Helper类,代码如下:
class CanalHelper
{
/// <summary>
/// 启动
/// </summary>
/// <param name="simpleCanalOptions"></param>
/// <param name="e">收到数据的回调处理</param>
/// <returns></returns>
public static async Task StartAsync(SimpleCanalOptions simpleCanalOptions, Action<CanalEventArg> e)
{
//1.初始化日志
var loggerFactory = LoggerFactory.Create(builder =>
{
builder
.AddFilter("Microsoft", LogLevel.Debug)
.AddFilter("System", LogLevel.Information)
.AddConsole();
});
var logger = loggerFactory.CreateLogger<SimpleCanalConnection>();
SimpleCanalConnection conn = null;
try
{
//2.创建连接
conn = new SimpleCanalConnection(simpleCanalOptions, logger);
//连接到 Canal Server
await conn.ConnectAsync();
//订阅
await conn.SubscribeAsync();
new Thread(() =>
{
try
{
//3.获取数据
while (true)
{
var msg = conn.GetAsync(1024).Result;
if (msg.Entries.Count <= 0)
{
Thread.Sleep(1000);
continue;
}
foreach (var entry in msg.Entries)
{
//不处理事务标记
if (entry.EntryType == EntryType.Transactionbegin || entry.EntryType == EntryType.Transactionend)
{
continue;
}
RowChange rowChange = RowChange.Parser.ParseFrom(entry.StoreValue);
foreach (var rowData in rowChange.RowDatas)
{
if (e != null)
{
e.Invoke(new CanalEventArg()
{
DatabaseName = entry.Header.SchemaName,
TableName = entry.Header.TableName,
BeforeColumns = rowData.BeforeColumns.ToList(),
AfterColumns = rowData.AfterColumns.ToList()
});
}
}
}
}
}
catch (Exception ex)
{
if (conn != null)
{
conn.DisposeAsync().GetAwaiter();
}
logger.LogError(ex, "读取canal server数据失败");
Thread.Sleep(5000);
//重连
StartAsync(simpleCanalOptions, e).Wait();
}
}).Start();
}
catch (Exception ex)
{
if (conn != null)
{
await conn.DisposeAsync();
}
logger.LogError(ex, "连接canal server端失败");
Thread.Sleep(5000);
//重连
await StartAsync(simpleCanalOptions, e);
}
}
public class CanalEventArg
{
/// <summary>
/// 数据库名称
/// </summary>
public string DatabaseName { get; set; }
/// <summary>
/// 表名
/// </summary>
public string TableName { get; set; }
/// <summary>
/// 变化之前的数据
/// </summary>
public List<Column> BeforeColumns { get; set; }
/// <summary>
/// 变化之后数据
/// </summary>
public List<Column> AfterColumns { get; set; }
}
}
在main方法中添加以下代码
await CanalHelper.StartAsync(new SimpleCanalOptions("127.0.0.1", 11111, "1234"), (e) =>
{
});
Console.ReadKey();//阻止客户端退出
多数据库实例配置
多数据库实例配置主要分为以下两种情况:
- 多个数据库之间没有任何联系(垂直分库)
- 分库分表(多个数据库是一个逻辑库,水平分库)
垂直分库配置:
主要配置项在canal.properties中destinations配置节中
canal.destinations:当前server上部署的instance列表,多个用英文逗号隔开
canal.conf.dir:instance配置文件所在的路径
canal.auto.scan:是否开启自动扫描,true为开启
canal.auto.scan.interval:自动扫描的间隔时间,单位秒
由以上可知,我们可以先启动canal服务,然后动态添加instance配置,我们先启动canal服务
接着再启动三个客户端,分别监控本地端口为3306、3307、3308三个数据库实例,代码如下
static async Task Main(string[] args)
{
await CanalHelper.StartAsync(new SimpleCanalOptions("127.0.0.1", 11111, "1234"), (e) =>//Destination默认为example
{
});
await CanalHelper.StartAsync(new SimpleCanalOptions("127.0.0.1", 11111, "1235") { Destination = "example1" }, (e) =>
{
});
await CanalHelper.StartAsync(new SimpleCanalOptions("127.0.0.1", 11111, "1236") { Destination = "example2" }, (e) =>
{
});
Console.ReadKey();//阻止客户端退出
}
在conf目录下分别创建两个文件夹example1和example2,并且复制example中的instance.properties文件,并将监听的数据库信息修改好
example1:
example2:
接着依次修改3306、3307、3308中的数据,则对应的客户端就会收到修改的数据
3306:
3307:
3308:
水平分库(分库分表)配置
在上一章节中就有介绍到group-instance.xml文件专门用于分库分表场景,为了更好的演示,我们将前面配置的exmaple2和example3实例删除
- 首先需要调整group-instance.xml文件中的模板
打开conf/spring/group-instance.xml文件
默认的模板中配置了两主两从的分库分表配置模板,但是我们目前有三个实例(三个分库),所以需要再复制一组
- 添加一个eventParse
- 拷贝一组eventParse的bean节点,并命名为eventParse3
- 修改以下配置项
group-instance.xml文件修改完后保存,接着再修改example的instance.properties文件,添加以下配置:
canal.instance.master1.address=127.0.0.1:3306
canal.instance.master1.journal.name=
canal.instance.master1.position=
canal.instance.master1.timestamp=
canal.instance.master1.gtid=
canal.instance.master2.address=127.0.0.1:3307
canal.instance.master2.journal.name=
canal.instance.master2.position=
canal.instance.master2.timestamp=
canal.instance.master2.gtid=
canal.instance.master3.address=127.0.0.1:3308
canal.instance.master3.journal.name=
canal.instance.master3.position=
canal.instance.master3.timestamp=
canal.instance.master3.gtid=
再次启动canle服务端和客户端并修改三个数据库实例即可