從零到日誌採集索引可視化、監控報警、rpc trace跟蹤-系統上下線監控

github開源  歡迎一起維護~~
  1. 之前說到註冊中心的設計,zookeeper中的節點部署如下:
    1. kafkaAppender初始化向zk進行app節點註冊,並寫入相關的信息
    2. kafkaAppender發生異常暫停工作會向app節點寫入相關信息,以便監控系統能夠實時感知併發送報警
    3. app正常或者異常退出後,zk中的app臨時節點會消失,shutdownhook會正常運行,監控系統能夠實時感知併發送報警(這裏就需要我們在自定義的log appender中寫好相應的hook,防止對接系統無法正常釋放資源,項目不要用kill -9 pid,應該使用kill pid)
    4. zk中有永久節點用來記錄app的最近一次部署信息

那麼我們只需要監控zk節點的變化,即可知道對接的系統上下線情況,以及內嵌的採集器是否存活,具體代碼如下(curator框架和zkclient一起混用):
public class ScrollChildrenChangeListener implements PathChildrenCacheListener  {

    private static final Logger LOGGER = LoggerFactory.getLogger(ScrollChildrenChangeListener.class);

    private RabbitmqService rabbitmqService;

    private ZkClient zkClient;

    private AppInfoService appInfoService;

    public ScrollChildrenChangeListener(RabbitmqService rabbitmqServiceZkClient zkClientAppInfoService appInfoService) {
        this.rabbitmqService = rabbitmqService;
        this.zkClient = zkClient;
        this.appInfoService = appInfoService;
    }

    @Override
    public void childEvent(CuratorFramework clientPathChildrenCacheEvent event) throws Exception {
        switch (event.getType()) {
            case CHILD_ADDED:
                PathChildrenCache pathChildrenCache = new PathChildrenCache(clientevent.getData().getPath(), true);
                pathChildrenCache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);
                pathChildrenCache.getListenable().addListener(new AppChildrenChangeListener(this.rabbitmqService, this.zkClient, this.appInfoService));
                LOGGER.info("app added: " + event.getData().getPath());
                break;
            case CHILD_REMOVED:
                LOGGER.info("app removed: " + event.getData().getPath());
                break;
        }
    }
}


public class AppChildrenChangeListener implements PathChildrenCacheListener {

    private static final Logger LOGGER = LoggerFactory.getLogger(AppChildrenChangeListener.class);

    private RabbitmqService rabbitmqService;

    private ZkClient zkClient;

    private AppInfoService appInfoService;

    public AppChildrenChangeListener(RabbitmqService rabbitmqServiceZkClient zkClientAppInfoService appInfoService) {
        this.rabbitmqService = rabbitmqService;
        this.zkClient = zkClient;
        this.appInfoService = appInfoService;
    }

