6

(在清楚地描述情况的同时,我会尽量保持这个问题的简短。如果有任何遗漏,请发表评论。)

情况

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

目标

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

在这些条件下

  • 集群保持分布式和高可用性
  • 每台服务器都在运行相同的应用程序代码。换句话说,不存在“将代码 A 部署到主服务器并将代码 B 部署到所有辅助服务器”这样的事情。

我不想区分服务器类型的原因是为了保持高可用性(避免所谓的主服务器宕机时出现问题)、冗余(分配负载),以及避免创建需要部署不同服务器的复杂部署过程应用到不同类型的服务器。

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

我能够使用分布式消息传递机制,例如Apache KafkaRedis。如果使用这样的机制来协调这样的任务,那么这样的“算法”将如何工作?

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

4

2 回答 2

3

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

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

这是一个红宝石的例子:

# 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

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

于 2012-10-31T18:11:40.553 回答
0

您也可以使用JGroups来实现这一点。示例实现可以在这里找到

于 2014-10-16T16:43:53.837 回答