Go实现负载均衡

仅仅是对Go语言接口的练习,并无实际业务代码!

  • balance.go 接口:

    1
    2
    3
    4
    5
    6
    package balance

    type Balance interface {
    DoBalance([]*Instance) (*Instance, error)
    }

  • instance.go 模拟服务器实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    package balance

    import "strconv"

    type Instance struct {
    host string
    port int
    }

    func NewInstance(host string, port int) *Instance {
    return &Instance{
    host: host,
    port: port,
    }
    }

    func (this *Instance) GetHost() string {
    return this.host
    }

    func (this *Instance) GetPort() int {
    return this.port
    }

    func (this *Instance) String() string {
    return this.host + ":" + strconv.Itoa(this.port)
    }

  • random.go 模拟负载均衡,随机算法实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    package balance

    import (
    "errors"
    "math/rand"
    "time"
    )

    type RandomBalance struct{}

    // init方法 包被引用时调用
    func init() {
    RegisterBalance("random", &RandomBalance{})
    }

    func (this *RandomBalance) DoBalance(insts []*Instance) (inst *Instance, err error) {
    lens := len(insts)
    if lens == 0 {
    err = errors.New("Instance is nil")
    return
    }
    rand.Seed(time.Now().Unix())
    index := rand.Intn(lens)
    inst = insts[index]
    return
    }

  • roundrobin.go 模拟负载均衡,轮训算法实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    package balance

    import (
    "errors"
    "fmt"
    )

    // init方法 包被引用时调用
    func init() {
    RegisterBalance("roundrobin", &RoundRobinBalance{})
    }

    type RoundRobinBalance struct {
    index int
    }

    func (this *RoundRobinBalance) DoBalance(insts []*Instance) (inst *Instance, err error) {
    lens := len(insts)
    if lens == 0 {
    err = errors.New("Instance is nil")
    return
    }

    if this.index >= lens {
    this.index = 0
    fmt.Println("一次轮训")
    }
    inst = insts[this.index]
    this.index += 1
    return
    }

  • mgr.go 对Balance接口实现的管理和注册

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    package balance

    import "fmt"

    // 声明一个BalanceMgr类型的变量,用来对外暴露注册
    var (
    mgr = BalanceMgr{
    // 这里要注意初始化BalanceMgr结构体的map
    allBalancer: make(map[string]Balance),
    }
    )

    type BalanceMgr struct {
    allBalancer map[string]Balance
    }

    // 注册实现Balance接口的结构体
    func (this *BalanceMgr) registerBalance(name string, b Balance) {
    this.allBalancer[name] = b
    }

    func RegisterBalance(name string, b Balance) {
    mgr.registerBalance(name, b)
    }

    // 调用对应name的Balance实现类,处理传入的实例slice
    func DoBalance(name string, insts []*Instance) (inst *Instance, err error) {
    b, ok := mgr.allBalancer[name]
    if !ok {
    err = fmt.Errorf("Not Fuond %s Balance", name)
    }

    inst, err = b.DoBalance(insts)
    return
    }

  • hash.go 模拟负载均衡,一致性hash,对Balance接口的实现 (golang hash值的获取方法)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    package main

    import (
    "fmt"
    "go_dev/day6/example7/balance"
    "hash/crc32"
    "math/rand"
    )

    func init() {
    balance.RegisterBalance("hash", &HashBalance{})
    }

    type HashBalance struct{}

    func (this *HashBalance) DoBalance(insts []*balance.Instance) (inst *balance.Instance, err error) {
    defKey := fmt.Sprintf("%d", rand.Int())
    lens := len(insts)
    if lens == 0 {
    err = fmt.Errorf("not backed instance")
    return
    }
    // 计算hash值
    crcTable := crc32.MakeTable(crc32.IEEE)
    hashVal := crc32.Checksum([]byte(defKey), crcTable)
    // 这里hashVal是uint32的类型 需要转成int进行取余
    index := int(hashVal) % lens
    inst = insts[index]
    return
    }

  • main.go 模拟收到请求后,进行请求的分发

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    package main

    import (
    "fmt"
    "go_dev/day6/example7/balance"
    "math/rand"
    "os"
    "time"
    )

    func main() {
    var insts []*balance.Instance
    rand.Seed(time.Now().Unix())
    // 创建一组机器实例
    for i := 0; i < 10; i++ {
    host := fmt.Sprintf("192.168.%d.%d", rand.Intn(255), rand.Intn(254)+1)
    port := 8888
    one := balance.NewInstance(host, port)
    insts = append(insts, one)
    }

    balanceName := "random"
    // 从控制台获取输入参数
    if len(os.Args) > 1 {
    balanceName = os.Args[1]
    }

    fmt.Printf("use %s balance\n", balanceName)

    // 模拟负载均衡
    for {
    inst, err := balance.DoBalance(balanceName, insts)
    if err != nil {
    fmt.Printf("do balance err:%s\n", err)
    continue
    }
    fmt.Printf("%v\n", inst)
    time.Sleep(time.Second)
    }
    }

    文章中并无实际业务代码,仅是对golang接口的练习,和对负载均衡的简单模拟