BFS Master 高可用设计方案

背景

在BFS中,nameserver负责管理文件元信息以及所有chunkserver的状态信息,是整个系统中唯一拥有全局信息的模块,同时也成为了系统的单点。nameserver的不可用会直接导致文件系统的瘫痪,于是提高nameserver的可用性至关重要。

整体设计

如下图所示,我们将nameserver扩展为集群,Client只与集群Leader进行交互。每一个nameserver中有一个同步模块(Sync),负责集群间的状态同步,保证元数据的一致性。
图片名称

主要操作流程方案一

Client向Leader Nameserver发起请求,Leader收到请求后,检查操作合法性。如果操作是合法的,Leader将需要落地的数据通过Sync扩散给从Nameserver。Sync模块返回扩散成功后,Leader向Client返回操作成功。
检查合法性可以并发执行,串行向Sync提交结果,Sync模块严格按照这个顺序扩散,扩散成功后Leader才可以将结果写进数据库。但是这样Leader的性能瓶颈就在于Sync的扩散,当Nameserver集群跨机房跨地域部署时,这样的延时是不能接受的。于是我们对这里进行了如下图所示的优化。
图片名称

Leader在收到操作后先对数据库打一个快照,检查完合法性后,在提交给Sync之前就将数据写入本地数据库。之后再将操作提交给Sync,Sync返回扩散成功后,Leader将快照删除并给向Client返回成功。在Sync返回成功前,所有的读请求都会读快照之前的数据,也就是说Client不会读到还未扩散成功的数据。

扩散的失败,例如RPC超时、写失败等需要重试处理,如果超过一定重试次数,则均视为Nameserver集群不可用,需人工介入处理。各一致性协议对于扩散失败的定义不同,例如Raft中,大于半数成员收到消息便认为扩散成功;主从模式中主或从任意一方写失败均认为是扩散失败。

主要操作流程方案二

Client向Leader Nameserver发起请求,Leader收到请求后,对所需操作的路径加锁(加锁逻辑见另一文档),检查操作合法性。如果操作是合法的,Leader将需要落地的数据通过Sync扩散给从Nameserver。Sync模块返回扩散成功后,Leader向Client返回操作成功。Follower收到提交操作的指令后,无需检查操作合法性,直接根据指令执行操作更改状态机和内存结构。

对于某一操作,具体流程如下:

  1. Leader 收到请求,检查请求合法性

  2. Leader 将操作指令序列化并交由Sync同步

  3. Follower 收到指令后持久化指令

  4. Both 确定操作同步成功后将操作应用到状态机,并更改内存状态

方案一为同步结果,方案二为同步操作。同步结果的问题在于当操作的结果很大(例如,rmr /),可能超出内存大小范围,从而很难保证操作原子性。同步操作基于一个假设:Leader和Followers将同一个指令应用到状态机及更改内存状态所产生的结果严格一致。

一期高可靠方案 - 主从模式

Nameserver的HA方案数据流如上描述,其中Sync模块是保证数据可靠和高可用的核心。我们把这个模块设计成可插拔的插件模式,可以选用任意一种一致性协议实现以满足不同可靠、可用和性能要求。一期方案是实现一个主从模式的Nameserver,首先保证数据的可靠性,在一定程度上提高可用性。

当主宕机时,需要将从切换为主。这是向从发送切换命令,从将自己的term加一,然后切换为主对外提供服务。term的作用主要为了标识曾经发生过主从切换,因为当前实现中,主的状态机中可能存在脏数据,之前的主作为从重启,而又没有清理自己的状态机,脏数据将不会被发现。在term机制下,之前的主以从的身份重启后,会发现有比自己term更高的主存在,会将自己的状态机和本地日志清理干净,然后等待主发送镜像。