[redisson]RScheduledExecutorService如何保证多个RedissonNode只有一个节点执行任务

2024-07-18 453 views
9

用官方的demo例子,在分布式环境下,scheduleAtFixedRate创建任务后,多个物理机的RedissonNode添加了setExecutorServiceWorkers来接收任务。 测试时发现不同物理机的节点每个都会收到任务并执行,同一个物理机不同端口启动的redissonNode,则只有一个会执行任务。 目前想要的效果是最好全局只有一个节点处理这个任务,请问该如何处理呢?

回答

0

如果你只需要一个物理节点处理这个任务,只需要在这一个节点创建这个服务的ServiceWorkers即可。

1

感谢指教。 如果只有一个节点注册服务的话,万一这个节点挂了,就丢失任务数据了。 起初以为redisson能做到只给一个node节点发送定时调度任务。现在既然行不通,想换个思路,仍然起了多个节点,每个节点收到任务后,加一个全局锁避免重复消费。 目前做法是加一个全局锁10秒后自动过期,10秒内获取不到锁的,说明有别的节点正在处理,直接跳过,保证只有一个节点在处理。 方法有点笨,不知道有没有更佳的实现,比如RScheduledExecutorService的定时任务,node节点执行的时候能不能获取到类似本次调度任务id之类的唯一标示,各个节点执行任务的时候可以根据这个标识来判断是否同一个任务?

2

感觉你定时任务的时间设定上有一些冲突。当一个任务执行的时间长于这个任务执行的频率的时候,才会发生你说的这个问题。同时你又希望同一时刻只能有一个任务执行,并且对该要求十分严格,必须用锁来协调,这个现象说明你执行的频率太频繁了。考虑把频率降低一点,可以减少很多比必要的操作。

7

@jackygurui 您好,其实频率不算高,每分钟才执行一次,每次开销正常一两秒就结束了。业务场景是下单之后,每隔1分钟去第三方轮询最新的订单状态,确保状态准实时同步(要求不超过1分钟的延迟),直到订单完结。

如果只注册一个node节点,那么万一线上这个节点宕机了,便不能及时地取到到最新的状态。起多个节点时,即使挂了一台,还有别的节点在执行每分钟的任务,除非集群全宕了。

我想过两个思路: 1、通过RScheduledExecutorService做,加的一个全局锁10秒过期,每分钟不同节点的任务同时开启时,通过锁控制只有一个节点在处理;但是这个条件互斥并不是很完美,比如极端情况两个节点收到同一个调度任务的间隔超过了10秒? 如果有其他更好的互斥条件,比方说每分钟的调度任务下发给多节点时,带了同一个唯一的任务标识,这样可以方便地控制一次调度任务只消费一次。

2、使用RDelayedQueue,生产者先发送一条任务,然后消费者take到任务后,在消费线程里直接发送下一条任务。

不知道哪种方式更好,或者有其他更好的实现思路,感谢指导。

1

@chuangzai 完全没用必要这么麻烦。Redisson的定时任务发送以后就可以不管了,任务内容和状态是保存在Redis里的,即便发送的节点关机,任务仍然会被工作节点继续执行。同样的道理,如果有多个工作节点时,各个工作节点之间会自动协同工作,当一个工作节点出现宕机的时候,其它的工作节点仍然会继续下去。就算所有的工作节点全部宕机后,当有新的工作节点加入进来时,任务仍然会继续执行,不会出现你所谓的丢失任务的情况。

5

@jackygurui 您说的正是我看中redission定时任务的优点,任务状态保存在redis里,保证任务本身不丢失,也验证过所有节点都下线再加入新的工作节点,确实都能收到任务。

我们的业务场景要求每分钟都能执行任务,又要求每次调度最多只执行一次任务,多个节点也只能有一个执行了实际的任务。

注册了多个工作节点是为了去除单点隐患,保证每分钟都有节点在处理。矛盾点也因为启动多个物理工作节点后,每个节点都会同时收到任务调度,重复执行浪费资源还是次要原因,最怕担心造成数据冲突。 所以我才加了单独又配了全局锁。

我本地测试时,本机开了不同的端口注册多个node节点来接受调度任务,发现本机节点会轮流来执行,A服务执行任务了,B就不会执行,窃喜这正是我想要的效果,结果部署后发现不同物理机都会收到并执行任务。如果RScheduledExecutorService可以通过类似某个可配置的参数控制,每次调度任务只给其中一个物理机节点发送消息,那就完美了 ^_^

8

您说的各节点自动协同工作,是指各节点之间跟创建任务的节点没有直接关系,任务创建后,所有节点都会各自收到调度信息。其实我想要实现的是,只要有一个节点消费了任务,其他的节点就不要重复消费了。

4

你能给一个重现吗?我这边多JVM测试没有遇到你描述的重复消费的问题。

4

@jackygurui 今天下午又仔细地测了下场景,确实是您说的频率的问题,之前用的是scheduleAtFixedRate,如果间隔非常小,在多节点调度可能会出现调度紊乱的问题,误以为是重复消费了(测试人员为了容易复现这个场景,特地把频率降低到2秒)。间隔小的场景可以使用scheduleWithFixedDelay测试了一段时间情况比较正常,感谢。