zoukankan      html  css  js  c++  java
  • 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
    ", ex.str().c_str());
            exit(1);
        }
        catch (mooon::utils::CException& ex)
        {
            fprintf(stderr, "%s
    ", 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
    ", _master_path.c_str(), _master_data.c_str());
                mooon::sys::CUtils::millisleep(10000);
                MYLOG_INFO("Start working now
    ");
    
                work();
                if (!_stop)
                {
                    退出work(),表示需要重新竞争master
                    MYLOG_INFO("Turn to slave from master at %s with %s successfully, stop working now
    ", _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
    ");
                }
                else
                {
                    MYLOG_ERROR("Race master at %s with %s failed: (state:%d)(errcode:%d)%s
    ", _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
    ");
                        recreate_session();
                    }
                }
    
                休息2秒后再尝试,不要过频重试,一般情况下1~10秒都是可接受的
                mooon::sys::CUtils::millisleep(2000);
            }
        }
    
        MYLOG_INFO("Exit now
    ");
    }
    
    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:33[1;33m%d33[m ...
    ", get_state());
        }
    }
    
    void CMyApplication::on_zookeeper_session_connected(const char* path)
    {
        MYLOG_INFO("[33[1;33mon_zookeeper_session_connected33[m] path: %s
    ", 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
    ", zk_parent_path.c_str(), zk_node_name.c_str());
        }
        catch (mooon::utils::CException& ex)
        {
            MYLOG_ERROR("Create %s/%s failed: %s
    ", 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("[33[1;33mon_zookeeper_session_connecting33[m] path: %s
    ", path);
    }
    
    void CMyApplication::on_zookeeper_session_expired(const char *path)
    {
        MYLOG_INFO("[33[1;33mon_zookeeper_session_expired33[m] path: %s
    ", path);
        //exit(1); 最安全的做法,在这里直接退出,通过重新启动方式再次竞争master
    }
    
    void CMyApplication::on_zookeeper_session_event(int state, const char *path)
    {
        MYLOG_INFO("[33[1;33mon_zookeeper_session_event33[m][state:%d] path: %s
    ", state, path);
    }
    
    void CMyApplication::on_zookeeper_event(int type, int state, const char *path)
    {
        MYLOG_INFO("[33[1;33mon_zookeeper_event33[m][type:%d][state:%d] path: %s
    ", 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, zk_data.size(), zk_data.c_str());
        }
    }
    

      

  • 相关阅读:
    【转】JSP三种页面跳转方式
    我要从头做起
    转载:用 Tomcat 和 Eclipse 开发 Web 应用程序
    html的style属性
    Java连接oracle数据库
    tomcat遇到的问题(总结)
    ceshi
    今天要小结一下
    argument.callee.caller.arguments[0]与window.event
    JavaScript事件冒泡简介及应用
  • 原文地址:https://www.cnblogs.com/aquester/p/9948601.html
Copyright © 2011-2022 走看看