Zookeeper C++程式設計實戰之主備切換
阿新 • • 發佈:2018-12-07
預設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()); } }