fix: use weighted random pick for load balancing instead of sequential iteration

This commit is contained in:
Sakurasan
2026-09-02 17:32:12 +08:00
parent 923ac79039
commit 2e3bb22f81
+20 -2
View File
@@ -163,11 +163,29 @@ func upstreamURL(ch *store.Channel, proto, path string) string {
return ch.UpstreamURL(proto, path)
}
// doProxy 通用代理(M5):遍历候选渠道,按需转换;可安全重试的失败自动故障转移。
// doProxy 通用代理(M5):加权随机选一个候选渠道;失败自动故障转移。
func (g *Gateway) doProxy(c *gin.Context, cands []channel.Candidate, clientProto string, body []byte, stream bool, sink *usageSink) {
if len(cands) == 0 {
apiError(c, http.StatusBadGateway, "upstream_error", "no available channel")
g.recordError(c, nil, nil, now(), "no_available_channel")
return
}
// 加权随机选择起始渠道
picked := g.ch.Pick(cands)
startIdx := 0
for i, cand := range cands {
if cand.Channel.ID == picked.ID {
startIdx = i
break
}
}
var lastStatus = http.StatusBadGateway
var lastBody = []byte("all upstream channels failed")
for _, cand := range cands {
// 从选中的渠道开始遍历,到末尾后再从头遍历到选中渠道之前
for offset := 0; offset < len(cands); offset++ {
idx := (startIdx + offset) % len(cands)
cand := cands[idx]
ch := cand.Channel
plan, err := prepareUpstream(ch, clientProto, body, cand.UpstreamModel)
if err != nil {