炼数成金 门户 大数据 编程开发 查看内容

底层I/O性能大PK:Python/Java被碾压,Rust有望取代C++

2021-3-24 15:02| 发布者: 炼数成金_小数| 查看: 11975| 评论: 0|原作者: 弯月 译|来自: CSDN

摘要: 实现后端服务的编程语言有许多。因此,人们对于比较这些语言的性能有着一种天然的好奇心,而比较的基准也各种各样。例如,有一个基准可以比较不同语言在解决不同的离线任务时的性能。还有一个基准TechEmpower,可以 ...
我发现一旦计算机没了互联网,我就无所事事。大多数时候,我们都使用笔记本电脑和智能手机访问其他地方存储或生成的信息。我们很难想象如果没有了网络通信,不面向用户的应用还有什么用处。尽管I/O操作与数据处理的比例可能有所不同,但此类操作可能会引发服务延迟。

实现后端服务的编程语言有许多。因此,人们对于比较这些语言的性能有着一种天然的好奇心,而比较的基准也各种各样。例如,有一个基准可以比较不同语言在解决不同的离线任务时的性能。还有一个基准TechEmpower,可以衡量Web框架的性能。这些度量非常实用,我们可以通过它们大致了解语言的性能。然而,一般这些基准都有特定的使用场合和特定的操作,所以不一定具有代表性。

因此,我对各个平台上基本I/O的不可降低的成本非常好奇。对TCP代理进行基准测试可能是最简单的情况。其中不涉及数据处理,只处理传入/传出连接,并中继原始的字节数据。微服务的速度基本上不可能比TCP代理更快,因为微服务所需做的处理不可能少于TCP代理,它的功能只会更多,比如在此基础上构建的其他功能:解析、验证、遍历、打包、计算等等。

在本文中,我们将比较以下解决方案:
HAProxy:TCP代理模式。这是一个使用C语言编写的成熟解决方案。http://www.haproxy.org/

draft-http-tunnel:一个使用C++的解决方案(以TCP模式运行),只有最基本的功能(trantor):https://github.com/cmello/draft-http-tunnel/(

http-tunnel:使用Rust(tokio)编写的简单的HTTP隧道 / TCP代理(在TCP模式下运行):https://github.com/xnuter/http-tunnel/

tcp-proxy:Golang解决方案:https://github.com/jpillora/go-tcp-proxy

NetCrusher:Java解决方案(Java NIO)。使用G1在JDK 11上运行基准测试:https://github.com/NetCrusherOrg/NetCrusher-java/

pproxy:基于asyncio的Python解决方案(以TCP代理模式运行):https://pypi.org/project/pproxy/

以上所有的解决方案均使用非阻塞I / O。

注意:我尽力挑选了Golang、Java和Python的较佳解决方案,如果你知道更好的解决方案,请在下方留言。

实际的后端是Nginx,具体配置为:以HTTP模式发送10kb的数据。

基准结果分为两组:
基准、C、C++、Rust:高性能语言。

Rust、Golang、Java、Python:内存安全的语言。

没错,两组中都包含Rust。

方法的简要说明
为TCP代理分配了两个核心(使用cpuset)。

为后端分配了两个核心(Nginx)。

请求速率从10k开始,较高至每秒25k请求。

每50个请求共用一个连接(每个请求10kb)。

测试在同一台虚拟机上运行,为的是避免网络噪音。

VM选择了针对计算优化的实例类型(独占所有分配到的CPU),为的是避免出现“嘈杂的邻居”问题。

延迟测量分辨率为微秒(μs)。

我们比较的统计数据包括:
百分位数(从p50到p99):关键统计数据。

离群值(p99.9和p99.99):对于大型分布式系统的组件非常关键。

较大延迟:最坏的情况永远不容忽视。

修整后的均值tm99.9:去除0.1%的较佳/最差值后得到的均值,为的是捕捉中心趋势(不考虑离群值)。

标准偏差:评估延迟的稳定性。

为了收集数据,我使用了perf-gauge。

下面,我们来看看结果!

高性能语言:C、C++、Rust
我经常听人说,Rust的性能可与C / C ++媲美。下面我们就来看一看在处理网络I/O时,Rust是否能够表现出同等的水平。 

以下四个图分别是:基准、C、C++、Rust:

图:绿色:p50;黄色:p90;蓝色:p99(以μs为单位)(左图);橙色-速率(右图)

