作为一个golang n00b,我有一个go程序,它将消息读入kafka,修改它们然后将它们发布到列表中的一个http端点。
截至目前,我们随机做了一些非常基本的循环赛
…
加权随机选择有一个非常简单的算法:
package main import ( "fmt" "math/rand" ) type Endpoint struct { URL string Weight int } func RandomWeightedSelector(endpoints []Endpoint) Endpoint { // this first loop should be optimised so it only gets computed once max := 0 for _, endpoint := range endpoints { max = max + endpoint.Weight } r := rand.Intn(max) for _, endpoint := range endpoints { if r < endpoint.Weight { return endpoint } else { r = r - endpoint.Weight } } // should never get to this point because r is smaller than max return Endpoint{} } func main() { endpoints := []Endpoint{ {Weight: 1, URL: "https://web1.example.com"}, {Weight: 2, URL: "https://web2.example.com"}, } count1 := 0 count2 := 0 for i := 0; i < 100; i++ { switch RandomWeightedSelector(endpoints).URL { case "https://web1.example.com": count1++ case "https://web2.example.com": count2++ } } fmt.Println("Times web1: ", count1) fmt.Println("Times web2: ", count2) }
在可以优化的情况下,这是最天真的。绝对是生产你不应该每次都计算最大值,但除此之外,这基本上是解决方案。
这里有一个更专业和OO版本,每次都不会重新计算max:
package main import ( "fmt" "math/rand" ) type Endpoint struct { URL string Weight int } type RandomWeightedSelector struct { max int endpoints []Endpoint } func (rws *RandomWeightedSelector) AddEndpoint(endpoint Endpoint) { rws.endpoints = append(rws.endpoints, endpoint) rws.max += endpoint.Weight } func (rws *RandomWeightedSelector) Select() Endpoint { r := rand.Intn(rws.max) for _, endpoint := range rws.endpoints { if r < endpoint.Weight { return endpoint } else { r = r - endpoint.Weight } } // should never get to this point because r is smaller than max return Endpoint{} } func main() { var rws RandomWeightedSelector rws.AddEndpoint(Endpoint{Weight: 1, URL: "https://web1.example.com"}) rws.AddEndpoint(Endpoint{Weight: 2, URL: "https://web2.example.com"}) count1 := 0 count2 := 0 for i := 0; i < 100; i++ { switch rws.Select().URL { case "https://web1.example.com": count1++ case "https://web2.example.com": count2++ } } fmt.Println("Times web1: ", count1) fmt.Println("Times web2: ", count2) }
对于基于端点等待时间等度量更新权重的部分,我将创建一个不同的对象,使用此度量来更新RandomWeightedSelector对象中的权重。我认为一起实施它将违背单一责任。