springmvc 异步支持

a455295165 2015-12-21 02:59:17
加精
今天测试了下springMVC 的异步支持,按理说在高并发的情况下springMVC 的异步方法比一般的方法性能高很多才对,然后 我用apache bench做了下压力测试,我竟然发现使用了异步比不适用异步的效率 还低。
以下是我的代码,望大家帮我解答下。
在controller中写了两个业务逻辑一样的方法(一个异步,一个同步)如下:

@RequestMapping(value = "/presuretest", method = RequestMethod.GET)
@ResponseBody
public JSONObject presureTest() throws Exception {
User user = new User();
user.setEmail("XXXX@XXX.com");
return userService.getUser(user);//the getUser method now is just Thread.sleep(500);
}

@RequestMapping(value = "/asyncpresuretest", method = RequestMethod.GET)
@ResponseBody
public Callable<JSONObject> asyncpresureTest() throws Exception {
return new Callable<JSONObject>() {

@Override
public JSONObject call() throws Exception {
User user = new User();
user.setEmail("xxxx@xxxxx.com");
return userService.getUser(user);//The same as presureTest() method;
}

};
}


其中getUser 什么都没做,除了 Thread.sleep(500);
然后 以下是我压力测试的结果:

./ab -c 600 -n 600 http://52.193.80.222/presuretest

