
实战|Flink不支持分库分表的改造之路(一)
大家好,我是威哥,《RocketMQ技术内幕》作者、RocketMQ社区首席布道师、中通快递基础架构资深架构师,越努力越幸运,唯有坚持不懈,与大家共勉。
1、背景
在flink提供的jdbc-connector中只支持单表的数据同步,但随着业务量的增大,单表记录数过多,会导致数据查询效率降低。
为了解决单表存在的性能瓶颈,会采用分库分表。例如将订单表order拆分为1024张分表:order -> order_0000~order_1023。
显然官方默认提供的flink jdbc插件并不适用这种情况,需要我们将会对flink插件进行改造,从而支持分库分表的数据同步。
2、技术方案
2.1 flink-jdbc-connector简介
我们在创建flink jdbc同步作业时,一般是通过下面的来声明一个table。
并且提供了可选配置,可以针对一个sql在指定数据固定范围内(scan.partition.lower-bound,scan.partition.upper-bound)根据拆分字段(scan.partition.column)和数量(scan.partition.num),将sql进行等步长拆分。
可选配置如下:
例如我们预估需要通过1000条订单数据,如果不做拆分,基于flink sql的同步语句如下:
如果按照id拆分成两个子任务,则sql语句如下:
上面只是为了方便举例,在真实的生产环境,同步订单表都是千万级别,将一条大SQL拆分成小任务,一方面可以减少对数据表的锁操作,降低对源端数据库的压力,另一方面可以结合flink配置的并发度,并发同步数据,增大同步效率。
基于flink-jdbc-connector数据拆分的原理如下图所示:
2.2 数据分库分表原理探究与技术方案
flink-jdbc-connector数据拆分属性原理如下:
在flink-jdbc-connector包中提供了JdbcParameterValuesProvider接口,被JdbcInputFormat用来计算要运行的并行查询列表(即拆分)。
每个查询将使用由每个JdbcParameterValuesProvider实现提供的矩阵行进行参数化。
其中getParameterValues()的返回值:Serializable[x][y] ,x值即为SQL拆分的数据,每个x对应的y个元素的一维数组,包含的是每个sql的变量信息,例如上述根据id进行拆分数量为2。
第一个关键点Serializable[][]的二维数组结构为:
SQL模版语句如下:
那么对于分表来说,其变量相当于又增加了一个table_name,这样我们只需要改动两个地方,就可以实现分表的效果:
在构建Serializable [] [] 时,新增维度:table_name,其结构如下:
对应SQL的模版为:
在分表的基础上继续再推导,例如如果实现2库(10.1.1.2、10.1.1.2),4个schema(order_00~order_03),1024张表,最终拆解如下:
Serializable [] [] 存储数据格式为:
对应的SQL模版如下:
文章转自公众号:中间件兴趣圈
