设计取舍
前八部分按代码讲机制,每一章都顺带碰到一些「这样做换来了什么、付出了什么」。这一部分只有一页,把它们收到一起:每一条先说 pingora 选了什么,再说收益和代价,数字取自本卷某一页的实验,链接指向那一页,这里不重讲机制。对照的对象是 hyper 卷(同样在 tokio 上的 HTTP 实现)、tower 卷(Service 套 Service 的中间件)和 tokio 卷(运行时);nginx 只写 pingora 自己的文档和源码里说了什么。这一页另外补了两组数:同一台机器上 pingora 和用 hyper 搭的代理转发同一组请求,以及从 git 历史里数出的 ProxyHttp 演变和各 crate 的版本变动。
- 设计取舍:十条取舍、一份上游问题记录、一张文档与代码不符的表和一节同机实测。自己写 HTTP/1 换来头名大小写原样和框架掌握的复用判断,代价是第一个请求之后不再空闲超时,同机实测每请求比 hyper 搭的代理慢约 3 µs;固定阶段的钩子让一个 GET 调 18 个方法、转发和重试都不用自己写,但不能包住一段;
ProxyHttp从 0.1.0 的 25 个方法长到 42 个,只加不删;默认的工作窃取运行时守得住重请求,NoSteal 下下游 socket 共用 accept 线程的反应器;服务级连接池跨下游连接复用,reuse_hash漏了ca;TLS 后端用 cfg 四选一,零分发,开两个就是 E0252;传 fd 的平滑升级只在 Linux 上实现;一组资源默认值不设上限,源码明说「Unlike nginx」;22 个 crate 同一个版本号,6 个 crate 没变也升号,0.8.1 是一条不在 main 历史里的岔路;本卷核对出 28 处文档与代码不符。
flowchart TB req["请求主线"] --> h1["自己的 HTTP/1"] req --> hook["固定阶段钩子"] req --> pool["服务级连接池"] req --> tls["cfg 四选一 TLS"] srv["服务主线"] --> rt["每服务运行时"] srv --> fd["传 fd 升级"] cache["缓存主线"] --> dflt["默认不设上限"] h1 --> hy["对照 hyper"] hook --> tw["对照 tower"] rt --> tk["对照 tokio"]
💬 关联讨论
发起讨论加载中...