服务实例下线,client 还会打多少请求给它?TTL 和客户端缓存的刷新间隔怎么影响?先注销再停、优雅退出各自解决什么?client 重试能补多少?这篇用 3 个实例和一个小注册中心量出来。
配置 | 错误请求 / 总数 | 错误发生的时间范围 | 平均每个请求尝试几次 ------------------+-----------+-------------+----------- TTL 1 s · R 0.5 s | 23 / 480 | 2.8 ~ 3.9 s | 1.00 TTL 1 s · R 1 s | 42 / 480 | 2.8 ~ 4.9 s | 1.00 TTL 2 s · R 0.5 s | 42 / 480 | 2.9 ~ 4.9 s | 1.00 TTL 2 s · R 1 s | 42 / 480 | 2.8 ~ 4.9 s | 1.00 TTL 4 s · R 0.5 s | 82 / 480 | 2.9 ~ 6.9 s | 1.00 TTL 4 s · R 1 s | 82 / 480 | 2.8 ~ 6.9 s | 1.00 死实例在 client 缓存里存在的时间 ≈ 注册中心发现它(TTL 内)加上下一次拉取(≤ R):TTL 和 R 越大,错误越多;每秒 60 个请求、轮询 3 个实例,发给死实例的约 20 个/秒,错误数 ≈ 20 × (从崩溃到缓存更新的秒数)
错误数取决于注册中心发现它所需的时间加上 client 缓存的刷新间隔。
做法 | 错误请求 / 总数 | 错误发生的时间范围 | 平均每个请求尝试几次 --------------------+-----------+-------------+----------- 注销后 kill · 等待 0 s | 22 / 480 | 2.8 ~ 3.9 s | 1.00 注销后 kill · 等待 1.2 s | 0 / 480 | - | 1.00 注销后 kill · 等待 2.5 s | 0 / 480 | - | 1.00 注销后优雅退出 · 等待 0 s | 18 / 480 | 3.0 ~ 3.9 s | 1.00 注销后优雅退出 · 等待 1.2 s | 0 / 480 | - | 1.00 注销后优雅退出 · 等待 2.5 s | 0 / 480 | - | 1.00 注销之后 client 的缓存里还有这个实例,最长 R 秒:drain 小于 R 时,这段时间里发给它的请求落在已经停掉的实例上;drain 大于 R 之后(client 的缓存已更新)再停,就不会有请求发给它。优雅退出还解决另一件事:在途请求(0.2 s)是被处理完还是被掐断——kill 会让注销瞬间在途的请求失败
注销后要等 client 缓存更新(≥ R)再停;优雅退出让在途请求被处理完。
做法 | 错误请求 / 总数 | 错误发生的时间范围 | 平均每个请求尝试几次 --------------------------+-----------+-------------+----------- 崩溃 · 不重试 | 42 / 480 | 2.8 ~ 4.9 s | 1.00 崩溃 · 重试一次 | 1 / 480 | 2.9 ~ 2.9 s | 1.13 注销后立刻 kill · 不重试 | 22 / 480 | 2.8 ~ 3.9 s | 1.00 注销后立刻 kill · 重试一次 | 1 / 480 | 2.9 ~ 2.9 s | 1.06 注销 + 等 2.5 s + 优雅退出 · 不重试 | 0 / 480 | - | 1.00 重试把用户可见的错误降到很低,代价是对死实例多发的那些尝试(右列);最彻底的是不让请求去到死实例:先注销、等 client 缓存更新、再优雅退出,错误为 0 而且不需要重试
重试把错误降到很低,代价是多打请求;最彻底的是不让请求去到死实例。