协调集群中服务器之间的单个定期任务的执行

Tom*_*Tom 5 high-availability distribution cluster-computing task-queue

(在清楚描述情况时,我将尽量使这个问题简短。如果缺少任何内容,请发表评论。)

情况

  • 我正在同一数据中心中运行具有三台服务器的集群
  • 为了简化部署,每个服务器运行完全相同的应用程序代码

目标

  • 要由一台服务器每分钟运行一个任务(称为任务X)。

在这些条件下

  • 群集保持分布式并且高度可用
  • 每个服务器保持运行相同的应用程序代码。换句话说,没有诸如“将代码A部署到主服务器并将代码B部署到所有辅助服务器之类的事情。

我不希望区分服务器类型的原因是为了保持高可用性(避免所谓的主服务器宕机),冗余(分布式负载),并避免在需要部署其他服务器的地方创建复杂的部署过程应用程序到不同类型的服务器。

为什么这么难?如果我要添加每5分钟执行一次此任务的代码,则每个服务器都将执行该代码,因为每个服务器都运行相同的应用程序代码。因此,他们需要能够协调每个滴答期间哪个服务器将运行相同的服务器。

我可以使用诸如Apache Kafka或的分布式消息传递机制Redis。如果使用这种机制来协调任务,那么这种“算法”将如何工作?

我向其他人提出了这个问题,他的回答是使用任务队列。但是,这似乎并不能解决问题,因为问题仍然存在:哪个服务器要将任务添加到任务队列中?如果所有服务器都将任务添加到队列中,则将导致重复条目。此外,哪个服务器将执行队列中的下一个任务?所有这些都需要通过集群内的协调来确定,而不必区分不同类型的服务器。

las*_*nal 3

听起来您正在寻找分布式锁。Redis 通过setnx. 如果将其结合起来,expire则可以创建每 N 秒释放一次的全局锁。

setnx只会写入值并在键不存在时返回 true。Redis 操作是原子操作,因此只有密钥过期后调用的第一个服务器setnx才能继续运行任务。

下面是 ruby​​ 中的一个例子:

# Attempt to get the lock for 'Task X' by setting the current server's hostname
if redis.setnx("lock:task:x", `hostname`.chomp)
  # Got the lock, now I set it to expire after 5 minutes
  redis.expire("lock:task:x", 60 * 5)
  # This server has the go ahead to execute the task
  execute_task_x
else
  # Failed to get the lock. Another server is doing the work this time around
end
Run Code Online (Sandbox Code Playgroud)

这样,您仍然依赖于调用一台服务器Redis Master,除非您利用redis-sentinel. 查看redis-sentinel 文档以获取有关如何配置自动故障转移的信息。