com.bfd.harpc.monitor.RpcMonitor.java Source code

Java tutorial

Introduction

Here is the source code for com.bfd.harpc.monitor.RpcMonitor.java

Source

/**
 * Copyright (C) 2015 Baifendian Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.bfd.harpc.monitor;

import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

import org.apache.commons.lang.time.FastDateFormat;
import org.apache.curator.framework.CuratorFramework;
import org.apache.zookeeper.CreateMode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.bfd.harpc.common.Constants;
import com.bfd.harpc.common.ServerNode;

/**
 * rpc
 * <p>
 * 
 * @author : dsfan
 * @date : 2015-6-2
 */
public class RpcMonitor {
    /** LOGGER */
    private static final Logger LOGGER = LoggerFactory.getLogger(RpcMonitor.class);

    /** ? */
    private static final int NODE_COUNT_LIMIT = 600;

    /**  */
    private final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3,
            new NamedThreadFactory("Harpc-SendStatisticsTimer", true));

    /** ??? */
    private final ScheduledFuture<?> sendFuture;

    /** (ms),5Min */
    private final long monitorInterval;

    /** {@link CuratorFramework} */
    private final CuratorFramework zkClient;

    /** ??? */
    private final String serverName;

    /** ?client?server */
    private final boolean isClient;

    /** ? */
    private final ConcurrentMap<ServerNode, AtomicReference<StatisticsInfo>> statisticsMap = new ConcurrentHashMap<ServerNode, AtomicReference<StatisticsInfo>>();

    /** ? */
    private final ConcurrentMap<ServerNode, AtomicReference<StatisticsInfo>> totalStatisticsMap = new ConcurrentHashMap<ServerNode, AtomicReference<StatisticsInfo>>();

    /** ? */
    private final ConcurrentMap<ServerNode, Long> startTimeMap = new ConcurrentHashMap<ServerNode, Long>();

    /** ? */
    private final ConcurrentMap<ServerNode, StatisticsTotal> statMap = new ConcurrentHashMap<ServerNode, StatisticsTotal>();

    /**  */
    private final long beginTime;

    /** ? */
    private long startTime;

    /**
     * @param interval
     * @param zkClient
     * @param serverName
     * @param isClient
     */
    public RpcMonitor(long interval, CuratorFramework zkClient, String serverName, boolean isClient) {
        this.monitorInterval = interval;
        this.zkClient = zkClient;
        this.serverName = serverName;
        this.isClient = isClient;

        // ??
        sendFuture = scheduledExecutorService.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                try {
                    // ???
                    send();
                } catch (Throwable t) {
                    LOGGER.error(t.getMessage(), t);
                }
            }
        }, monitorInterval, monitorInterval, TimeUnit.SECONDS);
        beginTime = startTime = System.currentTimeMillis();
    }

    /**
     * ???
     * <p>
     */
    protected void send() {
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Start send statistics to zookeeper!");
        }

        // 
        for (Map.Entry<ServerNode, AtomicReference<StatisticsInfo>> entry : statisticsMap.entrySet()) {
            // ??
            ServerNode serverNode = entry.getKey();
            AtomicReference<StatisticsInfo> reference = entry.getValue();
            StatisticsInfo numbers;
            do {
                numbers = reference.get();
            } while (!reference.compareAndSet(numbers, null)); // ?

            StatisticsInfo info = new StatisticsInfo();
            if (numbers != null) {
                info.setSuccess(numbers.getSuccess());
                info.setFailure(numbers.getFailure());
                info.setMaxtime(numbers.getMaxtime());
                info.setMintime(numbers.getMintime());
                info.setAvgtime(numbers.getAvgtime());

                startTimeMap.putIfAbsent(serverNode, startTime);
                long useTime = System.currentTimeMillis() - startTimeMap.get(serverNode);
                startTimeMap.put(serverNode, System.currentTimeMillis()); // ?

                info.setQps(1000 / (useTime / (float) (numbers.getSuccess() + numbers.getFailure())));
            }

            // ???
            sendToZookeeper(serverNode, info, false);
        }
        // ??clientservernode????
        startTime = System.currentTimeMillis();

        // 
        for (Map.Entry<ServerNode, AtomicReference<StatisticsInfo>> entry : totalStatisticsMap.entrySet()) {
            // ??
            ServerNode serverNode = entry.getKey();
            AtomicReference<StatisticsInfo> reference = entry.getValue();
            StatisticsInfo numbers = reference.get();

            StatisticsInfo info = new StatisticsInfo();
            if (numbers != null) {
                info.setSuccess(numbers.getSuccess());
                info.setFailure(numbers.getFailure());
                info.setMaxtime(numbers.getMaxtime());
                info.setMintime(numbers.getMintime());
                info.setAvgtime(numbers.getAvgtime());
                long useTime = System.currentTimeMillis() - beginTime;
                info.setQps(1000 / (useTime / (float) (numbers.getSuccess() + numbers.getFailure())));
            }

            // ???
            sendToZookeeper(serverNode, info, true);
        }
    }

    /**
     * ???zookeeper
     * <p>
     * 
     * @param serverNode
     * @param info
     * @param isTotal
     */
    private void sendToZookeeper(ServerNode serverNode, StatisticsInfo info, boolean isTotal) {
        StringBuilder parentPath = new StringBuilder();
        parentPath.append(serverName).append(Constants.ZK_SEPARATOR_DEFAULT)
                .append(Constants.ZK_NAMESPACE_STATISTICS);
        if (isClient) {
            parentPath.append(Constants.ZK_SEPARATOR_DEFAULT).append(Constants.ZK_NAMESPACE_CLIENTS);
        } else {
            parentPath.append(Constants.ZK_SEPARATOR_DEFAULT).append(Constants.ZK_NAMESPACE_SERVERS);
        }
        parentPath.append(Constants.ZK_SEPARATOR_DEFAULT).append(serverNode.genAddress());

        String timeStamp = FastDateFormat.getInstance(Constants.ZK_TIME_NODE_FORMAT).format(Calendar.getInstance());
        info.setTime(timeStamp);
        if (isTotal) {
            statMap.putIfAbsent(serverNode, new StatisticsTotal());
            statMap.get(serverNode).setTotal(info);
        } else {
            statMap.putIfAbsent(serverNode, new StatisticsTotal());

            statMap.get(serverNode).getDetail().add(info);
            // 
            StatisticsHelper.adjustNodesByLimit(statMap.get(serverNode).getDetail(), NODE_COUNT_LIMIT);
        }
        String jsonString = JSON.toJSONString(statMap.get(serverNode));
        String path = parentPath.toString();

        try {
            // ?
            if (zkClient.checkExists().forPath(path) != null) {
                zkClient.setData().forPath(path, jsonString.getBytes("utf-8"));
            } else {
                zkClient.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath(path,
                        jsonString.getBytes("utf-8"));
            }

        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
    }

    /**
     * ?
     * <p>
     * 
     * @param serverNode
     *            {@link ServerNode}
     * @param info
     *            {@link StatisticsInfo}
     */
    public void collect(ServerNode serverNode, StatisticsInfo info) {
        // ?
        // ??
        AtomicReference<StatisticsInfo> reference = statisticsMap.get(serverNode);
        if (reference == null) {
            statisticsMap.putIfAbsent(serverNode, new AtomicReference<StatisticsInfo>());
            reference = statisticsMap.get(serverNode);
        }
        // CompareAndSet??
        updateStatistics(info, reference);

        // ?
        // ??
        AtomicReference<StatisticsInfo> totalReference = totalStatisticsMap.get(serverNode);
        if (totalReference == null) {
            totalStatisticsMap.putIfAbsent(serverNode, new AtomicReference<StatisticsInfo>());
            totalReference = totalStatisticsMap.get(serverNode);
        }
        // CompareAndSet??
        updateStatistics(info, totalReference);
    }

    /**
     * ?
     * <p>
     * 
     * @param info
     * @param reference
     */
    private void updateStatistics(StatisticsInfo info, AtomicReference<StatisticsInfo> reference) {
        StatisticsInfo current;
        StatisticsInfo update = new StatisticsInfo();
        do {
            current = reference.get();
            if (current == null) {
                update.setSuccess(info.getSuccess());
                update.setFailure(info.getFailure());
                update.setMaxtime(info.getMaxtime());
                update.setMintime(info.getMintime());
                update.setAvgtime(info.getAvgtime());
            } else {
                update.setSuccess(current.getSuccess() + info.getSuccess());
                update.setFailure(current.getFailure() + info.getFailure());
                update.setMaxtime(
                        current.getMaxtime() > info.getMaxtime() ? current.getMaxtime() : info.getMaxtime());
                update.setMintime(
                        current.getMintime() < info.getMintime() ? current.getMintime() : info.getMintime());
                update.setAvgtime(
                        (current.getAvgtime() * (update.getSuccess() + update.getFailure()) + info.getAvgtime())
                                / (update.getSuccess() + update.getFailure() + 1));
            }
        } while (!reference.compareAndSet(current, update));
    }

    /**
     * ?
     * <p>
     */
    public void destroy() {
        try {
            sendFuture.cancel(true);
        } catch (Throwable t) {
            LOGGER.error(t.getMessage(), t);
        }
    }

}