系统中目前有些工具包含了一些定时任务,但是为了保证工具不出现单点故障,在部署多台服务器时,会只在一台服务器上开启定时任务,其他服务器关闭,但是在版本迭代部署过程中,因为配置文件的差异导致容易出现问题,一不小心就导致多台服务器同时开启了定时任务,或者多台服务器都没执行异步任务,说到底,还是因为工具无法做到完全一致。
说到底,还是因为没有一个机制保证一模一样的工具,无法实现定时类任务只在一台服务器运行。
后来经过思考,可以借鉴Redis的事物和Watch机制来实现,逻辑很简单:
1)所有服务器配置一样,每台服务器都可以定时启动任务
2)但是在任务启动的开始,判断是否已经有当前执行时间点的信息存储至Redis的Set里面去
比如,任务执行时间串为: 0 */1 * * * (cron4j)
那么到了整点的时候,先判断 set中是否存在 yyyyMMddHH
如果存在,则表示其他实例已经抢先运行了
否则,使用watch、multi命令来往redis的set中插入数据,
哪个插入成功,则该实例可以执行具体的任务了,
插入失败则不执行。
看代码:
/** * 设置信号量(用于决定当前工具实例是否有资格去执行任务) * @param taskName * @return * @throws Exception */ public boolean setRedisSemaphore(){ try { //1、先判断信号量是否存在(信号量的值以 quartz:{taskName} yyyyMMdd 或者 yyyyMMddHH (由任务对应的执行周期决定) 的形式存储)
String key = "quartz:" + taskName; String format = getFormat(); if(StringUtils.isBlank(format)){ return true; }else{ SimpleDateFormat sdf = new SimpleDateFormat(format); String value = sdf.format(new Date()); if(redisService.sismember(RedisName_Biz, key, value)){ return false; }else{ boolean keyExists = redisService.exists(RedisName_Biz, key); //2、如果存在则返回,否则设置信号量,设置成功就继续处理,设置失败,本次任务结束 Jedis jedis = redisService.getJedisByKey(RedisName_Biz); Pipeline p = jedis.pipelined(); p.watch(key); p.multi(); p.sadd(key, value); p.exec(); List<Object> list = p.syncAndReturnAll(); String result = list.get(list.size() - 1).toString(); if(!keyExists){ redisService.expire(RedisName_Biz, key, 7 * 24 * 60 * 60); } redisService.returnJedisByKey(RedisName_Biz, jedis); return result.equals("[1]"); } } } catch (Exception e) { logger.info(String.format("任务【%s】设置信号量出现异常:", this.taskName) + e); } return false; }
虽然我们开发了一个工具框架集成了这个机制,但是目前这个方式只能实现工具多实例同时运行的高可用机制,无法保证针对一批数据有多个实例同时去处理(队列性质的除外,因为队列性质的数据源不需要这个机制来保障)。
之前项目组使用过淘宝的开源框架TBSchedule,但是上线后遇到了各种各样的问题,还导致过现网故障,而由于TbSchedule设计的太过完美,功能比较丰富、复杂,在解决问题的过程中也遇到了不少麻烦,后来干脆直接把TbSchedule给抛弃了。 不过它的思路是非常优秀的,使用分配任务项的方式来决定实例需要处理哪些处理,而且不会造成数据的重复处理,同时增加实例、减少实例,都会及时的进行数据重新分配。
后续会继续研究下它的思路来时间一个精简版的高可用工具框架。
附:淘宝开源框架有兴趣的话见如下地址:
http://code.taobao.org/p/tbschedule/wiki/index/
相关推荐
Redis介绍与实现机制.PPT
redis+Keepalived实现Redis高可用性 主要包含两个文件: 1、安装文档 2、各种脚本文件
基于SpringBoot的轻量级redis事务回滚机制,使用栈和ThreadLocal记录业务链的redis操作,发生异常进行回滚,参考了阿里巴巴Seata AT模式的db回滚策略:补偿回滚,记录前镜像与当前操作语句,反向解析生成补偿动作。...
springboot-redis事务
自己封装redisson方法,同时通过注解的方式加入redis分布式事务锁,可靠。
java 集成redis 工具类
docker-compose 形式部署 redis 1主2从3哨兵 redis 多节点高可用 redis 主从哨兵 redis 集群高可用 redis 哨兵 redis 高可用
DelayQueue、Redis结合使延迟、定时任务使用 DelayQueue、Redis结合使延迟、定时任务使用 DelayQueue、Redis结合使延迟、定时任务使用 源代码下载
秒杀是电商系统非常常见的功能模块,是商家进行相关促销推广的常用方式。主要 特点是商品库存有限,抢购时间有限。那么在系统设计之初就应该考虑在数量和时 间有限的情况下导致的一个高...付那么就由定时任务来归还令牌
redis客户端连接工具 redis客户端连接工具 redis客户端连接工具
高可用可扩展集群化Redis设计与实现_闫明.caj
采用Keepalived实现Redis双机高可用,包括详细安装配置步骤和脚本等。
现在很多项目单机版已经不满足了,分布式变得越受欢迎,同时也带来很多问题,分布式锁也变得没那么容易实现,分享一个redis分布式锁工具类,里面的加锁采用lua脚本(脚本比较简单,采用java代码实现,无须外部调用...
Redis C# 工具类 操作Key,string,Set,SortSet,List 等。
主要给大家介绍了基于redis实现定时任务的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用redis具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
该资源是本人在学习redis过程中积累总结的经验以分享给大家:redis-sentinel高可用一键配置工具就是一键帮你从下载->安装->配置 好 redis 高可用的服务环境,省去了很多弯路,节约了更多的时间花在自己项目的主要...
zookeeper实现redis的高可用,包括监控心跳和切换,以及恢复等
可能是最全的Redis静态工具类,拿来即用,随时随地RedisUtils.方法名()存取数据,每个方法都有对应的注释,快速上手!
java操作redis代码和redis工具类相关包资料