约搏三公大吃小:gRPC负载平衡(自定义负载平衡计谋)

admin 3周前 (09-14) 科技 43 2

前言

上篇文章先容了若何实现gRPC负载平衡,但现在官方只提供了pick_firstround_robin两种负载平衡计谋,轮询法round_robin不能知足因服务器设置差别而负担差别负载量,这篇文章将先容若何实现自界说负载平衡计谋--加权随机法

加权随机法可以凭据服务器的处置能力而分配差别的权重,从而实现处置能力高的服务器可负担更多的请求,处置能力低的服务器少负担请求。

自界说负载平衡计谋

gRPC提供了V2PickerBuilderV2Picker接口让我们实现自己的负载平衡计谋。

type V2PickerBuilder interface {
	Build(info PickerBuildInfo) balancer.V2Picker
}

V2PickerBuilder接口:建立V2版本的子毗邻选择器。

Build方式:返回一个V2选择器,将用于gRPC选择子毗邻。

type V2Picker interface {
	Pick(info PickInfo) (PickResult, error)
}

V2Picker 接口:用于gRPC选择子毗邻去发送请求。
Pick方式:子毗邻选择

问题来了,我们需要把服务器地址的权重添加进去,然则地址resolver.Address并没有提供权重的属性。官方给的回答是:把权重存储到地址的元数据metadata中。

// attributeKey is the type used as the key to store AddrInfo in the Attributes
// field of resolver.Address.
type attributeKey struct{}

// AddrInfo will be stored inside Address metadata in order to use weighted balancer.
type AddrInfo struct {
	Weight int
}

// SetAddrInfo returns a copy of addr in which the Attributes field is updated
// with addrInfo.
func SetAddrInfo(addr resolver.Address, addrInfo AddrInfo) resolver.Address {
	addr.Attributes = attributes.New()
	addr.Attributes = addr.Attributes.WithValues(attributeKey{}, addrInfo)
	return addr
}

// GetAddrInfo returns the AddrInfo stored in the Attributes fields of addr.
func GetAddrInfo(addr resolver.Address) AddrInfo {
	v := addr.Attributes.Value(attributeKey{})
	ai, _ := v.(AddrInfo)
	return ai
}

界说AddrInfo结构体并添加权重Weight属性,Set方式把Weight存储到resolver.Address中,Get方式从resolver.Address获取Weight

解决权重存储问题后,接下来我们实现加权随机法负载平衡计谋。

首先实现V2PickerBuilder接口,返回子毗邻选择器。

func (*rrPickerBuilder) Build(info base.PickerBuildInfo) balancer.V2Picker {
	grpclog.Infof("weightPicker: newPicker called with info: %v", info)
	if len(info.ReadySCs) == 0 {
		return base.NewErrPickerV2(balancer.ErrNoSubConnAVailABLe)
	}
	var scs []balancer.SubConn
	for subConn, addr := range info.ReadySCs {
		node := GetAddrInfo(addr.Address)
		if node.Weight <= 0 {
			node.Weight = MinWeight
		} else if node.Weight > 5 {
			node.Weight = maxWeight
		}
		for i := 0; i < node.Weight; i++ {
			scs = append(scs, subConn)
		}
	}
	return &rrPicker{
		subConns: scs,
	}
}

加权随机法中,我使用空间换时间的方式,把权重转成地址个数(例如addr1的权重是3,那么添加3个子毗邻到切片中;addr2权重为1,则添加1个子毗邻;选择子毗邻时刻,按子毗邻切片长度天生随机数,以随机数作为下标就是选中的子毗邻),制止重复盘算权重。考虑到内存占用,权重界说从15权重。

接下来实现子毗邻的选择,获取随机数,选择子毗邻

type rrPicker struct {
	subConns []balancer.SubConn
	mu sync.Mutex
}

