<Executor name="tomcatThreadPool" namePrefix="tomcatThreadPool-" maxThreads="1000" maxIdleTime="300000" minSpareThreads="200"/>name:共享线程池的名字。这是Connector为了共享线程池要引用的名字,该名字必须唯一。默认值:None;
# 堆代码 duidaima.com <Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" minProcessors="5" maxProcessors="75" acceptCount="1000"/>executor:表示使用该参数值对应的线程池;
acceptCount:指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理。
/** * 自定义注解 限流 */ @Target({ElementType.PARAMETER, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ServiceLimit { String description() default ""; }自定义切面
/** * 堆代码 duidaima.com * 限流 AOP */ @Component @Scope @Aspect public class LimitAspect { //每秒只发出100个令牌,此处是单进程服务的限流,内部采用令牌捅算法实现 private static RateLimiter rateLimiter = RateLimiter.create(100.0); //Service层切点 限流 @Pointcut("@annotation(com.itstyle.seckill.common.aop.ServiceLimit)") public void ServiceAspect() { } @Around("ServiceAspect()") public Object around(ProceedingJoinPoint joinPoint) { Boolean flag = rateLimiter.tryAcquire(); Object obj = null; try { if(flag){ obj = joinPoint.proceed(); } } catch (Throwable e) { e.printStackTrace(); } return obj; } }业务实现:
@Override @ServiceLimit @Transactional public Result startSeckil(long seckillId, long userId) { //省略部分业务代码,详见秒杀源码 }
#统一在http域中进行配置 #限制请求 limit_req_zone $binary_remote_addr $uri zone=api_read:20m rate=50r/s; #按ip配置一个连接 zone limit_conn_zone $binary_remote_addr zone=perip_conn:10m; #按server配置一个连接 zone limit_conn_zone $server_name zone=perserver_conn:100m; server { listen 80; server_name seckill.52itstyle.com; index index.jsp; location / { #请求限流排队通过 burst默认是0 limit_req zone=api_read burst=5; #连接数限制,每个IP并发请求为2 limit_conn perip_conn 2; #服务所限制的连接数(即限制了该server并发连接数量) limit_conn perserver_conn 1000; #连接限速 limit_rate 100k; proxy_pass http://seckill; } } upstream seckill { fair; server 172.16.1.120:8080 weight=1 max_fails=2 fail_timeout=30s; server 172.16.1.130:8080 weight=1 max_fails=2 fail_timeout=30s; }配置说明
imit_conn_zone是针对每个IP定义一个存储session状态的容器。这个示例中定义了一个100m的容器,按照32bytes/session,可以处理3200000个session。
limit_rate 300k;对每个连接限速300k. 注意,这里是对连接限速,而不是对IP限速。如果一个IP允许两个并发连接,那么这个IP就是限速limit_rate×2。
burst=5;这相当于桶的大小,如果某个请求超过了系统处理速度,会被放入桶中,等待被处理。如果桶满了,那么抱歉,请求直接返回503,客户端得到一个服务器忙的响应。如果系统处理请求的速度比较慢,桶里的请求也不能一直待在里面,如果超过一定时间,也是会被直接退回,返回服务器忙的响应。
背影有没有很熟悉,对这就是那个直呼理解万岁老罗,2015年老罗在锤子科技T2发布会上将门票收入捐赠给了 OpenResty,也相信老罗是个有情怀的胖子。这里我们使用 OpenResty 开源的限流方案,测试案例使用OpenResty1.13.6.1最新版本,自带lua-resty-limit-traffic模块以及案例 ,实现起来更为方便。
# 安装 yum -y install httpd-tools # 查看ab版本 ab -v # 查看帮助 ab --help 测试命令: ab -n 1000 -c 100 http://127.0.0.1/测试结果:
Server Software: openresty/1.13.6.1 #服务器软件 Server Hostname: 127.0.0.1 #IP Server Port: 80 #请求端口号 Document Path: / #文件路径 Document Length: 12 bytes #页面字节数 Concurrency Level: 100 #请求的并发数 Time taken for tests: 4.999 seconds #总访问时间 Complete requests: 1000 #总请求树 Failed requests: 0 #请求失败数量 Write errors: 0 Total transferred: 140000 bytes #请求总数据大小 HTML transferred: 12000 bytes #html页面实际总字节数 Requests per second: 200.06 [#/sec] (mean) #每秒多少请求,这个是非常重要的参数数值,服务器的吞吐量 Time per request: 499.857 [ms] (mean) #用户平均请求等待时间 Time per request: 4.999 [ms] (mean, across all concurrent requests) # 服务器平均处理时间,也就是服务器吞吐量的倒数 Transfer rate: 27.35 [Kbytes/sec] received #每秒获取的数据长度 Connection Times (ms) min mean[+/-sd] median max Connect: 0 0 0.8 0 4 Processing: 5 474 89.1 500 501 Waiting: 2 474 89.2 500 501 Total: 9 475 88.4 500 501 Percentage of the requests served within a certain time (ms) 50% 500 66% 500 75% 500 80% 500 90% 501 95% 501 98% 501 99% 501 100% 501 (longest request)