基于 Flink 实现解决数据库分库分表任务拆分

简介: 基于 Flink 实现解决数据库分库分表任务拆分

1、场景描述


例如订单库进行了分库分表,其示例如下图所示:

e01363e4e52f4ae4ad54ab577cfc004f.png

现在的需求是希望创建一个任务就将数据同步到MQ集群,而不是为每一个数据库实例单独创建一个任务,将其数据导入到MQ集群,因为同步任务除了库不同之外,表的结构、数据映射规则都是一致的。


2、flinkx 的解决方案详解


2.1 fink Stream API 开发基本流程


使用 Flink Stream API 编程的通用步骤如下图所示:


18a0f132917828f59f1e9985691f1c4a.png

温馨提示:有关 Stream API 的详细内容将在后续的文章中展开,本文主要是关注 InputFormatSourceFunction,重点关注数据源的拆分。


2.2 flinkx Reader(数据源)核心类图


c2afa1885a0febbaced8e382666a0292.png

在 flinkx 中将不同的数据源封装成一个个 Reader,其基类为 BaseDataReader,上图中主要罗列了如下几个关键的类体系:


  • InputFormat
    flink 核心API,主要是对输入源进行数据切分、读取数据的抽象,其核心接口说明如下:
  • void configure(Configuration parameters)
    对输入源进行额外的配置,该方法在 Input 的生命周期中只需调用一次。
    BaseStatistics getStatistics(BaseStatistics cachedStatistics)
    返回 input 的统计数据,如果不需要统计,在实现的时候可以直接返回 null。
    T[] createInputSplits(int minNumSplits)
    对输入数据进行数据切片,使之支持并行处理,数据切片相关类体系见:InputSplit。
    InputSplitAssigner getInputSplitAssigner(T[] inputSplits)
    获取 InputSplit 分配器,主要是在具体执行任务时如何获取下一个 InputSplit,其声明如下图所示:
    101a1966b41febe194bf72aa95237f89.png

void open(T split)

根据指定的数据分片 (InputSplit) 打开数据通道。为了加深对该方法的理解,下面看一下 Flinkx 关于 jdbc、es 的写入示例:


da253530e78dc52f0434ea62d15f4b5f.png

  • boolean reachedEnd()
    数据是否已结束,在 Flink 中通常 InputFormat 的数据源通常表示有界数据 (DataSet)。
  • OT nextRecord(OT reuse)
    从通道中获取下一条记录。
  • void close()
    关闭。
  • InputSplit
    数据分片根接口,只定义了如下方法:
  • int getSplitNumber()
    获取当前分片所在所有分片中的序号。
    本文先简单介绍一下其通用实现子类:GenericInputSplit。
  • int partitionNumber
    当前 split 所在的序号
  • int totalNumberOfPartitions
    总分片数
    为了方便理解我们可以思考一下如下场景,对于一个数据量超过千万级别的表,在进行数据切分时可以考虑使用10个线程,即切割成 10分,那每一个数据线程查询数据时可以 id % totalNumberOfPartitions = partitionNumber,进行数据读取。
  • SourceFunction
    Flink 源的抽象定义。
  • RichFunction
    富函数,定义了生命周期、可获取运行时环境上下文。
  • ParallelSourceFunction
    支持并行的 source function。
  • RichParallelSourceFunction
    并行的富函数
  • InputFormatSourceFunction
    Flink 默认提供的 RichParallelSourceFunction 实现类,可以当成是RichParallelSourceFunction 的通用写法,其内部的数据读取逻辑由 InputFormat 实现。
  • BaseDataReader
    flinkx 数据读取基类,在 flinkx 中将所有的数据读取源封装成 Reader 。


2.3 flinkx Reader构建 DataStream 流程


经过了上面类图的梳理,大家应该 flink 中提到的上述类的含义有了一个大概的理解,但如何运用呢?接下来将通过查阅 flinkx 的 DistributedJdbcDataReader(BaseDataReader的子类)的 readData 调用流程,体会一下其使用方法。

