目录
一、为啥我们要路由策略:
二、基于gRPC 路由策略
一、为啥我们要路由策略:
我们可以重新回到调用方发起 RPC 调用的流程。在 RPC 发起真实请求的时候,有一个步骤就是从服务提供方节点集合里面选择一个合适的节点(就是我们常说的负载均衡),那我们是不是可以在选择节点前加上“筛选逻辑”,把符合我们要求的节点筛选出来。这就是路由
举个例子:比如我们要求新上线的节点只允许某个IP可以调用,那我们的注册中心会把这条规则下发到服务调用方。在调用方收到规则后,在选择具体节点前,会先通过筛选规则过滤节点集合,按照这个例子的逻辑,最后会过滤出一个节点。整个整个RPC 调用过程如下。
从上图可以看出路由就是从服务发现所有节点,帅选出合适节点的过程。
二、基于gRPC 路由策略
下面代码是加权轮询负载均衡算法,我们加上了Filter 对节点进行筛选,那么这个筛选的规则就是路由策略,加权轮询负载均衡算法详细解释可以参考负载均衡算法
type Filter func(info balancer.PickInfo, Group string) bool
type balanceWeightBuild struct {Filter Filter
}
func (b balanceWeightBuild) Build(info base.PickerBuildInfo) balancer.Picker {result := make([]*SubConnInfo, 0, len(info.ReadySCs))for k, v := range info.ReadySCs {weight := v.Address.Attributes.Value("weight").(string)group := v.Address.Attributes.Value("group").(string)w, _ := strconv.Atoi(weight)result = append(result, &SubConnInfo{Conn: k,Weight: w,CurrentWeight: w,EffectiveWeight: w,Group: group,})}return &balancepick{Address: result,Filter: b.Filter,}
}
type balancepick struct {Address []*SubConnInfoFilter Filter
}
type SubConnInfo struct {Conn balancer.SubConnWeight intGroup stringCurrentWeight intEffectiveWeight intlock sync.Mutex
}
func (b *balancepick) Pick(info balancer.PickInfo) (balancer.PickResult, error) {if len(b.Address) == 0 {return balancer.PickResult{}, balancer.ErrNoSubConnAvailable}if b.Filter == nil {b.Filter = func(info balancer.PickInfo, Group string) bool {return true}}res := make([]*SubConnInfo, 0, 5)for _, re := range b.Address {if !b.Filter(info, re.Group) {continue}res = append(res, re)}if len(res) == 0 {return balancer.PickResult{}, balancer.ErrNoSubConnAvailable}totalWeitht := 0var current *SubConnInfofor _, v := range res {v.lock.Lock()totalWeitht += v.EffectiveWeightv.CurrentWeight += v.EffectiveWeightif current == nil || current.CurrentWeight < v.CurrentWeight {current = v}v.lock.Unlock()}current.lock.Lock()current.CurrentWeight -= totalWeithtcurrent.lock.Unlock()return balancer.PickResult{SubConn: current.Conn,Done: func(info balancer.DoneInfo) {current.lock.Lock()if info.Err == nil && current.EffectiveWeight == math.MaxInt {current.EffectiveWeight--return}if info.Err != nil && current.EffectiveWeight == 0 {current.EffectiveWeight++return}if info.Err != nil {current.EffectiveWeight--} else {current.EffectiveWeight++}current.lock.Unlock()
},}, nil
}