您的位置:首页 > 数据库 > Redis

2种基于简单定时任务实现分布式定时任务的技术解决方案(zookeeper、redis和内联MQ)

2017-01-14 21:27 1171 查看
    最近项目中,需要实现分布式的定时任务,结合项目现有的中间件和技术,设计出了2种简单分布式定时任务的实现(这里的前提是定时任务是可拆分的)

需求背景:由于DB需要通过定时任务执行数据清理,每天需要清理N个分库M张分表的线下渠道的数据。(N>20,M>=10)

所以初步设计的定时任务是拆分成了N*M个子任务,假设服务器的数量大于N*M。关键点就是如何实现分布式,让每个服务器都利用起来执行任务,以下是设计出的2种实现方案

一、基于zookeeper和redis实现的一种分布式定时任务

由于目前存在基于zookeeper开发出的支持分布式服务器的统一配置管理中间件,还有分布式redis缓存的中间件,所以设计出了基于zookeeper和redis的一种分布式定时任务。步骤如下:

1、修改任务配置

配置一个简单的定时任务,假设每天0点触发,仅由一台服务器执行任务,具体逻辑是:

修改统一配置中的归档任务文件中针对于该任务的节点内容:

      

#数据清理任务
clearArchive=【当前服务器唯一标识的信息即可】  (可以是IP+时间戳,需要保证每次任务触发的值都不一样)
2、获取子任务

由于zookeeper的功能,修改内容会被所有的服务器监听到,此时可以进行数据清理任务的执行了。但如何保证所有服务器在N*M个子任务分配中,一台服务器仅分配一个子任务,且不会与其他服务器领取到的子任务重复呢(注意,此时属于高并发场景,所有服务器都会同时监听到)?这时就要用到分布式redis了,步骤如下:

a) 获取子任务号

     遍历N*M次子任务的子任务号(由分库号+"-"+分表号+第一步获取的clearArchive对应的值构成),把该子任务号作为key,服务器ip等信息作为value进行setnx操作,若结果为0,表示已经被其他服务器获取到了,遍历下一个。若结果为1,表示获取成功,则返回此子任务号。

b) 若子任务号不为空,则表示该服务器成功领取了一个子任务了,根据该任务号,执行对应分库分表的数据清理任务。

分析:此设计方案可以保证每一台服务器仅执行一个子任务,可以达到分布式定时任务的处理效果,但缺陷是扩展性和适用性不够,若服务器的数量过小,若子任务过大,还是会存在服务器领取的子任务不均匀的现象。但在此种场景下,应该是比较适合的,目前的技术实现就是采用这种的。

二、内联MQ

1、技术背景

由于项目中存在中间件ActiveMQ消息队列和分布式缓存锁jedis,所以使用了ActiveMQ消息队列的本地通讯的实现。

2、实现步骤如下:

a) 配置一个简单的定时任务,假设每天0点触发,仅由一台服务器执行任务,发送N*M个对应不同分库号和分表号的MQ消息。

b) 集群的所有服务器进行消息的处理,根据消息里的分库号和分表号,进行对应子任务的处理,从而实现了分布式的定时任务处理。

综合来比较:内联MQ的方式相对实现简单,且仅需要配置对应的JMS和Listen即可,但缺点是服务器分布式处理的可能不均匀,有可能某台服务器处理了多条子任务,但往往能流传下来的都是简单的方式。

        
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息