DAOS系统架构-RSVC

1. 概述

rsvc模块实现了一个通用的replicated service framework。在讲述rsvc模块之前,先谈谈服务副本的基本基本知识。

某些DAOS RPC服务,比如Pool Service (pool_svc)以及Container Service (cont_svc),都是采用Raft状态机制方法进行复制的。这类服务可以容忍少数副本中的任何一个出现故障。通过将服务副本分布在不同的故障域中,该服务可以实现高可用性。由于这种复制方法是自包含的,即它只需要本地持久化存储以及点对点地不可靠消息传递,而不需要借助任何外部管理服务。因此这些服务对于引导DAOS系统以及管理轻量级I/O复制协议的配置是必不可少的。

   

2. 架构

一个RPC服务会根据其当前的服务状态来处理传入的服务请求。因此,复制一个服务实际上就是复制它的状态,以便每个请求都可以基于之前处理的状态来处理。

服务的状态是通过Raft日志进行复制的。该服务将请求转换为状态查询和确定性的状态更新。在应用该状态之前,该状态的所有更新操作都必须要先提交到Raft日志中。由于Raft保证了日志副本之间的一致性,因此服务副本最终以相同的顺序应用相同的更新状态集,并经历完全相同的状态历史。

Raft采用强领导地位设计,每个复制的服务也是如此。一个任期内的领导者服务与统一Raft任期内的Raft领导者是同一实体。在所有的副本服务中,只有最高任期的领导者可以处理请求。在服务端侧,领导者与非领导者服务的代码类似,只是对领导地位变更事件的处理有所不同。在客户端侧,请求必须要发送给当前领导者,如果不知道当前领导者是谁,则必须进行查找。

一个复制的服务是通过一堆模块来实现的:

[ pool_svc, cont_svc, ... ]
[ ds_rsvc ]
[                rdb                ]
[ raft ]
[                vos                ]

pool_svccont_svc都各自实现了2个句柄:请求句柄和领导地位变更事件句柄。它们根据rdb数据模型来定义各自的服务状态,使用rdb事务实现状态查询和更新,并将领导地位变更事件句柄注册到rsvc提供的框架中。

rdb(daos_srv/rdb)实现了一种具有事务功能的key-value存储模型,并通过Raft进行复制。它将Raft领导地位变更事件传递给ds_rsvc,通过Raft日志实现事务,并使用VOS数据模型存储服务的数据模型及其自身的内部元数据。领导者服务上的rdb与VOS进行交互,以监控可用的持久化存储。当可用空间降至阈值以下时,在将条目追加到Raft日志之前,将拒绝新的事务。否则可能导致服务不可用(因为在应用这些条目时,部分成功,部分因为空间不足而失败)。它还与VOS交互,通过触发旧版本日志的聚合来定期压缩存储空间。

raft(rdb/raft/include/raft.h)以库的形式实现了Raft核心协议。它通过回调函数在 rdb 内部完成与VOS和CaRT的集成。

一个复制的服务的客户端(例如:dc_pool)使用dc_rsvc来搜索当前服务的领导者。

[ dc_pool ]
[ dc_rsvc ]

搜索是通过结合客户端维护的候选服务副本列表以及在某些情况下server的RPC错误响应来完成的,这些错误响应中包含了当前领导者可能所在位置的提示。未运行该服务的server会返回一个错误,客户端会根据此错误将该server从其列表中移除。非领导者副本的server会返回不同的错误,其中包括一个提示,客户端可根据该提示将该server添加到列表中,并改变其对领导者的搜索。而且,在客户端启动时以及之后客户端的候选服务副列表可能为空时(例如,服务成员的变化),dc_rsvc会联系运行在管理服务节点上的其中一个DAOS server,以获取该池的最新服务副本列表。

   

rsvc模块

rsvc的主要目是避免不同的复制服务在实现上出现代码重复。这个回调密集型的API源于尽可能地提取通用代码,即使是以牺牲API简洁性为代价。这是它与其他模块API设计方式地一个关键区别。

rsvc有2个部分:

  • ds_rsvc(daos_srv/rsvc.h):服务端框架
  • dc_rsvc(daos/rsvc.h):客户端库