Add experimental least-load strategy, proxy-maintained inflight counters, and instance-load debug API#118
Conversation
zhy1658858023
left a comment
There was a problem hiding this comment.
我不建议直接合并当前 PR #118,需要先清理分支并修一个策略语义问题。
主要问题:
- 分支不干净 / 包含 PR #116 内容
当前 PR 的 head 仍然是 codex/add-least_load-instance-selection-strategy,也就是 PR #116 用过的分支。compare 显示当前分支相对 main 是 diverged,behind_by=3,merge base 仍然是 PR #116 合并前的提交。因此 proxy/strategy/least_load.py、proxy/strategy/factory.py、proxy/README.md 里的 PR #116 内容又被重复包含进了 PR #118。
请从最新 origin/main 新建干净分支,例如:
codex/issue-117-proxy-instance-load-counters
然后只提交 Issue #117 的增量。PR diff 应该主要集中在:
proxy/resource/instance_pool.py
proxy/proxy.py
proxy/resource/p_control_plane.py
proxy/README.md # 如只补充 debug/load-counter 文档
除非确实需要调整策略,否则不要重新提交 PR #116 已经合并的 least_load.py / factory.py 内容。
- Proxy-maintained inflight 应该初始化所有 alive Instance,而不是只在 begin_request 后才变成 known
当前 begin_request() 会把 None 当作 0 并加 1,end_request() 会降到 0。这意味着被选中过的实例会变成已知 inflight=0,但从未被选中过的新实例仍然是 inflight=None。
而 least_load 当前会在存在任何 known inflight 的情况下,只在 known candidates 里选择。这样可能导致:
instance A 被选中过 -> inflight 变成已知 0
instance B 从未被选中过 -> inflight 仍是 unknown
least_load 后续只看 known inflight,可能一直选择 A,B 被饥饿
建议在 InstancePool.upsert() 创建新 InstanceInfo 时,把 Proxy-maintained load.inflight 初始化为 0。这样在 Proxy 已经接管 lifecycle counter 后,所有 alive Instance 都有真实的本地 inflight 值,least_load 不会把 unknown 和 known 混在一起造成偏置。
保留的好方向:
begin_request/end_request集中在InstancePool内部是对的。- chat streaming 将 decrement 放进 streaming generator lifecycle 是对的。
- completions 用
finallydecrement 是对的。 /debug/instance_loads的方向是对的。pool_resource.metric_source.inflight_total = proxy_lifecycle_counter是合理的。
请修正后再提交一个干净 PR。PR 描述里请明确:
zhy1658858023
left a comment
There was a problem hiding this comment.
我看了更新后的 PR #118,这版有进展,但仍然不建议直接合并。
已经修好的点:
InstancePool.upsert()现在会在新建 InstanceInfo 时设置load=InstanceLoad(inflight=0),已有 Instance 如果load.inflight is None也会补成0。这修掉了上轮指出的 unknown Instance 饥饿问题。begin_request()/end_request()集中在InstancePool内部维护 inflight,并且end_request()有 floor 0。- heartbeat 不再覆盖 inflight,只保留
qps_1m/gpu_util等非 lifecycle load 字段。 - chat streaming 和 completions 都接入了 begin/end 生命周期钩子。
/debug/instance_loads的方向正确。
但 PR 仍有一个关键问题:它仍然包含 PR #116 的重复 diff。
当前 PR #118 的文件列表仍包含:
proxy/strategy/least_load.py
proxy/strategy/factory.py
proxy/README.md
其中 proxy/strategy/least_load.py 和 proxy/strategy/factory.py 是 PR #116 已经实现并合并过的内容,不应该再次作为 Issue #117 的增量出现。README 里也混合了 PR #116 的策略文档和 Issue #117 的 /debug/instance_loads 文档,导致 review 边界不清楚。
请继续清理分支,目标是让 PR #118 只包含 Issue #117 的增量。理想 changed files 应该主要是:
proxy/resource/instance_pool.py
proxy/proxy.py
proxy/resource/p_control_plane.py
proxy/README.md # 只补充 inflight lifecycle / debug endpoint 文档
除非确实要微调 least_load 策略本身,否则不要让 proxy/strategy/least_load.py 和 proxy/strategy/factory.py 出现在 PR #118 的 diff 中。
建议做法:
- 从最新
origin/main新开干净分支:
codex/issue-117-proxy-instance-load-counters
-
只 cherry-pick / 重新应用 Issue #117 的增量:
InstancePool.begin_request/end_request/snapshot_instance_loadsload.inflight=0初始化proxy.py请求生命周期 begin/end hook/debug/instance_loads- README 只补充 load counter/debug endpoint 的说明
-
PR 描述里明确:
功能方向已经对了,现在主要是 PR 边界需要继续清理。
zhy1658858023
left a comment
There was a problem hiding this comment.
这一版比上一版干净很多,主要问题已经修掉了。
检查结果:
- PR 现在
mergeable=true。 - changed files 已经从 6 个降到 4 个:
proxy/resource/instance_pool.pyproxy/proxy.pyproxy/resource/p_control_plane.pyproxy/README.md
proxy/strategy/least_load.py和proxy/strategy/factory.py已经不再出现在 diff 里,PR #116 的重复策略 diff 已经被清掉。InstancePool.upsert()新建 Instance 时初始化load=InstanceLoad(inflight=0),已有 Instance 若load.inflight is None也会补为 0,解决了 unknown Instance 饥饿问题。heartbeat()不再覆盖inflight,符合 Proxy lifecycle counter 接管 inflight 的设计。begin_request()/end_request()集中在InstancePool,并且end_request()有 floor 0。- chat streaming 的 decrement 放在 generator lifecycle 的
finally里;completions 也用finally做 decrement。 /debug/instance_loads已接入,并能带 queue snapshot provider 的 per-instance queue hints。
剩余注意点:
- PR metadata 里的 body 仍然有一些旧描述,例如“Added least-load strategy implementation / Updated factory aliases”,这已经不是当前 diff 的内容了。建议更新 PR description,避免 review 时误解。
- Testing 仍写着没有自动测试。合并前建议至少在本地跑 py_compile、begin/end counter smoke test、以及
/debug/instance_loadsruntime smoke test。 - compare 仍显示分支历史是 diverged,但当前文件 diff 已经是 Issue #117 范围,且 GitHub 显示 mergeable=true。若 GitHub 页面没有强制要求 update branch,这不是 blocker。
我建议:本地 smoke test 通过后可以合并。
Motivation
inflightlifecycle counter so selection can rely on a consistent, local primary load signal rather than heartbeats alone.Description
proxy/strategy/least_load.pythat prefersload.inflightthenload.qps_1m, and falls back to round-robin usingRoundRobinStrategywhen no metrics exist.proxy/strategy/factory.pyto register theleast_loadstrategy aliases (ll,least-load).proxy/resource/instance_pool.pyto stop treatinginflightas heartbeat-maintained, addedbegin_requestandend_requestmethods to increment/decrement the Proxy-maintainedinflightcounter, and implementedsnapshot_instance_loadsto return load/debug info (including queue hints) used by strategies and debug views.proxy/proxy.pyto callbegin_requestimmediately after selecting an instance and to callend_requestat the end of request lifetime in both streaming and non-streaming paths, and to guard against the selected instance being unregistered by returning503ifbegin_requestfails./debug/instance_loadscontrol-plane endpoint inproxy/resource/p_control_plane.pythat queries the poolsnapshot_instance_loadsand optionally gathers queue-depth hints from the registered queue snapshot provider.proxy_lifecycle_countersource for inflight totals and added README documentation and CLI notes to documentleast_loadselection and debug endpoints.Testing
Codex Task