web系统流量控制 一个新系统上线之前都要做性能测试(并发数、QPS、TPS、页面响应时间等),该措施一个有效前提是我们知道系统的预估承载量,
比如我们知道网站的日访问PV,访问的时间段等,有了这些数据并根据下面的公式,就不难做性能测试了。
日PV和TPS之间如何对应?公式就是80%的日PV,发生在T小时内。则公式为:
TPS = 日PV * 80% / 24 * 60 * 60 * (T/24)
定义 R = 1万 * 80% / 24 * 60 * 60 * (T/24) = 10000 * 24 * 0.8 / 24 * 3600 * T = 2.2222/T
TPS = 日PV(万) * R 这里的TPS就是平均的TPS。
但是也存在另外一种情况,比如一个网站要搞一个周年庆大型促销活动,由于第一次搞这样的活动,在数据方面并没有多少经验,只能凭经验粗略预估访问量。此时我们保证系统在满足预估访问量同时,还要重点考虑一些突发情况,比如那天pv量真的超过预值怎么办?如果系统设计不当,就会导致大量的请求阻塞,响应超时,后果相当严重。此时一个行之有效的方法是限流,也称之为流量控制。
今天介绍一种简单的流量控制方法,借助于servlet容器机制,对所有的请求进行拦截,并通过缓存计算每秒的访问数,如果超过了阀值,直接返回错误页面。好处是:配置简单,通过代码来实现 ;缺点:超过阀值的请求直接丢弃,不做处理。
1.在web.xml文件中配置一个Filter过滤器
- <filter>
- <filter-name>name</filter-name>
- <filter-class>类名</filter-class>
- <init-param>
- <param-name>name</param-name>
- <param-value>value</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>name</filter-name>
- <url-pattern>/order/*</url-pattern>
- </filter-mapping>
<filter> <filter-name>name</filter-name> <filter-class>类名</filter-class> <init-param> <param-name>name</param-name> <param-value>value</param-value> </init-param> </filter> <filter-mapping> <filter-name>name</filter-name> <url-pattern>/order/*</url-pattern> </filter-mapping>
2.定义一个类实现Filer接口
将<init-param>标签里面用于初始化的属性读出来。
- public void init(FilterConfig arg0) throws ServletException {
- //预设每秒系统处理请求数的最大值
- String max= arg0.getInitParameter(“maxRequest”);
- if (sd != null) {
- max= max;
- }
- }
public void init(FilterConfig arg0) throws ServletException { //预设每秒系统处理请求数的最大值 String max= arg0.getInitParameter("maxRequest"); if (sd != null) { max= max; } }
核心拦截业务
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
- ServletException {
- //统一资源标识符,不含有域名
- String uri = ((HttpServletRequest) request).getRequestURI();
- if (enabled && isUriNeedFiltered(uri)) {
- if (controller.isAllowed()) {
- chain.doFilter(request, response);
- } else {
- request.getRequestDispatcher(“错误页面”).forward(request, response);
- }
- } else {
- chain.doFilter(request, response);
- }
- }
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //统一资源标识符,不含有域名 String uri = ((HttpServletRequest) request).getRequestURI(); if (enabled && isUriNeedFiltered(uri)) { if (controller.isAllowed()) { chain.doFilter(request, response); } else { request.getRequestDispatcher(“错误页面”).forward(request, response); } } else { chain.doFilter(request, response); } }
缓存的key值(以秒做为key值)
- public String getKey() {
- return new SimpleDateFormat(“yyyyMMddHHmmss”).format(new Date());
- }
public String getKey() { return new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); }