C++网络通信库性能大比拼

本文通过压力测试工具wrk对比cppcms、boostasio、libevent、muduo及nginx的网络I/O性能,发现muduo表现最佳,cppcms虽垫底但仍优于PHP、Ruby等语言编写的RESTful服务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C/C++网络通信库有不少,本次benchmark的目的是为了公平的评估它们的网络I/O性能,当然是作为REST server, 因此每个server都写了一些代码,好在不是特别复杂。这个测试经过了好几轮,本文给出了最终的结论。

先上结论,大家都忙:)

候选者:cppcms, boost asio, libevent, muduo和 nginx,nginx不是库,这里做测试使用它作为基准,毕竟很多人心里,它是不可挑战的。

结论:QPS的比拼结果,cppcms最弱,boost asio好很多,libevent好更多,nginx比libevent还要好点,muduo最好。

但是,不要小瞧这里最弱的cppcms,它仍可以轻易击败php, ruby, java, go, python, nodejs等语言编写的rest server。

下面介绍测试的方法

测试工具:wrk
之前选用过apache的ab test工具,不要被名字骗了,和常说的ab test方法没什么关系。这是一个压力测试工具,但是明显不能将压力升到最高,还是wrk效果最好。因为压测的目标是,击穿服务器,然后减少点压力,找到能够让服务器网络程序正常工作的最大压力。

找测试工具的唯一标准就是能不能用足压测客户机器的资源,释放最大的压力。其他非C/C++的压测工具也就直接谢绝了,这不是什么开发效率至上的场合。

wrk -t4 -c200 -d60s "http://167serverip:serverport/collect?v=1"
wrk tool; 4 threads; 200 concurrency connection; duration 60s.

测试服务器
Table 1: benchmark env
Machine    CPU Model    MEM    NETCARD(Gbps)    OS
client     Intel(R) Xeon(R) CPU E5620 @2.40GHz 8 core    16G    1    CentOS release 6.5 (Final) x86_64
server     Intel(R) Xeon(R) CPU E5620 @2.40GHz 8 core    16G    1    CentOS release 6.5 (Final) x86_64

8核服务器,CentOS系统是乐视大运维同事优化过内核的,性能应该超过下载下来的默认系统。测试服务器分成两种,client负责发出http调用,server负责接受http请求,我们测量的就是server成功处理的最大QPS.


网络程序架构
都使用epoll,不过还是有差别,主要在多线程模型上。

Table 2: server architecture
Server    Process Num    Thread Num    IO Pattern
cppcms_based    1    default threads = core*5    epoll one thread io_loop
asio_based    1    8    epoll io_loop-per-thread
muduo_based    1    8    epoll io_loop-per-thread
libevent_based    1    8    epoll io_loop-per-thread
nginx    8 worker    1    epoll one thread io_loop


测试结果
format: min/max/average

Table 3: benchmark result
Server    Cpu    Mem    Disk    Netcard(in/out)    Requests/sec
libevent_based    684% / 768% / 756%    7276 / 9.9M / 8231    -    -    104797 / 112025 / 111998
asio_based    302% / 357% / 309%    5522 / 5976 / 5743    -    -    18971 / 19246 / 19163
cppcms_based    230% / 249% / 231%    9210 / 9428 / 9378    -    -    15434 / 16391 / 15500
muduo_based    680% / 754% / 702%    6644 / 7332 / 6720    -    -    286586 / 289423 / 287332
nginx    8*80% / 8*86 / 8*82    8*44M / 8*44M / 8*44M    -    -    112658 / 114127 / 113406

如果使用O3优化选项, 发现对于boost asio和muduo有较大提升。

Table 5: more details httpserver all versions benchmark
Server    Compiler    Optimization option    Cpu    Mem    Disk    Netcard(in/out)    Requests/sec
cppcms_based    clang++ 3.6.2    -O3    228% / 239% / 228%    9356 / 9416 / 9416    -    -    14252 / 16124 / 15820
asio_based    clang++ 3.6.2    -O3    300% / 305% / 303%    4368 / 4564 /4416    -    -    33069 / 34247 / 33360
libevent_based    clang++ 3.6.2    -O3    763% / 764% / 764%    5560 / 10M / 5520    -    -    113373 / 114072 / 113713
muduo_based    clang++ 3.6.2    -O3    650% / 694% / 658%    6272 / 6324 / 6312    -    -    303202 / 307204 / 305839

