为了应对双十一的动态服务降级(redis+disconf)

背景

为了应对双十一,服务需要高峰期内进行动态降级
选用disconf+redis的方式,选取这个方式的原因是因为我们的服务大多都提供的查询服务,不涉及修改
如果量多很容易压垮数据库,很容易联想到redis缓存结果,原来我们的服务都有redis缓存不过大多都是静态写死的
但是原来有些接口使用的注解式的redis,每个接口都改造成RedisTemplate的形式有些繁琐
所以借助Spring的切向编程完成工作


code

@Slf4j
@Component
@Aspect
public class RedisAopUtil {
    @Autowired
    private DynamicConfig config;

    private static RedisTemplate<String, Object> redisTemplateAny;

    static {
        redisTemplateAny = (RedisTemplate<String, Object>) SpringContextUtil.getBean("redisTemplate");
    }

    /**
     * redis缓存5S
     */
//    @Around("")
    public Object redisFiveSecond(ProceedingJoinPoint pjp) throws Throwable {
        Object redisObject = getRedisObject(pjp);
        if (redisObject != null) {
            return redisObject;
        }
        Object re = pjp.proceed();
        saveToRedis(pjp, re, 5L);
        return re;
    }

    /**
     * redis缓存30S
     */
    @Around(
            
            "execution(* com.xxx.xxxx.xxxxx.xxxx.xxxxx.xxx(..))||" +
            "execution(* com.xxx.xxxx.xxxxx.xxxx.xxxxx.xxx(..))"
    )
    public Object redisHalfMinute(ProceedingJoinPoint pjp) throws Throwable {
        Object redisObject = getRedisObject(pjp);
        if (redisObject != null) {
            return redisObject;
        }
        //方法调用
        Object re = pjp.proceed();
        saveToRedis(pjp, re, config.getHalfAMinute());
        return re;
    }

    /**
     * redis缓存外部接口30S
     */
    @Around(
            "execution(* com.xxx.xxxx.xxxxx.xxxx.xxxxx.xxx(..))||"+
            "execution(* com.xxx.xxxx.xxxxx.xxxx.xxxxx.xxx(..))||"+
            "execution(* com.xxx.xxxx.xxxxx.xxxx.xxxxx.xxx(..))||"+
            "execution(* com.xxx.xxxx.xxxxx.xxxx.xxxxx.xxx(..))"
    )
    public Object redisOutHalfMinute(ProceedingJoinPoint pjp) throws Throwable {
        Object redisObject = getRedisObject(pjp);
        if (redisObject != null) {
            return redisObject;
        }
        //方法调用
        Object re = pjp.proceed();
        saveToRedis(pjp, re, config.getOutHalfAMinute());
        return re;
    }

    /**
     * 获取对象
     */
    private Object getRedisObject(ProceedingJoinPoint pjp) {
        try {
            Object[] args = pjp.getArgs();
            //方法名
            String methodName = pjp.getSignature().getName();
            String firstArg = null;
            if (args.length > 0) {
                firstArg = JSONObject.toJSONString(args[0]);
            }
            Object result;
            String key = CommonUtils.getRedisString(methodName, firstArg);
            result = redisTemplateAny.opsForValue().get(key);
            if (result != null) {
                return result;
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 存到redis
     *
     * @param re         存储对象,能够序列化
     * @param expireTime 过期时间
     */
    private void saveToRedis(ProceedingJoinPoint pjp, Object re, long expireTime) {
        try {
            Object argObject = pjp.getArgs()[0];
            if (argObject != null) {
                redisTemplateAny.opsForValue().set(CommonUtils.getRedisString(pjp.getSignature().getName(), JSONObject.toJSONString(argObject)), re, expireTime, TimeUnit.SECONDS);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }
}

ps:
涉及公司的一些代码就用xxx代替了
注意这里固定将 方法名和第一个参数的字符串 组成redis的key
DynamicConfig是disconf的类,可以通过页面动态改变值,以此来做到服务降级
如果有错误欢迎交流

你可能感兴趣的:(后台开发)