func (p *rrPicker) Pick(balancer.PickInfo) (balancer.PickResult, error) {
	p.mu.Lock()
	index := rand.Intn(len(p.subConns))
	sc := p.subConns[index]
	p.mu.Unlock()
	return balancer.PickResult{SubConn: sc}, nil
}

要害代码完成后,我们把加权随机法负载平衡计谋命名为weight,并注册到gRPC的负载平衡计谋中。

// Name is the name of weight balancer.
const Name = "weight"
// NewBuilder creates a new weight balancer builder.
func newBuilder() balancer.Builder {
	return base.NewBalancerBuilderV2(Name, &rrPickerBuilder{}, base.Config{HealthCheck: false})
}

func init() {
	balancer.Register(newBuilder())
}

完整代码weight.go

最后,我们只需要在服务端注册服务时刻附带权重,然后客户端在服务发现时把权重Setresolver.Address中,最后客户端把负载论衡计谋改成weight就完成了。

//SetServiceList 设置服务地址
func (s *ServiceDiscovery) SetServiceList(key, val string) {
	s.lock.Lock()
	defer s.lock.Unlock()
	//获取服务地址
	addr := resolver.Address{Addr: strings.TrimPrefix(key, s.prefix)}
	//获取服务地址权重
	nodeWeight, err := strconv.Atoi(val)
	if err != nil {
		//非数字字符默认权重为1
		nodeWeight = 1
	}
	//把服务地址权重存储到resolver.Address的元数据中
	addr = weight.SetAddrInfo(addr, weight.AddrInfo{Weight: nodeWeight})
	s.serverList[key] = addr
	s.cc.UpdateState(resolver.State{Addresses: s.getServices()})
	log.Println("put key :", key, "wieght:", val)
}

客户端使用weight负载平衡计谋

func main() {
	r := etcDV3.NewserviceDiscovery(EtcdEndpoints)
	resolver.Register(r)
	// 毗邻服务器
	conn, err := grpc.Dial(
		fmt.Sprintf("%s:///%s", r.Scheme(), SerName),
		grpc.WithBalancerName("weight"),
		grpc.WithInsecure(),
	)
	if err != nil {
		log.Fatalf("net.Connect err: %v", err)
	}
	defer conn.Close()

运行效果:

运行服务1,权重为1

运行服务2,权重为4

运行客户端

查看前50次请求在服务1服务器2的负载情形。服务1分配了9次请求,服务2分配了41次请求,靠近权重比值。

约搏三公大吃小:gRPC负载平衡(自定义负载平衡计谋) 第1张

约搏三公大吃小:gRPC负载平衡(自定义负载平衡计谋) 第2张

断开服务2,所有请求流向服务1

约搏三公大吃小:gRPC负载平衡(自定义负载平衡计谋) 第3张

以权重为4,重启服务2,请求以加权随机法流向两个服务器

约搏三公大吃小:gRPC负载平衡(自定义负载平衡计谋) 第4张

总结

本篇文章以加权随机法为例,先容了若何实现gRPC自界说负载平衡计谋,以知足我们的需求

源码地址:https://github.com/Bingjian-Zhu/etcd-example

,

在线手机版下载

诚信在线(现:阳光在线官网)现已开放诚信在线手机版、诚信在线电脑客户端下载。诚信在线娱乐游戏公平、公开、公正,用实力赢取信誉。

AllBetGaming声明:该文看法仅代表作者自己,与本平台无关。转载请注明:约搏三公大吃小:gRPC负载平衡(自定义负载平衡计谋)

网友评论

  • (*)

最新评论

  • Allbet官网 2020-09-14 00:09:06 回复

    欧博代理欢迎进入欧博代理(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。好多人都看啊

    1
  • Allbet官网 2020-09-14 00:09:17 回复

    欧博代理欢迎进入欧博代理(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。好多人都看啊

    2

文章归档

站点信息

  • 文章总数:668
  • 页面总数:0
  • 分类总数:8
  • 标签总数:1130
  • 评论总数:254
  • 浏览总数:8295