guava RateLimiter 使用笔记

使用guava包中的RateLimiter限制每个IP接口请求速率,添加如下filter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package com.caiyi.financial.nirvana.loan.filter;

import com.google.common.util.concurrent.RateLimiter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
* Created by liu
*/
@WebFilter
public class RateLimiterFilter implements Filter {
private static Logger logger = LoggerFactory.getLogger(PrivilegeFilter.class);

/**
* The Limiter map.
*/
static Map<String, RateLimiter> limiterMap = new ConcurrentHashMap<>();

@Override
public void init(FilterConfig filterConfig) throws ServletException {

}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
//IP限制
String ip = getRemoteHost(httpServletRequest);
RateLimiter limiterIp = limiterMap.get(ip);
if (limiterIp == null) {
limiterIp = RateLimiter.create(16.0); // 每秒不超过16个请求被提交
limiterMap.put(ip, limiterIp);
logger.debug("IP个数:{}", limiterMap.size());
} else {
limiterWithReturn(limiterIp, httpServletRequest, response);
}
}

@Override
public void destroy() {

}

/**
* 方法一:请求RateLimiter, 超过permits会被阻塞
*/
@SuppressWarnings("useless")
private void limiterWithBlock(RateLimiter limiter, ServletRequest requestWrapper, ServletResponse servletResponse) {
logger.info("实际接口访问频率:{}次/秒", limiter.acquire());
}

/**
* 方法二:请求RateLimiter, 超过permits直接返回
*/
private void limiterWithReturn(RateLimiter limiter, HttpServletRequest request, ServletResponse servletResponse) throws IOException, ServletException {
if (!limiter.tryAcquire()) {
logger.warn("接口超频:{},rate:{},ip地址:{}",
request.getRequestURI(), limiter.getRate(), getRemoteHost(request));
request.getRequestDispatcher("/error").forward(request, servletResponse);
}
}

/**
* Gets remote host.
*
* @param request the request
* @return the remote host
*/
public static String getRemoteHost(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
}
}


guava RateLimiter 使用笔记
https://www.wekri.com/guava-ratelimiter-使用笔记/
Author
Echo
Posted on
January 25, 2018
Licensed under