路由策略,gRPC 路由如何实现

目录

一、为啥我们要路由策略:

二、基于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 []*SubConnInfo
   Filter  Filter
}
​
type SubConnInfo struct {
   Conn            balancer.SubConn
   Weight          int
   Group           string
   CurrentWeight   int
   EffectiveWeight int
   lock            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 := 0
   var current *SubConnInfo
   for _, v := range res {
      v.lock.Lock()
      totalWeitht += v.EffectiveWeight
      v.CurrentWeight += v.EffectiveWeight
      if current == nil || current.CurrentWeight < v.CurrentWeight {
         current = v
      }
      v.lock.Unlock()
   }
   current.lock.Lock()
   current.CurrentWeight -= totalWeitht
   current.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
}

你可能感兴趣的:(golang,后端,golang,grpc,路由,负载均衡)