dousi7919 2019-03-04 15:34
浏览 115
已采纳

不提供http时,golang客户端负载均衡器

As a golang n00b, I have a go program that reads messages into kafka, modifies them then post them to one of the http endpoints in a list.

As of now we do some really basic round robin with random

cur := rand.Int() % len(httpEndpointList)

I'd like to improve that and add weight to the endpoints based on their response time or something similar.

I've looked into libraries but all I seem to find are written to be used as middleware using http.Handle. For example see the oxy lib roundrobin

I my case I do not serve http requests per say.

Any Ideas how could I accomplish that sort of more advanced client side load balancing in my golang program ?

I'd like to avoid to use yet another haproxy or similar in my environment.

  • 写回答

1条回答 默认 最新

  • dongzhi9906 2019-03-04 21:14
    关注

    There is a very simple algorithm for weighted random selection:

    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)
    }
    

    In can be optimized, this is the most naive. Definitely for production you should not calculate max every time, but apart from that, this basically is the solution.

    Here a more profesional and OO version, that does not recompute max everytime:

    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)
    }
    

    For the part of updating weights based on a metric like endpoint latency, I would create a different object that uses this metrics to update the weights in the RandomWeightedSelector object. I think to implement it all together would be against single responsibility.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥50 树莓派安卓APK系统签名
  • ¥15 maple软件,用solve求反函数出现rootof,怎么办?
  • ¥65 汇编语言除法溢出问题
  • ¥15 Visual Studio问题
  • ¥15 state显示变量是字符串形式,但是仍然红色,无法引用,并显示类型不匹配
  • ¥20 求一个html代码,有偿
  • ¥100 关于使用MATLAB中copularnd函数的问题
  • ¥20 在虚拟机的pycharm上
  • ¥15 jupyterthemes 设置完毕后没有效果
  • ¥15 matlab图像高斯低通滤波