Web Server多线程模式下,redis的incr注意点

场景。

1) Spring MVC下Controller是多线程的,所有调用controller方法之前会进入切面。@Around("within(@org.springframework.stereotype.Controller *) && @annotation(limit)")
2)获得请求的真实ip,(nginx代理之前的ip)

public class NginxUtils {
    public static String getRealIp(HttpServletRequest request){

        String ip = request.getHeader("X-Forwarded-For");
        if(ip == null || ip.equals("") || "unknown".equalsIgnoreCase(ip)){
            ip = request.getHeader("X-Real-IP");
        }
        if(ip == null || ip.equals("") || "unknown".equalsIgnoreCase(ip)){
            ip = request.getHeader("Proxy-Client-IP");
        }
        if(ip == null || ip.equals("") || "unknown".equalsIgnoreCase(ip)){
            ip = request.getRemoteAddr();
        }

        return ip;

    }

}

3)构造redis中需要存的key。
String ip = NginxUtils.getRealIp(request);
String url = request.getRequestURI();
String key = "req_limit_" + url + "_" + ip;

BoundValueOperations ops = stringRedisTemplate.boundValueOps(key);
String countString = ops.get();
            if(countString == null || countString.equals("")){
                logger.info("ip:" + ip + ", first request within 1s");
                ops.set("0", 1000, TimeUnit.MILLISECONDS);
}
long count = Long.valueOf(ops.get());`这里可能会为null, 因为多线程导致有请求执行到这里时,刚好key的超时时间到了`
if(count > 10){
                logger.info("url:\t" + url + ",  ip:\t" + ip + " limit request");
                map.put("success", false);
                map.put("message", "the ip: " + ip + " is up to the limit " + 10 + " within " + "1s");
                return map;
}
ops.increment(1);`执行incr,或创建一个key, 并且增加1, 此时ttl为 -1`
Web Server多线程模式下,redis的incr注意点_第1张图片
image.png

4)解决方案, 在incr之前,判断是否过期了,过期则重新设置ttl。

Long milSeconds = stringRedisTemplate.getExpire(key, TimeUnit.MILLISECONDS);
            if(milSeconds == null || milSeconds <= 0){
                ops.set("0", 1000, TimeUnit.MILLISECONDS);
            }
ops.increment(1);```


![image.png](http://upload-images.jianshu.io/upload_images/5148056-2ae4015bead72b1b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

你可能感兴趣的:(Web Server多线程模式下,redis的incr注意点)