package com.github.ltsopensource.core.monitor; import com.github.ltsopensource.cmd.DefaultHttpCmd; import com.github.ltsopensource.cmd.HttpCmd; import com.github.ltsopensource.cmd.HttpCmdClient; import com.github.ltsopensource.cmd.HttpCmdResponse; import com.github.ltsopensource.core.AppContext; import com.github.ltsopensource.core.cluster.Node; import com.github.ltsopensource.core.cluster.NodeType; import com.github.ltsopensource.core.cmd.HttpCmdNames; import com.github.ltsopensource.core.cmd.HttpCmdParamNames; import com.github.ltsopensource.core.commons.utils.CollectionUtils; import com.github.ltsopensource.core.constant.ExtConfig; import com.github.ltsopensource.core.domain.monitor.MData; import com.github.ltsopensource.core.domain.monitor.MNode; import com.github.ltsopensource.core.json.JSON; import com.github.ltsopensource.core.loadbalance.LoadBalance; import com.github.ltsopensource.core.logger.Logger; import com.github.ltsopensource.core.logger.LoggerFactory; import com.github.ltsopensource.core.spi.ServiceLoader; import com.github.ltsopensource.core.support.SystemClock; import com.github.ltsopensource.jvmmonitor.JVMCollector; import java.util.ArrayList; import java.util.Calendar; import java.util.Comparator; import java.util.List; import java.util.concurrent.PriorityBlockingQueue; /** * @author Robert HG (254963746@qq.com) on 3/11/16. */ public class MStatReportWorker implements Runnable { protected final Logger LOGGER = LoggerFactory.getLogger(MStatReportWorker.class); private int interval = 1; // 1分钟 private Integer preMinute = null; // 上一分钟 private AppContext appContext; private AbstractMStatReporter reporter; // 这里面保存发送失败的,不过有个最大限制,防止内存爆掉 private PriorityBlockingQueue<MData> queue = new PriorityBlockingQueue<MData>(16, new Comparator<MData>() { @Override public int compare(MData o1, MData o2) { return o1.getTimestamp().compareTo(o2.getTimestamp()); } }); private final static int MAX_RETRY_RETAIN = 500; private final static int BATCH_REPORT_SIZE = 10; private volatile boolean running = false; private LoadBalance loadBalance; public MStatReportWorker(AppContext appContext, AbstractMStatReporter reporter) { this.appContext = appContext; this.reporter = reporter; interval = appContext.getConfig().getParameter(ExtConfig.LTS_MONITOR_REPORT_INTERVAL, 1); this.loadBalance = ServiceLoader.load(LoadBalance.class, appContext.getConfig(), ExtConfig.MONITOR_SELECT_LOADBALANCE); } @Override public void run() { if (running) { return; } running = true; try { Calendar calendar = Calendar.getInstance(); int minute = calendar.get(Calendar.MINUTE); if (preMinute == null) { preMinute = minute; return; } int diff = minute - preMinute; diff = diff < 0 ? diff + 60 : diff; if (diff != 0 && diff % interval == 0) { try { // 变化超过了间隔时间,要立马收集 MData mData = reporter.collectMData(); long seconds = SystemClock.now() / 1000; seconds = seconds - (seconds % 60); // 所有都向下取整,保证是60的倍数 seconds = seconds - interval * 60; // 算其实时间点的数据 mData.setTimestamp(seconds * 1000); // JVM monitor mData.setJvmMData(JVMCollector.collect()); // report report(mData); } finally { preMinute = minute; } } } catch (Throwable t) { LOGGER.error("MStatReportWorker collect failed.", t); } finally { running = false; } } private void report(MData mData) { int size = queue.size(); if (size >= MAX_RETRY_RETAIN) { int needRemoveSize = size - (MAX_RETRY_RETAIN - 1); for (int i = 0; i < needRemoveSize; i++) { queue.poll(); } } queue.add(mData); final List<Node> monitorNodes = appContext.getSubscribedNodeManager().getNodeList(NodeType.MONITOR); if (CollectionUtils.isEmpty(monitorNodes)) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Please Start LTS-Monitor"); } return; } while (queue.size() > 0) { List<MData> list = new ArrayList<MData>(); queue.drainTo(list, BATCH_REPORT_SIZE); boolean success = false; try { HttpCmd cmd = new DefaultHttpCmd(); cmd.setCommand(HttpCmdNames.HTTP_CMD_ADD_M_DATA); cmd.addParam(HttpCmdParamNames.M_NODE, JSON.toJSONString(buildMNode())); cmd.addParam(HttpCmdParamNames.M_DATA, JSON.toJSONString(list)); if (sendReq(monitorNodes, cmd)) { success = true; } } catch (Throwable t) { LOGGER.warn("Report monitor data Error : " + t.getMessage(), t); } finally { if (!success) { // 放回去 queue.addAll(list); } } if (!success) { // 停止while break; } } } // 发送请求 private boolean sendReq(List<Node> monitorNodes, HttpCmd cmd) { while (true) { Node node = selectMNode(monitorNodes); try { cmd.setNodeIdentity(node.getIdentity()); HttpCmdResponse response = HttpCmdClient.doPost(node.getIp(), node.getPort(), cmd); if (response.isSuccess()) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Report Monitor Data Success."); } return true; } else { LOGGER.warn("Report Monitor Data Failed: " + response.getMsg()); monitorNodes.remove(node); } } catch (Exception e) { LOGGER.warn("Report Monitor Data Error: " + e.getMessage(), e); // 重试下一个 } if (monitorNodes.size() == 0) { return false; } } } private Node selectMNode(List<Node> monitorNodes) { return loadBalance.select(monitorNodes, appContext.getConfig().getIdentity()); } private MNode buildMNode() { MNode mNode = new MNode(); mNode.setNodeType(reporter.getNodeType()); mNode.setNodeGroup(appContext.getConfig().getNodeGroup()); mNode.setIdentity(appContext.getConfig().getIdentity()); return mNode; } }