JavaWeb限流QPS简易框架

 

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

 

JavaWeb限流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)