为了账号安全,请及时绑定邮箱和手机立即绑定

不提供 http 服务时的 golang 客户端负载均衡器

不提供 http 服务时的 golang 客户端负载均衡器

Go
慕森王 2023-06-19 11:09:45
作为一个golang n00b,我有一个 go 程序,它将消息读入 kafka,修改它们,然后将它们发布到列表中的一个 http 端点。到目前为止,我们用随机数做了一些非常基本的循环cur := rand.Int() % len(httpEndpointList)我想改进它并根据端点的响应时间或类似的东西增加端点的权重。我查看了库,但我似乎发现的所有内容都是为使用 http.Handle 用作中间件而编写的。我的情况是,我不为每个人提供 http 请求。任何想法我怎么能在我的 golang 程序中完成那种更高级的客户端负载平衡?我想避免在我的环境中使用另一个 haproxy 或类似的。
查看完整描述

1 回答

?
偶然的你

TA贡献1841条经验 获得超3个赞

有一个非常简单的加权随机选择算法:


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)

}

在可以优化的情况下,这是最幼稚的。当然对于生产你不应该每次都计算最大值,但除此之外,这基本上是解决方案。


这是一个更专业和面向对象的版本,不会每次都重新计算最大值:


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 对象中的权重。我认为一起实施它会违反单一责任。


查看完整回答
反对 回复 2023-06-19
  • 1 回答
  • 0 关注
  • 99 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信