其他测试结论
我们使用的是clang++编译器和g++编译器,优化选项是O3, 发现两个编译器编译出来的程序性能相当。

我们做了C++11和之前的C++03版本的对比,发现C++11略好于C++03。

还有很多轮测试,限于篇幅,不在这里描述。

为什么cppcms和boost asio性能不高?
因为mutex,对epoll使用最高效的方式在多线程里面每个线程都调用epoll_wait,而这两个库都增加了mutex去锁,导致性能低下。

mudoo性能特别高的原因是它的设计只考虑linux平台,只把一个平台的通信库做到极致,设计目的单纯,因此能够做到最好。

具体的原因后面会专门发表文章剖析。今天先写这么多。
————————————————
版权声明:本文为优快云博主「csfreebird」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/csfreebird/article/details/49283743

1.1 什么是Herm Herm是一套快速开发高性能的网络应用的C++库。比如开发网络游戏、即时通信、流媒体、文件下载、P2P等基于TCP/IP网络应用。 Herm包括三个组件: (1)Utilities 最基础的组件,提供线程、一读一写线程不加锁的ring buffer、二进制消息解析器、支持多态的对象管理器等。 (2)Socket 用面向对象和泛型的方法抽象了TCP/UDP的Socket IOs;抽象了Win32 Select、Linux epoll和FreeBSD kqueue的多路复用API。统一了三者水平模式(Level Triggered)的语义(一套代码在Win32/Linux/FreeBSD运行结果是一样的),Linux上也支持了边缘模式(Edge Triggered)。 (3)Framework 基于Utilities和Socket的简化开发网络应用的框架,抽象出Peer和Session对象。Peer和Session对象以及Framework实现的功能将在第2章介绍。 Herm目前仅支持Linux/Windows/FreeBSD 32bits平台。调用者可以基于不同的需求使用不用的组件。 1.2 最简单的例子 本节给出两个分别用Framework和Socket组件实现的简单TCP Server的例子。所有的例子可以参考examples frameworks和multiplexors目录。 1.2.1 用Framework实现TCP Server 首先,实现一个Listener, class Listener : public Herm::Listener { virtual void Accept(Herm::Session* session) { // 在这里得到一个于客户端通信的Session // 注册用于处理收到的消息的handler // 用Session::Push将数据写到发送buffer,最终数据传给client } }; 实现一个App, class App : public Herm::App { virtual bool Init() { // 1. 创建Network Herm::Network* net = CreateNetwork(); // 2. 创建一个TCP Server Peer,将Listener注册到Peer,进行监听 Herm::Peer* peer = net->CreateTCPServer(addr, new Listener); } }; 1.2.2 用Socket实现TCP Server 用Socket实现TCP Server更灵活,但实现者要做一些额外的工作,比如tcp stream解析,缓冲队列处理等等。 首先实现一个AcceptHandler,处理Client连接, class AcceptHandler : public Herm::EventHandler { virtual int Receive(int) { m_acceptor->Accept(streamHandler->GetStream()); g_reactor->Register(streamHandler, Herm::READ_MASK); ... } private: Herm::Acceptor* m_acceptor; }; 实现StreamHandler, 处理数据收发, class StreamHandler : public Herm::EventHandler { // Handle onle int param on FreeBSD, pls see the example of FreeBSD_tcp_server virtual int Receive(int) { m_stream->Recieve(buf, .......); ..... } private: Herm::Stream* m_stream; }; 最后,在一个线程里把上面Handler执行起来, while (true) g_reactor->Run(); 1.3 Herm地址 https://sourceforge.net/projects/speed/ 1.4 下一章话题 下章将较详细地介绍Framework组件,主要介绍如何用Framework实现真实可用的网络游戏的接入网关Server(gated)和逻辑Server(zoned) 转自优快云的herm_lib http://blog.youkuaiyun.com/herm_lib
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值