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

本文涉及的产品
实时计算 Flink 版,5000CU*H 3个月
简介: 基于 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轻松玩转一站式实时仓库
本场景介绍如何利用阿里云MaxCompute、实时计算Flink和交互式分析服务Hologres开发离线、实时数据融合分析的数据大屏应用。
Linux入门到精通
本套课程是从入门开始的Linux学习课程,适合初学者阅读。由浅入深案例丰富,通俗易懂。主要涉及基础的系统操作以及工作中常用的各种服务软件的应用、部署和优化。即使是零基础的学员,只要能够坚持把所有章节都学完,也一定会受益匪浅。
相关文章
|
1月前
|
存储 监控 数据处理
flink 向doris 数据库写入数据时出现背压如何排查?
本文介绍了如何确定和解决Flink任务向Doris数据库写入数据时遇到的背压问题。首先通过Flink Web UI和性能指标监控识别背压,然后从Doris数据库性能、网络连接稳定性、Flink任务数据处理逻辑及资源配置等方面排查原因,并通过分析相关日志进一步定位问题。
169 61
|
22天前
|
存储 数据管理 关系型数据库
数据库分库分表的原因?
分库分表通过减少单库单表负担来提升查询性能。垂直切分按业务耦合度将表或列分布于不同库或表中,减少数据量,优化性能。水平切分则按数据逻辑关系将表分散至多库多表,减小单表数据量,实现分布式处理。选择方式需根据具体需求决定。
54 19
|
4月前
|
存储 数据处理 Apache
超越传统数据库:揭秘Flink状态机制,让你的数据处理效率飞升!
【8月更文挑战第26天】Apache Flink 在流处理领域以其高效实时的数据处理能力脱颖而出,其核心特色之一便是状态管理机制。不同于传统数据库依靠持久化存储及 ACID 事务确保数据一致性和可靠性,Flink 利用内存中的状态管理和分布式数据流模型实现了低延迟处理。Flink 的状态分为键控状态与非键控状态,前者依据数据键值进行状态维护,适用于键值对数据处理;后者与算子实例关联,用于所有输入数据共享的状态场景。通过 checkpointing 机制,Flink 在保障状态一致性的同时,提供了更适合流处理场景的轻量级解决方案。
68 0
|
1月前
|
SQL 关系型数据库 MySQL
体验使用DAS实现数据库SQL优化,完成任务可得羊羔绒加厚坐垫!
本实验介绍如何通过数据库自治服务DAS对RDS MySQL高可用实例进行SQL优化,包含购买RDS实例并创建数据库、数据导入、生成并优化慢SQL、执行优化后的SQL语句等实验步骤。完成任务,即可领取羊羔绒加厚坐垫,限量500个,先到先得。
151 12
|
6天前
|
存储 消息中间件 SQL
微服务改造血泪史:数据库拆分踩过的那些坑!
本文复盘了传统项目改造成微服务架构时,数据库拆分过程中遇到的问题。主要问题包括:1. 数据库拆分过细,导致跨服务调用频繁,破坏服务独立性;2. 数据一致性难以保证,分布式事务管理复杂;3. 跨服务查询影响性能,复杂查询难以实现。初次改造时应避免过度拆分,逐步演进架构。
17 0
|
1月前
|
消息中间件 资源调度 关系型数据库
如何在Flink on YARN环境中配置Debezium CDC 3.0,以实现实时捕获数据库变更事件并将其传输到Flink进行处理
本文介绍了如何在Flink on YARN环境中配置Debezium CDC 3.0,以实现实时捕获数据库变更事件并将其传输到Flink进行处理。主要内容包括安装Debezium、配置Kafka Connect、创建Flink任务以及启动任务的具体步骤,为构建实时数据管道提供了详细指导。
91 9
|
1月前
|
缓存 NoSQL 数据库
运用云数据库 Tair 构建缓存为应用提速,完成任务得苹果音响、充电套装等好礼!
本活动将带大家了解云数据库 Tair(兼容 Redis),通过体验构建缓存以提速应用,完成任务,即可领取罗马仕安卓充电套装,限量1000个,先到先得。邀请好友共同参与活动,还可赢取苹果 HomePod mini、小米蓝牙耳机等精美好礼!
|
3月前
|
存储 SQL 关系型数据库
一篇文章搞懂MySQL的分库分表,从拆分场景、目标评估、拆分方案、不停机迁移、一致性补偿等方面详细阐述MySQL数据库的分库分表方案
MySQL如何进行分库分表、数据迁移?从相关概念、使用场景、拆分方式、分表字段选择、数据一致性校验等角度阐述MySQL数据库的分库分表方案。
528 15
一篇文章搞懂MySQL的分库分表,从拆分场景、目标评估、拆分方案、不停机迁移、一致性补偿等方面详细阐述MySQL数据库的分库分表方案
|
2月前
|
Java Shell Maven
Flink-11 Flink Java 3分钟上手 打包Flink 提交任务至服务器执行 JobSubmit Maven打包Ja配置 maven-shade-plugin
Flink-11 Flink Java 3分钟上手 打包Flink 提交任务至服务器执行 JobSubmit Maven打包Ja配置 maven-shade-plugin
133 4
|
2月前
|
资源调度 分布式计算 大数据
大数据-111 Flink 安装部署 YARN部署模式 FlinkYARN模式申请资源、提交任务
大数据-111 Flink 安装部署 YARN部署模式 FlinkYARN模式申请资源、提交任务
124 0