分布式系统--时间和时钟

时间、时钟与事件排序

为什么我们需要对事件进行排序?

示例:Facebook

  • 移除老板为好友(或拉黑)
  • 发布“我的老板是最糟的,我需要一份新工作!”
  • 不希望顺序搞错了!
  • 这些事件怎么会顺序错乱呢?

为什么事件会顺序错乱?

  • 数据不是存储在一个服务器上——实际上有10万+服务器
  • 隐私设置和帖子分开存储
  • 大量数据副本:数据中心的副本、缓存、跨数据中心复制、边缘缓存
  • 我们如何一致地更新所有这些东西?

我们如何对事件进行排序?

物理时钟:同步
  • 基于信标的方法
  • 指定带有GPS/原子钟的服务器作为主服务器
  • 主服务器定期广播时间
  • 客户端接收广播,重置它们的时钟
  • 这个方法效果如何?
网络延迟

  • 网络延迟是不可预测的,有一个下限
方法 #2:基于询问的协议
  • 客户端查询服务器
  • 时间 = T1 + (T2-T0)/2
  • 多次采样,平均多个服务器的结果;排除异常值
  • 考虑时钟速率偏差
  • NTP, PTP

我们如何在没有物理时钟的情况下对事件进行排序?

先行关系
  • 捕获事件之间的逻辑(因果)依赖关系
  • (非自反的)部分排序:→
  • a →/ a
  • 如果 a → b,则非 b → a
  • 如果 a → b 且 b → c,则 a → c
分布式系统中的先行关系
  • 进程
  • 消息
  • 事件
  • 先行规则:
  • 在一个进程内,a 在 b 之前,则 a → b
  • 如果 a = 发送(M),且 b = 接收(M),则 a → b
  • 传递性:如果 a → b 且 b → c,则 a → c
Lamport 论文

示例 → 意味着什么?
  • a → b 意味着“b 可能受到 a 的影响”
  • 那 a /→ b 呢?这意味着 b → a 吗?
  • a /→ b 且 b /→ a:事件是并发的
  • 事件并发意味着什么?
  • 关键洞见:
  • 没人能分辨出 a 或 b 先发生!

逻辑时钟

  • 为事件分配时间戳的方法
  • 保留先行关系
  • 目标:如果 a → b,则 C(a) < C(b)
  • 时钟条件:
  • 如果 a 和 b 在同一进程 i 上,且 a 在 b 之前,则 Ci(a) < Ci(b)
  • 如果 a = 进程 i 发送 M,且 b = 进程 j 接收 M,则 Ci(a) < Cj(b)
  • 如何实现这样的时钟?
实现逻辑时钟
  • 保持一个本地时钟 T
  • 事件发生时增加 T
  • 在所有消息上发送时钟值作为 Tm
  • 接收消息时:T = max(T, Tm) + 1

使用逻辑时钟形成全序
  • 新的关系:=>
  • 如果 C(a) < C(b),那么 a => b
  • 如果 C(a) == C(b) 呢? 示例平局决断:进程ID
  • 如果 a -> b,那么 a => b
  • 反过来呢?

互斥

确保共享资源一次只被一个进程访问,防止数据冲突和不一致。

  • 使用时钟实现锁:每个消息都带有一个时间戳,用于确定请求的顺序。
  • 目标:
    • 一次只有一个进程持有锁
    • 按请求顺序授予锁
    • 请求进程最终获得锁
  • 假设:
    • 按顺序的点对点消息传递
    • 没有故障

互斥实现-概念

  • 每条消息携带一个时间戳 Tm
  • 三种消息类型:
    • 请求(广播):当一个进程想要访问共享资源时,它会向所有其他进程广播一个带时间戳的请求消息。
    • 释放(广播):当进程完成对共享资源的访问后,它会广播一个释放消息,表示资源现在可用。
    • 确认(收到时):当一个进程收到请求消息时,它会回复一个确认消息。
  • 每个节点的状态:
    • 一个按 Tm 排序的请求消息队列
    • 它从每个节点收到的最新时间戳

互斥实现-过程

  • 收到请求时:
    • 记录消息时间戳
    • 将请求加入队列
    • 发送一个确认
  • 收到释放时:
    • 记录消息时间戳
    • 从队列中移除对应的请求
  • 收到确认时:
    • 记录消息时间戳

互斥实现-锁

  • 要获取锁:
    • 向所有人发送请求,包括自己
    • 当满足以下条件时获得锁:
      • 我的请求在我的队列头部,且
      • 我已经从每个人那里收到了更高时间戳的消息
      • 所以我的请求必须是最早的
  • 释放锁:
    • 向所有人发送释放,包括自己

