网上看了很多cdc的方案,说实在的,flink也不好弄,主要是驱动。
flink sql中的方案,好不容易弄到了所有的驱动,结果,字段非常难搞,例如uuid对应flink的String,结果执行flink sql的时候,字段类型不对。导入布尔值的时候,提示true不合法,哎,也是醉了!
换一个方法,flink-cdc,按网上的配置弄好了,结果,提示找不到驱动,sqlserver都没有。
用java写?很直白说,我不会!
于是暂时放弃所有flink的方法,用net6写了一个搬运工具,这个搬运工具有个缺陷,只能用mergaTree!这个东东从官方文档说,排序有点慢,感觉是很慢,非常慢!没关系,先摸索一下,主要是说说这个工具的思路。
sqlserver好几个表都是千万级的,只是7天的部分数据,试试水。
总体方法:sqlserver->IDataReader->queue->bulk insert->clickhouse
不要尝试一次性把数据从sqlserver中读出来再写到目标库,这个方案是最不可接受的:
第一:读取千万数据级的表,需要的时间不少,返回结果后,内存爆了!
第二:浪费大量的时间读取数据,即使硬件支撑得起,时间也等不起!
dataReader设置每1000条记录就返回一个结果列表
protected override (IEnumerable<object[]>, int Length) GetRows(string table, int count)
{
var list = new object[count][];
var i = 0;
var _reader = GetDatabaseReader(table);
if(_reader == null)
return (new object[0][], 0);
while (_reader.Read())
{
object[] data = new object[_reader.FieldCount];
_reader.GetValues(data);
list[i] = data;
i++;
if (i >= count)
{
break;
}
}
return (list, i);
}
这里的reader是在读取完一个表之前,都是要保持的,通过GetDatabaseReader方法从内存中获取出来。list对象就是每次读取的数据包。
定义一个队列
var queue = new Queue<object[][]>();
每读一个包,就往队列中推,这样就形成一个完整的数据队列。
注意的是,用多线程来执行GetRows方法,并没有什么用,速度不会快起来,于是就只用了单线程获取数据。
写入数据,驱动用的是clickhouse.client,nuget安装即可。文档也很清楚了,用bulk方法,支持object[]这样的数据,也支持DataTable对象。
用多线程从queue获取数据包,然后写入到ck,注意一下,有时候写入速度慢,例如网络,线程调度不优等各方面的问题,防止队列中的数据包过多占用内存,每次获取包的时候,如果队列数量大于5个包,就暂停一下获取数据,实际上,3个线程写一个线程读,是不会出现等待的情况的。
quue对象不需要线程安全,不会出问题的,放心。
其实数据库之间迁移数据,最麻烦的就是字段类型的对应,所以需要建立一个映射对应表,理论上,把这个逻辑优化一下,大部分数据库的迁移都是可以的,只是驱动和字段不一样而已。
这个工具写了两天,迁移了4个数据库,没报错,基本是一次成功,还是有点小满足的,有数据就可以玩一下clickhouse了,体验一下高速的查询。
但是,还是要研究一下flink-cdc,否则自己写也很麻烦,主要是有点懒,呵呵,谁给个线程的库让我玩转flink-cdc,其实最理想的还是想sqlserver->flink cdc->rabbitmq->clickhouse,虽然同步会慢一点,但是这样更加灵活,可以同步到多个数据库中,中间环节用json传输。但是,也没搞定,flink官方的rabbitmq库不知道怎么用。