基于zookeeper的主备切换方法

继承CZookeeperHelper即可快速实现主备切换: https://github.com/eyjian/mooon/blob/master/mooon/include/mooon/net/zookeeper_helper.h zookeeper的ZOO_EPHEMERAL节点(如果ZOO_EPHEMERAL满足不了需求,可以考虑和ZOO_SEQUENCE结合使用),在会话关闭或过期时,会自动删除,利用这一特性可以实现两个或多节点间的主备切换。 实现方法: 1)在进程启动时调用zookeeper_init()初始化: bool X::init_zookeeper() {     // 第一次调用时_clientid总是为NULL,     // 状态为ZOO_EXPIRED_SESSION_STATE时,需要重新调用zookeeper_init,     // 这个时候可传入的_clientid为前一次zookeeper_init()产生的_clientid     // 请注意zookeeper_init()是一个异步调用,返回非NULL并不表示会话建立成功,     // 只有当zk_watcher中的type为ZOO_SESSION_EVENT和state为ZOO_CONNECTED_STATE时,     // 才真正表示会话建立成功。     _zhandle = zookeeper_init(zk_hosts, zk_watcher, 5000, _clientid, this, 0);     if (NULL == _zhandle)     {         MYLOG_ERROR("init zookeeper failed: %s\n", zerror(errno));         return false;     }     MYLOG_INFO("init zookeeper(%s) successfully\n", zk_hosts);     return true; } 2)进入工作之前,先尝试切换成主,只有成功切换成主后才进入work bool X::run() {     while (true)     {         int num_items = 0;         // 备机最简单的方法是每隔一定时间,如1秒就尝试转成master,         // 如果不使用轮询,则可以采用监视_zk_path的方式         mooon::sys::CUtils::millisleep(1000);         // 如果不是master,则尝试转成master,如果转成不成功则继续下一次尝试         if (!is_master() && !change_to_master())             continue;         do_work();     } } bool X::is_master() const {     return _is_master; } bool X::change_to_master() {     static uint64_t log_counter = 0; // 打log计数器,备状态时的日志输出     // ZOO_EPHEMERAL|ZOO_SEQUENCE     // _myip为本地IP地址,可以通过它来判断当前谁是master     // _zk_path值示例:/master/test,注意需要先保证/master已存在     int errcode = zoo_create(_zhandle, _zk_path.c_str(), _myip.c_str(), _myip.size()+1, &ZOO_OPEN_ACL_UNSAFE, ZOO_EPHEMERAL, NULL, 0);     // (-4)connection loss,比如为zookeeper_init()指定了无效的hosts(一个有效的host也没有)     if (errcode != ZOK)     {         _is_master = false;         // 减少为备状态时的日志输出         if (0 == log_counter++ % 600)         {             MYLOG_DEBUG("become master[%s] failed: (%d)%s\n", _zk_path.c_str(), errcode, zerror(errcode));         }         return false;     }     else     {         _is_master = true;         log_counter = 0;         MYLOG_INFO("becase master[%s]\n", _zk_path.c_str());         // sleep一下,以便让原master正在进行的完成         mooon::sys::CUtils::millisleep(2000);         return true;     } } 3)当zookeeper会话成功建立或过期时均会触发zk_watcher,可通过type和state来区分 void zk_watcher(zhandle_t *zh, int type, int state, const char *path, void *context) {     X* x = static_cast(context);     MYLOG_DEBUG("zh=%p, type=%d, state=%d, context=%p, path=%s\n", zh, type, state, context, path);     // zookeeper_init成功时type为ZOO_SESSION_EVENT,state为ZOO_CONNECTED_STATE     if ((ZOO_SESSION_EVENT == type) && (ZOO_CONNECTED_STATE == state))     {         x->on_zookeeper_connected(path);     }     else if ((ZOO_SESSION_EVENT == type) && (ZOO_EXPIRED_SESSION_STATE == state))     {         // 需要重新调用zookeeper_init(),简单点可以退出当前进程重启         x->on_zookeeper_expired();     } } 附: zookeeper日志 默认情况下zookeeper日志是输出到stderr,但可以通过zoo_set_log_stream()来定向到自己的日志输出中,还可以使用zoo_set_debug_level()来控制zookeeper的日志级别。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏日常分享

NIO 服务端TCP连接管理的方案

   因为服务端与客户端实现的是长连接,所以需要对客户端的连接情况进行监控,防止无效连接占用资源。

1235
来自专栏SAP最佳业务实践

SAP最佳业务实践:SD–销售订单处理:自库存销售(109)-3发货

VL10C交货处理 在此活动中,创建交货。 角色仓库文员 后勤 ®后勤执行®外向处理®外向交货的发货 ®外向交货®创建®交货凭证到期日的集中处理 ®销售订单项目...

3423
来自专栏xdecode

Netty与传统Server对比

前言 本文旨在介绍传统Socket服务端与NIO服务端的差异. 以餐厅服务员简单举例,每个客人对应一个请求. 传统Socket / OIO 1 public ...

2587
来自专栏架构师之旅

【Java SE】Java NIO系列教程(六) Selector

Selector(选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件。这样,一个单独的线程可以管理多个cha...

1855
来自专栏coolblog.xyz技术专栏

基于 Java NIO 实现简单的 HTTP 服务器

本文是上一篇文章实践篇,在上一篇文章中,我分析了选择器 Selector 的原理。本篇文章,我们来说说 Selector 的应用,如标题所示,这里我基于 Jav...

71812
来自专栏专注于主流技术和业务

SpringMVC源码阅读:ContextLoaderListener初始化过程

ContextLoaderListener监听器的作用就是启动web容器时,自动装配ApplicationContext的配置信息。它实现了ServletCon...

3164
来自专栏chenssy

【死磕Netty】-----NIO基础详解

原文出处http://cmsblogs.com/ 『chenssy』 转载请注明原创出处,谢谢! Netty 是基于Java NIO 封装的网络通讯框架,只有充...

4776
来自专栏大数据架构

Java进阶(五)Java I/O模型从BIO到NIO和Reactor模式

2105
来自专栏Linux驱动

Linux-使用patch命令给uboot打补丁(3)

patch:修改文件,让用户对原文件打补丁 用法   patch -p[剥离层级]  <[补丁文件] 打补丁示例: u-boot-1.1.6_jz2440.p...

3059
来自专栏芋道源码1024

【Netty 专栏】Netty 源码分析之 accept 过程

在Netty源码分析之NioEventLoop章节中,已经分析了NioEventLoop的工作机制,当有客户端connect请求,selector可以返回其对应...

1200

扫码关注云+社区

领取腾讯云代金券