基於zookeeper的主備服務

摘要

爲了高可用通產我們一個服務會部署多節點。但是有時我們希望對某些操作要求單線程處理,此時可以通過主備服務形式實現。正常情況下主節點服務處理,當主節點宕機後備用節點相關服務繼續處理。

需求

資源中心會將資源文件相關操作分發至各個項目節點,資源的操作包括添加、分享、刪除、和諧、恢復。資源中心向mq發佈消息,各個項目節點通過訂閱mq消息處理對應資源。各項目節點HA部署雙節點。此時有可能出現其中一個節點正在處理資源的上傳操作,由於涉及到文件IO,此操作比較慢,同時另一個節點接收到了刪除的mq消息,執行對應的資源刪除操作。爲了避免這種情況,要求對消息的操作必須是順序的。

解決方案

項目的兩個節點在啓動完成後搶注zookeeper同時訂閱zk的節點disconnect事件,搶注成功的節點成爲主節點通知執行啓動操作,搶註失敗的節點爲從節點不做操作。當主節點宕機後,從節點會接收到disconnect消息,從而執行啓動操作。

實現

  1. 服務啓動後搶注zk
    @Override
    public void run(ApplicationArguments args) throws Exception {
        if(enable){
            zookeeperWatcher.connect();
            if(!zookeeperWatcher.exists()){
                zookeeperWatcher.create();
            }else{
                log.info("節點已被搶注,不再發布節點搶注成功事件!!!");
            }
        }else{
            log.info("不啓用,默認發佈搶注成功事件");
            SpringContextUtil.getApplicationContext().publishEvent(new MainStandbyRunnerEvent(true));
        }
    }
    
  2. 通過publishEvent+listener將主備啓動與主備解耦
    搶注zk節點成功發佈啓動事件
    SpringContextUtil.getApplicationContext().publishEvent(new MainStandbyRunnerEvent(true));
    
    各個業務方通過添加listener實現啓動邏輯
    @Override
    public void onApplicationEvent(MainStandbyRunnerEvent event) {
        log.info("執行節點服務啓動時間!");
        //TODO 啓動邏輯
        log.info("節點服務啓動完成!");
    }
    
  3. 監聽zk節點斷開事件並註冊節點發布註冊成功事件
    @Override
    public void process(WatchedEvent event){
        if(path.equals(event.getPath()) && event.getType() == Event.EventType.NodeDeleted){
            log.info("節點斷開連接");
           	//搶注節點
            create();
        }
    }
    /**
     * 創建節點併發布事件
     */
    public void create(){
        try {
            byte[] bytes = value.getBytes(CHARSET);
            this.zookeeper.create(path, bytes, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
            log.info("發佈節點搶注成功事件");
            SpringContextUtil.getApplicationContext().publishEvent(new MainStandbyRunnerEvent(true));
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }
    

效果

主節點啓動

2020-01-13 16:24:02.196 [main] INFO  c.i.s.common.mainstandby.config.MainStandbyProperties - 主備啓動參數:[enable=true,host=127.0.0.1,path=/MainStandbyStart,value=MainNodeStart]
2020-01-13 16:26:36.127 [main] INFO  c.i.sclass.common.mainstandby.watcher.ZookeeperWatcher - 發佈節點搶注成功事件
2020-01-13 16:26:36.127 [main] INFO  c.i.sclass.baseauth.listener.MainStandbyRunnerListener - 執行節點服務啓動事件!
2020-01-13 16:26:36.127 [main] INFO  c.i.sclass.baseauth.listener.MainStandbyRunnerListener - 節點服務啓動完成!

從節點啓動

2020-01-13 16:27:46.292 [main] INFO  c.i.s.common.mainstandby.config.MainStandbyProperties - 主備啓動參數:[enable=true,host=127.0.0.1,path=/MainStandbyStart,value=StandbyNodeStart]
2020-01-13 16:27:46.762 [main] INFO  c.i.s.common.mainstandby.component.MainStandbyRunner - 節點已被搶注,不再發布節點搶注成功事件!!!

主節點宕機

2020-01-13 16:28:39.509 [main-EventThread] INFO  c.i.sclass.common.mainstandby.watcher.ZookeeperWatcher - 節點斷開連接
2020-01-13 16:28:39.516 [main-EventThread] INFO  c.i.sclass.common.mainstandby.watcher.ZookeeperWatcher - 發佈節點搶注成功事件
2020-01-13 16:28:39.516 [main-EventThread] INFO  c.i.s.baseauthtest.listener.MainStandbyRunnerListener - 執行節點服務啓動事件!
2020-01-13 16:28:39.517 [main-EventThread] INFO  c.i.s.baseauthtest.listener.MainStandbyRunnerListener - 節點服務啓動完成!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章