持久化 Bucket 通知深入解析
可靠性 ¶
持久化 Bucket 通知 将在 Ceph "Pacific" 中引入。其背后的想法是允许从 RADOS 网关 (RGW) 到配置在主题中的端点的可靠且异步的通知传递。常规通知也可以被认为是可靠的,因为向端点的传递是在请求期间同步执行的。
常规通知的可靠性来自 RGW。例如,客户端在从端点收到 ACK 之前不会收到 ACK。但是,如果端点不可靠,则解决方案也不可靠。例如,如果端点离线,客户端将不会重试。
此外,请注意,对于常规通知,如果端点发送回 NACK,操作仍然被认为成功(因为无法回滚在尝试通知之前发生的 RADOS 操作)。
当端点关闭时,唯一的指示是通知超时;使用常规通知会减慢 RGW 的操作速度,甚至可能使其完全停止。
使用持久化通知,即使端点关闭或操作期间发生与端点的网络断开,RGW 也允许重试发送通知(即,如果未成功传递到端点,则重试通知)。
在异步操作期间,通知被推入队列(如下所示)。队列操作分两个阶段完成(预留 和 提交 或 中止),以保证队列操作与其它操作的原子性。
| 类型 | RGW 故障 | 端点故障 | 原子操作 | 同步操作 |
|---|---|---|---|---|
| 常规 | 是 | 否 | 否 | 是 |
| 持久化 | 是 | 是 | 是^ | 否 |
^ 如下所述,即使 预留 成功,提交 也可能失败
两阶段提交 队列 ¶
我们使用持久化(RADOS 备份)、有界、两阶段提交队列来存储通知。这通过 2pc_cls_queue Ceph 对象类 实现。
将通知发送到此队列将分 2 步进行
- 预留 队列上的通知位置。如果队列已满(例如,端点关闭,并且队列中存在太多待处理的通知),则预留将失败,这将导致 RGW 上的操作失败。
> 注意:预留应在执行任何 RADOS 操作之前进行,因此不需要回滚)。
- 执行 RGW 的实际操作。/并执行 提交 或 中止 预留。如果任何操作失败,我们将 中止 预留。如果一切都成功,我们将 提交 预留,将通知推入队列。
> 注意:> 1. 如果由于某种原因(例如,RGW 在 预留 和 提交/中止 之间崩溃)未显式中止,则会自动清理旧的预留。 > 2. 虽然不太可能,但 提交 操作也可能失败,但在这种情况下,我们无法回滚 RADOS 操作,因此我们将不会使整个操作失败,而是会记录错误。
异步地,RGW 中的一个(不一定是推送通知到队列中的那个)将 列出 队列中的通知并将这些通知发送到端点。一旦端点 ACK 通知,我们就从队列中 删除 它们。未 ACK 的通知将保留在队列中,并在下次处理队列时重试。列出 和 删除 操作都是批量完成的,这意味着一旦我们从端点收到 NACK,只有已经 ACK 的通知才会被删除,其它通知将保留。
主题和队列 ¶
每次创建持久化 Bucket 通知主题时,都会创建一个匹配的队列(名称相同)。队列是属于“log”池中“notif”命名空间的 RADOS 对象。
为每个端点拥有单独的队列允许隔离端点之间的问题。例如,一个关闭的端点可能会填满其队列,但不会影响其他队列。
> 注意:由于通知的大小通常远小于实际对象,并且每次写入或删除对象时都会写入,因此建议“log”池位于快速介质上,并且可以小于对象所在的池。
除了队列对象之外,还将在“queues_list_object”命名的全局对象中保存所有队列的列表;系统使用此对象在不同的行之间分配队列处理所有权。例如,如果我们在集群中创建了两个持久化主题,一个名为“fishtopic”,另一个名为“dogtopic”,我们将看到
# rados -p default.rgw.log -N notif ls
fishtopic
queues_list_object
dogtopic
通过 删除主题 删除队列(及其所有待处理通知)。
在许多情况下,来自多个来源的通知可以共享同一个主题,即使单个 Bucket 为主题生成通知。 删除通知 定义或 Bucket 将阻止新的通知推送到该队列,但不会删除队列中的任何待处理通知。
队列所有权 ¶
任何 RGW 都可以将通知推送到任何队列(队列是允许多个并发写入者的 RADOS 对象)。但是,为了防止重复通知并保证在其他 RGW 发生故障的情况下进行处理,每个队列在任何时候都由单个 RGW 拥有。
所有权通过 lock Ceph 对象类实现。
每 30 秒,每个 RGW 都会遍历“queues_list_object”中的队列列表,并尝试独占地 锁定 它们
- 如果此 RGW 已经锁定队列,它将 续订 它
- 如果另一个 RGW 锁定队列,它将对其不做任何操作
- 如果任何 RGW 没有锁定队列,它将 锁定 它并开始对其进行处理。当添加新主题或 RGW 崩溃并且未在 90 秒内 续订 其锁时,这种情况可能会发生(这确保了只有在 RGW 崩溃时才会转移所有权)> 锁的名称将类似于队列的名称,并带有“_lock”后缀
要查看队列的所有权,请执行以下命令
# rados -p default.rgw.log -N notif lock info fishtopic fishtopic_lock
{"name":"fishtopic_lock","type":"exclusive","tag":"","lockers":[{"name":"client.4137","cookie":"gEToHBoc635RTGPp","description":"","expiration":"2021-03-16T18:58:11.244676+0200","addr":"10.46.11.34:0/4074536612"}]}
此输出指示哪个 RGW 拥有锁,以及它是否每 30 秒续订一次。
多个行可能位于同一主机上(具有相同的 IP),但它们将使用其 nonce(“addr”字段中的斜杠数)来区分。此唯一地址在 RGW 日志文件中(设置 debug-ms 标志时)找到。