负载均衡与限流
这一部分讲三个 crate:pingora-load-balancing 0.9.0(src/ 6596 行,其中一半是单元测试,正文 3318 行)、pingora-ketama(609 行,一个文件)和 pingora-limits(633 行)。门面 crate 的 lb feature 带上前两个,pingora-limits 要自己加依赖。
它们和前面几部分的关系很松:pingora-proxy 不知道它们的存在。代理只在 upstream_peer 里要一个 HttpPeer,用户决定从哪来,LoadBalancer::select 是一种来法;限流也只是在 request_filter 里数一数、自己写 429。唯一和框架接上的地方是 LoadBalancer 实现了 BackgroundService,作为服务主线上的一个后台服务定期刷新后端和做健康检查。
- LoadBalancer:
Backend的身份是地址加权重;Static发现装好就不能改,try_from_iter把localhost解析成两个后端;select_with无锁读选择器快照、逐个问就绪状态,max_iterations=1时轮询会卡在被禁用的后端上;换后端集合时先发布新旧并集的就绪表;0.9.0 的LoadBalancerGroup在阻塞线程池里排队重建选择器,实测重建完成前旧选择器还会选中刚删掉的后端。 - 选择算法:
Weighted的加权下标表只对首选生效,权重 0 的后端仍会当备选,全为 0 时除以零 panic;加权轮询是连续几次同一个后端;Ketama 环每个后端 160 个 crc32 点,1001 行 nginx 采样全部一致,加一个后端只迁移 20.9% 的键,FNV 取模迁移 80.0%;point_multiple不开v2feature 时被静默忽略。 - 健康检查与后台服务:新后端默认健康,没有被动检查;后台循环先发现、再报就绪、再检查;实测杀掉一个上游后,下一次检查之前约一半请求 502,配合
fail_to_connect重试和select_with可以降到 0;0.9.0 的race_shutdown让挂住的检查在 SIGTERM 的同一毫秒被丢掉。 - 限流:
Estimator是只会多算的 count-min sketch,实测误差取决于窗口内的不同键数;Rate是红蓝两格轮换的固定窗口,由调用触发翻转;interval小于 1 秒时第一秒内并发调用会 panic;上游文档的限流例子原样可跑,所有键共用一个窗口。
flowchart TB up["upstream_peer"] --> sel["LoadBalancer::select"] sel --> algo["选择算法"] algo --> ketama["pingora-ketama"] sel --> ready["就绪状态"] bg["后台服务"] --> disc["ServiceDiscovery"] bg --> hc["HealthCheck"] disc --> ready hc --> ready rf["request_filter"] --> rate["pingora-limits"]
第一页是骨架,第二页是骨架里的算法,第三页是让骨架动起来的后台服务,第四页和前三页无关,是另一种在钩子里调用的工具。选好后端之后连接怎么建、失败了要不要换一个后端重试,见 连接上游 和 错误、重试与故障转移。和 tower 对照:tower 的负载均衡是一个 Service,从 Discover 流里读增删、按负载做 P2C(见 tower 卷的 负载均衡),限流是包在服务外面的中间件;pingora 这里都是普通的数据结构,由钩子调用。
💬 关联讨论
发起讨论加载中...