将每个统计信息的后端也加上去,所得到的微秒数如下所示。以下数字是在较大请求速率下间隔的平均值(不包括加速):

图:开销(微秒)

相对结果(开销占基准的百分比):

图:基准统计的开销(%)

有趣的是,尽管在p99.9级别上,用C++编写的代理比HAProxy和Rust都快一点,但在p99.99和max上的表现却最糟。但这可能是由于实现导致的,在这里是非常基本的(而且通过回调实现,没有通过处理future实现)。

此外,我测量了CPU和内存消耗,详情请看这里(https://github.com/xnuter/perf-gauge/wiki/Moderate-request-rate#cpu-and-memory-consumption)。

总的来说,使用C、C++和Rust编写的三个TCP代理表现出的性能不相上下:精简且稳定。

比较内存安全语言:Rust、Golang、Java和Python
下面,我们来比较一下内存安全语言。不幸的是,Java和Python的解决方案无法仅通过两个核心处理25,000 rps,因此Java的基准测试为15,000 rps,而Python的基准测试为10,000 rps。

下列四个图分别是:Rust、Golang、Java和Python。

图:绿色:p50;黄色:p90;蓝色:p99(以μs为单位)(左图);橙色-速率(右图)

我们看到了巨大的差异。对于Rust,上一张图中的“噪声”似乎很多,但在这张图中非常稳定。另外,请注意Java的冷启动高峰。以下数字是在较大请求速率下间隔的平均值(不包括加速):

如你所见,Golang在p50 / p90级别上也具备一定的竞争力。但是,在更高的百分位上,差异急剧增加,标准偏差充分反映了这一点。但是,请再看一下Java的数字!

离群值(p99.9和p99.99)百分位非常耐人寻味。与Rust的差异肉眼可见:

图:绿色:p99.9;蓝色:p99.99(μs)(左图);橙色-速率(右图)

相对结果(开销占基准的百分比):

图:基准统计的开销(%)

总的来看,Rust的延迟差异远低于Golang、Python,尤其是Java。在p50 / p90的延迟级别上, Golang可与Rust并肩。

较大吞吐量
还有一个问题:每个代理可以处理的较大请求速率是多少?

Nginx能够处理的请求量超过60,000 rps。如果我们在客户端和后端之间建立一个代理,就会降低吞吐量。如下所示,C、C ++、Rust和Golang服务的请求量可以达到Nginx的70%~80%,而Java和Python的表现则比较差:

图:左轴:延迟开销;右轴:吞吐量

蓝线是tail延迟(Y轴在左侧):越低越好。

灰色代表吞吐量(Y轴在右侧):越高越好。

总结
这些基准测试并不全面,我的目标是比较各个语言基本的I / O。

根据以上测试结果,再结合Benchmarks Game和TechEmpower的结果表明,如果性能对你的服务来说非常重要,那么与Golang、Java或Python相比,Rust可能是更好的替代方案。另外,在使用C或C++编写新服务之前,可以考虑一下Rust。因为Rust不仅具有可与C / C++同等出色的性能,而且还具备以下优势:

内存安全。

无数据竞争。

易于编写方便理解的代码。

与Python一样易于访问和灵活。

它会迫使工程师在投入生产之前,提前设计和理解数据的所有权。

它有一个了不起的社区和一个庞大的组件库。

所有试过的人都说好!

原文链接:https://medium.com/star-gazers/benchmarking-low-level-i-o-c-c-rust-golang-java-python-9a0d505f85f7

声明:文章收集于网络,版权归原作者所有,为传播信息而发,如有侵权,请联系小编删除,谢谢!

欢迎加入本站公开兴趣群
软件开发技术群
兴趣范围包括:Java,C/C++,Python,PHP,Ruby,shell等各种语言开发经验交流,各种框架使用,外包项目机会,学习、培训、跳槽等交流
QQ群:26931708

Hadoop源代码研究群
兴趣范围包括:Hadoop源代码解读,改进,优化,分布式系统场景定制,与Hadoop有关的各种开源项目,总之就是玩转Hadoop
QQ群:288410967 

鲜花

握手

雷人

路过

鸡蛋

相关阅读

最新评论

热门频道

  • 大数据
  • 商业智能
  • 量化投资
  • 科学探索
  • 创业

即将开课

 

GMT+8, 2021-4-13 05:07 , Processed in 0.171063 second(s), 25 queries .