以工作日计算功能为例对各框架性能进行测试

代码项目地址:WorkDayProject

事起缘由

因为好奇,(其实是因为闲),顺带看了 Benchmark 天梯,于是就写了一些代码来测试一下,以工作的项目中最简单的一个工作日计算功能为例实践了一些框架。

先解释一下什么是工作日?在这里的工作日不是指一般职员周一-周五上班的工作日,而是指证券交易所的交易日。以中国股市收盘时间15:00为界,15:01之前为当前工作日,15:01(含)为下一工作日,周六周日(非工作日)的所属交易工作日为第二周第一个工作日。举个栗子,2019/05/05周日是职工工作日,但它的所属工作日是2019/05/06。

公司线上使用了一套 WCF basicHttpBinding(webservice)和一套 SpringMvc。作者另外实现了 WCF webHttpBinding(webapi)、asp.net core webapi和 SpringBoot WebFlux。作者分别对这5套进行了性能测试。

测试说明

测试接口:获取当前时间的工作日,例:返回字符串2019/10/14

测试工具:wrk、Jmeter(仅web service)

测试环境:

CPU:Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz *4

内存:16GB

网络:10Gbps

虚拟化:KVM

测试结果

框架systemavg cost(ms)QPSreceived(MB/s)
WCF basicHttpBindingwin + .net4.726(估算)3740.682.33
WCF webHttpBinding
win + .net4.7
18.858557.321.43
WCF webHttpBinding + Async
win + .net4.7
7.0514684.702.46
SpringBoot SpringMvcwin + java820.9915880.591.88
SpringBoot SpringMvclinux + java812.7915759.821.86
asp.net core 2.2win8.8021320.753.68
asp.net core 2.2linux6.6218999.793.28
SpringBoot WebFluxlinux + java8 4.3329549.332.51
asp.net core 3.0win4.7026490.963.66
asp.net core 3.0linux4.9521176.392.93
asp.net core 3.0 + http/2 + https
(未清理Header)
linux5.1121770.443.92
asp.net core 3.0 + http/2 + https
(清理了Header)
linux5.1121692.513.00

结论

从数据中可以得到一些性能结论。

  • 1、在同样的 WCF 框架下,从 webservice 迁移到 webapi,最多可以获得近3倍的 QPS 提升,其中这种场景下修改接口为异步可以获得1倍的提升。soap 繁复的序列化还大大增大了报文体积。
  • 2、在同样是webapi的情况下, WCF 和 SpringMvc 的性能相近,但 WCF 的报文体积依旧比 SpringMvc 大。WCF 的响应报文大小为154字节,Http Header 中除 Content-Length外还包含 Content-Type、Date、Server,SpringMvc 少了 Server,大小为124字节。
  • 3、asp.net core 性能优于 WCF,3.0的QPS比WCF高约80%。asp.net core 在 win 上表现比 linux 上好,3.0性能比2.2提升了约20%
  • 4、Spring WebFlux 的性能获得了极大提升,近乎倍杀 SpringMvc,说明了异步式编程的优势。
  • 5、asp.net core 的 QPS 在此场景测试中弱于 Spring WebFlux,但是实际流量却高于 Spring WebFlux,这是因为响应报文体积的问题。asp.net core 响应报文大小为125字节,Http Header中包含 Content-Type、Date、Transfer-Encoding。而 Spring WebFlux 的响应报文体积仅为78字节,Http Header 中仅包含 Content-Length 和 Content-Length。作者在测试时已经优化掉了 asp.net core 自动添加的 Server,从而已经获得15%的提升,其他的 Header 中可以通过添加 Middleware (移除当前 HttpContext 中的所有 Header)去除 Transfer-Encoding,但无法去除 Content-Type 和 Date。
  • 6、虽然表中没给出数据,给 asp.net core 的接口方法上添加异步并不能提升 QPS,而会获得15%的下降。大概是因为 asp.net core 本来的 IO 就已经是异步的了,这还是一个计算密集型程序,再添加异步只能徒增线程,增加线程切换消耗。
  • 7、虽然表中没给出数据,给 SpringBoot 的这2个项目添加 Alibaba SofaBoot 会导致 QPS 下降约25%。
  • 8、这次压测中的平均用时看起来意义不大,不同于那种同步写数据库等待 IO 的那种程序,并不能导出公式 QPS = (1000 * CPU核数)/ 平均用时。
  • 9、虽然表中没给出数据,WCF basicHttpBinding(webservice)这套框架每次请求实际上要走2步,每次都必须“打开通道 Channel”,然后再请求实际接口。其中这次测试中打开通道平均用时约22ms,请求接口仅约4ms, 打开通道产生了极大的开销。相比于上一篇测试中的 netTcpBinding,net.tcp 可以选择打开一次通道后,保持长连接,同时之后的请求和响应体积还能进一步压缩,这也是微软对 webservice 的一种性能优化吧。

感想

其实一开始的测试结果挺出乎我的意料的。一是没想到不同的框架大家的性能差距这么大,二是作者的测试结果同天梯上的不一样,WebFlux 竟然吊打 asp.net core。后来经过一些研究才发现是响应报文里的 Http Header 拖累了 asp.net core,因为我的报文内容实在太短了。同时计算密集型程序不像天梯测试中读写数据库场景的 IO 密集型程序 QPS 差距那么大。

这个测试和代码主要是2019年初的春节回来后的一段时间做的(闲),这次整理出来主要是因为上一篇博客研究了如何用 Jmeter 对 WCF 进行压力测试,测出了 web service 的 QPS,同时 .net core 正式发布了3.0,所以在此展开了重新的代码整理和测试。

虽然在此提升了7倍的 QPS,但感觉 C10k 问题依旧任重而道远。然而即使我如此提升 QPS,优化性能,大家依旧没有足够的勇气去升级框架和缩减机器。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注