Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

balancer: 平滑的加权轮询算法 #1

Open
flycash opened this issue Jan 21, 2024 · 3 comments
Open

balancer: 平滑的加权轮询算法 #1

flycash opened this issue Jan 21, 2024 · 3 comments

Comments

@flycash
Copy link
Contributor

flycash commented Jan 21, 2024

仅限中文

使用场景

行业分析

如果你知道有框架提供了类似功能,可以在这里描述,并且给出文档或者例子

WRR 应该算是非常常见的算法,但是在 grpc 的默认实现里面,这个算法的权重并不是服务端提供的,而是客户端自己计算的,不太适合一些基于权重的负载均衡的场景。

现在要求你提供一个基于平滑的加权轮询算法的负载均衡算法的实现。

可行方案

如果你有设计思路或者解决方案,请在这里提供。你可以提供多个方案,并且给出自己的选择

你需要考虑,对于不同的服务注册与发现的实现来说,权重可能放到了不同的地方。也就是你拿到了的 SubConnInfo 的时候,你需要设计一个抽象,允许通过不同的字段将权重读取出来。

其它

任何你觉得有利于解决问题的补充说明

你使用的是 grpx 哪个版本?

你设置的的 Go 环境?

上传 go env 的结果

@Stone-afk
Copy link

type PickerBuilder struct{}

func (p *PickerBuilder) Build(info base.PickerBuildInfo) balancer.Picker {
	conns := make([]*conn, 0, len(info.ReadySCs))
	for sc, sci := range info.ReadySCs {
		cc := &conn{cc: sc, ci: sci}
		cc.weight = cc.GetByMetadata()
		cc.currentWeight = cc.weight
		conns = append(conns, cc)
	}
	return &Picker{
		conns: conns,
	}
}

type Picker struct {
	conns []*conn
	mutex sync.Mutex
}

func (p *Picker) Pick(info balancer.PickInfo) (balancer.PickResult, error) {
	p.mutex.Lock()
	defer p.mutex.Unlock()
	if len(p.conns) == 0 {
		return balancer.PickResult{}, balancer.ErrNoSubConnAvailable
	}
	var total int
	var maxCC *conn
	for _, cc := range p.conns {
		if !cc.available {
			continue
		}
		total += cc.weight
		cc.currentWeight = cc.currentWeight + cc.weight
		if maxCC == nil || cc.currentWeight > maxCC.currentWeight {
			maxCC = cc
		}
	}
	maxCC.currentWeight = maxCC.currentWeight - total
	return balancer.PickResult{
		SubConn: maxCC.cc,
	}, nil

}

type WeightHandler interface {
	GetByMetadata() int
}

type conn struct {
	weight        int
	currentWeight int
	available     bool
	cc            balancer.SubConn
	ci            base.SubConnInfo
}

var _ WeightHandler = &conn{}

func (c *conn) GetByMetadata() int {
	md, ok := c.ci.Address.Metadata.(map[string]any)
	if !ok {
		return 10
	}
	weightVal := md["weight"]
	weight, _ := weightVal.(float64)
	return int(weight)
}

@Stone-afk
Copy link

SubConnInfo 的抽象应该不对外暴露的吧

@flycash
Copy link
Contributor Author

flycash commented Feb 23, 2024

嗯,做成私有的更加好

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: No status
Development

No branches or pull requests

2 participants