Rust in Everything
基于 pingora 0.9.0

服务器

这一部分讲服务主线:一个 pingora 进程从 Server::new 到退出。代码在 pingora-core 的 server/(mod.rs、configuration/、bootstrap_services.rs、daemon.rs、transfer_fd/,共 3170 行,含测试)、services/(1197 行)、listeners/(mod.rs 和 l4.rs 共 1589 行,TLS 后端另算),以及独立的 pingora-runtime crate(782 行)。

Server 自己不懂 HTTP,它只管四件事:配置从哪来;服务怎么启动、按什么顺序;每个服务跑在哪种运行时上;收到信号以后怎么停、怎么把端口交给下一个进程。HTTP 在 ServerApp 那一层,见协议。

  1. 配置与命令行:Server::new 分三路生成 ServerConf,Server::new(None) 不看命令行;字段默认值和读它们的代码,work_stealing 默认 true,宽限期默认 300 秒,upgrade_sock_connect_accept_max_retries 没有代码读;bootstrap 只处理 -t 和 -u,threads: 0 能通过校验、到建运行时才 panic。
  2. 服务与监听器:三个服务 trait 和依赖图;监听器先查共享 fd 表再决定接手还是 bind,端口被占时重试 29 秒后只让服务线程 panic、进程不退出;accept 循环把握手和 set_buffer 推给连接任务,零容量缓冲区是 0.5.0 为了 accept 速度加的,也是 tokio 1.54 panic 的位置。
  3. 运行时:Steal 是 tokio 多线程运行时,NoSteal 是 N 个单线程运行时,current_handle 随机挑线程;一个连接上有重请求时,Steal 的其他连接不受影响,NoSteal 视随机分配而定;NoSteal 下所有下游 socket 注册在 accept 线程的反应器上,那个线程一忙,整个服务一起慢。
  4. 平滑升级与停机:SIGTERM 睡满宽限期再关运行时,graceful_shutdown_timeout_seconds 只管阻塞线程;SIGINT 不通知任何服务;SIGQUIT 在 Linux 上经 SCM_RIGHTS 传监听 fd,在 macOS 上新进程直接退出、旧进程却报告发送成功;守护进程化与 0.9.0 的 daemon_wait_for_ready。
flowchart TB
  new["Server new"] --> conf["ServerConf"]
  conf --> boot["bootstrap"]
  boot --> add["add_service"]
  add --> run["run"]
  run --> dmn["daemonize 可选"]
  dmn --> rts["每服务一个运行时"]
  rts --> lis["监听器与 accept"]
  lis --> app["ServerApp"]
  run --> ml["main_loop 等信号"]
  ml --> stop["停机或升级"]
  stop --> rts

第一页是输入,第二、三页是服务跑起来以后的样子,第四页是怎么结束。整个过程的时序在一个 Server 的一生里有一次完整的打点;本部分的实验都在 macOS 上做,transfer_fd 的 Linux 实现只读了源码。

💬 关联讨论

发起讨论
加载中...