如何在分发服务时停止调度器并行运行



我们正在处理的应用程序有一些调度器,实际上是在特定时间运行的cron作业。这些服务是用PHP编写的,我们有这些调度器,它们部署在具有多个实例的服务器中。假设我们有3个工作服务实例,其中有这些调度器。因此,当调度程序运行时,它实际上会在所有三个实例上运行,间隔几秒。这意味着调度器正在执行相同的动作3次。那么,如何才能停止在多个实例中运行相同的调度器呢?我想在一个实例中运行一个调度程序。

您将需要在服务实例之间进行一些协调。你选择的方法需要权衡,所以要确定你为什么不希望这个动作发生三次。更具体地说,您需要回答以下问题:

哪个更糟糕:动作发生两次还是根本没有发生?

无论您选择哪种协调方式,都会出现故障模式,导致操作多次发生或未发生。没有一种协调方法涉及通过网络进行的通信,可以保证只进行一次(如果动作是幂等的,那么接近只进行一一次的事情是可能的(做两次与做一次没有什么不同(,但如果动作是等等的,发生两次可能一点也不坏*,因此根本不发生可能会更糟(。

如果发生两次是可取的,那么简单的事情就是为每个实例分配一个唯一的(甚至是唯一的ish(标识符,并让每个实例运行(当调度程序启动时(一个类似INSERT INTO leases (id, holder, timestamp) VALUES ('scheduler', identifier, now())的DB查询(id是主键(。如果所有实例的时钟都大致同步,那么只有其中一个插入会成功:如果成功,则获取租约,并可以执行计划的操作;在此之后,经过一段时间后,您将DELETE FROM leases WHERE id = 'scheduler' AND holder = identifier。在比调度器更频繁但比该时间段不频繁的某个时段,每个节点都执行DELETE FROM leases WHERE id = 'scheduler' AND timestamp before now() - period来取消太旧的租约。

如果根本不发生,最好使用etcd、领事或动物园管理员之类的东西来执行租约。对于这些系统来说,这是一个相当常见的用途,因此它经过了战斗测试并有充分的文档记录。请注意,在最大安全的情况下(租约在明确发布之前永远不会过期(,您需要进行一些外部监控,以确定计划的操作是否在应该发生的时候发生。如果监控显示没有,请提醒操作员(最终协调层(,操作员可以进行调查并手动终止租约。

*:我想,像向随机目标发射足够多的核导弹,使地球变得不适合居住这样的事情,从所有意图和目的来看都是徒劳的,尽管我希望我们都同意,最好不要发生这种事。。。

最新更新