package com.sohu.cache.inspect.impl; import com.sohu.cache.alert.impl.BaseAlertService; import com.sohu.cache.constant.InstanceStatusEnum; import com.sohu.cache.entity.InstanceInfo; import com.sohu.cache.inspect.InspectParamEnum; import com.sohu.cache.inspect.Inspector; import com.sohu.cache.redis.RedisCenter; import com.sohu.cache.util.IdempotentConfirmer; import com.sohu.cache.util.TypeUtil; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang.StringUtils; import redis.clients.jedis.Jedis; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; /** * Created by yijunzhang on 15-1-30. */ public class RedisIsolationPersistenceInspector extends BaseAlertService implements Inspector { public static final int REDIS_DEFAULT_TIME = 5000; private RedisCenter redisCenter; @Override public boolean inspect(Map<InspectParamEnum, Object> paramMap) { final String host = MapUtils.getString(paramMap, InspectParamEnum.SPLIT_KEY); List<InstanceInfo> list = (List<InstanceInfo>) paramMap.get(InspectParamEnum.INSTANCE_LIST); outer: for (InstanceInfo info : list) { final int port = info.getPort(); final int type = info.getType(); final long appId = info.getAppId(); int status = info.getStatus(); //非正常节点 if (status != InstanceStatusEnum.GOOD_STATUS.getStatus()) { continue; } if (TypeUtil.isRedisDataType(type)) { Jedis jedis = redisCenter.getJedis(appId, host, port, REDIS_DEFAULT_TIME, REDIS_DEFAULT_TIME); try { Map<String, String> persistenceMap = parseMap(jedis); if (persistenceMap.isEmpty()) { logger.error("{}:{} get persistenceMap failed", host, port); continue; } if (!isAofEnabled(persistenceMap)) { continue; } long aofCurrentSize = MapUtils.getLongValue(persistenceMap, "aof_current_size"); long aofBaseSize = MapUtils.getLongValue(persistenceMap, "aof_base_size"); //阀值大于60% long aofThresholdSize = (long) (aofBaseSize * 1.6); double percentage = getPercentage(aofCurrentSize, aofBaseSize); if (aofCurrentSize >= aofThresholdSize //大于64Mb && aofCurrentSize > (64 * 1024 * 1024)) { //bgRewriteAof boolean isInvoke = invokeBgRewriteAof(jedis); if (!isInvoke) { logger.error("{}:{} invokeBgRewriteAof failed", host, port); continue; } else { logger.warn("{}:{} invokeBgRewriteAof started percentage={}", host, port, percentage); } while (true) { try { //before wait 1s TimeUnit.SECONDS.sleep(1); Map<String, String> loopMap = parseMap(jedis); Integer aofRewriteInProgress = MapUtils.getInteger(loopMap, "aof_rewrite_in_progress", null); if (aofRewriteInProgress == null) { logger.error("loop watch:{}:{} return failed", host, port); break; } else if (aofRewriteInProgress <= 0) { //bgrewriteaof Done logger.warn("{}:{} bgrewriteaof Done lastSize:{}Mb,currentSize:{}Mb", host, port, getMb(aofCurrentSize), getMb(MapUtils.getLongValue(loopMap, "aof_current_size"))); break; } else { //wait 1s TimeUnit.SECONDS.sleep(1); } } catch (Exception e) { logger.error(e.getMessage(), e); } } } else { if (percentage > 50D) { long currentSize = getMb(aofCurrentSize); logger.info("checked {}:{} aof increase percentage:{}% currentSize:{}Mb", host, port, percentage, currentSize > 0 ? currentSize : "<1"); } } } finally { jedis.close(); } } } return true; } private long getMb(long bytes) { return (long) (bytes / 1024 / 1024); } private boolean isAofEnabled(Map<String, String> infoMap) { Integer aofEnabled = MapUtils.getInteger(infoMap, "aof_enabled", null); return aofEnabled != null && aofEnabled == 1; } private double getPercentage(long aofCurrentSize, long aofBaseSize) { if (aofBaseSize == 0) { return 0.0D; } String format = String.format("%.2f", (Double.valueOf(aofCurrentSize - aofBaseSize) * 100 / aofBaseSize)); return Double.parseDouble(format); } private Map<String, String> parseMap(final Jedis jedis) { final StringBuilder builder = new StringBuilder(); boolean isInfo = new IdempotentConfirmer() { @Override public boolean execute() { String persistenceInfo = null; try { persistenceInfo = jedis.info("Persistence"); } catch (Exception e) { logger.warn(e.getMessage() + "-{}:{}", jedis.getClient().getHost(), jedis.getClient().getPort(), e.getMessage()); } boolean isOk = StringUtils.isNotBlank(persistenceInfo); if (isOk) { builder.append(persistenceInfo); } return isOk; } }.run(); if (!isInfo) { logger.error("{}:{} info Persistence failed", jedis.getClient().getHost(), jedis.getClient().getPort()); return Collections.emptyMap(); } String persistenceInfo = builder.toString(); if (StringUtils.isBlank(persistenceInfo)) { return Collections.emptyMap(); } Map<String, String> map = new LinkedHashMap<String, String>(); String[] array = persistenceInfo.split("\r\n"); for (String line : array) { String[] cells = line.split(":"); if (cells.length > 1) { map.put(cells[0], cells[1]); } } return map; } public boolean invokeBgRewriteAof(final Jedis jedis) { return new IdempotentConfirmer() { @Override public boolean execute() { try { String response = jedis.bgrewriteaof(); if (response != null && response.contains("rewriting started")) { return true; } } catch (Exception e) { String message = e.getMessage(); if (message.contains("rewriting already")) { return true; } logger.error(message, e); } return false; } }.run(); } public void setRedisCenter(RedisCenter redisCenter) { this.redisCenter = redisCenter; } }