Zookeeper C++编程实战之主备切换

默认zookeeper日志输出到stderr, 可以调用zoo_set_log_stream(FILE*)设置输出到文件中 还可以调用zoo_set_debug_level(ZooLogLevel)控制日志级别!!! 类CZookeeperHelper提供基于zookeeper的主备切换接口和读取数据等接口: https://github.com/eyjian/libmooon/blob/master/include/mooon/net/zookeeper_helper.h 使用示例:

 class CMyApplication: public mooon::net::CZookeeperHelper
  
 {
 
 public:
 
 			    CMyApplication(const char* data);
 
 			    void stop() { _stop = true; }
 
 			    void run();
 
 			    void wait();
 
 
 
 private:
 
 			    void work();
 
 
 
 private:
 
 			    virtual void on_zookeeper_session_connected(const char* path);
 
 			    virtual void on_zookeeper_session_connecting(const char* path);
 
 			    virtual void on_zookeeper_session_expired(const char *path);
 
 			    virtual void on_zookeeper_session_event(int state, const char *path);
 
 			    virtual void on_zookeeper_event(int type, int state, const char *path);
 
 
 
 private:
 
 			    volatile bool _stop;
 
 			    std::string _master_path; 用来竞争master的zookeeper节点路径
 
 			    std::string _master_data; 成功竞争为master时,写入_master_path的数据,主备应当提供不同的数据,以方便判断自己是否处于主状态
 
 };
 
 
 
 int main(int argc, char* argv[])
 
 {
 
 			    try
 
 {
 
 			        mooon::sys::g_logger = mooon::sys::create_safe_logger();
 
 const std::string zk_nodes = "127.0.0.1:2181";
 
 const int session_timeout_seconds = 1;
 
 
 
 			        CMyApplication myapp(argv[1]);
 
 			        myapp.create_session(zk_nodes, session_timeout_seconds);
 
 			        myapp.run();
 
 			        myapp.wait();
 
 
 
 			        return 0;
 
 }
 
 			    catch (mooon::sys::CSyscallException& ex)
 
 {
 
 			        fprintf(stderr, "%s\n", ex.str().c_str());
 
 exit(1);
 
 }
 
 			    catch (mooon::utils::CException& ex)
 
 {
 
 			        fprintf(stderr, "%s\n", ex.str().c_str());
 
 exit(1);
 
 }
 
 }
 
 
 
 			CMyApplication::CMyApplication(const char* data)
 
 : _stop(false)
 
 {
 
 			    _master_path = "/tmp/a";
 
 if (data != NULL)
 
 			        _master_data = data;
 
 }
 
 
 
 			void CMyApplication::run()
 
 {
 
 			    启动时竞争master,
 
 			    在成为master之前不能进入工作状态
 
 while (!_stop)
 
 {
 
 int zk_errcode;
 
 			        std::string zk_errmsg;
 
 
 
 if (race_master(_master_path, _master_data, &zk_errcode, &zk_errmsg))
 
 {
 
 			            成为master后,
 
 			            要让原来的master有足够时间退出master状态
 
 			            MYLOG_INFO("Race master at %s with %s successfully, sleep for 10 seconds to let the old master quit\n", _master_path.c_str(), _master_data.c_str());
 
 			            mooon::sys::CUtils::millisleep(10000);
 
 			            MYLOG_INFO("Start working now\n");
 
 
 
 			            work();
 
 if (!_stop)
 
 {
 
 			                退出work(),表示需要重新竞争master
 
 			                MYLOG_INFO("Turn to slave from master at %s with %s successfully, stop working now\n", _master_path.c_str(), _master_data.c_str());
 
 }
 
 }
 
 else
 
 {
 
 			            如果node_exists_exception()返回true,表示已有master,
 
 			            即_master_path已存在,返回false为其它错误,应将错误信息记录到日志
 
 if (node_exists_exception(zk_errcode))
 
 {
 
 			                MYLOG_INFO("A master exists\n");
 
 }
 
 else
 
 {
 
 			                MYLOG_ERROR("Race master at %s with %s failed: (state:%d)(errcode:%d)%s\n", _master_path.c_str(), _master_data.c_str(), get_state(), zk_errcode, zk_errmsg.c_str());
 
 if (invalid_handle_exception(zk_errcode))
 
 {
 
 			                    MYLOG_INFO("To recreate session\n");
 
 			                    recreate_session();
 
 }
 
 }
 
 
 
 			            休息2秒后再尝试,不要过频重试,一般情况下1~10秒都是可接受的
 
 			            mooon::sys::CUtils::millisleep(2000);
 
 }
 
 }
 
 
 
 			    MYLOG_INFO("Exit now\n");
 
 }
 
 
 
 			void CMyApplication::wait()
 
 {
 
 }
 
 
 
 			void CMyApplication::work()
 
 {
 
 			    要及时检查is_connected(),以防止master失效后同时存在两个master
 
 while (!_stop && !is_session_expired())
 
 {
 
 			        mooon::sys::CUtils::millisleep(2000);
 
 			        MYLOG_INFO("Working with state:\033[1;33m%d\033[m ...\n", get_state());
 
 }
 
 }
 
 
 
 			void CMyApplication::on_zookeeper_session_connected(const char* path)
 
 {
 
 			    MYLOG_INFO("[\033[1;33mon_zookeeper_session_connected\033[m] path: %s\n", path);
 
 
 
 const std::string zk_parent_path = "";
 
 const std::string zk_node_name = "test";
 
 const std::string zk_node_data = "123";
 
 
 
 			    try
 
 {
 
 			        create_node(zk_parent_path, zk_node_name, zk_node_data, ZOO_EPHEMERAL);
 
 			        MYLOG_INFO("Create %s/%s ok\n", zk_parent_path.c_str(), zk_node_name.c_str());
 
 }
 
 			    catch (mooon::utils::CException& ex)
 
 {
 
 			        MYLOG_ERROR("Create %s/%s failed: %s\n", zk_parent_path.c_str(), zk_node_name.c_str(), ex.str().c_str());
 
 }
 
 }
 
 
 
 			void CMyApplication::on_zookeeper_session_connecting(const char* path)
 
 {
 
 			    MYLOG_INFO("[\033[1;33mon_zookeeper_session_connecting\033[m] path: %s\n", path);
 
 }
 
 
 
 			void CMyApplication::on_zookeeper_session_expired(const char *path)
 
 {
 
 			    MYLOG_INFO("[\033[1;33mon_zookeeper_session_expired\033[m] path: %s\n", path);
 
 //exit(1); 最安全的做法,在这里直接退出,通过重新启动方式再次竞争master
 
 }
 
 
 
 			void CMyApplication::on_zookeeper_session_event(int state, const char *path)
 
 {
 
 			    MYLOG_INFO("[\033[1;33mon_zookeeper_session_event\033[m][state:%d] path: %s\n", state, path);
 
 }
 
 
 
 			void CMyApplication::on_zookeeper_event(int type, int state, const char *path)
 
 {
 
 			    MYLOG_INFO("[\033[1;33mon_zookeeper_event\033[m][type:%d][state:%d] path: %s\n", type, state, path);
 
 
 
 if (type == 3)
 
 {
 
 const int data_size = mooon::SIZE_4K;
 
 const bool keep_watch = true;
 
 			        std::string zk_data;
 
 const int n = get_zk_data(path, &zk_data, data_size, keep_watch);
 
 			        printf("(%d/%zd)%s\n", n, zk_data.size(), zk_data.c_str());
 
 }
 
 }

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏刘君君