3125d56092bd541e793476bc81facdfb.png

基本遵循创建 InputFormat、从而创建对应的 SourceFunction,然后通过 StreamExecutionEnvironment 的 addSource 方法将 SourceFunction 创建对应的 DataStreamSource。


2.4 flinkx 针对数据库分库分表任务拆分解决方案


正如本文开头部分的场景描述那样,某订单系统被设计成4库8表,每一个库(Schema)中包含2个表,如何提高数据导出的性能呢,如何提高数据的抽取性能呢?通常的解决方案如下:


  1. 首先按库按表进行拆分,即4库8表,可以进行切分8份,每一个数据分配处理一个实例中的1个表。
  2. 单个表的数据抽取再进行拆分,例如按ID进行取模进一步分解。


flinkx 就是采取上面的策略,我们来看一下其具体做法。


f20cc2fcc035efe4ae15a54f268fd527.png

Step1:首先先根据数据库实例、表进行拆分,按表维度组织成一个 DataSource 列表,后续将基于这个原始数据执行拆分算法。


接下来具体的任务拆分在 InputFormat 中实现,本实例在 DistributedJdbcInputFormat 的 createInputSplitsInternal 中。

5e5596b8e22506e40eb842bb5b499d3b.png


Step2:根据分区创建 inputSplit 数组,这里分区的概念就相当于上文提到方案中的第一条。

268a74b66800d47df782d8bf3889fcfb.png

Step3:如果指定了 splitKey 的任务拆分算法,首先 DistributedJdbcInputSplit 继承自 GenericInputSplit,总分区数为 numPartitions,然后生成数据库的参数,这里主要是生成 SQL Where 语句中的 splitKey mod totalNumberOfPartitions = partitionNumber,其中 splitKey 为分片键,例如 id,而 totalNumberOfPartitions 表示分区总数,partitionNumber 表示当前分片的序号,通过 SQL 取模函数进行数据拆分。

0876316644a7c2cc12c24423f4b6fbd1.png

Step4:如果未指定表级别的数据拆分键,则拆分策略是对 sourceList 进行拆分,即一些分区处理其中几个表。


关于 flinkx 中关于任务切分的介绍就到这里了。


3、总结


本文主要是基于 flinkx 介绍 MySQL 分库分表情况下如何基于 flink 进行任务切分,简单介绍了 Flink 中关于基本的编程范式、InputFormat、SourceFunction 的基本类体系。


温馨提示:本文并没有太详细对 Flink API 进行深入研究,后续会单独对 Flink 内容进行逐一剖析,但 Flink 系列的文章组织,其文章的组织并不具备顺序性,笔者会在不断实践 Flink 的过程中对 FLink 进行剖析。