Concurrency Level: 600
Time taken for tests: 2.227 seconds
Complete requests: 600
Failed requests: 0
Write errors: 0
Total transferred: 112200 bytes
HTML transferred: 0 bytes
Requests per second: 269.44 [#/sec] (mean)
Time per request: 2226.826 [ms] (mean)
Time per request: 3.711 [ms] (mean, across all concurrent requests)
Transfer rate: 49.20 [Kbytes/sec] received


./ab -c 600 -n 600 http://52.193.80.222/asyncpresuretest

Concurrency Level: 600
Time taken for tests: 3.445 seconds
Complete requests: 600
Failed requests: 0
Write errors: 0
Total transferred: 112200 bytes
HTML transferred: 0 bytes
Requests per second: 174.15 [#/sec] (mean)
Time per request: 3445.252 [ms] (mean)
Time per request: 5.742 [ms] (mean, across all concurrent requests)
Transfer rate: 31.80 [Kbytes/sec] received


./ab -c 700 -n 700 http://52.193.80.222/asyncpresuretest

Concurrency Level: 700
Time taken for tests: 2.682 seconds
Complete requests: 700
Failed requests: 0
Write errors: 0
Total transferred: 130900 bytes
HTML transferred: 0 bytes
Requests per second: 261.04 [#/sec] (mean)
Time per request: 2681.588 [ms] (mean)
Time per request: 3.831 [ms] (mean, across all concurrent requests)
Transfer rate: 47.67 [Kbytes/sec] received


./ab -c 700 -n 700 http://52.193.80.222/presuretest

Concurrency Level: 700
Time taken for tests: 2.325 seconds
Complete requests: 700
Failed requests: 0
Write errors: 0
Total transferred: 130900 bytes
HTML transferred: 0 bytes
Requests per second: 301.09 [#/sec] (mean)
Time per request: 2324.909 [ms] (mean)
Time per request: 3.321 [ms] (mean, across all concurrent requests)
Transfer rate: 54.98 [Kbytes/sec] received

./ab -c 900 -n 900 http://52.193.80.222/presuretest

Concurrency Level: 900
Time taken for tests: 3.761 seconds
Complete requests: 900
Failed requests: 94
(Connect: 0, Receive: 47, Length: 0, Exceptions: 47)
Write errors: 0
Total transferred: 159511 bytes
HTML transferred: 0 bytes
Requests per second: 239.31 [#/sec] (mean)
Time per request: 3760.847 [ms] (mean)
Time per request: 4.179 [ms] (mean, across all concurrent requests)
Transfer rate: 41.42 [Kbytes/sec] received

./ab -c 900 -n 900 http://52.193.80.222/asyncpresuretest

Concurrency Level: 900
Time taken for tests: 3.769 seconds
Complete requests: 900
Failed requests: 164
(Connect: 0, Receive: 82, Length: 0, Exceptions: 82)
Write errors: 0
HTML transferred: 0 bytes
Requests per second: 238.80 [#/sec] (mean)
Time per request: 3768.787 [ms] (mean)
Time per request: 4.188 [ms] (mean, across all concurrent requests)
Transfer rate: 39.64 [Kbytes/sec] received


我发现 使用异步的方法的效率并不比一般的高,很多时候反而还低了。
这个是什么原因呢?还是我代码本身有问题?
...全文
8760 28 打赏 收藏 转发到动态 举报
写回复
用AI写文章
28 条回复
切换为时间正序
请发表友善的回复…
发表回复
ITjavaman 2019-05-28
  • 打赏
  • 举报
回复
我觉得楼主在问题的概念上存在一个误区, 这个异步的效率并不是直接体现在你上面测试的结果,以你的代码为例 同步方式: 客户端request请求serlvet容器,servlet处理完使用response返回信息到客户端,整个过程没有释放请求容器的连接 异步: 客户端request请求serlvet容器,这个时候启动一个线程(A)去处理serlevt,启动完线程就把容器的连接释放了,等到线程(A)处理完相关业务员操作后,把返回信息写入response返回到客户端 servlet的线程池里的线程数量(容器连接)是有限的,记得默认是200,当你用同步的方式去调用而且调用的该方法执行时间很长的话,那么这些线程很快就被占满,占满后新的请求就进不来了 异步的形式在你执行耗时的操作之前就把连接释放了,使得容器相对于同步方式来说可以接收更多的请求(我觉得所谓的效率应该是体现在这里) 所以你用上面的压测数据来比较,我觉得不是一码事 水平有限,欢迎大佬痛戳
l594771604 2019-05-27
  • 打赏
  • 举报
回复
引用 29 楼 水边2 的回复:
谁说异步一定会提升效率?你真正理解异步的目的吗?

举个医院拿药的例子,
同步就是 a去窗口拿药,然后堵在窗口,拿到药后结束,然后b上去拿药。
异步就是 a和b各拿一个号,等窗口叫号。

如果窗口只有1个护士,同步和异步效率几乎没区别,异步还可能因为有多个号导致护士错乱,导致效率更低。
如果窗口有2个护士,异步的效率才会提升,但是提升提窗口的效率,a和b的实际拿药时间没变,异步只是减少了b的排队时间。

回到程序,异步增加了上下文切换的损耗,
如果代码都是属于纯cpu运算,不存在IO等待,明显同步效率高,异步的效率更低下。
同样的,如果有IO等待,异步才有意义,能增加服务器的吞吐量,但是对于每个客户端而言,异步本来只要1秒,增加上下文切换后反而变成了1.1秒了。


如果IO比较多的话,理论上异步的吞吐量应该更高的,使用了SpringMVC异步之后,发现系统吞吐量还不如同步了,不知道是不是的哪里出了问题,请问您对SpringMVC的异步处理了解吗?
游北亮 2019-05-24
  • 打赏
  • 举报
回复
谁说异步一定会提升效率?你真正理解异步的目的吗? 举个医院拿药的例子, 同步就是 a去窗口拿药,然后堵在窗口,拿到药后结束,然后b上去拿药。 异步就是 a和b各拿一个号,等窗口叫号。 如果窗口只有1个护士,同步和异步效率几乎没区别,异步还可能因为有多个号导致护士错乱,导致效率更低。 如果窗口有2个护士,异步的效率才会提升,但是提升提窗口的效率,a和b的实际拿药时间没变,异步只是减少了b的排队时间。 回到程序,异步增加了上下文切换的损耗, 如果代码都是属于纯cpu运算,不存在IO等待,明显同步效率高,异步的效率更低下。 同样的,如果有IO等待,异步才有意义,能增加服务器的吞吐量,但是对于每个客户端而言,异步本来只要1秒,增加上下文切换后反而变成了1.1秒了。
l594771604 2019-05-24
  • 打赏
  • 举报
回复
你好,这个问题最后有结论了吗,我们也遇到类似的问题
小流氓dy 2018-11-16
  • 打赏
  • 举报
回复
你没明白异步是用来处理什么的!!
积木 2017-04-23
  • 打赏
  • 举报
回复
异步其实效率是会更差的,但是带来的好处是容量的提升,异步从来不是提高效率的,它提高的是容量。。 你这个认识本身就有问题
ytyt-111 2016-12-19
  • 打赏
  • 举报
回复
楼主问题解决了吗? 是什么原因呢?
ytyt-111 2016-12-19
  • 打赏
  • 举报
回复
引用 7 楼 sinat_27650399 的回复:
[quote=引用 5 楼 a455295165 的回复:] [quote=引用 2 楼 sinat_27650399 的回复:] 你容器用的什么? 容器是同步还是异步?如果容器的模式是同步的,你Controller异步有卵用 另外,为什么异步性能就一定比同步的性能好?该阻塞的还是要阻塞,响应慢的地方依然响应慢,与异步和同步无关。。。
再高并发的情况下,如果是同步方式。servlet容器 线程池的线程不是很快就耗尽吗, 如果是异步,线程池里的线程接收请求后会开开其他的线程处理,它本身不是就可以释放处理其他请求了吗?[/quote] 服务的线程资源分为:容器IO线程P1 -》容器请求处理线程池P2 -》业务回调线程池P3 前面P2放过去1000个请求,请求全部都阻塞在P3,响应依旧很慢,这时候看着好像Servlet线程池P2很闲的样子,但是其实你的应用已经满负荷跑,累的要死,P2里面的闲的要死几百个线程围观P3里面的线程自嗨 关键是你SpringMVC里面配置的线程池多大?容器是否支持Servlet3的异步机制? 异步提高性能的前提是请求的每个环节都能做到异步化,你这样sleep自然不行 为什么你的测试数据异步比同步差? 我想你SpringMVC的线程池P3肯定是用的默认配置,线程数少的可怜 同步的调用因为使用的是容器自己的处理线程池P2,默认最大200个线程(不大记得,应该是200) 在你这种业务阻塞的情况下,P3的线程池肯定跑不过200个线程的线程池啊[/quote] 你所说的业务回调线程池是什么东西?一个request请求到tomcat,web服务器或者说servlet容器会开一个线程来处理这个请求,现在是异步模式就是将这个线程业务处理那块拿出来,单独在开一个线程运行业务逻辑这块,原来servlet容器开的线程就释放了。然后处理结果会交给一个回掉线程(这个回调线程本质上就是servlet容器线程池里面的一个线程)。这个业务回调线程池是什么?在哪里设置大小?这不应该是在程序里面自己new的thread?
0307wgj 2016-07-22
  • 打赏
  • 举报
回复
回到了当初大学的感觉。。。
z154651391 2016-07-01
  • 打赏
  • 举报
回复
先看看大神怎么解决这个问题
h2plus0 2016-07-01
  • 打赏
  • 举报
回复
貌似异步的方法需要用 @Async 注释? https://spring.io/guides/gs/async-method/
宋玮-深圳 2016-01-12
  • 打赏
  • 举报
回复
1.首先你要启用了servlet3, http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-ann-async 2.异步不等于一定高效, 解决的是阻塞、竞争问题。 如果把web线程限制在20, 600并发过来, 同步的需要处理30个时常;而异步的只要后端返回速度够快,理论上是可以1-2周期返回的。
jianguole 2016-01-04
  • 打赏
  • 举报
回复
Servlet 3.0 之前,一个普通 Servlet 的主要工作流程大致如下:首先,Servlet 接收到请求之后,可能需要对请求携带的数据进行一些预处理;接着,调用业务接口的某些方法,以完成业务处理;最后,根据处理的结果提交响应,Servlet 线程结束。其中第二步的业务处理通常是最耗时的,这主要体现在数据库操作,以及其它的跨网络调用等,在此过程中,Servlet 线程一直处于阻塞状态,直到业务方法执行完毕。在处理业务的过程中,Servlet 资源一直被占用而得不到释放,对于并发较大的应用,这有可能造成性能的瓶颈。对此,在以前通常是采用私有解决方案来提前结束 Servlet 线程,并及时释放资源。 Servlet 3.0 针对这个问题做了开创性的工作,现在通过使用 Servlet 3.0 的异步处理支持,之前的 Servlet 处理流程可以调整为如下的过程:首先,Servlet 接收到请求之后,可能首先需要对请求携带的数据进行一些预处理;接着,Servlet 线程将请求转交给一个异步线程来执行业务处理,线程本身返回至容器,此时 Servlet 还没有生成响应数据,异步线程处理完业务以后,可以直接生成响应数据(异步线程拥有 ServletRequest 和 ServletResponse 对象的引用),或者将请求继续转发给其它 Servlet。如此一来, Servlet 线程不再是一直处于阻塞状态以等待业务逻辑的处理,而是启动异步线程之后可以立即返回。 从中可以看出同步和异步和效率没有必然关系。
神月歆晟 2015-12-31
  • 打赏
  • 举报
回复
比较高深啊是
Java_er 2015-12-29
  • 打赏
  • 举报
回复
表示 不明觉厉额。 话说 压力测试 是咋测试的啊?
_南天北落 2015-12-24
  • 打赏
  • 举报
回复
引用 7 楼 sinat_27650399 的回复:
[quote=引用 5 楼 a455295165 的回复:] [quote=引用 2 楼 sinat_27650399 的回复:] 你容器用的什么? 容器是同步还是异步?如果容器的模式是同步的,你Controller异步有卵用 另外,为什么异步性能就一定比同步的性能好?该阻塞的还是要阻塞,响应慢的地方依然响应慢,与异步和同步无关。。。
再高并发的情况下,如果是同步方式。servlet容器 线程池的线程不是很快就耗尽吗, 如果是异步,线程池里的线程接收请求后会开开其他的线程处理,它本身不是就可以释放处理其他请求了吗?[/quote] 服务的线程资源分为:容器IO线程P1 -》容器请求处理线程池P2 -》业务回调线程池P3 前面P2放过去1000个请求,请求全部都阻塞在P3,响应依旧很慢,这时候看着好像Servlet线程池P2很闲的样子,但是其实你的应用已经满负荷跑,累的要死,P2里面的闲的要死几百个线程围观P3里面的线程自嗨 关键是你SpringMVC里面配置的线程池多大?容器是否支持Servlet3的异步机制? 异步提高性能的前提是请求的每个环节都能做到异步化,你这样sleep自然不行 为什么你的测试数据异步比同步差? 我想你SpringMVC的线程池P3肯定是用的默认配置,线程数少的可怜 同步的调用因为使用的是容器自己的处理线程池P2,默认最大200个线程(不大记得,应该是200) 在你这种业务阻塞的情况下,P3的线程池肯定跑不过200个线程的线程池啊[/quote] 有道理,你改下配置试试。楼主解决了请@ 我一下。我mark一下。
a455295165 2015-12-22
  • 打赏
  • 举报
回复
引用 7 楼 sinat_27650399 的回复:
[quote=引用 5 楼 a455295165 的回复:] [quote=引用 2 楼 sinat_27650399 的回复:] 你容器用的什么? 容器是同步还是异步?如果容器的模式是同步的,你Controller异步有卵用 另外,为什么异步性能就一定比同步的性能好?该阻塞的还是要阻塞,响应慢的地方依然响应慢,与异步和同步无关。。。
再高并发的情况下,如果是同步方式。servlet容器 线程池的线程不是很快就耗尽吗, 如果是异步,线程池里的线程接收请求后会开开其他的线程处理,它本身不是就可以释放处理其他请求了吗?[/quote] 服务的线程资源分为:容器IO线程P1 -》容器请求处理线程池P2 -》业务回调线程池P3 前面P2放过去1000个请求,请求全部都阻塞在P3,响应依旧很慢,这时候看着好像Servlet线程池P2很闲的样子,但是其实你的应用已经满负荷跑,累的要死,P2里面的闲的要死几百个线程围观P3里面的线程自嗨 关键是你SpringMVC里面配置的线程池多大?容器是否支持Servlet3的异步机制? 异步提高性能的前提是请求的每个环节都能做到异步化,你这样sleep自然不行 为什么你的测试数据异步比同步差? 我想你SpringMVC的线程池P3肯定是用的默认配置,线程数少的可怜 同步的调用因为使用的是容器自己的处理线程池P2,默认最大200个线程(不大记得,应该是200) 在你这种业务阻塞的情况下,P3的线程池肯定跑不过200个线程的线程池啊[/quote] 有道理,确实是用的默认的,容器是支持servlet3的异步机制的,所以说我现在去试下把这个P3的配置调高?
  • 打赏
  • 举报
回复
引用 5 楼 a455295165 的回复:
[quote=引用 2 楼 sinat_27650399 的回复:] 你容器用的什么? 容器是同步还是异步?如果容器的模式是同步的,你Controller异步有卵用 另外,为什么异步性能就一定比同步的性能好?该阻塞的还是要阻塞,响应慢的地方依然响应慢,与异步和同步无关。。。
再高并发的情况下,如果是同步方式。servlet容器 线程池的线程不是很快就耗尽吗, 如果是异步,线程池里的线程接收请求后会开开其他的线程处理,它本身不是就可以释放处理其他请求了吗?[/quote] 服务的线程资源分为:容器IO线程P1 -》容器请求处理线程池P2 -》业务回调线程池P3 前面P2放过去1000个请求,请求全部都阻塞在P3,响应依旧很慢,这时候看着好像Servlet线程池P2很闲的样子,但是其实你的应用已经满负荷跑,累的要死,P2里面的闲的要死几百个线程围观P3里面的线程自嗨 关键是你SpringMVC里面配置的线程池多大?容器是否支持Servlet3的异步机制? 异步提高性能的前提是请求的每个环节都能做到异步化,你这样sleep自然不行 为什么你的测试数据异步比同步差? 我想你SpringMVC的线程池P3肯定是用的默认配置,线程数少的可怜 同步的调用因为使用的是容器自己的处理线程池P2,默认最大200个线程(不大记得,应该是200) 在你这种业务阻塞的情况下,P3的线程池肯定跑不过200个线程的线程池啊
a455295165 2015-12-22
  • 打赏
  • 举报
回复
引用 3 楼 dracularking 的回复:
试试把sleep时间调长点呢
试过,还是一样的结果。。。
a455295165 2015-12-22
  • 打赏
  • 举报
回复
引用 2 楼 sinat_27650399 的回复:
你容器用的什么? 容器是同步还是异步?如果容器的模式是同步的,你Controller异步有卵用 另外,为什么异步性能就一定比同步的性能好?该阻塞的还是要阻塞,响应慢的地方依然响应慢,与异步和同步无关。。。
再高并发的情况下,如果是同步方式。servlet容器 线程池的线程不是很快就耗尽吗, 如果是异步,线程池里的线程接收请求后会开开其他的线程处理,它本身不是就可以释放处理其他请求了吗?
加载更多回复(8)

67,515

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