1

我有集群应用程序,需要将其中一个节点指定为主节点。集群节点在带有nodeIDisMasterlastTimestamp列的表中进行跟踪。

集群中的每个节点每X秒都会尝试成为主节点。节点只能成为主节点,如果

  • 没有其他主节点
  • 当前主节点上的lastTimestamp早了2*X

满足上述条件之一时

  • 当前主节点的isMaster应该被清除
  • 应该设置新主节点的isMaster
  • 新主节点的lastTimestamp应设置为“now”时间戳。

在没有两个或更多节点成为主节点的情况下,实现上述目标的单个(可移植)SQL 语句是什么?

4

2 回答 2

1

我可以想象一个 Oracle 数据库的解决方案,但我不确定它是否可移植。为什么这需要是一个可移植的 SQL 语句?大多数数据库允许表锁定和事务,这允许您在多个语句中执行此类操作。

于 2008-11-28T00:09:33.667 回答
1

这种协调通常不是由 DBMS 本身处理,而不是由运行在 DBMS 上的应用程序处理吗?我也可以设想在我熟悉的 DBMS 中执行此操作的方法,但对您的系统没有更多了解(它可能使用共享磁盘,因此所有节点都看到相同的数据;可能存在阻止并发访问的锁定协议到数据;是否是主节点上的用户进程定期更新 lastTimestamp),这将很难有多大帮助。而且,正如 Jamie Love 所指出的,DBMS 应该允许多个进程协调对相关记录的访问——主要的相关记录是当前的主记录。

[编辑:也许我读得太多了。

单个 UPDATE 语句必须对表的两行进行差异更新,并且如果两个更新中只有一个是可能的,则必须失败。也就是说,它必须既将当前的主服务器更改为非主服务器,也必须更改自己的记录,使其成为主服务器。一个问题是 DBMS 如何强制执行“只有一行可能是主”约束。让我们假设如果出现问题,它的工作原理和整个语句将失败 - 正如它应该的那样。为什么人们经常忽略表名,即使他们提供了列名?哦,好吧,表名以下是ClusterControl。每个节点必须以某种方式知道自己的 NodeID;我使用 {MyNodeID} 来指示它出现在 SQL 中的位置。

您需要单独的心跳更新:

 UPDATE ClusterControl
     SET lastTimestamp = CURRENT_TIMESTAMP
     WHERE NodeID = {MyNodeID};

“获取主状态”更新可能是:

UPDATE ClusterControl
    SET lastTimestamp = (CASE
                         WHEN NodeID = {MyNodeID} THEN CURRENT_TIMESTAMP
                         ELSE lastTimestamp END),
        isMaster      = (CASE
                         WHEN NodeID = {MyNodeId} THEN 'Y'
                         ELSE 'N' END)
    WHERE (NodeID  = {MyNodeID} AND isMaster = 'N') OR
          (NodeID != {MyNodeID} AND
           lastTimestamp < CURRENT_TIMESTAMP - INTERVAL '120' SECOND AND
           isMaster = 'Y'
          );

“获取主状态”更新背后的理论是(SET 子句):

  • 新 master 的 lastTimestamp 字段设置为当前时间戳,但旧 master 保持不变。
  • isMaster 字段更改为新主服务器的“Y”和旧主服务器的“N”。

WHERE 子句背后的理论是:

  • 仅当当前节点不是当前节点且时间戳超过 120 秒(问题中的“2 * X”)时更改当前节点的记录,如果它不是当前主节点或当前主节点的记录.

由于有一个(可能是神话般的)约束来确保只有一行具有“Y”标志,因此当主服务器是最新的时,这应该会按要求失败。

未经测试的 SQL!

]

于 2008-12-01T05:53:55.563 回答