{"id":19674733,"url":"https://github.com/cloudwego/netpoll-benchmark","last_synced_at":"2025-04-29T02:30:24.980Z","repository":{"id":44580583,"uuid":"409913480","full_name":"cloudwego/netpoll-benchmark","owner":"cloudwego","description":null,"archived":false,"fork":false,"pushed_at":"2023-11-22T09:10:41.000Z","size":1722,"stargazers_count":39,"open_issues_count":4,"forks_count":11,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-04-05T12:33:10.292Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cloudwego.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null}},"created_at":"2021-09-24T09:52:07.000Z","updated_at":"2025-03-20T10:05:01.000Z","dependencies_parsed_at":"2023-11-22T11:08:04.202Z","dependency_job_id":null,"html_url":"https://github.com/cloudwego/netpoll-benchmark","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudwego%2Fnetpoll-benchmark","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudwego%2Fnetpoll-benchmark/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudwego%2Fnetpoll-benchmark/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloudwego%2Fnetpoll-benchmark/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cloudwego","download_url":"https://codeload.github.com/cloudwego/netpoll-benchmark/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251420861,"owners_count":21586693,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-11T17:19:35.945Z","updated_at":"2025-04-29T02:30:24.467Z","avatar_url":"https://github.com/cloudwego.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# netpoll-benchmark\n\n**置顶声明:**\n\n本 [RPC 场景测试](#测试设定) 项目中，部分包含面向 [Redis 场景][redis] 的 [evio][evio], [gnet][gnet] 测试数据，不构成参考建议。\n\n## 什么是 RPC 场景\n\n这里所说的 [RPC 场景](#什么是-RPC-场景)，是为了区别于 [Redis 场景][redis]，特点是处理逻辑(Handler)耗时较长。\n\n以 Server 为例，一次服务调用过程可描述为：\n\n*接收数据(Read Buffer) -\u003e 解析请求(Decode) -\u003e 逻辑处理(Handler) -\u003e 响应编码(Encode) -\u003e 发送数据(Write Buffer)*\n\n如果上述过程处理速度很快(特别是 Handler), 则可以通过线程内串行处理的方式, 减少上下文切换，达到性能上的理论最优。 cache/proxy/纯计算类业务均属于这种情况，典型的如 [nginx][nginx]\n, [redis][redis] 等。 由于没有专门的术语描述，以下我们将其称为 [Redis 场景][redis]。\n\n而 RPC 业务特征是 Handler 逻辑较重，耗时较长，显然是不能串行处理的。 因此 [RPC 场景](#什么是-RPC-场景)，Handler 必须要异步处理，上下文切换、I/O 协作等都是必须考虑的代价。\n\n## Netpoll 解决什么问题\n\n### 1. 过多长连接下的问题：\n\n线上微服务场景中，由于上下游实例众多，上下游之间的连接数是 k(M x N) 的关系，导致 client/server 均持有大量长连接。 而由于数据分发的负载均衡，长连接的工作总是间歇式的，即存在一定比例的空闲连接，以下描述为\"空闲率\"。\n\n当我们使用 [go net][net] 编写 server 端代码时，必然的为每个连接都分配了一个独立的 goroutine，理想情况下，协程空闲率 = 连接空闲率; 而在 [netpoll][netpoll] 中，空闲连接是不持有 goroutine 的，只有正在工作的连接会在协程池中处理，这就尽可能的减少了协程数量，提高协程利用率。\n\n我们构建了 [测试场景 2](#测试场景-2) 来评估空闲连接的代价。\n\n### 2. 连接多路复用下的问题：\n\n连接多路复用(以下简称 mux)是指在一条长连接上，合并「发送/接收」多个「请求/响应」。这种模式也是长连接利用率低下的一种解决方式。\n\nmux 性能瓶颈主要在 合并包/拆分包，这里涉及到「并行转队列」和「队列转并行」的具体实现。 \n\n常见的基于 [go net][net] 编写的框架，会采用 `go readloop(conn)` \u0026\u0026 `go writeloop(conn)` 方式，构建两个协程，`循环式(串行)的完成编解码`，这在 [go net][net] 下确实是最优的。\n\n但是 [netpoll][netpoll] 有更优的实现，提供的 nocopy API 可以将编解码转为异步。为此，我们构建了 [测试场景 3](#测试场景-3) 来评估收益。\n\n#### PS: [netpoll][netpoll] 为什么不采用 `串行编解码` ？\nA: 这里需要明确指出 `串行编解码` 适用场景更有限，在 LT(水平触发) 下，`串行编解码` 意味着需要快速判断包大小。然而并不是所有 RPC 协议都有头部来表明长度，比如 HTTP、Thrift Buffered 等，这些协议下，转异步编解码是效率更好的方式。\n\n## 测试设定\n\n我们认可 [brpc][brpc] 的测试观点，上下文切换是 [RPC 场景](#什么是-RPC-场景) 必须付出的代价，每个线程独立循环地收发数据，对真实场景缺乏指导意义。 我们希望 benchmark\n可以指导后续的优化工作，为了更切合 [RPC 场景](#什么是-RPC-场景) 测试，引入了以下设定：\n\n1. 不能串行处理\n    * 上述我们说明了 [RPC 场景](#什么是-RPC-场景) 和 [Redis 场景][redis]的区别，因此 Handler 必须异步执行。\n    * `time.Sleep` 虽然能够规避串行处理，但 `timer` 唤醒拥有更高的调度优先级，干扰了 `runtime` 的正常调度，因此没有使用。\n2. 不能边收边发\n    * [RPC 场景](#什么是-RPC-场景)，必须要接收到完整的数据包，才可以继续处理，不能接收到一半就开始回包。\n    * [evio][evio], [gnet][gnet] 欠缺异步处理机制(异步关闭、资源清理等)，因此我们做了近似处理，**不构成参考建议**。\n3. 接收和发送的数据不能是同一份\n    * [RPC 场景](#什么是-RPC-场景) 下的请求和响应，是通过序列化/反序列化产生的两份不同的数据。\n    * 如果直接把读数据 buffer 直接写回，则忽略了这部分开销，并忽略了在这方面所做的一些优化。\n\n## 开始测试\n\n`Echo 测试` 将收到的 string 数据原样返回，定义了 `Message` 来模拟编解码过程。\n\n协议格式为 `header(4 Byte)(=payload length), payload(n Byte)`。\n\n[RPC 场景](#什么是-RPC-场景) 在 Client 和 Server 端使用方式不同，因此分别测试两端的性能表现。\n\n* Client 测试：不同的 client，调用相同的 net server，评估 client 端性能表现。\n* Server 测试：相同的 net client，调用不同的 server，评估 server 端性能表现\n\n### 测试场景 1\n\n`测试场景 1` 模拟「长连接池模式」下的 `Echo 测试`，用来评估连接池场景的性能上限。\n\n* 连接池容量 = 1024\n\n### 测试场景 2\n\n`测试场景 2` 模拟「带空闲连接」下的 `Echo 测试`，用来评估空闲连接对性能的影响。\n\n* 连接空闲率 = 80%\n\n### 测试场景 3\n\n`测试场景 3` 模拟「连接多路复用模式」下的 `Echo 测试`，用来评估拆包/组包的实际效率。\n\n* 连接个数 = 4\n\n### 快速执行：loopback 模式\n\n以上测试场景，通过执行「脚本 + 场景号」，可以快速开始测试。执行前请先确认满足[环境要求](#环境要求)。\n\n* client 测试\n\n```bash\n./scripts/benchmark_client.sh 1 # or 2, 3\n```\n\n* server 测试\n\n```bash\n./scripts/benchmark_server.sh 1 # or 2, 3\n```\n\n### 环境要求\n\nOS: Linux\n\n* 默认依赖了命令 `taskset`, 限定 client 和 server 运行的 CPU; 如在其他系统执行, 请修改脚本。\n\nCPU: 推荐配置 \u003e=20核, 最低要求 \u003e=4核\n\n* 压测脚本默认需要 20核 CPU, 具体在脚本的 `taskset -c ...` 部分, 可以修改或删除。\n\n软件依赖: Python3 + matplotlib 用于绘图\n\n* 在运行压测前， 可以使用 pip3 install matplotlib 安装依赖\n\n\n## 参考数据 (echo size 1KB)\n\n相关说明:\n\n该压测数据是在调用端有充分机器资源**压满服务端**的情况下测试，更侧重于关注服务端性能。后续会提供调用端性能数据情况。\n\n### 配置\n\n* CPU:    Intel(R) Xeon(R) CPU E5-2630 v4 @ 2.20GHz\n   * 运行限定 server 4CPU, client 16CPU\n* OS:     Debian 6.4.7-amd64 x86_64 GNU/Linux\n* Go:     go1.21.4\n\n### [测试场景 1](#测试场景-1)\n\n|             | QPS                                   | TP99                                   | TP999                                   |\n| :---------- | :------------------------------------ | :------------------------------------: | :-------------------------------------: |\n| Server(4C)  | ![image](docs/images/server1_qps.png) | ![image](docs/images/server1_tp99.png) | ![image](docs/images/server1_tp999.png) |\n| Client(16C) | ![image](docs/images/client1_qps.png) | ![image](docs/images/client1_tp99.png) | ![image](docs/images/client1_tp999.png) |\n\n### [测试场景 2](#测试场景-2)\n\n|             | QPS                                   | TP99                                   | TP999                                   |\n| :---------- | :------------------------------------ | :------------------------------------: | :-------------------------------------: |\n| Server(4C)  | ![image](docs/images/server2_qps.png) | ![image](docs/images/server2_tp99.png) | ![image](docs/images/server2_tp999.png) |\n| Client(16C) | ![image](docs/images/client2_qps.png) | ![image](docs/images/client2_tp99.png) | ![image](docs/images/client2_tp999.png) |\n\n\n### [测试场景 3](#测试场景-3)\n\n|             | QPS                                   | TP99                                   | TP999                                   |\n| :---------- | :------------------------------------ | :------------------------------------: | :-------------------------------------: |\n| Server(4C)  | ![image](docs/images/server3_qps.png) | ![image](docs/images/server3_tp99.png) | ![image](docs/images/server3_tp999.png) |\n| Client(16C) | ![image](docs/images/client3_qps.png) | ![image](docs/images/client3_tp99.png) | ![image](docs/images/client3_tp999.png) |\n\n\n[net]: https://github.com/golang/go/tree/master/src/net\n\n[netpoll]: https://github.com/cloudwego/netpoll\n\n[gnet]: https://github.com/panjf2000/gnet\n\n[evio]: https://github.com/tidwall/evio\n\n[redis]: https://redis.io\n\n[nginx]: https://www.nginx.com\n\n[brpc]: https://github.com/apache/incubator-brpc/blob/master/docs/cn/benchmark.md\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudwego%2Fnetpoll-benchmark","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcloudwego%2Fnetpoll-benchmark","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloudwego%2Fnetpoll-benchmark/lists"}