示例1

  • A、B 和 C 同时请求访问文件。
  • A 的请求时间戳最早,所以它的请求在所有进程的队列头部。
  • A 从 B 和 C 那里收到确认消息。
  • A 获得锁,开始访问文件。
  • A 完成访问后,发送释放消息,其他进程更新队列。
  • 接下来,B 或 C 根据时间戳顺序获得锁。

示例2

在一个分布式系统中,三个服务器(或节点)S1、S2、S3使用基于时间戳的方法来处理互斥锁请求。每个服务器维护一个队列来记录其他服务器的锁请求,并根据时间戳来排序这些请求。这个过程涉及到时间戳的更新和队列的调整。

初始状态
  • 所有服务器(S1、S2、S3)的时间戳初始设置为0。
  • S1的队列中有一个请求:S1@0(S1在时间戳0的请求)。
  • 每个服务器还记录了它从其他服务器收到的最高时间戳(S1max, S2max, S3max),初始都设置为0。

第一步:S2 发送请求
  1. S2 发送请求:S2 将其时间戳更新为1,并向 S1 和 S3 发送一个请求(request@1),表示 S2 想要在时间戳1获得锁。

  2. 更新状态

    • S2:更新自己的时间戳为1。但队列和最大时间戳记录暂时不变,因为它还没有收到来自 S1 和 S3 的回复。
    • S1S3:在收到 S2 的请求后,它们需要将这个请求加入自己的队列,并更新与 S2 相关的最大时间戳记录。

第二步:队列更新和时间戳记录
  1. S2 更新队列

    • S2 将自己的请求(S2@1)加入队列,队列变为 [S1@0, S2@1]。这表示 S2 现在等待在 S1 后获得锁。
  2. S1 和 S3 更新队列和时间戳

    • 当 S1 和 S3 收到 S2 的请求后,它们将 S2@1 添加到各自的队列中,队列变为 [S1@0, S2@1]
    • 同时,S1 更新其记录的 S2 的最大时间戳为1(S2max:1),因为它刚刚收到了来自 S2 时间戳为1的请求。
    • S3 也做类似的更新,将其记录的 S2 的最大时间戳更新为1(S2max:1)。

第三步:S2发送ack@3到S1和S3
  • S2 发送一个带时间戳3的确认消息(ack@3)给 S1 和 S3。此时S2的时间戳仍为1。
  • S1 和 S3 收到 ack@3 后,将它们的时间戳更新为3(因为收到的时间戳3比它们当前的时间戳2大)。

S2 更新队列和时间戳
  • S2 将时间戳更新为5,并将 S1maxS3max 都更新为3。这可能是因为它收到了来自 S1 和 S3 的响应,说明它们知道的最大时间戳是3。

S1 发送 release@4 给 S2 和 S3
  • S1 发送一个带时间戳4的释放消息(release@4)给 S2 和 S3,并将自己的时间戳更新为4。
  • S2 和 S3 收到这个消息后,不会立即改变它们的时间戳,因为它们的当前时间戳已经比4大了。

最终更新
  • S2 将时间戳更新为6,并从队列中移除 S1@0,同时更新 S1max 为4(因为S1的最新已知时间戳是4)。
  • S1 将队列中的 S1@0 移除,只保留 S2@1
  • S3 将时间戳更新为5(可能是因为接收到另一个节点的消息),并在队列中保留 S2@1,同时更新 S1max 为4。

Lamport 时钟的问题?

  • 如果 a → b,则 C(a) < C(b)
  • 反之是否成立:如果 C(a) < C(b) 则 a → b?
    • 不,它们也可以是并发的
    • 如果我们使用 Lamport 时钟作为全局顺序,我们将引入一些不必要的排序约束

更好的逻辑锁

  • 一个使得反向也成立的锁
    • 如果 C(a) < C(b),那么 a → b
    • 注意仍然必须有并发事件
    • 有时既不是 C(a) < C(b) 也不是 C(b) < C(a)
    • 向量时钟!

向量时钟

  • 时钟是一个向量 C,长度等于节点数
    • 例如,对于一个3节点系统是 (0, 0, 0)
  • 在节点 i 上,每个事件递增 C[i]
    • 节点 0 (3, 5, 2);事件后:(4, 5, 2)
  • 在节点 i 收到带有时钟 Cm 的消息时:
    • 递增 C[i]
    • 对于每个 j != i
    • C[j] = max(C[j], Cm[j])
    • 示例:
    • 节点 0 (4, 5, 2) 收到消息 (2, 7, 0):(5, 7, 2)

向量时钟-比较

  • 逐元素比较向量
  • 如果对于某些 i, j,Cx[i] < Cy[i] 且 Cx[j] > Cy[j]
    • Cx 和 Cy 是并发的
  • 如果对于所有 i,Cx[i] <= Cy[i],并且存在 j 使得 Cx[j] < Cy[j]
    • Cx 在 Cy 之前发生

  • 23
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值