package com.sohu.cache.stats.instance.impl; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; import org.apache.commons.lang.time.DateUtils; import org.apache.velocity.app.VelocityEngine; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.sohu.cache.dao.InstanceAlertValueDao; import com.sohu.cache.dao.InstanceDao; import com.sohu.cache.dao.InstanceStatsDao; import com.sohu.cache.entity.InstanceAlert; import com.sohu.cache.entity.InstanceAlert.StatusEnum; import com.sohu.cache.entity.InstanceAlert.ValueTypeEnum; import com.sohu.cache.entity.InstanceAlertValueResult; import com.sohu.cache.entity.InstanceAlertValueResult.CompareTypeEnum; import com.sohu.cache.entity.InstanceInfo; import com.sohu.cache.entity.StandardStats; import com.sohu.cache.stats.instance.InstanceAlertValueService; import com.sohu.cache.util.JsonUtil; import com.sohu.cache.web.component.EmailComponent; import com.sohu.cache.web.service.AppService; import com.sohu.cache.web.util.VelocityUtils; /** * 实例报警阀值 * * @author leifu * @Date 2016年8月24日 * @Time 上午11:46:12 */ public class InstanceAlertValueServiceImpl implements InstanceAlertValueService { private Logger logger = LoggerFactory.getLogger(InstanceAlertValueServiceImpl.class); private InstanceAlertValueDao instanceAlertValueDao; private InstanceStatsDao instanceStatsDao; private InstanceDao instanceDao; private EmailComponent emailComponent; private VelocityEngine velocityEngine; private AppService appService; @Override public List<InstanceAlert> getAllInstanceAlert() { try { return instanceAlertValueDao.getAllInstanceAlert(); } catch (Exception e) { logger.error(e.getMessage(), e); return Collections.emptyList(); } } @Override public int saveOrUpdate(InstanceAlert instanceAlert) { return instanceAlertValueDao.saveOrUpdate(instanceAlert); } @Override public InstanceAlert getByConfigKey(String configKey) { try { return instanceAlertValueDao.getByConfigKey(configKey); } catch (Exception e) { logger.error(e.getMessage(), e); return null; } } @Override public int updateStatus(String configKey, int status) { return instanceAlertValueDao.updateStatus(configKey, status); } @Override public int remove(String configKey) { return instanceAlertValueDao.remove(configKey); } @Override public int monitorLastMinuteAllInstanceInfo() { List<InstanceAlertValueResult> resultList = new ArrayList<InstanceAlertValueResult>(); // 固定值 List<InstanceAlert> staticInstanceAlertList = instanceAlertValueDao.getByValueType(ValueTypeEnum.STATIC.getValue(), StatusEnum.YES.getValue()); // 差值 List<InstanceAlert> diffInstanceAlertList = instanceAlertValueDao.getByValueType(ValueTypeEnum.DIFF.getValue(), StatusEnum.YES.getValue()); // 取上1分钟Redis实例统计信息 Date date = new Date(); Date beginTime = DateUtils.addMinutes(date, -2); Date endTime = DateUtils.addMinutes(date, -1); // 上一分钟Redis实例信息统计 long start = System.currentTimeMillis(); List<StandardStats> standardStatsList = instanceStatsDao.getStandardStatsByCreateTime(beginTime, endTime, "redis"); long cost = System.currentTimeMillis() - start; if (cost > 2000) { logger.warn("getStandardStatsByCreateTime {} to {} costtime is {} ms", beginTime, endTime, cost); } // 遍历所有Redis实例统计信息,和预设阀值对比报警 for (StandardStats standardStats : standardStatsList) { try { if (standardStats == null) { continue; } // 固定值 if (CollectionUtils.isNotEmpty(staticInstanceAlertList)) { List<InstanceAlertValueResult> staticInstanceAlertResultList = checkStaticInstanceInfoAlert(standardStats, staticInstanceAlertList); resultList.addAll(staticInstanceAlertResultList); } // 差值 if (CollectionUtils.isNotEmpty(diffInstanceAlertList)) { List<InstanceAlertValueResult> diffInstanceAlertResultList = checkDiffInstanceInfoAlert(standardStats, diffInstanceAlertList); if (CollectionUtils.isNotEmpty(diffInstanceAlertResultList)) { resultList.addAll(diffInstanceAlertResultList); } } } catch (Exception e) { logger.error(e.getMessage(), e); } } // 最终报警 sendInstanceAlertEmail(beginTime, endTime, resultList); return standardStatsList.size(); } /** * 发送邮件 * @param instanceAlertValueResultList */ private void sendInstanceAlertEmail(Date beginTime, Date endTime, List<InstanceAlertValueResult> instanceAlertValueResultList) { if (CollectionUtils.isEmpty(instanceAlertValueResultList)) { return; } Collections.sort(instanceAlertValueResultList, new Comparator<InstanceAlertValueResult>() { @Override public int compare(InstanceAlertValueResult o1, InstanceAlertValueResult o2) { return (int) (o1.getAppId() - o2.getAppId()); } }); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); String emailTitle = String.format("Redis实例分钟报警(%s~%s)", sdf.format(beginTime), sdf.format(endTime)); String emailContent = VelocityUtils.createText(velocityEngine, null, null, null, instanceAlertValueResultList, "instanceAlert.vm","UTF-8"); emailComponent.sendMailToAdmin(emailTitle, emailContent.toString()); } /** * 检测每个实例统计信息 * * @param standardStats * @param instanceAlertList * @return */ public List<InstanceAlertValueResult> checkStaticInstanceInfoAlert(StandardStats standardStats, List<InstanceAlert> instanceAlertList) { List<InstanceAlertValueResult> resultList = new ArrayList<InstanceAlertValueResult>(); // 标准Redis info统计信息 String jsonInfo = standardStats.getInfoJson(); if (StringUtils.isBlank(jsonInfo)) { return null; } // 转换成Map Map<String, Object> infoMap = JsonUtil.fromJson(jsonInfo, Map.class); if (MapUtils.isEmpty(infoMap)) { return null; } // 转换成Map<String, Map<String,Object>> for (Entry<String, Object> entry : infoMap.entrySet()) { Object object = entry.getValue(); if (!(object instanceof Map)) { continue; } Map<String, Object> sectionInfoMap = (Map<String, Object>) object; for (Entry<String, Object> sectionInfoEntry : sectionInfoMap.entrySet()) { String infoKey = sectionInfoEntry.getKey(); Object infoValue = sectionInfoEntry.getValue(); InstanceAlertValueResult instanceAlertValueResult = generateInstanceValueResult(instanceAlertList, infoKey, infoValue, standardStats.getIp(), standardStats.getPort()); if (instanceAlertValueResult != null) { resultList.add(instanceAlertValueResult); } } } return resultList; } /** * 检测每个实例统计信息 * * @param standardStats * @param instanceAlertList * @return */ public List<InstanceAlertValueResult> checkDiffInstanceInfoAlert(StandardStats standardStats, List<InstanceAlert> instanceAlertList) { List<InstanceAlertValueResult> resultList = new ArrayList<InstanceAlertValueResult>(); // 标准Redis info差值 String jsonInfo = standardStats.getDiffJson(); if (StringUtils.isBlank(jsonInfo)) { logger.error("id={}'s standardStats is empty", standardStats.getId()); return null; } // 转换成Map Map<String, Object> infoMap = JsonUtil.fromJson(jsonInfo, Map.class); if (MapUtils.isEmpty(infoMap)) { return null; } // 转换成Map<String, Map<String,Object>> for (Entry<String, Object> entry : infoMap.entrySet()) { String infoKey = entry.getKey(); Object infoValue = entry.getValue(); InstanceAlertValueResult instanceAlertValueResult = generateInstanceValueResult(instanceAlertList, infoKey, infoValue, standardStats.getIp(), standardStats.getPort()); if (instanceAlertValueResult != null) { resultList.add(instanceAlertValueResult); } } return resultList; } /** * 比较info的没有一个属性 * * @param instanceAlertList * @param infoKey * @param infoValue * @return */ private InstanceAlertValueResult generateInstanceValueResult(List<InstanceAlert> instanceAlertList, String infoKey, Object infoValue, String ip, int port) { for (InstanceAlert instanceAlert : instanceAlertList) { String alertConfigKey = instanceAlert.getConfigKey(); if (StringUtils.isBlank(infoKey) || StringUtils.isBlank(alertConfigKey) || !infoKey.equals(alertConfigKey)) { continue; } String alertInfoValue = instanceAlert.getAlertValue(); // 比较类型 1和-1是大于和小于 int compareType = instanceAlert.getCompareType(); if (compareType == CompareTypeEnum.SMALLER.getValue() || compareType == CompareTypeEnum.BIGGER.getValue()) { double infoValueDouble = NumberUtils.toDouble(infoValue.toString()); double alertInfoValueDouble = NumberUtils.toDouble(alertInfoValue); if ((compareType == -1 && infoValueDouble < alertInfoValueDouble) || (compareType == 1 && infoValueDouble > alertInfoValueDouble)) { return generateByInstanceStat(instanceAlert, infoKey, infoValue, ip, port); } } // 比较类型为0,表示等于 else if (compareType == CompareTypeEnum.EQUAL.getValue() && infoValue.toString().equals(alertInfoValue)) { return generateByInstanceStat(instanceAlert, infoKey, infoValue, ip, port); } // 比较类型为2,表示不等于 else if (compareType == CompareTypeEnum.NOT_EQUAL.getValue() && !infoValue.toString().equals(alertInfoValue)) { return generateByInstanceStat(instanceAlert, infoKey, infoValue, ip, port); } } return null; } /** * 生成实例报警结果 * * @param instanceAlert * @param infoKey * @param infoValue * @param ip * @param port * @return */ private InstanceAlertValueResult generateByInstanceStat(InstanceAlert instanceAlert, String infoKey, Object infoValue, String ip, int port) { //根据infoKey决定单位等 String alertValue = instanceAlert.getAlertValue(); String infoValueStr = infoValue.toString(); //网络输入输出流量、客户端最大输入buffer、aof文件当前尺寸 if ("total_net_output_bytes".equals(infoKey) || "total_net_input_bytes".equals(infoKey) || "client_biggest_input_buf".equals(infoKey) || "aof_current_size".equals(infoKey)) { // 以MB为单位显示 alertValue = changeByteToMB(alertValue); infoValueStr = changeByteToMB(infoValueStr); } InstanceAlertValueResult instanceAlertValueResult = new InstanceAlertValueResult(); instanceAlertValueResult.setAlertValue(alertValue); instanceAlertValueResult.setCompareType(instanceAlert.getCompareType()); instanceAlertValueResult.setValueType(instanceAlert.getValueType()); instanceAlertValueResult.setConfigKey(infoKey); instanceAlertValueResult.setCurrentValue(infoValueStr); instanceAlertValueResult.setIp(ip); instanceAlertValueResult.setPort(port); InstanceInfo instanceInfo = instanceDao.getInstByIpAndPort(ip, port); if (instanceInfo != null) { long appId = instanceInfo.getAppId(); instanceAlertValueResult.setAppId(appId); instanceAlertValueResult.setAppDesc(appService.getByAppId(appId)); } return instanceAlertValueResult; } private String changeByteToMB(String value) { return NumberUtils.toLong(value) / 1000 / 1000 + "MB"; } public void setInstanceStatsDao(InstanceStatsDao instanceStatsDao) { this.instanceStatsDao = instanceStatsDao; } public void setInstanceAlertValueDao(InstanceAlertValueDao instanceAlertValueDao) { this.instanceAlertValueDao = instanceAlertValueDao; } public void setInstanceDao(InstanceDao instanceDao) { this.instanceDao = instanceDao; } public void setEmailComponent(EmailComponent emailComponent) { this.emailComponent = emailComponent; } public void setVelocityEngine(VelocityEngine velocityEngine) { this.velocityEngine = velocityEngine; } public void setAppService(AppService appService) { this.appService = appService; } }