tfs主从nameserver节点容错性—源码解读
2015-10-23 19:52
381 查看
1 前言
在tfs集群服务里,nameserver采用HA架构:由heart agent维护着的nameserver的vip,对于客户端和数据节点来说,会直接和nameserver的vip沟通,所以至于后台有多少个nameserver和具体由那个nameserver提供服务是透明的。
另外nameserver的职责:维护了所有block数据的位置信息、元数据信息及其两者之间的映射信息,所以其是一个有状态的节点;并且负责所有dataserver的状态检查;负载、迁移等任务下发;所以nameserver类似整个集群的大脑,作用至关重要。而要完成nameserver主从之间的无缝实时切换,需要保证两点要求:
a. 运行服务时期,保证主nameserver控制器与从nameserver是状态对等的;
b. 发生故障切换时期,保证主从nameserver的切换对用户是透明的。
2 代码实现与原理
a. 透明切换
NameServerHeartManager 负责与从nameserver之间的心跳,完成master和slave角色之间的切换。切换的逻辑较简单:只需将vip从原来的主nameserver控制器到从nameserver控制器的映射切换,代码如下:
b. 状态同步:
切换后仍需要正常提供工作,不影响用户的操作,即需要镜像主nameserver到从nameserver的状态。OpLogSyncManager: 负责主控服务nameserver节点的所有操作日志在从控服务nameserver上的发送、接收与重放,同步两者之间的状态,代码如下:
在tfs集群服务里,nameserver采用HA架构:由heart agent维护着的nameserver的vip,对于客户端和数据节点来说,会直接和nameserver的vip沟通,所以至于后台有多少个nameserver和具体由那个nameserver提供服务是透明的。
另外nameserver的职责:维护了所有block数据的位置信息、元数据信息及其两者之间的映射信息,所以其是一个有状态的节点;并且负责所有dataserver的状态检查;负载、迁移等任务下发;所以nameserver类似整个集群的大脑,作用至关重要。而要完成nameserver主从之间的无缝实时切换,需要保证两点要求:
a. 运行服务时期,保证主nameserver控制器与从nameserver是状态对等的;
b. 发生故障切换时期,保证主从nameserver的切换对用户是透明的。
2 代码实现与原理
a. 透明切换
NameServerHeartManager 负责与从nameserver之间的心跳,完成master和slave角色之间的切换。切换的逻辑较简单:只需将vip从原来的主nameserver控制器到从nameserver控制器的映射切换,代码如下:
//nameserver主备状态信息 struct NsRuntimeGlobalInformation { uint64_t heart_ip_port_; uint64_t owner_ip_port_; uint64_t peer_ip_port_; int64_t switch_time_; int64_t discard_newblk_safe_mode_time_; int64_t lease_id_; int64_t lease_expired_time_; int64_t startup_time_; uint32_t vip_; bool destroy_flag_; int8_t owner_role_; int8_t peer_role_; int8_t owner_status_; int8_t peer_status_; } //peer_ip_port_ 表示对等的对方ip&port //owner_ip_port_ 表示本地的ip&port //vip_ 表示当前主控服务器的代理ip,通过vip_可以判断自己的身份 // 心跳检查 void NameServerHeartManager::check_() { time_t now = 0; NsKeepAliveType keepalive_type_ = NS_KEEPALIVE_TYPE_LOGIN; int32_t sleep_time = SYSPARAM_NAMESERVER.heart_interval_ / 2; NsRuntimeGlobalInformation& ngi = GFactory::get_runtime_info(); while (!ngi.is_destroyed()) { now = Func::get_monotonic_time(); ns_role_establish_(ngi, now); if (ngi.is_master()) { ns_check_lease_expired_(ngi, now); } else { keepalive_(sleep_time, keepalive_type_, ngi, now); if (!ngi.has_valid_lease(now)) keepalive_type_ = NS_KEEPALIVE_TYPE_LOGIN; else keepalive_type_ = NS_KEEPALIVE_TYPE_RENEW; } if (sleep_time <= 0) { sleep_time = SYSPARAM_NAMESERVER.heart_interval_ / 2; sleep_time = std::max(sleep_time, 1); } Func::sleep(sleep_time, ngi.destroy_flag_); } keepalive_type_ = NS_KEEPALIVE_TYPE_LOGOUT; keepalive_(sleep_time, keepalive_type_, ngi, now); } //如果vip飘到本地ip,则表示本节点成主控制器 int NameServerHeartManager::ns_role_establish_(NsRuntimeGlobalInformation& ngi, const time_t now) { if (check_vip_(ngi))//vip is local ip { if (!ngi.is_master())//slave, switch switch_role_salve_to_master_(ngi, now); } else { if (ngi.is_master()) switch_role_master_to_slave_(ngi, now); } return TFS_SUCCESS; }
b. 状态同步:
切换后仍需要正常提供工作,不影响用户的操作,即需要镜像主nameserver到从nameserver的状态。OpLogSyncManager: 负责主控服务nameserver节点的所有操作日志在从控服务nameserver上的发送、接收与重放,同步两者之间的状态,代码如下:
//重播日志消息类 class OpLogSyncMessage: public common::BasePacket { bool alloc_; int32_t length_; char* data_; }; //解析日志消息类,并根据日志的操作类型,进行相应的重放在从nameserver上 int OpLogSyncManager::replay_helper(const char* const data, const int64_t data_len, int64_t& pos, const time_t now) { OpLogHeader header; int32_t ret = ((NULL != data) && (data_len - pos >= header.length())) ? TFS_SUCCESS : EXIT_PARAMETER_ERROR; if (TFS_SUCCESS == ret) { ret = header.deserialize(data, data_len, pos); if (TFS_SUCCESS == ret) { uint32_t crc = 0; crc = Func::crc(crc, (data + pos), header.length_); if (crc != header.crc_) { TBSYS_LOG(ERROR, "check crc: %u<>: %u error", header.crc_, crc); ret = EXIT_CHECK_CRC_ERROR; } else { int8_t type = header.type_; switch (type) { case OPLOG_TYPE_REPLICATE_MSG: case OPLOG_TYPE_COMPACT_MSG: ret = replay_helper_do_msg(type, data, data_len, pos); break; case OPLOG_TYPE_BLOCK_OP: ret = replay_helper_do_oplog(now, type, data, data_len, pos); break; default: TBSYS_LOG(WARN, "type: %d not found", type); ret = EXIT_PLAY_LOG_ERROR; break; } } } } return ret; }
相关文章推荐
- 第 三 十 九 天:vim 设 置 自 动 缩 进 及 详 解
- 轻松学习JavaScript二:JavaScript语言的基本语法要求
- 字符串找字符串
- 【基础练习】【IDA*】codevs1288 埃及分数题解
- 函数传参测试(传地址还是传值)
- 【单例模式】单例模式 & GCD单例模式 & 将封装单例模式到宏
- HDU 2845 Beans
- tomcat绑定域名
- Java网络爬虫讲解
- c++宏源证券编程
- 【POJ 3122】Pie
- codechef Cleaning Up 解决问题的方法
- TCP状态转换
- JS Replace全部替换字符方法
- MySQL 1045登录失败
- dataStructure@ Find if there is a path between two vertices in a directed graph
- ubuntu 操作补充 查找文件 和 awk
- My coding way (7)
- 视频
- 通过Intent传递对象,已Map为例