Authored by jack

增加 新redis监控

package com.monitor.middleware.redis.constants;
import com.monitor.middleware.redis.model.RedisInfo;
import com.monitor.middleware.redis.model.TwemproxyInfo;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Created by yoho on 2016/9/21.
*/
public interface Constants {
//key: "ip:port"
Map<String, RedisInfo> REDIS_INFO_MAP = new ConcurrentHashMap<>();
//key: "ip:port"
Map<String, TwemproxyInfo> TWEMPROXY_INFO_MAP = new ConcurrentHashMap<>();
}
... ...
package com.monitor.middleware.redis.constants;
import org.apache.commons.lang.StringUtils;
import redis.clients.jedis.Jedis;
/**
* Created by yoho on 2016/9/22.
*/
public class RedisTest {
public static boolean test(String ip,int port)
{
Jedis testClient = new Jedis(ip, Integer.valueOf(port), 200);
String testKey = "test" + ip;
String testValue = ip;
testClient.set(testKey.getBytes(), testValue.getBytes());
String resultValue = new String(testClient.get(testKey.getBytes()));
testClient.close();
if (StringUtils.equals(ip, resultValue)) {
return true;
}
return false;
}
}
... ...
package com.monitor.middleware.redis.controller;
import com.model.MObjectInfo;
import com.monitor.cmdb.service.IMObjectInfoService;
import com.monitor.cmdb.service.ITypeInfoService;
import com.monitor.middleware.redis.constants.Constants;
import com.monitor.middleware.redis.model.RedisInfo;
import com.monitor.middleware.redis.model.RedisVo;
import com.monitor.middleware.redis.model.TwemproxyInfo;
import com.monitor.middleware.redis.model.TwemproxyVo;
import com.monitor.model.response.BaseResponse;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Created by yoho on 2016/9/21.
*/
@RestController
@RequestMapping(value = "redisMonitor")
public class RedisCtrl {
@Autowired
IMObjectInfoService imObjectInfoService;
@Autowired
ITypeInfoService iTypeInfoService;
@RequestMapping(value = "/allTwemproxy")
public BaseResponse queryAllTwemproxy() {
BaseResponse response = new BaseResponse();
List<TwemproxyVo> twemproxyVOList = new ArrayList<>();
for (Map.Entry<String, TwemproxyInfo> entry : Constants.TWEMPROXY_INFO_MAP.entrySet()) {
TwemproxyVo twemproxyVO = buildTwemproxyVO(entry.getKey(), entry.getValue());
twemproxyVOList.add(twemproxyVO);
}
response.setData(twemproxyVOList);
return response;
}
/**
* 后台视图 转 前台视图
*
* @param key
* @param value
* @return
*/
private TwemproxyVo buildTwemproxyVO(String key, TwemproxyInfo value) {
TwemproxyVo twemproxyVO = new TwemproxyVo();
twemproxyVO.setUrl(key);
twemproxyVO.setConnections(String.valueOf(value.getCurrConnections()));
MObjectInfo mObjectInfo = imObjectInfoService.queryMObjectInfo(Integer.parseInt(value.getMoId()));
twemproxyVO.setName(value.getType());
twemproxyVO.setAlias(mObjectInfo.getMoName());
if (mObjectInfo.getMoHostIp().startsWith("172.")) {
twemproxyVO.setNetwork("AWS");
} else {
twemproxyVO.setNetwork("QCloud");
}
String redisList = "";
for (Map.Entry<String, Long> entry : value.getRequestMap().entrySet()) {
redisList += entry.getKey() + "\r\n";
}
twemproxyVO.setRedisList(redisList);
if (value.test()) {
twemproxyVO.setState("OK");
} else {
twemproxyVO.setState("Not-OK");
}
long updateDays = value.getUpTime() / (60 * 60 * 24);
twemproxyVO.setTaskCtime(String.valueOf(updateDays) + " Days");
twemproxyVO.setType(iTypeInfoService.queryTypeInfo(mObjectInfo.getMoTypeId()).getTypeName());
return twemproxyVO;
}
@RequestMapping(value = "/allRedis")
public BaseResponse queryAllRedis(@RequestParam("twemproxy") String twemproxy) {
BaseResponse response = new BaseResponse();
List<RedisVo> redisInfoList = new ArrayList<>();
TwemproxyInfo twemproxyInfo = Constants.TWEMPROXY_INFO_MAP.get(twemproxy);
for (Map.Entry<String, Long> entry : twemproxyInfo.getRequestMap().entrySet()) {
RedisInfo redisInfo = Constants.REDIS_INFO_MAP.get(entry.getKey());
RedisVo redisVo = buildRedisVo(redisInfo);
redisInfoList.add(redisVo);
}
response.setData(redisInfoList);
return response;
}
private RedisVo buildRedisVo(RedisInfo redisInfo) {
RedisVo redisVo = new RedisVo();
redisVo.setIp(redisInfo.getIp());
redisVo.setPort(redisInfo.getPort());
redisVo.setRole(redisInfo.getRole());
redisVo.setMaxMem(redisInfo.getMaxMem());
redisVo.setUsedMem(redisInfo.getUsedMem());
redisVo.setMemUsedRate(redisInfo.getUsedRate() + " %");
redisVo.setRssRate(String.valueOf(redisInfo.getRssRate()));
if (redisInfo.test()) {
redisVo.setStatus("OK");
} else {
redisVo.setStatus("NOT-OK");
}
if (StringUtils.equals("master", redisInfo.getRole())) {
//组织slave信息
redisVo.setMasterOrSlave(redisInfo.getSlaves());
} else {
//组织master信息
redisVo.setMasterOrSlave(redisInfo.getMasters());
}
redisVo.setOpSec(String.valueOf(redisInfo.getOpCaps()));
redisVo.setRequestSec(String.valueOf(redisInfo.getReqCaps()));
redisVo.setHitRate(redisInfo.getHitRate()+" %");
return redisVo;
}
}
... ...
package com.monitor.middleware.redis.model;
import com.monitor.middleware.redis.constants.RedisTest;
import lombok.Data;
/**
* Created by yoho on 2016/9/19.
*/
@Data
public class RedisInfo {
String ip;
String port;
long requests;
long reqCaps;
long opCaps;
String role;
String maxMem;
String usedMem;
String usedRate;
String status;
//从信息
String slaves;
//主信息
String masters;
//命中率
String hitRate;
//碎片化程度 数值越大 碎片化越大
double rssRate;
public boolean test() {
return RedisTest.test(this.ip, Integer.valueOf(this.port));
}
}
... ...
package com.monitor.middleware.redis.model;
import lombok.Data;
/**
* Created by yoho on 2016/9/21.
*/
@Data
public class RedisVo {
String ip;
String port;
String role;
String maxMem;
String usedMem;
String memUsedRate;
String rssRate;
String status;
String masterOrSlave;
String opSec;
String requestSec;
String hitRate;
}
... ...
package com.monitor.middleware.redis.model;
import com.monitor.middleware.redis.constants.RedisTest;
import lombok.Data;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.node.ObjectNode;
import java.io.IOException;
import java.util.*;
/**
* Created by yoho on 2016/9/19.
*/
@Data
public class TwemproxyInfo {
public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper().configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
String moId;
String type;
//监控数据
long upTime;
long currConnections;
String ip;
int port;
String info;
Map<String, Long> requestMap = new HashMap<>();
public TwemproxyInfo(String ip, int port, String info) {
try {
this.info = info;
this.ip = ip;
this.port = port;
JsonNode infoJson = OBJECT_MAPPER.readTree(info);
this.upTime = infoJson.get("uptime").getLongValue();
this.currConnections = infoJson.get("curr_connections").getLongValue();
JsonNode serversNode = infoJson.get("alpha");
Iterator<String> fieldIter = serversNode.getFieldNames();
while (fieldIter.hasNext()) {
String field = fieldIter.next();
if (field.contains(":")) {
JsonNode fieldNode = (ObjectNode) serversNode.get(field);
requestMap.put(field, fieldNode.get("requests").getLongValue());
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void buildServersInfoByRelations(Map<String, String> relationMaps) {
try {
JsonNode infoJson = OBJECT_MAPPER.readTree(info);
JsonNode serversNode = infoJson.get("alpha");
for (Map.Entry<String, String> entry : relationMaps.entrySet()) {
JsonNode serverNode = serversNode.get(entry.getKey());
long request = serverNode.get("requests").getLongValue();
requestMap.put(entry.getValue(), request);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public boolean test() {
return RedisTest.test(this.ip, this.port);
}
}
... ...
package com.monitor.middleware.redis.model;
import lombok.Data;
/**
* Created by yoho on 2016/9/21.
*/
@Data
public class TwemproxyVo {
String alias;
String url;
String connections;
String taskCtime;
String name;
String type;
String network;
String state;
String redisList;
}
... ...
package com.monitor.middleware.redis.service.impl;
import com.model.MObjectInfo;
import com.model.TypeInfo;
import com.monitor.cmdb.service.IMObjectInfoService;
import com.monitor.cmdb.service.ITypeInfoService;
import com.monitor.middleware.redis.task.TwemproxyTask;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created by yoho on 2016/9/19.
*/
@Service
@EnableScheduling
public class RedisMonitorImpl {
public static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(10);
@Autowired
private ITypeInfoService typeService;
@Autowired
private IMObjectInfoService mobjectService;
private Map<Integer, List<MObjectInfo>> serversMap;
@Scheduled(fixedRate = 2 * 60 * 1000)
public void monitor() {
//遍历所有的redis / twemproxy
serversMap = getServersMap();
for (Map.Entry<Integer, List<MObjectInfo>> entry : serversMap.entrySet()) {
String typeName = typeService.queryTypeInfo(entry.getKey()).getTypeName();
List<MObjectInfo> redisList = new ArrayList<>();
List<TwemproxyTask> twemproxyTaskList = new ArrayList<>();
for (MObjectInfo info : entry.getValue()) {
if (info.getMoName().startsWith("redis")) {
redisList.add(info);
}
if (info.getMoName().startsWith("twemproxy")) {
TwemproxyTask twemproxyTask = buildTwemproxyTask(info, typeName, redisList);
twemproxyTaskList.add(twemproxyTask);
}
}
for (TwemproxyTask twemproxyTask : twemproxyTaskList)
if (null != twemproxyTask) {
EXECUTOR_SERVICE.submit(twemproxyTask);
}
}
}
public Map<Integer, List<MObjectInfo>> getServersMap() {
Map<Integer, List<MObjectInfo>> serversMap = new HashMap<>();
List<TypeInfo> typeList = typeService.queryAllTypesInfo();
TypeInfo parentTypeInfo = null;
for (TypeInfo typeInfo : typeList) {
if (StringUtils.equals("redis", typeInfo.getTypeName()) && 0 == typeInfo.getTypeIsLeaf()) {
parentTypeInfo = typeInfo;
break;
}
}
List<TypeInfo> childTypeList = typeService.queryChildTypesInfo(parentTypeInfo.getTypeId());
for (TypeInfo typeInfo : childTypeList) {
List<TypeInfo> childList = typeService.queryChildTypesInfo(typeInfo.getTypeId());
for (TypeInfo childType : childList) {
List<MObjectInfo> mObjectInfos = mobjectService.queryMObjectsInfoByType(childType.getTypeId());
if (null != mObjectInfos && 0 < mObjectInfos.size()) {
if (serversMap.containsKey(typeInfo.getTypeId())) {
serversMap.get(typeInfo.getTypeId()).addAll(mObjectInfos);
} else {
serversMap.put(typeInfo.getTypeId(), mObjectInfos);
}
}
}
}
return serversMap;
}
/**
* 构造twemproxy监控任务
*
* @param mObjectInfo
* @param name
* @return
*/
private TwemproxyTask buildTwemproxyTask(MObjectInfo mObjectInfo, String name, List<MObjectInfo> mObjectInfos) {
String tags[] = mObjectInfo.getMoTags().split(",");
String url = null;
int mPort = 0;
for (String tag : tags) {
if (tag.startsWith("monitor:")) {
String tagKV[] = tag.split(":");
mPort = Integer.parseInt(tagKV[1]);
}
if (tag.startsWith("port:")) {
String tagKV[] = tag.split(":");
url = mObjectInfo.getMoHostIp() + ":" + tagKV[1];
}
}
if (StringUtils.isBlank(url) || 0 == mPort) {
return null;
}
TwemproxyTask twemproxyTask = new TwemproxyTask(url, mPort, name, mObjectInfo.getMoId());
twemproxyTask.setMObjectInfoList(mObjectInfos);
return twemproxyTask;
}
}
... ...
package com.monitor.middleware.redis.task;
import com.monitor.middleware.redis.constants.Constants;
import com.monitor.middleware.redis.model.RedisInfo;
import org.apache.commons.lang.StringUtils;
import redis.clients.jedis.Jedis;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;
/**
* Created by yoho on 2016/9/20.
*/
public class RedisTask extends Task {
private Long requests = 0L;
public RedisTask(String url, Long requests) {
super(url);
this.requests = requests;
}
@Override
public void doTask() {
Jedis client = new Jedis(this.getIp(), this.getPort(), 2 * 1000);
String info = client.info();
client.close();
Map<String, String> infoMap = buildInfo(info);
RedisInfo redisInfo = buildRedisInfo(infoMap);
redisInfo.setRequests(this.requests);
long reqCaps = 0L;
//每秒请求数
if (Constants.REDIS_INFO_MAP.containsKey(this.getUrl())) {
reqCaps = (this.requests - Constants.REDIS_INFO_MAP.get(this.getUrl()).getRequests()) / 60;
}
redisInfo.setReqCaps(reqCaps);
//save
Constants.REDIS_INFO_MAP.put(this.getUrl(), redisInfo);
}
private Map<String, String> buildInfo(String info) {
Map<String, String> infoMap = new HashMap<>();
if (StringUtils.isNotBlank(info)) {
String[] itemArray = info.split("\r\n");
for (String item : itemArray) {
if (item.startsWith("#") || item.startsWith("\r\n")) {
continue;
}
String[] kv = item.split(":", 2);
if (StringUtils.isNotBlank(kv[0]) && StringUtils.isNotBlank(kv[1])) {
infoMap.put(kv[0], kv[1]);
}
}
}
return infoMap;
}
private RedisInfo buildRedisInfo(Map<String, String> infoMap) {
RedisInfo redisInfo = new RedisInfo();
redisInfo.setIp(this.getIp());
redisInfo.setPort(String.valueOf(this.getPort()));
redisInfo.setRole(infoMap.get("role"));
redisInfo.setMaxMem(infoMap.get("maxmemory_human"));
redisInfo.setUsedMem(infoMap.get("used_memory_human"));
Double used = Double.parseDouble(infoMap.get("used_memory"));
Double max = Double.parseDouble(infoMap.get("maxmemory"));
//使用率
redisInfo.setUsedRate(new DecimalFormat("0.00").format(used * 100 / max));
//设置从节点
if (StringUtils.equals(redisInfo.getRole(), "master")) {
String slaveInfo = "";
for (Map.Entry<String, String> entry : infoMap.entrySet()) {
if (entry.getKey().startsWith("slave")) {
slaveInfo.concat("slave: " + entry.getValue() + "\r\n");
}
}
redisInfo.setSlaves(slaveInfo);
}
//设置主节点
else {
String masterInfo = "";
masterInfo.concat("master: " + infoMap.get("master_host") + "," + infoMap.get("master_port") + "," + infoMap.get("master_link_status"));
redisInfo.setMasters(masterInfo);
}
Double hit = Double.parseDouble(infoMap.get("keyspace_hits"));
Double miss = Double.parseDouble(infoMap.get("keyspace_misses"));
//命中率
redisInfo.setHitRate(new DecimalFormat("0.00").format((hit * 100) / (hit + miss)));
//碎片率
redisInfo.setRssRate(Double.parseDouble(infoMap.get("mem_fragmentation_ratio")));
//每秒处理命令数量
redisInfo.setOpCaps(Long.parseLong(infoMap.get("instantaneous_ops_per_sec")));
return redisInfo;
}
}
... ...
package com.monitor.middleware.redis.task;
import lombok.Getter;
import java.io.IOException;
import java.util.concurrent.Callable;
/**
* Created by yoho on 2016/9/21.
*/
public class Task implements Callable {
@Getter
private String url;
@Getter
private String ip;
@Getter
private int port;
public Task(String url) {
this.url=url;
String[] urls = url.split(":", 2);
this.ip = urls[0];
this.port = Integer.parseInt(urls[1]);
}
private Task() {
}
@Override
public Object call() throws Exception {
doTask();
return null;
}
protected void doTask() throws IOException {
}
}
... ...
package com.monitor.middleware.redis.task;
import com.model.MObjectInfo;
import com.monitor.common.util.TelnetUtils;
import com.monitor.middleware.redis.constants.Constants;
import com.monitor.middleware.redis.model.TwemproxyInfo;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang.StringUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created by yoho on 2016/9/20.
*/
public class TwemproxyTask extends Task {
private int monitPort;
private String name;
private int moId;
@Getter
@Setter
private List<MObjectInfo> mObjectInfoList;
public TwemproxyTask(String url, int monitPort, String name, int moId) {
super(url);
this.monitPort = monitPort;
this.name = name;
this.moId = moId;
}
@Override
public void doTask() {
String info = TelnetUtils.getResult(this.getIp(), this.monitPort);
TwemproxyInfo twemproxyInfo = new TwemproxyInfo(this.getIp(), this.getPort(), info);
twemproxyInfo.setType(name);
twemproxyInfo.setMoId(String.valueOf(this.moId));
//构建redis与twemproxy的关系
Map<String, String> relationMaps = new HashMap<>();
for (MObjectInfo mObjectInfo : mObjectInfoList) {
String tags[] = mObjectInfo.getMoTags().split(",");
String a_name = "";
String port = "";
for (String tag : tags) {
if (tag.startsWith("a-name:")) {
a_name = tag.split(":", 2)[1];
}
if (tag.startsWith("port:")) {
port = tag.split(":", 2)[1];
}
}
if (StringUtils.isNotBlank(port) && StringUtils.isNotBlank(a_name)) {
relationMaps.put(a_name, mObjectInfo.getMoHostIp() + ":" + port);
}
}
if (!relationMaps.isEmpty()) {
twemproxyInfo.buildServersInfoByRelations(relationMaps);
}
//存储
Constants.TWEMPROXY_INFO_MAP.put(this.getUrl(), twemproxyInfo);
//根据redis的信息 分发 redis监控任务
dispatchRedisTask(twemproxyInfo);
}
/**
* 根据twemproxy中查询的redis 信息 发布 redis监控任务
*
* @param twemproxyInfo
*/
private void dispatchRedisTask(TwemproxyInfo twemproxyInfo) {
int redisCount = twemproxyInfo.getRequestMap().size();
ExecutorService taskService = Executors.newFixedThreadPool(redisCount);
for (Map.Entry<String, Long> entry : twemproxyInfo.getRequestMap().entrySet()) {
taskService.submit(new RedisTask(entry.getKey(), entry.getValue()));
}
}
}
... ...