zoukankan      html  css  js  c++  java
  • 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" />" +
                "
    <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);
            }
        }
    
    }
  • 相关阅读:
    [DNN模块] DNNPortalDownload_1_0_9a_PA(C#)汉化版
    我的第一个DNN皮肤
    调试DNN的方法
    DotNetNuke系列文章 Skin 與 Container 設計介紹
    DotNetNuke 語言包的上傳步驟
    pstools使用说明
    Android Prefence 总结
    android 来电自动接听和自动挂断
    Android 颜色选择器(ColorPicker)
    修改文件权限与归属
  • 原文地址:https://www.cnblogs.com/icanth/p/4077263.html
Copyright © 2011-2022 走看看