Spring Cloud Netflix OSS 学习总结

7454
来自专栏Core Net

Ios8之后, 定位的delegate不能触发的问题

2918
来自专栏IT 指南者专栏

SpringMVC 框架系列之组件概述与配置详解

微信公众号:compassblog 欢迎关注,互相学习,共同进步! 有任何问题,请后台留言联系! 在上一篇文章 SpringMVC 框架系列之初识与入门实例 的...

2947
来自专栏IT笔记

SpringBoot开发案例之奇技淫巧

spring-boot-starter-parent包含了大量配置好的依赖管理,在自己项目添加这些依赖的时候不需要写<version>版本号

3836
来自专栏散尽浮华

Centos6.9下RocketMQ3.4.6高可用集群部署记录(双主双从+Nameserver+Console)

之前的文章已对RocketMQ做了详细介绍,这里就不再赘述了,下面是本人在测试和生产环境下RocketMQ3.4.6高可用集群的部署手册,在此分享下:

2413
来自专栏jianhuicode

构建ReactJs项目node-sass编译出错

npm run dev本地项目出错 问题栈 verbose Please try running this command again as root/Adm...

22710
来自专栏DevOps时代的专栏

Jenkins 在 Tomcat 中的部署及代码静态检查工具集成

在安装了 Jenkins 运行所需的依赖(主要是 JDK)之后,可以通过如下步骤简单快速地部署 Jenkins:

1412
来自专栏程序猿DD

使用Intellij中的Spring Initializr来快速构建Spring Boot/Cloud工程

在之前的所有Spring Boot和Spring Cloud相关博文中,都会涉及Spring Boot工程的创建。而创建的方式多种多样,我们可以通过Maven来...

2238
来自专栏何俊林

Android Studio如何Debug对应so文件C/C++代码

在C/C++跨平台开发中,我们知道在Windows上可以通过VS,进行单步断点调试,这非常方便。但是我们如果编译好的动态库so,想要跟踪下其流程及各个阶段,如,...

6859
来自专栏Linyb极客之路

hazelcast初探

Hazelcast作为一个高度可扩展的数据分发和集群平台,提供了高效的、可扩展的分布式数据存储、数据缓存。Hazelcast是开源的,在分布式技术方面,Haze...

2146

扫码关注云+社区

领取腾讯云代金券