r1笔记day23 负载均衡 3

本文介绍了如何在系统中添加用户自定义的负载均衡算法,通过创建一个调度算法管理模块来管理和动态添加算法。实现了一个名为mgr的负载均衡管理类,并通过init函数注册默认算法。在main.go中使用mgr进行调用。还展示了如何实现一个自定义的调度算法并利用registerBalancer进行注册,调整DoBalance接口以接受可变长参数。文章最后提到了需要进一步梳理项目调用链和关系。
摘要由CSDN通过智能技术生成

需要添加支持用户自定义的算法,这样怎么实现呢?可以通过添加一个调度算法管理的模块,对系统提供的,自定义的调度算法进行管理。并且动态地添加支持。

实现一个支持负载均衡管理的类:(如果VSC保存时候,没有自动调整格式,那就是代码有问题了,struct初始化时候每一行需要 逗号 "," 。 不然回报错:“syntax error: unexpected newline, expecting comma or } ”。运行main.go之前,先进行go build,这样子才会去执行init函数注册到BalanceMgr里面。不然不会调用init函数。

package balance

import "fmt"

//定义一个map,动态管理所有的调度算法。定义一个map,判断是什么算法。
//value 放接口,这样可以存很多
type BalanceMgr struct {
	allBalancer map[string]Balancer
}

//对map进行初始化
var mgr = BalanceMgr{
	allBalancer: make(map[string]Balancer),
}

// func RegisterBalancer(name string, b Balancer) {}
// 给负载均衡实例添加注册方法,注册到map里面。以key:value的方式存。
//这个函数是私有的,小写
func (p *BalanceMgr) registerBalancer(name string, b Balancer) {
	p.allBalancer[name] = b
}

//通过mgr调用 registerBalancer(name string, b Balancer)
func RegisterBalancer(name string, b Balancer) {
	mgr.registerBalancer(name, b)
}

func DoBalance(name string, insts []*Instance) (inst *Instance, err error) {
	balancer, ok := mgr.allBalancer[name]
	if !ok {
		//利用fmt包中的错误格式化方法输出
		err = fmt.Errorf("Not found %s balancer", name)
		return
	}
	fmt.Printf("use %s balance\n",name)
	inst, err = balancer.DoBalance(insts)
	return
}

实现了mgr 这个调度算法的管理类,同时,系统默认的方法,通过init() 函数实现注册。

random.go 添加以下init函数
//利用init函数注册方法到mgr
func init()  {
	RegisterBalancer("random",&RandomBalance{})
}

roundrobin.go 添加以下init函数
//利用init函数注册方法到mgr
func init() {
	RegisterBalancer("randomrobin", &RandomRobinBalance{})
}

调整main.go,通过mgr实现。

package main

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

func main() {
	//[<nil> ... <nil>  0xc0000044c0...0xc0000045e0] 会出现10个nil
	//insts := make([]*balance.Instance, 10)
	var insts []*balance.Instance
	for i := 0; i < 10; i++ {
		host := fmt.Sprintf("192.168.%d.%d", rand.Intn(255), rand.Intn(255))
		one := balance.NewInstance(host, 8080)
		insts = append(insts, one)
	}

	//默认是random
	var balancerName = "random"
	//如果有输入参数,就选择输入的参数,os.Args代表用户输入参数
	if len(os.Args) > 1 {
		balancerName = os.Args[1]
	}

	for {
		//调用了mgr里面的Dobalance,这样子就实现了,指定了用什么方法,Dobalance帮忙处理
		inst, err := balance.DoBalance(balancerName, insts)
		if err != nil {
			fmt.Println("do balance rr err:", err)
			time.Sleep(1 * time.Second)
			continue
		}
		fmt.Println(inst)
		time.Sleep(1 * time.Second)
	}
}

运行结果:

#不指定参数用默认的
PS F:\go\src\go_dev\day6\homework\work02> go run .\main\main.go
RegisterBalancer random
RegisterBalancer randomrobin
use random balance
192.168.119.151:8080
use random balance
192.168.42.59:8080

#指定了参数
PS F:\go\src\go_dev\day6\homework\work02> go run .\main\main.go randomrobin
RegisterBalancer random
RegisterBalancer randomrobin
use randomrobin balance
192.168.86.132:8080
PS F:\go\src\go_dev\day6\homework\work02>

#报错的地方注意加sleep,不然会刷频,很快就会把日志打满
PS F:\go\src\go_dev\day6\homework\work02> go run .\main\main.go roundomrobin
RegisterBalancer random
RegisterBalancer randomrobin
do balance rr err: Not found roundomrobin balancer
do balance rr err: Not found roundomrobin balancer

下面,自己实现一个调度算法,利用提供的registerBalancer 进行注册。

调整DoBalance,让接口成为可以接收可变长参数的接口,接口里面的函数有点像是func type,不需要参数,直接写类型就好。

type Balancer interface {
	DoBalance([]*Instance, ...string) (*Instance, error)
}

实现一个自定义的balance:

package main

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

func init() {
	//注册random方法
	fmt.Println("RegisterBalancer hash")
	balance.RegisterBalancer("hash", &HashBalance{})
}

type HashBalance struct {
	key string
}

//一致性哈希,不同的用户对应不同的后端
func (p *HashBalance) DoBalance(insts []*balance.Instance, key ...string) (inst *balance.Instance, err error) {
	var defKey string = fmt.Sprintf("%d", rand.Int())
	if len(key) > 0 {
		defKey = key[0]
		return
	}

	lens := len(insts)

	if lens == 0 {
		err = fmt.Errorf("No backend instance")
		return
	}
	//crcTable := crc64.MakeTable(crc64.ECMA)
	crcTable := crc32.MakeTable(crc32.IEEE)
	hashVal := crc32.Checksum([]byte(defKey), crcTable)
	index := int(hashVal) % lens //int(hashVal) int64转int 会出现负数
	inst = insts[index]

	return
}

