如何设计一个高可用的分布式跑批系统

高可用出现在哪?

出现在你数据量非常的庞大,比如你的业务在1秒内有上亿条数据,然后调用你的业务接口,把结果存到你的数据库里面,进行保存。

那么都需要考虑哪方面呢?

  1. 亿级数据如何存储?
  2. 如何避免跑批任务重复调度?
  3. 如何利用集群进行负载均衡?
  4. 同一节点上任务如何并行?
  5. 如何动态调整任务并发度?
  6. 节点挂了如何保证任务不受影响?

答案解决

数据怎么存?

亿级的数据普通的 MySQL 数据库单表肯定存不下,因为 MySQL 的单表极限一般在 3000万行。首先想到的解决方案是分库分表,比如把 1 亿行分到 10 个表中。

但是使用数据库也伴随者两个问题:一是遍历数据对数据库的压力是很大的,越往后速度越慢。二是一般跑批的数据只用一次,每次跑完都要删除数据,会造成数据碎片问题。(这两个问题也不是说不能解决,遍历数据库越往后查压力越大,可以设置在每次查询的时候携带上一次的极值,让你分页查找的offect永远控制在0;至于碎片问题我现在确实没找到有效的方法,但是我知道它肯定存在)

所以考虑另一种方案,选择文件系统。一般跑批的数据都是从数仓或者其它来源导入的,跟分库分表的思路一样,导入时就切分成多个文件。这个文件系统可以是 FTP,也可以是分布式对象存储,比如阿里云的 oss。使用文件系统的好处有 2 个,一个是数据可以一直存着,什么时候想重跑都行。二是顺序读文件的速度很快,可以利用磁盘io顺序读的特性提高性能。

如何避免跑批任务重复调度?

在集群上调度任务,首选分布式任务调度,主流的比如 xxl-job。


分布式任务调度只能保证准时调到一个节点上,而且通常都有失败重试的功能。所以任务幂等都是要的,一般都是通过分布式锁来实现,这里遵循简单原则使用数据库就可以了,可以通过在任务表里 insert 一条唯一的任务记录,通过唯一键来防止重复调度。


除了用唯一键,还可以在记录中增加一个状态字段,使用乐观锁来更新状态。比如开始是初始化状态,更新成正在运行的状态,更新失败说明别的节点已经在跑这个任务。当然分布式锁的实现方案有很多,比如 redis、zk 等等。

集群怎么搭?

上一步中,只创建了一个任务,要上集群首先要做的是任务拆分,就是把一个跑批任务拆分成多个子任务。记不记得第一步我们把文件拆成多个了,这样就可以一个文件创建一个子任务。

子任务有了,那怎么分发出去呢?最简单的方式是通过消息队列。每个子任务一个消息,集群中所有节点在一个消费者组中,消息队列会保证任务得均匀分发。这里就到了消息队列得选型问题了,当然也可以选择 Kafka 或者 RocketMQ,以及Redis的list来实现。

任务并行

如果上一步选择了 MQ,那在每个节点上,肯定还是要同时跑多个子任务才能资源利用最大化。那么你可以使用线程池。

如果选择的是Kafka或者 RocketMQ,他们的客户端本来就是线程池消费的,只需要合理调整客户端参数就可以了。如果使用的是 Redis,那就需要自己创建一个线程池,然后让一个 EventLoop 线程从 Redis 队列中取任务。

放入线程池中运行,因为我们已经使用 Redis 队列做缓冲,所以线程池的队列长度设为0,这里直接使用JDK提供的 SynchronousQueue。(这里以java为例)

动态调整并发度

跑批任务中能动态调整速度是很重要的,有 2 个地方可以进行操作:

  1. 任务中调用远程接口,这个速度控制其实用 Thread.sleep() 就好了。
  2. 控制任务并发度,就是有多少个线程同时运行任务。这个控制可以通过调整线程池的线程数来实现,但是线程池动态调整线程数比较麻烦。动态调整可以通过开源的限流组件来实现,比如 Guava 的 RateLimiter。可以在每次调用远程接口前调用限流组件来控制并发速度。

失败任务如何继续

理一下整个路径:分布式任务调度创建跑批任务,然后拆分子任务并发到消息队列。线程池执行任务调用远程接口。

在这个链条中,可能导致任务失败或者中止的原因无非下面几个。

  1. 机器重启,导致这台上面的任务都异常中止了
  2. 任务执行过程中,接口一直失败,超过次数子任务终止
  3. 机器资源不足,内存溢出了。

要解决上面的问题,重点就 2 个:记录进度、任务重试。
首先在子任务执行过程中,需要一直刷新现在执行到文件哪一行了,同时记录更新时间,再次,分布式任务调度系统中增加一个补偿任务,定时扫描所有还在执行中的子任务,如果发现任务进度长时间未更新。那就说明任务没有在运行了。将这个任务状态改成待执行,重新放入消息队列就可以了。

ok,如果感兴趣的话,可以添加我网站主页的微信,或者在此网站上面注册账号进行登录,注册账号的会在我每次发布文章后都会收到邮箱提醒,谢谢你的观看。

我的个人网站:www.zpf0000.com

  • 18
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值