Rust in Everything
基于 pingora 0.9.0

常见坑

每一章对着一个报错或一个现象:先用最小的程序复现,再到源码里找它从哪一行来,最后给出修法和检查办法。前面几部分讲过的机制,这里只链过去。

复现环境都是 M2 Max、macOS 27、rustc 1.99.0、pingora 0.9.0、tokio 1.53.2(为什么钉这个版本见第 1 章)。和本站网关有关的几章,同时在网关用的 pingora 0.8.0 上复现,章里写明。有几个坑是上游的问题,章里写明 main 上修了没有。

  1. capacity must be greater than zero:tokio 1.54 起,第一个连接进来就 panic,监听停掉,进程还活着。
  2. the name tls is defined multiple times:两个 TLS feature 同时打开。
  3. No tls feature was specified:没选 TLS 后端也能编过,握手时才 panic。
  4. 升级到 0.9.0 的编译错误:DerefMut 没了(E0596 / E0594);CacheKey 少了一个参数,照 rustc 的提示改会让键冲突。
  5. Worker threads cannot be set to 0:配置校验放过了 threads: 0。
  6. still in use:端口被占,重试约 30 秒后服务线程 panic,进程不退出。
  7. -c 配置文件不生效:Server::new(None) 不读命令行。
  8. grace period 300s starts:默认宽限期比容器的停机时限长,每次停机都被 SIGKILL。
  9. Upgrade is not currently supported outside of Linux platforms:macOS 上平滑升级失败,旧进程却说 listener sockets sent。
  10. 在钩子里阻塞:Steal 下所有新连接一起卡住(4 个线程 18/18 次);NoSteal 下 accept 线程一忙,整个服务都慢。
  11. 第一个请求之后,连接永不空闲超时:HTTP/1 keep-alive 的超时变成无限,h2 连接不发 preface 也一样。
  12. 管线化的第二个请求没有回应:默认关闭 pipelining,回完第一个就断开;第二个在代理途中到达时,连第一个也变成 400。
  13. Some(H2Options::new()) 丢了默认上限:自己传 h2 选项,有界的默认值就没了。
  14. Failed to load provided certificates:rustls 后端到 build 时才读证书,panic 后这个服务的所有端口都拒绝连接,明文端口也一样。
  15. failed to lookup address information:HttpPeer::new 同步解析,失败就 panic;localhost 先走 ::1。
  16. 上游 h2 不复用连接:max_h2_streams 默认 1;对只会 h1 的 TLS 上游要 h2,每次都新建连接。
  17. 上游不回应,连接永远挂着:PeerOptions 默认没有任何超时。
  18. Upstream ConnectionClosed ... retry: false:复用的连接被上游关掉,0.9.0 的 POST 回 502,0.8.0 把 POST 发两次。
  19. Ok(true) 却没写响应:客户端一直等到超时。
  20. Empty reply from server:max_retries: 0 一次也不连上游,也没有日志。
  21. Retry is not decided:覆盖 error_while_proxy 时没有决定 ReusedOnly。
  22. 响应带 Vary 却没压缩:在 request_filter 里才打开压缩,已经晚了。
  23. 打开了缓存却什么都没缓存:默认的 response_cache_filter 一律不缓存。
  24. POST 命中 GET 的缓存、Set-Cookie 发给别人:缓存的默认判断不看方法、不看 Set-Cookie、不看 Vary。
  25. response too large:超过最大文件大小时,chunked 响应被截断,客户端可能一个字节都拿不到,日志却写 status 500。
  26. attempt to calculate the remainder with a divisor of zero:后端权重全是 0。
  27. assertion failed: new >= now - 1000:Rate 的窗口小于 1 秒、多线程同时用,上游问题。
  28. RTCache 的写者被取消后:同一个键永远等,或者永远 miss,上游问题。

按出在哪里分:

出在哪里坑
依赖与 feature1 tokio 1.54、2 两个 TLS、3 没有 TLS、4 升级到 0.9.0
服务器与停机5 threads 0、6 端口被占、7 配置不生效、8 宽限期、9 macOS 升级、10 阻塞
下游协议11 keep-alive、12 管线化、13 h2 选项、14 rustls 证书
连接上游15 DNS、16 h2 复用、17 没有超时、18 复用连接上的 POST
代理钩子19 Ok(true)、20 max_retries、21 ReusedOnly、22 压缩
缓存23 不缓存、24 不安全的默认、25 最大文件大小
负载均衡与组件26 权重 0、27 Rate、28 RTCache

本站网关(pingora 0.8.0)中了其中几个:1 的风险(锁文件挡着)、8、11、18,见在本站中。

flowchart TB
  q{"碰到了什么"}
  q -->|编译失败| cf{"哪一句"}
  cf -->|"E0252 tls"| p2["2 两个 TLS"]
  cf -->|"E0596 E0594 E0061"| p4["4 升级 0.9.0"]
  q -->|启动就 panic| st{"原文"}
  st -->|"threads"| p5["5 threads 0"]
  st -->|"still in use"| p6["6 端口被占"]
  st -->|"Upgrade is not"| p9["9 macOS 升级"]
  q -->|请求时 panic| pn{"原文"}
  pn -->|"capacity"| p1["1 tokio 1.54"]
  pn -->|"No tls feature"| p3["3 没有 TLS"]
  pn -->|"certificates"| p14["14 rustls"]
  pn -->|"lookup address"| p15["15 DNS"]
  pn -->|"Retry is not"| p21["21 ReusedOnly"]
  pn -->|"divisor of zero"| p26["26 权重 0"]
  pn -->|"now - 1000"| p27["27 Rate"]
  q -->|客户端拿到错误| ce{"哪种"}
  ce -->|"POST 502"| p18["18 复用连接"]
  ce -->|"Empty reply"| p20["20 max_retries"]
  ce -->|"一直等"| p1917["19 或 17"]
  ce -->|"body 截断"| p25["25 文件大小"]
  q -->|行为不对| bh{"哪种"}
  bh -->|"配置没生效"| p7["7 或 13"]
  bh -->|"连接不关"| p11["11 keep-alive"]
  bh -->|"停机被杀"| p8["8 宽限期"]
  bh -->|"全部变慢"| p10["10 阻塞"]
  bh -->|"缓存不对"| p2324["23 或 24"]
  bh -->|"没压缩"| p22["22 压缩"]
  bh -->|"连接太多"| p16["16 h2"]
  bh -->|"键永远等"| p28["28 RTCache"]

💬 关联讨论

发起讨论
加载中...