package com.sohu.tv.cachecloud.client.jedis.stat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sohu.tv.cachecloud.client.basic.util.DateUtils;
import com.sohu.tv.cachecloud.client.basic.util.NamedThreadFactory;
import com.sohu.tv.cachecloud.client.basic.util.NetUtils;
import com.sohu.tv.jedis.stat.constant.ClientReportConstant;
import com.sohu.tv.jedis.stat.data.UsefulDataCollector;
import com.sohu.tv.jedis.stat.enums.ClientCollectDataTypeEnum;
import com.sohu.tv.jedis.stat.enums.ClientExceptionType;
import com.sohu.tv.jedis.stat.model.ClientReportBean;
import com.sohu.tv.jedis.stat.model.CostTimeDetailStatKey;
import com.sohu.tv.jedis.stat.model.CostTimeDetailStatModel;
import com.sohu.tv.jedis.stat.model.ExceptionModel;
import com.sohu.tv.jedis.stat.model.ValueLengthModel;
import com.sohu.tv.jedis.stat.utils.AtomicLongMap;
import com.sohu.tv.jedis.stat.utils.NumberUtil;
/**
* jedis数据收集上报任务执行器
*
* @author leifu
* @Date 2015年1月14日
* @Time 上午11:45:09
*/
public class ClientDataCollectReportExecutor {
private final Logger logger = LoggerFactory.getLogger(ClientDataCollectReportExecutor.class);
/**
* 客户端ip(实际使用了web中统计的ip作为真正的客户端ip, 这个作为备用)
*/
private static String clientIp = NetUtils.getLocalHost();
/**
* 数据收集上报
*/
private final ScheduledExecutorService jedisDataCollectReportScheduledExecutor = Executors.newScheduledThreadPool(3,
new NamedThreadFactory("jedisDataCollectReportScheduledExecutor", true));
private ScheduledFuture<?> jedisDataCollectReportScheduleFuture;
private final int delay = 5;
private final int fixCycle = 60;
private volatile static ClientDataCollectReportExecutor jedisDataCollectAndReportExecutor;
private ClientDataCollectReportExecutor() {
init();
}
public static ClientDataCollectReportExecutor getInstance() {
if (jedisDataCollectAndReportExecutor == null) {
synchronized (ClientDataCollectReportExecutor.class) {
if (jedisDataCollectAndReportExecutor == null) {
jedisDataCollectAndReportExecutor = new ClientDataCollectReportExecutor();
}
}
}
return jedisDataCollectAndReportExecutor;
}
/**
* 初始化
*/
public void init() {
Thread clientDataCollectReportThread = new Thread(new Runnable() {
@Override
public void run() {
try {
String currentMinuteStamp = ClientReportConstant.getCollectTimeSDf().format(new Date());
collectReportAllData(currentMinuteStamp);
} catch (Exception e) {
UsefulDataCollector.collectException(e, "", System.currentTimeMillis(), ClientExceptionType.CLIENT_EXCEPTION_TYPE);
logger.error("ClientDataCollectReport thread message is" + e.getMessage(), e);
}
}
});
clientDataCollectReportThread.setDaemon(true);
// 启动定时任务
jedisDataCollectReportScheduleFuture = jedisDataCollectReportScheduledExecutor.scheduleWithFixedDelay(
clientDataCollectReportThread, delay, fixCycle, TimeUnit.SECONDS);
}
/**
* 收集上报数据
* @param currentMinuteStamp
*/
private void collectReportAllData(String currentMinuteStamp) {
//1. 获取上一分钟的所有数据
String lastMinute = getLastMinute(currentMinuteStamp);
if (lastMinute == null || "".equals(lastMinute.trim())) {
return;
}
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
list.addAll(collectReportCostTimeData(lastMinute));
list.addAll(collectReportValueDistriData(lastMinute));
list.addAll(collectReportExceptionData(lastMinute));
//上报统计数据,观察是否存在内存泄露的情况
Map<String, Object> otherInfo = new HashMap<String, Object>(4, 1);
otherInfo.put(ClientReportConstant.COST_MAP_SIZE, UsefulDataCollector.getDataCostTimeMapAll().size());
otherInfo.put(ClientReportConstant.VALUE_MAP_SIZE, UsefulDataCollector.getDataValueLengthDistributeMapAll().size());
otherInfo.put(ClientReportConstant.EXCEPTION_MAP_SIZE, UsefulDataCollector.getDataExceptionMapAll().size());
otherInfo.put(ClientReportConstant.COLLECTION_MAP_SIZE, UsefulDataCollector.getCollectionCostTimeMapAll().size());
//2. 上报数据
if (!list.isEmpty()) {
ClientReportBean ccReportBean = new ClientReportBean(clientIp, NumberUtil.toLong(lastMinute), System.currentTimeMillis(), list, otherInfo);
ClientReportDataCenter.reportData(ccReportBean);
}
}
/**
* 收集耗时
*
* @param lastMinute
*/
private List<Map<String, Object>> collectReportCostTimeData(String lastMinute) {
try {
//1. 收集数据
Map<CostTimeDetailStatKey, AtomicLongMap<Integer>> map = UsefulDataCollector.getCostTimeLastMinute(lastMinute);
if (map == null || map.isEmpty()) {
return Collections.emptyList();
}
// 2. 组装数据
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
for (Entry<CostTimeDetailStatKey, AtomicLongMap<Integer>> entry : map.entrySet()) {
CostTimeDetailStatKey costTimeDetailStatKey = entry.getKey();
AtomicLongMap<Integer> statMap = entry.getValue();
CostTimeDetailStatModel model = UsefulDataCollector.generateCostTimeDetailStatKey(statMap);
Map<String, Object> tempMap = new HashMap<String, Object>();
tempMap.put(ClientReportConstant.COST_COUNT, model.getTotalCount());
tempMap.put(ClientReportConstant.COST_COMMAND, costTimeDetailStatKey.getCommand());
tempMap.put(ClientReportConstant.COST_HOST_PORT, costTimeDetailStatKey.getHostPort());
tempMap.put(ClientReportConstant.COST_TIME_90_MAX, model.getNinetyPercentMax());
tempMap.put(ClientReportConstant.COST_TIME_99_MAX, model.getNinetyNinePercentMax());
tempMap.put(ClientReportConstant.COST_TIME_100_MAX, model.getHundredMax());
tempMap.put(ClientReportConstant.COST_TIME_MEAN, model.getMean());
tempMap.put(ClientReportConstant.COST_TIME_MEDIAN, model.getMedian());
tempMap.put(ClientReportConstant.CLIENT_DATA_TYPE, ClientCollectDataTypeEnum.COST_TIME_DISTRI_TYPE.getValue());
list.add(tempMap);
}
return list;
} catch (Exception e) {
UsefulDataCollector.collectException(e, "", System.currentTimeMillis(), ClientExceptionType.CLIENT_EXCEPTION_TYPE);
logger.error("collectReportCostTimeData:" + e.getMessage(), e);
return Collections.emptyList();
}
}
/**
* 收集异常
* @param lastMinute
*/
private List<Map<String, Object>> collectReportExceptionData(String lastMinute) {
try {
// 1. 只取当前时间前一分钟的的数据
Map<ExceptionModel, Long> map = UsefulDataCollector.getExceptionLastMinute(lastMinute);
if (map == null || map.isEmpty()) {
return Collections.emptyList();
}
// 2. 组装数据
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
Map<String, Object> tempMap = null;
for (Entry<ExceptionModel, Long> entry : map.entrySet()){
ExceptionModel exceptionModel = entry.getKey();
Long exceptionCount = entry.getValue();
tempMap = new HashMap<String, Object>();
tempMap.put(ClientReportConstant.EXCEPTION_CLASS, exceptionModel.getExceptionClass());
tempMap.put(ClientReportConstant.EXCEPTION_MSG, "");
tempMap.put(ClientReportConstant.EXCEPTION_HAPPEN_TIME, System.currentTimeMillis());
tempMap.put(ClientReportConstant.EXCEPTION_HOST_PORT, exceptionModel.getHostPort());
tempMap.put(ClientReportConstant.EXCEPTION_COUNT, exceptionCount);
tempMap.put(ClientReportConstant.EXCEPTION_TYPE, exceptionModel.getClientExceptionType().getType());
tempMap.put(ClientReportConstant.CLIENT_DATA_TYPE, ClientCollectDataTypeEnum.EXCEPTION_TYPE.getValue());
list.add(tempMap);
}
return list;
} catch (Exception e) {
UsefulDataCollector.collectException(e, "", System.currentTimeMillis(), ClientExceptionType.CLIENT_EXCEPTION_TYPE);
logger.error("collectReportExceptionData:" + e.getMessage(), e);
return Collections.emptyList();
}
}
/**
* 收集值分布
*
* @param lastMinute
*/
private List<Map<String, Object>> collectReportValueDistriData(String lastMinute) {
try {
// 1. 只取当前时间前一分钟的的数据
Map<ValueLengthModel, Long> jedisValueLengthMap = UsefulDataCollector.getValueLengthLastMinute(lastMinute);
if (jedisValueLengthMap == null || jedisValueLengthMap.isEmpty()) {
return Collections.emptyList();
}
// 2.解析拼接数据
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
for (Entry<ValueLengthModel, Long> entry : jedisValueLengthMap.entrySet()) {
ValueLengthModel model = entry.getKey();
Long count = entry.getValue();
Map<String, Object> tempMap = new HashMap<String, Object>();
tempMap.put(ClientReportConstant.VALUE_DISTRI, model.getRedisValueSizeEnum().getValue());
tempMap.put(ClientReportConstant.VALUE_COUNT, count);
tempMap.put(ClientReportConstant.VALUE_COMMAND, model.getCommand());
tempMap.put(ClientReportConstant.VALUE_HOST_PORT, model.getHostPort());
tempMap.put(ClientReportConstant.CLIENT_DATA_TYPE, ClientCollectDataTypeEnum.VALUE_LENGTH_DISTRI_TYPE.getValue());
list.add(tempMap);
}
return list;
} catch (Exception e) {
UsefulDataCollector.collectException(e, "", System.currentTimeMillis(), ClientExceptionType.CLIENT_EXCEPTION_TYPE);
logger.error("collectReportValueDistriData:" + e.getMessage(), e);
return Collections.emptyList();
}
}
/**
* 获取上一分钟的字符串
*
* @param currentMinuteStamp
* @return
*/
private String getLastMinute(String currentMinuteStamp) {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
Date currentDate = sdf.parse(currentMinuteStamp);
Date lastMinute = DateUtils.addMinutes(currentDate, -1);
return sdf.format(lastMinute);
} catch (ParseException e) {
logger.error(e.getMessage(), e);
return null;
}
}
/**
* 关闭
*/
public void close() {
//TODO可以加个JVM钩子
try {
jedisDataCollectReportScheduleFuture.cancel(true);
} catch (Throwable t) {
logger.error(t.getMessage(), t);
}
}
public static String getClientIp() {
return clientIp;
}
}