    @Override
    public void childEvent(CuratorFramework clientPathChildrenCacheEvent event) throws Exception {
        String node = Constants.EMPTY_STR;
        String app = Constants.EMPTY_STR;
        String host = Constants.EMPTY_STR;
        String info = Constants.EMPTY_STR;
        String[] datas = null;
        switch (event.getType()) {
            case CHILD_ADDED:
                node = event.getData().getPath();
                app = this.getApp(node);
                host = this.getHost(node);
                if (!CacheService.appHosts.contains(node)) {
                    datas = this.zkClient.readData(Constants.ROOT_PATH_PERSISTENT + Constants.SLASH + app + Constants.SLASH + host).toString().split(Constants.SEMICOLON);

                    info = this.buildMsg(DateUtil.format(new Date(System.currentTimeMillis())DateUtil.YYYYMMDDHHMMSS)app,
                            this.getHost(node)datas[1]Constants.APP_START);

                    // add to the queue
                    this.rabbitmqService.sendMessage(infodatas[0]);
                    LOGGER.info(info);
                    CacheService.appHosts.add(node);
                    this.appInfoService.add(hostappConstants.ZK_NODE_TYPE_EPHEMERALLogCollectionStatus.RUNNING);
                }
                this.appInfoService.add(hostappConstants.ZK_NODE_TYPE_PERSISTENTLogCollectionStatus.HISTORY);
                break;
            case CHILD_REMOVED:
                node = event.getData().getPath();
                app = this.getApp(node);
                host = this.getHost(node);
                datas = this.zkClient.readData(Constants.ROOT_PATH_PERSISTENT + Constants.SLASH + app + Constants.SLASH + host).toString().split(Constants.SEMICOLON);

                info = this.buildMsg(DateUtil.format(new Date(System.currentTimeMillis())DateUtil.YYYYMMDDHHMMSS)app,
                        this.getHost(node)datas[1]Constants.APP_STOP);

                // add to the queue
                this.rabbitmqService.sendMessage(infodatas[0]);
                LOGGER.info(info);
                if (CacheService.appHosts.contains(node)) {
                    CacheService.appHosts.remove(node);
                    this.appInfoService.delete(hostappConstants.ZK_NODE_TYPE_EPHEMERAL);
                }
                break;
            case CHILD_UPDATED:
                node = event.getData().getPath();
                datas = this.zkClient.readData(node).toString().split(Constants.SEMICOLON);
                app = this.getApp(node);
                host = this.getHost(node);

                info = this.buildMsg(DateUtil.format(new Date(Long.parseLong(datas[0]))DateUtil.YYYYMMDDHHMMSS)app,
                        this.getHost(node)datas[1]Constants.APP_APPENDER_STOP);

                // add to the queue
                this.rabbitmqService.sendMessage(info, this.zkClient.readData(Constants.ROOT_PATH_PERSISTENT + Constants.SLASH + app + Constants.SLASH + host).toString().split(Constants.SEMICOLON)[0]);
                LOGGER.info(info);
                this.appInfoService.update(hostappConstants.ZK_NODE_TYPE_EPHEMERALLogCollectionStatus.STOPPED);
                break;
        }
    }

    /**
     * 根據node獲取app
     * @param node
     @return
     */
    private String getApp(String node) {
        String tmp = node.substring(0node.lastIndexOf(Constants.SLASH));
        return this.getLast(tmp);
    }

    /**
     * 根據node獲取host
     * @param node
     @return
     */
    private String getHost(String node) {
        return this.getLast(node);
    }

    /**
     * 返回末尾字符串
     @param line
     @return
     */
    private String getLast(String line) {
        return line.substring(line.lastIndexOf(Constants.SLASH) + 1);
    }

    /**
     * 構造報警msg
     * @param time
     @param app
     @param host
     @param deploy
     @param msg
     @return
     */
    private String buildMsg(String timeString appString hostString deployString msg) {
        AlertDto alertDto = new AlertDto(timeapphostdeploymsg);
        return alertDto.toString();
    }
}


@Service
public class AppInfoService {

    @Autowired
    private ZkClient zkClient;
    @Autowired
    private AppInfoRepository appInfoRepository;

    /**
     * 保存appInfo
     * @param host
     @param app
     @param type
     @param logCollectionStatus
     */
    public void add(String hostString app, int typeLogCollectionStatus logCollectionStatus) {
        AppInfo appInfo = new AppInfo();
        AppInfoPK appInfoPK = new AppInfoPK(hostapptype);
        appInfo.setAppInfoPK(appInfoPK);
        appInfo.setStatus(logCollectionStatus.symbol());
        if (logCollectionStatus.symbol().equals(LogCollectionStatus.HISTORY.symbol())) {
            appInfo.setDeploy(this.getDeploy(Constants.ROOT_PATH_PERSISTENT + Constants.SLASH + app + Constants.SLASH + host));
        else {
            appInfo.setDeploy(this.getDeploy(Constants.ROOT_PATH_EPHEMERAL + Constants.SLASH + app + Constants.SLASH + host));
        }
        this.appInfoRepository.save(appInfo);
    }

    /**
     * 修改記錄的收集日誌狀態
     @param host
     @param app
     @param type
     @param logCollectionStatus
     */
    public void update(String hostString app, int typeLogCollectionStatus logCollectionStatus) {
        AppInfo appInfo = this.appInfoRepository.findOne(new AppInfoPK(hostapptype));
        appInfo.setStatus(logCollectionStatus.symbol());
        this.appInfoRepository.save(appInfo);
    }

    /**
     * 根據hostapp進行刪除
     @param host
     @param app
     @param type
     */
    public void delete(String hostString app, int type) {
        AppInfo appInfo = this.appInfoRepository.findOne(new AppInfoPK(hostapptype));
        if (null != appInfo) {
            this.appInfoRepository.delete(appInfo);
        }
    }

    /**
     * 刪除所有的數據
     */
    public void deleteAll() {
        this.appInfoRepository.deleteAll();
    }

    /**
     * 獲取app的部署位置
     @param path
     @return
     */
    private String getDeploy(String path) {
        String data = this.zkClient.readData(path);
        return data.split(Constants.SEMICOLON)[1];
    }
}