相关实践学习
基于Hologres+Flink搭建GitHub实时数据大屏
通过使用Flink、Hologres构建实时数仓,并通过Hologres对接BI分析工具(以DataV为例),实现海量数据实时分析.
实时计算 Flink 实战课程
如何使用实时计算 Flink 搞定数据处理难题?实时计算 Flink 极客训练营产品、技术专家齐上阵,从开源 Flink功能介绍到实时计算 Flink 优势详解,现场实操,5天即可上手! 欢迎开通实时计算 Flink 版: https://cn.aliyun.com/product/bigdata/sc Flink Forward Asia 介绍: Flink Forward 是由 Apache 官方授权,Apache Flink Community China 支持的会议,通过参会不仅可以了解到 Flink 社区的最新动态和发展计划,还可以了解到国内外一线大厂围绕 Flink 生态的生产实践经验,是 Flink 开发者和使用者不可错过的盛会。 去年经过品牌升级后的 Flink Forward Asia 吸引了超过2000人线下参与,一举成为国内最大的 Apache 顶级项目会议。结合2020年的特殊情况,Flink Forward Asia 2020 将在12月26日以线上峰会的形式与大家见面。
相关文章
|
SQL 运维 Java
蚂蚁 Flink 实时计算编译任务 Koupleless 架构改造
本文介绍了对Flink实时计算编译任务的Koupleless架构改造。为解决进程模型带来的响应慢、资源消耗大等问题,团队将进程模型改为线程模型,并借助Koupleless的类加载隔离能力实现版本和包的隔离。通过动态装配Plugin及其Classpath,以及Biz运行时仅对依赖Plugin可见的设计,大幅优化了编译任务的性能。结果表明,新架构使编译耗时降低50%,吞吐量提升5倍以上。
蚂蚁 Flink 实时计算编译任务 Koupleless 架构改造
|
前端开发 Java 关系型数据库
基于ssm的社区物业管理系统,附源码+数据库+论文+任务书
社区物业管理系统采用B/S架构,基于Java语言开发,使用MySQL数据库。系统涵盖个人中心、用户管理、楼盘管理、收费管理、停车登记、报修与投诉管理等功能模块,方便管理员及用户操作。前端采用Vue、HTML、JavaScript等技术,后端使用SSM框架。系统支持远程安装调试,确保顺利运行。提供演示视频和详细文档截图,帮助用户快速上手。
547 17
|
存储 监控 数据处理
flink 向doris 数据库写入数据时出现背压如何排查?
本文介绍了如何确定和解决Flink任务向Doris数据库写入数据时遇到的背压问题。首先通过Flink Web UI和性能指标监控识别背压,然后从Doris数据库性能、网络连接稳定性、Flink任务数据处理逻辑及资源配置等方面排查原因,并通过分析相关日志进一步定位问题。
1200 61
|
SQL 运维 关系型数据库
体验用分布式数据库突破资源瓶颈,完成任务领智能台灯!
体验用分布式数据库突破资源瓶颈,完成任务领智能台灯!
|
移动开发 监控 关系型数据库
使用云数据库RDS和低代码开发平台“魔笔”,高效构建门户网站,完成任务领智能台灯!
使用云数据库RDS和低代码开发平台“魔笔”,高效构建门户网站,完成任务领智能台灯!
|
存储 数据管理 关系型数据库
数据库分库分表的原因?
分库分表通过减少单库单表负担来提升查询性能。垂直切分按业务耦合度将表或列分布于不同库或表中,减少数据量,优化性能。水平切分则按数据逻辑关系将表分散至多库多表,减小单表数据量,实现分布式处理。选择方式需根据具体需求决定。
449 19
|
SQL 关系型数据库 MySQL
体验使用DAS实现数据库SQL优化,完成任务可得羊羔绒加厚坐垫!
本实验介绍如何通过数据库自治服务DAS对RDS MySQL高可用实例进行SQL优化,包含购买RDS实例并创建数据库、数据导入、生成并优化慢SQL、执行优化后的SQL语句等实验步骤。完成任务,即可领取羊羔绒加厚坐垫,限量500个,先到先得。
528 19
|
存储 SQL 关系型数据库
一篇文章搞懂MySQL的分库分表,从拆分场景、目标评估、拆分方案、不停机迁移、一致性补偿等方面详细阐述MySQL数据库的分库分表方案
MySQL如何进行分库分表、数据迁移?从相关概念、使用场景、拆分方式、分表字段选择、数据一致性校验等角度阐述MySQL数据库的分库分表方案。
2317 15
一篇文章搞懂MySQL的分库分表,从拆分场景、目标评估、拆分方案、不停机迁移、一致性补偿等方面详细阐述MySQL数据库的分库分表方案
|
消息中间件 资源调度 关系型数据库
如何在Flink on YARN环境中配置Debezium CDC 3.0,以实现实时捕获数据库变更事件并将其传输到Flink进行处理
本文介绍了如何在Flink on YARN环境中配置Debezium CDC 3.0,以实现实时捕获数据库变更事件并将其传输到Flink进行处理。主要内容包括安装Debezium、配置Kafka Connect、创建Flink任务以及启动任务的具体步骤,为构建实时数据管道提供了详细指导。
841 9