9.2.4 UpdateServer选主
为了确保一致性,RootServer需要确保每个集群中只有一台UpdateServer提供写服务,这个UpdateServer称为主UpdateServer。
RootServer通过租约(Lease)机制实现UpdateServer选主。主UpdateServer必须持有RootServer的租约才能提供写服务,租约的有效期一般为3~5秒。正常情况下,RootServer会定期给主UpdateServer发送命令,延长租约的有效期。如果主UpdateServer出现异常,RootServer等待主UpdateServer的租约过期后才能选择其他的UpdateServer为主UpdateServer继续提供写服务。
RootServer可能需要频繁升级,升级过程中UpdateServer的租约将很快过期,系统也会因此停服务。为了解决这个问题,RootServer设计了优雅退出的机制,即RootServer退出之前给UpdateServer发送一个有效期超长的租约(比如半小时),承诺这段时间不进行主UpdateServer选举,用于RootServer升级。代码如下:
enum ObUpsStatus
{
UPS_STAT_OFFLINE=0,//UpdateServer已下线
UPS_STAT_NOTSYNC=1,//UpdateServer为备机且与主UpdateServer不同步
UPS_STAT_SYNC=2,//UpdateServer为备机且与主UpdateServer同步
UPS_STAT_MASTER=3,//UpdateServer为主机
};
//RootServer中记录UpdateServer信息的结构
class ObUps
{
ObServer addr_;//UpdateServer地址
int32t inner_port;//UpdateServer内部端口
int64t log_seq_num;//UpdateServer的日志号
int64t lease;//UpdateServer的租约
ObUpsStatus stat_;//UpdateServer状态
};
class ObUpsManager
{
public:
//UpdateServer向RootServer注册
int register_ups(const ObServer&addr,int32_t inner_port,int64_t log_seq_num,int64_t lease,const char*server_version);
//检查所有UpdateServer的租约,RootServer内部有专门的线程会定时调用该函数
int check_lease();
//RootServer给UpdateServer发送租约
int grant_lease();
//RootServer给UpdateServer发送超长租约
int grant_eternal_lease();
private:
ObUps upsarray[MAX_UPS_COUNT];
int32t ups_master_idx;
};
RootServer模块中有一个ObUpsManager类,它包含一个数组upsarray,其中的每个元素表示一个UpdateServer,upsmaster_idx表示主UpdateServer在数组里的下标。ObUps结构记录了UpdateServer的信息,包括UpdateServer的地址(addr)以及内部端口(inner_port),UpdateServer的状态(stat,分为UPS_STAT_OFFLINE/UPS_STAT_NOTSYNC/UPS_STAT_SYNC/UPS_STAT_MASTER这四种),UpdateServer的日志号(log_seq_num)以及租约(lease_)。
UpdateServer首先通过register_ups向RootServer注册,将它的信息告知RootServer。一段时间之后,RootServer会从所有注册的UpdateServer中选取一台日志号最大的作为主UpdateServer。ObUpsManager类中还有一个check_lease函数,由RootServer内部线程定时调用,如果发现UpdateServer的租约快要过期,则会通过grant_lease给UpdateServer延长租约。如果发现主UpdateServer的租约已经失效,则会从所有Update-Server中选择一个日志号最大的UpdateServer作为新的主UpdateServer。另外,Root-Server还可以通过grant_eternal_lease给UpdateServer发送超长租约。