 */
@Service
public class AppStatusMonitorService implements InitializingBean {

    @Autowired
    private CuratorFramework curatorFramework;
    @Autowired
    private RabbitmqService rabbitmqService;
    @Autowired
    private ZkClient zkClient;
    @Autowired
    private AppInfoService appInfoService;

    @Override
    public void afterPropertiesSet() throws Exception {
        PathChildrenCache pathChildrenCache = new PathChildrenCache(curatorFrameworkConstants.ROOT_PATH_EPHEMERAL, true);
        pathChildrenCache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);
        pathChildrenCache.getListenable().addListener(new ScrollChildrenChangeListener(this.rabbitmqService, this.zkClient, this.appInfoService));
    }
}


@Service
public class CacheService implements InitializingBean {

    private static final Logger LOGGER = LoggerFactory.getLogger(CacheService.class);

    public static List<String> appHosts new ArrayList<String>();

    @Autowired
    private CuratorFramework curatorFramework;
    @Autowired
    private AppInfoService appInfoService;
    @Autowired
    private ZkClient zkClient;

    @Override
    public void afterPropertiesSet() throws Exception {
        // mysql數據進行清空
        this.appInfoService.deleteAll();
        List<String> apps = curatorFramework.getChildren().forPath(Constants.ROOT_PATH_EPHEMERAL);

        // 啓動時獲取所有的節點數據寫入本地緩存和mysql
        for (String app : apps) {
            List<String> hosts = curatorFramework.getChildren().forPath(Constants.ROOT_PATH_EPHEMERAL + Constants.SLASH + app);
            for (String host : hosts) {
                appHosts.add(Constants.ROOT_PATH_EPHEMERAL + Constants.SLASH + app + Constants.SLASH + host);
                this.appInfoService.add(hostappConstants.ZK_NODE_TYPE_EPHEMERAL, this.calLogCollectionStatus(apphost));
            }
        }

        apps = curatorFramework.getChildren().forPath(Constants.ROOT_PATH_PERSISTENT);
        for (String app : apps) {
            List<String> hosts = curatorFramework.getChildren().forPath(Constants.ROOT_PATH_PERSISTENT + Constants.SLASH + app);
            for (String host : hosts) {
                this.appInfoService.add(hostappConstants.ZK_NODE_TYPE_PERSISTENTLogCollectionStatus.HISTORY);
            }
        }
    }

    /**
     * 根據apphost計算LogCollectionStatus
     * @param app
     @param host
     @return
     */
    private LogCollectionStatus calLogCollectionStatus(String appString host) {
        String[] datas = this.zkClient.readData(Constants.ROOT_PATH_EPHEMERAL + Constants.SLASH + app + Constants.SLASH + host).toString().split(Constants.SEMICOLON);
        if (datas[0].equals(Constants.APPENDER_INIT_DATA)) {
            return LogCollectionStatus.RUNNING;
        }
        return LogCollectionStatus.STOPPED;
    }
}

代碼較爲簡單,不再贅述,主要就是監聽zk節點的變化情況,並且將app和host信息採集進入了mysql(同時本項目進程中緩存了一份用來提高速度)。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章