简介
RocketMQ Connect是RocketMQ数据集成重要组件,可将各种系统中的数据通过高效,可靠,流的方式,流入流出到 RocketMQ,它是独立于 RocketMQ 的一个单独的分布式,可扩展,可容错系统,它具备低延时,高靠性,高性能,低代码,扩展性强等特点,可以实现各种异构数据系统的连接,构建数据管道,ETL,CDC,数据湖等能力。
RocketMQ EventBridge架起高可伸缩,高吞吐的事件通道。 EventBridge可以看作是runtime(connect)的管理台,构建逻辑(based domain模块)云事件通道,调用runtime api(adapter)创建物理(可运行)事件通道
本系列文章分析RocketMQ Connect和RocketMQ EventBridge源码原理,为两组件的改造和应用开发提供支持,
本文是第二部分,分析worker,worker connector,worker source task,worker sink task
关键词
CloudEvent
OpenMessaging OpenMessaging 是 Linux 基金会下一个开源组织,致力于制定消息领域的标准;
参考资料
《rocketmq Connect/EventBridge原理源码分析 I》 介绍架构,服务和组件,是本文的基础
发布计划
M1 事件通道构建控制台
- 拖拽方式构建事件通道,包括source connector/sink connector,及其transform链;集成rule based transform;支持cloudevent标准
- 可视化worker/worker集群状态和启停,connector/task启停
M2 分布式重构
- 引入elastic-platform(based zookeeper),实现worker集群管理,配置存储,集群成员变更,分片,位点存储等
M3 动态资源管理
- 引入资源管理器,支持k8s资源申请,计算能力的高伸缩
原理分析
原理源码分析通过场景用例分析完成,包括启动,服务,worker(包括连接器和任务),系统组件
Worker
本章分析worker模块,及位点,状态服务相关的分析
worker
Worker是Connector和Task运行环境,提供 RESTful 能力,接受HTTP请求,Connector和Task的新增,启停,配置变更等。
Worker可以组成集群,共同运行事件通道,worker间互为负载均衡和容错
SourceTaskOffsetCommitter 开启worker sourcetask定时位点提交,关于位点提交到worker sourcetask在详细分析
RebalanceService 即上篇的分片服务,驱动分片,分片完成后,调用Worker的startConnectors和startTasks;
startConnectors启动worker下的Connector;startTasks没有直接启动Task,只是赋值给latestTaskConfigs,真正启动task是在maintainTaskState
StateMachineService 顾名思义,服务不停地检查task任务,维护着任务的状态;继承ServiceThread,拥有定时执行和唤醒执行的特性,但该类没有被唤醒,一直定时执行maintainTaskState
startConnectors 方法接收分片给该worker 的Connector列表,引用方法注释,很好描述处理逻辑
start a collection of connectors with the given configs.
If a connector is already started with the same configs, it will not start again.
If a connector is already started but not contained in the new configs, it will stop.
maintainTaskState 与startConnectors差不多,接收分片给该worker 的Tasks列表,检查Task逻辑,新的任务启动,正在运行的不在该任务列表,停止,移除。
worker connector
worker connector包装运行Connector,主要是start,stop,pause操作,而操作的发起者是Worker,驱动Worker发起操作的是分片服务
worker sourcetask
worker sourceTask职责是运行sourceTask,拉取数据,转换,发送到中间通道;关键的支持服务,位点提交,状态的更新和报告
OffsetStorageReader openmessaging标准接口,位点读取,WorkerSourceTask传给sourceTask组件,后者使用OffsetStorageReader实现获取数据源的读取位点
poll/sendRecord 拉取数据,转换,发送到中间消息通道,比较简单,不多分析
- 位点管理
下面分析一下WorkerSourceTask的位点管理,对于WorkerSourceTask,并不了解位点数据内容,位点的使用者是sourceTask,不同数据源位点数据不相同,因此WorkerSourceTask只负责提取,保存,提供读取实现。
SourceTaskOffsetCommitter 分析worker时提到,worker调起,定时调用commitOffsets,提交位点
上图是以时间为主线的位点提交流程
线路一:
- 提交位点到位点管理器,后者包装位点为带ack标记的位点,放到缓存records
- 等待消息发送完成,使用CountDownLatch同步,调用awaitAllMessages,注意,此时消息发送进行中,awaitAllMessages可以说是走到哪,在哪开始计数,最极端两个情况,1) 等待时没有发送消息,则countdown数等于消息数,2) 等待时消息已发送完,countdown=0,不用等待
- 等待结束,有两种情况,消息发送完毕;超时结束等待,若是超时结束,存在未acked的消息
- 分区(Partition)抓取可提交的位点,即,已acked的位点
- 位点管理器推送位点缓存到PositionStorageWriter,然后异步刷新
- PositionStorageWriter提交给PositionManagementService
- PositionManagementService保存到存储
- PositionManagementService同步,同步就是通过datasync组件分发给集群的worker
线路二:
直接从5开始,如第3所述,超时结束存在未提交的位点,后面随着发送继续,acked消息增加
线路二定时提交属于补偿操作,是否与线路一冲突
上图,抓取代码采取多线程隔离措施,转到本地变量, 不会与线路一冲突
另外,线路二从5开始,哪里抓取可提交位点
每轮的执行,为线路二抓取好了位点
worker sinktask
worker sinktask的职责是运行sinktask,接收数据,转换,写入目标,关键的支持服务,位点更新,状态的更新
MessageQueueListener rocketmq的消费负载机制,worker sinktask维护着当前消费队列,messageQueues属性,位点管理对应着每个messge queue
pollConsumer/receiveMessages 同样,数据拉取,推送比较简单,这里不详细分析
- 位点管理
下面分析worker sinktask位点管理,首先说一下worker sourcetask和worker sinktask位点管理的区别,worker sourcetask管理是SourceTask的位点,worker只负责存储,搬运,不是自身使用;worker sinktask位点是中间消息的位点,正是worker sinktask用来记录拉取数据位点
nextCommit 位移提交时间间隔,即,位移提交是每隔一段时间执行一次
下图展示位点提交流程
1. receiveMessages 消息处理方法,从消息获取偏移,放到originalOffsets,然后putAll到currentOffsets,currentOffsets多轮消息处理叠加,直到netxCommit达到配置的时间间隔
2. commitOffsets,构造3个偏移集合,为下一步组装准备
local offsetsToCommit 拷贝 currentOffsets 最新的,最近poll数据的偏移,但数据put进sinkTask,可能并未写入
local lastCommittedQueuesOffsets 拷贝 lastCommittedOffsets 最稳妥的,刚提交过,作为提交偏移最重要是稳,即宁愿靠前不靠后,靠后导致数据丢失,而数据重复处理时允许的
local taskProvidedOffsets 拷贝 offsetsToCommit 最可信的,该偏移组通过sinkTask的preCommit,WorkerSinkTask调用sinkTask.put写数据,真正写数据的是sinkTask,只有sinkTask才知道数据有没有写入,因此通过preCommit是最可信的偏移,当然,put是同步实现,没有异常,认为全部写入成功
3. 第2步构建3个偏移集合,第3步组装最终的提交,
首先,committableOffsets = lastCommittedQueuesOffsets
committableOffsets是最终的提交集合,以最稳妥的lastCommittedQueuesOffsets作为基底,
接着比较currentOffset >= taskProvidedOffset,一般情况下是true,使用taskProvidedOffset提交,
若为false,意味着currentOffset < taskProvidedOffset,最新获取的数据偏移小于sinkTask写入偏移,说明consumer的偏移被rewind,两者都不可信,使用已提交的Offset
4. 最后consumer.getOffsetStore().updateOffset,更新偏移