基于zookeeper的主备切换方法
来源:互联网 发布:网站搜索排名优化 编辑:程序博客网 时间:2024/06/18 12:55
继承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的日志级别。
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
上一篇:如何正确配置Nginx+PHP
下一篇:新版mysql搭建多线程主从复制
相关热门文章
- Hadoop集群完全分布式模式环境...
- 大数据之快速搭建hadoop2.6集...
- Zookeeper分布式集群部署...
- Hadoop初探之Hadoop生态圈...
- Hadoop学习全程记录——在Ecli...
- linux dhcp peizhi roc
- 关于Unix文件的软链接
- 求教这个命令什么意思,我是新...
- sed -e "/grep/d" 是什么意思...
- 谁能够帮我解决LINUX 2.6 10...
给主人留下些什么吧!~~
评论热议
0 0
- 基于zookeeper的主备切换方法
- 基于zookeeper的主备切换方法
- Dubbo+Zookeeper+SpringMVC:基于注解的配置方法
- 基于zookeeper的线程及其zookeeper简介
- zookeeper HA 实现主备切换
- Zookeeper 05 示例代码-主备节点切换
- Spring中基于注解的动态切换数据源方法
- 基于Zookeeper的使用详解
- 基于zookeeper的分布式Queue
- Spark基于zookeeper的HA
- 基于zookeeper的配置中心
- 基于zookeeper的dubbo配置
- 基于zookeeper的dubbo入门教程
- 基于zookeeper的dubbo基础教程
- zookeeper-基于的Paxos算法
- 基于Zookeeper的分布式锁
- 基于ZooKeeper的分布式锁
- 通过dubbo暴露接口调用方法,及基于zookeeper的dubbo涉及配置文件
- java学习:ArrayList的实现及原理
- hdu4965——Fast Matrix Calculation(快速矩阵幂优化)
- Spring中获取数据库表主键序列
- 如何正确配置Nginx+PHP
- java程序操作Geometry对象
- 基于zookeeper的主备切换方法
- 线程池ExecutorService
- Reabble.com-KindleRSS新闻杂志订阅
- 同步异步阻塞非阻塞区别
- Docker+Redis3集群环境搭建
- Git服务器的搭建
- 关于Redis数据过期策略
- LeetcodeUnique Paths
- ArcGIS Engine实现图层间空间选择的优化策略
原创粉丝点击
热门IT博客
热门问题
老师的惩罚
人脸识别
我在镇武司摸鱼那些年
重生之率土为王
我在大康的咸鱼生活
盘龙之生命进化
天生仙种
凡人之先天五行
春回大明朝
姑娘不必设防,我是瞎子
怎样包书皮
自粘书皮
如何包书皮
塑料书皮
书皮图片
书皮网
书皮设计
包书皮厂家
书皮封面
怎么做书皮
自制书皮
纸书皮
包书皮方法
包书皮教程
不织布书皮
书皮包装纸
书本书皮
自己做书皮
绿书皮在线完整观看
5款包书皮样品或致儿童性早熟
怎么包书皮的步骤图解
纸书皮怎么包
包书皮怎么包
创意包书皮10种方法
包书皮的方法
包书皮好看的十种方法
包书皮的步骤
怎么用纸包书皮
怎样用纸包书皮
包书皮的步骤图解
如何用纸包书皮
必读书目
阅读书目
推荐书目
书目
参考书目
书目推荐
初中必读书目
小学生阅读书目
六年级必读书目
高中生必读书目