服务器
这一部分讲服务主线:一个 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 那一层,见协议。
- 配置与命令行:
Server::new分三路生成ServerConf,Server::new(None)不看命令行;字段默认值和读它们的代码,work_stealing默认true,宽限期默认 300 秒,upgrade_sock_connect_accept_max_retries没有代码读;bootstrap只处理-t和-u,threads: 0能通过校验、到建运行时才 panic。 - 服务与监听器:三个服务 trait 和依赖图;监听器先查共享 fd 表再决定接手还是
bind,端口被占时重试 29 秒后只让服务线程 panic、进程不退出;accept 循环把握手和set_buffer推给连接任务,零容量缓冲区是 0.5.0 为了 accept 速度加的,也是 tokio 1.54 panic 的位置。 - 运行时:Steal 是 tokio 多线程运行时,NoSteal 是 N 个单线程运行时,
current_handle随机挑线程;一个连接上有重请求时,Steal 的其他连接不受影响,NoSteal 视随机分配而定;NoSteal 下所有下游 socket 注册在 accept 线程的反应器上,那个线程一忙,整个服务一起慢。 - 平滑升级与停机: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 实现只读了源码。
💬 关联讨论
发起讨论加载中...