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()); } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义