12. 路由

在大型的微服务系统中,我们会为同一个服务部署多个节点, 以便服务可以支持大并发的访问。它们可能部署在同一个数据中心的多个节点,或者多个数据中心中。

那么, 客户端该如何选择一个节点呢? rpcx通过 Selector来实现路由选择, 它就像一个负载均衡器,帮助你选择出一个合适的节点。rpcx提供了多个路由策略算法,你可以在创建XClient来指定。注意,这里的路由是针对 ServicePathServiceMethod的路由。

随机

  • 示例: random
  • 从配置的节点中随机选择一个节点。
  • 最简单,但是有时候单个节点的负载比较重。这是因为随机数只能保证在大量的请求下路由的比较均匀,并不能保证在很短的时间内负载是均匀的。

轮询

  • 示例: roundrobin
  • 使用轮询的方式,依次调用节点,能保证每个节点都均匀的被访问。在节点的服务能力都差不多的时候适用。

WeightedRoundRobin

  • 示例: weighted
  • 使用Nginx 平滑的基于权重的轮询算法
  • 比如如果三个节点abc的权重是{ 5, 1, 1 }, 这个算法的调用顺序是 { a, a, b, a, c, a, a }, 相比较 { c, b, a, a, a, a, a }, 虽然权重都一样,但是前者更好,不至于在一段时间内将请求都发送给a

网络质量优先

  • 示例: ping
  • 首先客户端会基于ping(ICMP)探测各个节点的网络质量,越短的ping时间,这个节点的权重也就越高。但是,我们也会保证网络较差的节点也有被调用的机会。
  • 假定t是ping的返回时间, 如果超过1秒基本就没有调用机会了:
    • weight=191 if t <= 10
    • weight=201 -t if 10 < t <=200
    • weight=1 if 200 < t < 1000
    • weight=0 if t >= 1000

一致性哈希

  • 示例: hash
  • 使用 JumpConsistentHash 选择节点, 相同的servicePath, serviceMethod 和 参数会路由到同一个节点上。 JumpConsistentHash 是一个快速计算一致性哈希的算法,但是有一个缺陷是它不能删除节点,如果删除节点,路由就不准确了,所以在节点有变动的时候它会重新计算一致性哈希。

地理位置优先

  • 示例: geo
  • 如果我们希望的是客户端会优先选择离它最新的节点, 比如在同一个机房。
  • 如果客户端在北京, 服务在上海和美国硅谷,那么我们优先选择上海的机房。
  • 它要求服务在注册的时候要设置它所在的地理经纬度。
  • 如果两个服务的节点的经纬度是一样的, rpcx会随机选择一个。
  • 比必须使用下面的方法配置客户端的经纬度信息:
    func (c *xClient) ConfigGeoSelector(latitude, longitude float64)
    

定制路由规则

  • 示例: customized
  • 如果上面内置的路由规则不满足你的需求,你可以参考上面的路由器自定义你自己的路由规则。
  • 曾经有一个网友提到, 如果调用参数的某个字段的值是特殊的值的话,他们会把请求路由到一个指定的机房。这样的需求就要求你自己定义一个路由器,只需实现实现下面的接口:
    type Selector interface {
        Select(ctx context.Context, servicePath, serviceMethod string, args interface{}) string
        UpdateServer(servers map[string]string)
    }
    
    • -Select: 定义选择算法。
    • -UpdateServer: 客户端初始化节点,并在节点更改时更新。
下一节:超时机制可以保护服务调用陷入无限的等待之中。超时定义了服务的最长等待时间,如果在给定的时间没有相应,服务调用就进入下一个状态,或者重试、或者立即返回错误。