一次webflux与webmvc性能测试实践

最近Josh Long等Spring社区的大师来中国进行交流与宣传,并现场建立了一个spring-webflux的服务demo,首先从start.spring.io上构建一个基于spring boot、reactive、mongo的reservation微服务,然后基于微服务构建routing支持,引入Spring Cloud Gateway,Spring Hystrix,Spring Security,Flow Control,Client检测,Rsocket等机制。整体Demo演示下来,让与会的开发者充分了解Spring Framework的新功能与机制。
webflux是基于netty server,其实很早以前我就有一个疑惑,既然tomcat是阻塞式服务器,而netty是一个优秀的nio通信框架,为什么没有一个基于netty的server呢,性能会不会优秀特别多呢。后来研究spring boot源码的时候,发现它内置了4个server,分别是jetty、netty、tomcat和undertow,路径位于org.springframework.boot.web.embedded包下。因此其实netty server已经有了,只是我之前并不知道罢了,既然有了netty和tomcat,很自然的我会希望对他们进行一次benchmark测试下是否存在性能差异。
我先搜了下看有没有前人的测试结果,国内还是有的,一篇叫Spring WebFlux性能测试——响应式Spring的道法术器的博客已经写了一篇比较系统的关于webflux与webmvc的性能测试总结。

image

这是他的测试结果,说实话,看到这个结果我还是挺震撼的,异步事件模型的网络性能优势竟然如此巨大,那看来在对高并发有需求的场景下我们应该选用webflux和netty server进行编程了。
于是我激动的开启了自己的benchmark之旅,不过却并没能如同这位博主一样比较顺利。

Apache ab.exe测试

我没有用过gatling,因此我首先还是用最简单的工具apache.exe进行测试
首先是对web-mvc的测试,测试一个 /hello的接口

   @GetMapping("/hello")
   public String getEcho() throws InterruptedException {
        Thread.sleep (100);
        return "ok";
   }

测试命令: ab -n 20000 -c 5000 http://localhost:8082/hello
测试结果:

ab_20000n_5000c.png

可以看到95%的响应在3s内完成,说明在达到spring boot默认线程数上限后,剩余的请求就会开始排队了,spring boot默认线程数是200,可以通过server.tomcat.max-threads属性进行修改,这里我改成了400,在测试过程中我用jconsole进行观测,发现idea的线程数峰值达到了425,和预想的情况相符。
下面是对webflux进行测试
webflux接口代码:

    @GetMapping("/hello")
    public Mono<String> hello() {
        return Mono.just ("hello").delayElement (Duration.ofMillis (100));
    }

测试结果如下:


ab_webflux_20000n_5000c.png

我很惊讶,因为和预期的效果差距很远,可以看到吞吐量和95% 请求响应时间上限仅仅比 webmvc的版本优秀一点点(1606->1548,2944->3050)。按照之前博主的结果,95%结果应该在110ms以内,我又调整了参数,分别对5000并发-20000并发进行了测试,结果webflux在一些并发数情况下,性能要比webmvc还差。于是我猜想是不是我的测试工具有问题,毕竟ab.exe测试的结论过于简单。于是我开始使用jmeter

Jmeter测试

我用jmeter对webflux进行了测试,设置如下


jmeter_setting.png

其中并发数5000,在2s内到达5000,每个并发请求15次,结果大吃一惊,webflux不但吞吐量随着并发的增加而不断下降,在后期并发打满的情况下,httpresponse还出现了error。


jmeter_5000_15.png

95%响应时间为3438ms,也不如人意。
然后我对webmvc进行了测试

结果如下
webmvc_jmeter.png

依然有许多error,95%响应时间也是3930ms,并不令人满意。
后面我又增加了从3000-20000的并发数测试,结果都不令人满意,频繁出现error,而且响应时间也不理想。
到这里为止,我开始有点怀疑博主的测试结果了,不过毕竟我们用的测试工具不同,前面文章的博主用的gatling,而我是jmeter,于是我开始了我第三轮测试。

gatling