运行结果:

PS F:\go\src\go_dev\day6\homework> .\main.exe
RegisterBalancer random
RegisterBalancer randomrobin
RegisterBalancer hash
use random balance
192.168.119.151:8080
use random balance
192.168.42.59:8080

PS F:\go\src\go_dev\day6\homework> .\main.exe randomrobin
RegisterBalancer random
RegisterBalancer randomrobin
RegisterBalancer hash
use randomrobin balance
192.168.86.132:8080
use randomrobin balance
192.168.122.254:8080

PS F:\go\src\go_dev\day6\homework> .\main.exe hash
RegisterBalancer random
RegisterBalancer randomrobin
RegisterBalancer hash
use hash balance
192.168.167.131:8080
use hash balance
192.168.122.254:8080
use hash balance
192.168.88.239:8080
PS F:\go\src\go_dev\day6\homework>

本次作业文件结构如下:

F:.
├─balance
│      balance.go
│      instance.go
│      mgr.go
│      random.go
│      roundrobin.go
│
└─main
        hash.go
        main.go

main.go:

package main

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

func main() {
	//[<nil> ... <nil>  0xc0000044c0...0xc0000045e0] 会出现10个nil
	//insts := make([]*balance.Instance, 10)
	var insts []*balance.Instance
	for i := 0; i < 10; i++ {
		host := fmt.Sprintf("192.168.%d.%d", rand.Intn(255), rand.Intn(255))
		one := balance.NewInstance(host, 8080)
		insts = append(insts, one)
	}

	//默认是random
	var balancerName = "random"
	//如果有输入参数,就选择输入的参数,os.Args代表用户输入参数
	if len(os.Args) > 1 {
		balancerName = os.Args[1]
	}

	for {
		//调用了mgr里面的Dobalance,这样子就实现了,指定了用什么方法,Dobalance帮忙处理
		inst, err := balance.DoBalance(balancerName, insts)
		if err != nil {
			fmt.Println("do balance err:", err)
			time.Sleep(1 * time.Second)
			continue
		}
		fmt.Println(inst)
		time.Sleep(1 * time.Second)
	}
}

balance.go:

package balance

//定义一个接口,由具体的调度算法去实现 DoBalance([]*Instance) (*Instance, error)
type Balancer interface {
	DoBalance([]*Instance, ...string) (*Instance, error)
}

instance.go:

package balance

import "strconv"

type Instance struct {
	host string
	port int
}

//为了封装,写一个构造函数,这样instance就不需要对外暴露,也没需求
func NewInstance(host string, port int) *Instance {
	return &Instance{
		host: host,
		port: port,
	}
}

//提供访问接口
func (p *Instance) GetHost() string {
	return p.host
}

//提供访问接口
func (p *Instance) GetPort() int {
	return p.port
}

//实现String接口
func (p *Instance) String() string {
	return p.host + ":" + strconv.Itoa(p.port)
}

mgr.go:

package balance

import "fmt"

//定义一个map,动态管理所有的调度算法。定义一个map,判断是什么算法。
//value 放接口,这样可以存很多
type BalanceMgr struct {
	allBalancer map[string]Balancer
}

//对map进行初始化
var mgr = BalanceMgr{
	allBalancer: make(map[string]Balancer),
}

// func RegisterBalancer(name string, b Balancer) {}
// 给负载均衡实例添加注册方法,注册到map里面。以key:value的方式存。
//这个函数是私有的,小写
func (p *BalanceMgr) registerBalancer(name string, b Balancer) {
	p.allBalancer[name] = b
}

//通过mgr调用 registerBalancer(name string, b Balancer)
func RegisterBalancer(name string, b Balancer) {
	mgr.registerBalancer(name, b)
}

func DoBalance(name string, insts []*Instance) (inst *Instance, err error) {
	balancer, ok := mgr.allBalancer[name]
	if !ok {
		//利用fmt包中的错误格式化方法输出
		err = fmt.Errorf("Not found %s balancer", name)
		return
	}
	fmt.Printf("use %s balance\n", name)
	inst, err = balancer.DoBalance(insts)
	return
}

random.go:

package balance

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

//利用init函数注册方法到mgr,调用这个函数时候,才会执行这一步
func init() {
	//注册random方法
	fmt.Println("RegisterBalancer random")
	RegisterBalancer("random", &RandomBalance{})
}

type RandomBalance struct {
}

func (p *RandomBalance) DoBalance(insts []*Instance, key ...string) (inst *Instance, err error) {
	if len(insts) == 0 {
		err = errors.New("No instancd")
		return
	}

	lens := len(insts)
	index := rand.Intn(lens)
	inst = insts[index]
	return
}

roundrobin.go:

package balance

import (
	"errors"
	"fmt"
)

//利用init函数注册方法到mgr
func init() {
	//注册randomrobin方法
	fmt.Println("RegisterBalancer randomrobin")
	RegisterBalancer("randomrobin", &RandomRobinBalance{})
}

type RandomRobinBalance struct {
	curIndex int
}

func (p *RandomRobinBalance) DoBalance(insts []*Instance, key ...string) (inst *Instance, err error) {
	if len(insts) == 0 {
		err = errors.New("No instancd")
		return
	}

	lens := len(insts)
	if p.curIndex >= lens {
		p.curIndex = 0
	}

	inst = insts[p.curIndex]
	p.curIndex = (p.curIndex + 1) % lens //取余数方法很棒
	return
}

接下来,还需要梳理下这个项目的调用链,理清之间的关系。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值