首页 > 代码库 > JavaWeb限流QPS简易框架

JavaWeb限流QPS简易框架

 

Java Web利用filter实现拦截请求,统计信息、并控制单台机器QPS。

 

 

/** * 网络流量控制器 */public class TrafficFilter implements Filter {    private ITrafficStatic trafficStatic;    private ITrafficHandler trafficHandler;    @Override    public void init(FilterConfig filterConfig) throws ServletException {        trafficHandler = new AgentTrafficHandler();        trafficStatic = new TrafficStatic();        trafficStatic.init();    }    @Override    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {        // step1: parse bizFunId        String bizFunId = request.getParameter("funBizId");        if (StringUtils.isBlank(bizFunId)) {            chain.doFilter(request, response);            return;        }        bizFunId = StringUtils.trim(bizFunId);        // step2: check whether it should be cached.        if (!trafficStatic.shouldLimitTraffic(bizFunId)) {            chain.doFilter(request, response);            return;        }        // step3: static the visitor.        if (trafficStatic.isOutOfTrafficLimit(bizFunId)) {            trafficHandler.handle((HttpServletRequest) request, (HttpServletResponse) response);            return;        }        int visNum = trafficStatic.incAndGetTraffic(bizFunId);        if (trafficStatic.isOutOfTrafficLimit(bizFunId, visNum)) {            trafficHandler.handle((HttpServletRequest) request, (HttpServletResponse) response);            return;        } else {            chain.doFilter(request, response);            return;        }    }    @Override    public void destroy() {        trafficStatic.destroy();    }}

 

public interface ITrafficStatic {    public void init();    public void destroy();    public boolean shouldLimitTraffic(String bizId);    public int incAndGetTraffic(String bizId);    public boolean isOutOfTrafficLimit(String bizId, int number);    public boolean isOutOfTrafficLimit(String bizId);}

 

public class TrafficStatic implements ITrafficStatic {    private static final AvatarLogger LOGGER = AvatarLoggerFactory.getLogger(TrafficStatic.class);    private Map<Integer, Map<String, AtomicInteger>> staticMap = new ConcurrentHashMap<Integer, Map<String, AtomicInteger>>();    private volatile Map<String, Integer> limitMap = new HashMap<String, Integer>();    private volatile Map<String, Integer> tempMap;    @Override    public void init() {        initCleanThread();        initSyncThread();    }    @Override    public void destroy() {    }    private void initCleanThread() {        new Thread(new Runnable() {            @Override            public void run() {                while (true) {                    sleep(60 * 1000); // sync pv every 1 min.                    int version = (int) System.currentTimeMillis() / 1000 - 60;                    Iterator<Map.Entry<Integer, Map<String, AtomicInteger>>> iterator = staticMap.entrySet().iterator();                    while (iterator.hasNext()) {                        Map.Entry<Integer, Map<String, AtomicInteger>> entry = iterator.next();                        if (entry.getKey() <= version) {                            iterator.remove();                        }                    }                } // while            }        }).start();    }    private void initSyncThread() {        new Thread(new Runnable() {            @Override            public void run() {                while (true) {                    sleep(60 * 1000); // sync pv every 1 min.                    if (MapUtils.isNotEmpty(tempMap)) {                        tempMap.clear();                        tempMap = null;                    }                    int version = getTimestampVersion();                    tempMap = limitMap;                    limitMap = readConfigFromLion();                    for (int i = version; i < (version + 5*60); ++i) {                        if (!staticMap.containsKey(i)) {                            staticMap.put(i, new ConcurrentHashMap<String, AtomicInteger>());                        }                        checkAndNewMapEntries(limitMap, staticMap.get(i));                    }                } // while            }        }).start();    }    private static Map<String, Integer> readConfigFromLion() {        try {            Map<String, Integer> map = JsonUtils.fromJson(PropertiesLoaderSupportUtils.getProperty("tpfun-promo-web.networktraffic.traffic-config", "{}"), Map.class);            return MapUtils.isEmpty(map) ? MapUtils.EMPTY_MAP : map;        } catch (Exception e) {            LOGGER.error("[networktraffic] error with reading config from lion", e);            return MapUtils.EMPTY_MAP;        }    }    private void checkAndNewMapEntries(Map<String, Integer> source, Map<String, AtomicInteger> target) {        for (Map.Entry<String, Integer> entry : source.entrySet()) {            if (!target.containsKey(entry.getKey())) {                target.put(entry.getKey(), new AtomicInteger(0));            }        }    }    private void sleep(long mills) {        try {            Thread.sleep(mills);        } catch (InterruptedException e) {            LOGGER.error("[networktraffic] PvCounterBiz threads.sleep error", e);        }    }    private int getTimestampVersion() {        return (int) (System.currentTimeMillis() / 1000);    }    @Override    public boolean shouldLimitTraffic(String bizId) {        return limitMap.containsKey(bizId);    }    @Override    public int incAndGetTraffic(String bizId) {        int ver = getTimestampVersion();        if (!staticMap.containsKey(ver)) {            return 1;        }        Map<String, AtomicInteger> map = staticMap.get(ver);        if (MapUtils.isEmpty(map) || !map.containsKey(bizId)) {            return 1;        }        return map.get(bizId).incrementAndGet();    }    @Override    public boolean isOutOfTrafficLimit(String bizId, int number) {        int ver = getTimestampVersion();        if (!limitMap.containsKey(bizId)) {            return false;        }        return (number > limitMap.get(bizId));    }    @Override    public boolean isOutOfTrafficLimit(String bizId) {        int ver = getTimestampVersion();        if (!staticMap.containsKey(ver)) {            return false;        }        Map<String, AtomicInteger> map = staticMap.get(ver);        if (MapUtils.isEmpty(map) || !map.containsKey(bizId)) {            return false;        }        return isOutOfTrafficLimit(bizId, map.get(bizId).intValue());    }}

 

public interface ITrafficHandler {    void handle(HttpServletRequest request, HttpServletResponse response);}

 

public class AgentTrafficHandler implements ITrafficHandler {    private AjaxTrafficHandler ajaxTrafficHandler = new AjaxTrafficHandler();    private MobileTrafficHandler mobileTrafficHandler = new MobileTrafficHandler();    @Override    public void handle(HttpServletRequest request, HttpServletResponse response) {        if (StringUtils.contains(request.getRequestURI(), "ajax")) {            ajaxTrafficHandler.handle(request, response);        } else {            mobileTrafficHandler.handle(request, response);        }    }}
public class AjaxTrafficHandler implements ITrafficHandler {    private static final AvatarLogger LOGGER = AvatarLoggerFactory.getLogger(MobileTrafficHandler.class);    private final static String RETURN_JSON = "{code:509, message:‘out of max req limit‘}";    @Override    public void handle(HttpServletRequest request, HttpServletResponse response) {        response.setHeader("Content-Type", "application/json;charset=UTF-8");        response.setCharacterEncoding("UTF-8");        response.setStatus(200);        try {            response.getOutputStream().write(RETURN_JSON.getBytes("UTF-8"));        } catch (IOException e) {            LOGGER.error(e);        }    }}

 

public class MobileTrafficHandler implements ITrafficHandler {    private static final AvatarLogger LOGGER = AvatarLoggerFactory.getLogger(MobileTrafficHandler.class);    private final static String RETURN_HTML = "<html>" +            "<head>" +            "<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\" />" +            "\n<meta charset=‘utf-8‘>" +            "<title>大众点评网</title>" +            "</head><body>" +            "<center>挤爆了、请稍等...</center>" +            "</body>" +            "<script type=‘text/javascript‘>(function(){function reload(){ window.location.reload(); setTimeout(reload, 1500);} setTimeout(reload, 1500);})();" +            "</script>" +            "</html>";    @Override    public void handle(HttpServletRequest request, HttpServletResponse response) {        response.setHeader("Content-Type", "text/html;charset=utf-8");        response.setCharacterEncoding("utf-8");        response.setStatus(200);        try {            response.getOutputStream().write(RETURN_HTML.getBytes("UTF-8"));        } catch (IOException e) {            LOGGER.error(e);        }    }}

 

JavaWeb限流QPS简易框架