fix: use weighted random pick for load balancing instead of sequential iteration
This commit is contained in:
@@ -163,11 +163,29 @@ func upstreamURL(ch *store.Channel, proto, path string) string {
|
|||||||
return ch.UpstreamURL(proto, path)
|
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) {
|
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 lastStatus = http.StatusBadGateway
|
||||||
var lastBody = []byte("all upstream channels failed")
|
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
|
ch := cand.Channel
|
||||||
plan, err := prepareUpstream(ch, clientProto, body, cand.UpstreamModel)
|
plan, err := prepareUpstream(ch, clientProto, body, cand.UpstreamModel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user