我借用了博主的测试脚本,地址是https://github.com/get-set/get-reactive/tree/master/gatling。 然后下载了gatling、scala、sbt环境。不过运行的时候始终报错,我研究了下gatling的官方demo,我猜测可能是gatling新版本的api产生了变化,博主用的 over 在新版本里面已经换成了 during。
修改了代码后,脚本可以正常运行,因为加入了1s的每个并发每次的请求间隔,所以我感觉这个更符合真实的并发场景,因此对它的结果更加产生了期待。
然后事实依然是残酷的,gatling的测试结果竟然仅仅比jmeter的要稍好一点,我猜测这个结果还是因为在请求间加入了时延导致的。我不断修改参数,对3000-10000的并发的两种server分别测试了20多次,依然没有得到一个理想的结果,下面贴一个不是很好的结果做个示例。

gatling.png

可以看到高并发下,95%请求已经达到了可怕的20s左右,并且有大量的error response。

不过中间有一次测试结果,我使用gatling测试5000并发,结果是95%结果为104ms,我非常惊讶,感觉又有了希望。不过再也没有重现过,后来我检查了下代码,我将请求repeat次数改小了,而during依然是30s,因此我猜测可能是因为实际运行过程中,线程并没有完全打满5000导致的。

测试环境的问题?

我后面回过头去看前面博主的博客,发现评论区很多小伙伴出现了和我一样的问题,就是jmerer测试webflux和webmvc的性能差距并不太大,博主也进行了一些解答,其中提到了操作系统,而我测试确实用的是windows系统,而我们知道windows的nio采用的是IOCP而linux采用的是epoll,会不会是这个区别导致的呢?
于是我将程序部署到linux系统上,一开始我选择的是我的阿里云,后来做benchmark结果简直不忍直视,果然在高并发情况下,网络情况也是会影响结果的。我只好用本机的虚拟机进行测试,结果一波十几折,首先是因为虚拟机好久没用了,网络都忘了配置了,结果虚拟机和主机之间都无法通信,主机可以ping通虚拟机,反向则不行。捣鼓了半天后终于ok了,我开始测试,一开始测试3000并发,结果狂报错,io.netty.channel.unix.Errors$NativeIoException: accept(..) failed: Too many open files。一看是fd打开太多,我输入ulimit -n,果然虚拟机配置的默认上限只有1024, vi /etc/security/limits.conf,修改连接数为65535并重启,ulimt -n 确认连接数后测试没有继续报错。but but but no use啊...
测试结果依然没有好转:


virtual_jmeter.png

测试的参数是5000并发,during是3s,每个并发重复10次。
可以看到无论是吞吐量还是95%响应时间,都terrible。看来webflux还有很多我需要深究的地方,要搞清楚他异步高性能的配置还需要下更大的功夫。

总结&TODO

经过前面的测试,可以知道在我当前的环境下,webflux并不是解决高性能高并发场景的银弹。
但是既然前面的博主有这样的测试结论,我相信他的数据结果也不是凭空来的,那么这接下来就是研究我们之间的环境究竟还有哪些差异。我可以想见的有:

  1. spring boot版本
  2. jdk版本
  3. 我是测试机与server都在同一台机器,测试中也发现CPU完全被打满了,而且测试脚本占用了大量CPU
  4. 操作系统

因此接下来需要在这些方面找找原因。
另外,我理解的webflux,确实非常适合做不间断的响应式数据推送的场景,例如滚动聊天室,百度贴吧最上面的那种聊天,交易信息推送等等。不过这些都是后话,也许以后我会把之前的一些响应式编程的总结记录一下,不过当前还是思考下benchmark的问题吧。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架,建立于...
    Hsinwong阅读 22,358评论 1 92
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,773评论 6 342
  • 这一周我读了81万1千,是因为几本书我不爱看森林报我不喜欢看,全是小故事,没有意思,大故事才有意思呢。这是爸爸给...
    09小溪流家臣阅读 113评论 1 0
  • 时隔一年后的今天,我终于可以坦然地写出这件事情。对于这场劫后余生,我真切的感受是庆幸。 去年的今天,半夜12点,我...
    自律女性vlog阅读 446评论 9 7