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简易框架的更多相关文章
- Spring Cloud Alibaba | Sentinel: 服务限流高级篇
目录 Spring Cloud Alibaba | Sentinel: 服务限流高级篇 1. 熔断降级 1.1 降级策略 2. 热点参数限流 2.1 项目依赖 2.2 热点参数规则 3. 系统自适应限 ...
- 流量治理神器-Sentinel的限流模式,选单机还是集群?
大家好,架构摆渡人.这是我的第5篇原创文章,还请多多支持. 上篇文章给大家推荐了一些限流的框架,如果说硬要我推荐一款,我会推荐Sentinel,Sentinel的限流模式分为两种,分别是单机模式和集群 ...
- spring cloud gateway 之限流篇
转载请标明出处: https://www.fangzhipeng.com 本文出自方志朋的博客 在高并发的系统中,往往需要在系统中做限流,一方面是为了防止大量的请求使服务器过载,导致服务不可用,另一方 ...
- SpringCloudGateWay之限流
一.引言在高并发系统中,经常需要限制系统中的电流化妆.一方面是防止大量的请求使服务器过载,导致服务不可用,另一方面是防止网络攻击.常用的限流方法,如hystrix.应用线程池隔离.超过线程池的负载和g ...
- 简易RPC框架-客户端限流配置
*:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...
- WebApiThrottle限流框架使用手册
阅读目录: 介绍 基于IP全局限流 基于IP的端点限流 基于IP和客户端key的端点限流 IP和客户端key的白名单 IP和客户端key自定义限制频率 端点自定义限制频率 关于被拒请求的计数器 在we ...
- 【Dnc.Api.Throttle】适用于.Net Core WebApi接口限流框架
Dnc.Api.Throttle 适用于Dot Net Core的WebApi接口限流框架 使用Dnc.Api.Throttle可以使您轻松实现WebApi接口的限流管理.Dnc.Api.Thr ...
- webapi限流框架WebApiThrottle
为了防止网站意外暴增的流量比如活动.秒杀.攻击等,导致整个系统瘫痪,在前后端接口服务处进行流量限制是非常有必要的.本篇主要介绍下Net限流框架WebApiThrottle的使用. WebApiThro ...
- 限流10万QPS、跨域、过滤器、令牌桶算法-网关Gateway内容都在这儿
一.微服务网关Spring Cloud Gateway 1.1 导引 文中内容包含:微服务网关限流10万QPS.跨域.过滤器.令牌桶算法. 在构建微服务系统中,必不可少的技术就是网关了,从早期的Zuu ...
随机推荐
- struts2的工作机制
struts2的工作机制 原文:http://eoasis.iteye.com/blog/642586 概述 本章讲述Struts2的工作原理. 读者如果曾经学习过Struts1.x或者有过Strut ...
- 配置Tomcat中的Context元素中的中文问题
发布一个名叫helloapp的web应用,helloapp位于D:\我\helloapp.发布的方式是通过配置<CATALINA_HOME>/conf/Catalina/localhost ...
- [置顶] highcharts封装使用总结
Highcharts 是一个用纯JavaScript编写的一个图表库, 能够很简单便捷的在web网站或是web应用程序添加有交互性的图表,并且免费提供给个人学习.个人网站和非商业用途使用.目前High ...
- 使用Promise规定来处理ajax请求的结果
ajax()返回结果是成功的,调用done()中的回调函数: 失败则调用fail()中的回调函数; always()的回调函数不管成功是否都会调用: 可以是使用then()函数代替done()和fai ...
- js经典代码技巧学习之一:使用三元运算符处理javascript兼容
window.Event = { add: function() { //使用条件表达式检测标准方法是否存在 return document.addEventListener ? function(a ...
- [原]C++关于运算符重载的程序报错error…
错误信息如下: 1>t2.obj : error LNK2019: 无法解析的外部符号 "public: __thiscall Date::Date(void)" (??0D ...
- [转]MySQL 5.6 全局事务 ID(GTID)实现原理(二)
原文连接:http://qing.blog.sina.com.cn/1757661907/68c3cad333002qsk.html 原文作者:淘长源 转载注明以上信息 前文 MySQL 5.6 全局 ...
- JS笔试题
JS 引用相关题目 以下代码输出什么? 为什么? var a = {n:1}; var b = a; a = {n:2}; a.x = a ; console.log(a.x); console.lo ...
- jdbc 通过rs.getString()获取数据库中的时间字段问题
例如在mysql中的一张表中存在一个字段opr_time为datetime类型, 在JDBC 中通过rs.getString("opr_time");来获取使会在日期后面添加&qu ...
- mybatis第一个入门demo
学习框架技术,一般先写个demo,先知道是什么,然后在知道为什么,这也是进步的一种. 源码链接:http://pan.baidu.com/s/1eQJ2wLG