7 服务发现

7.1 基本概念

  • Resolver解析器: 用于拉取服务列表
  • Balancer平衡器: 用于选择节点

7.2 常见服务发现方式

  • dns服务发现
  • etcd服务发现
  • k8s API服务发现

7.3 名字解析

7.3.1 名字数据结构

名字解析是通过scheme来选择对应的resolver。如果consumer没有选择特定的resolver,那么gRPC会默认选择dns作为解析器。 URI路径表示了一个服务名称是如何解析,如下所示:

  • dns:[//authority/]host[:port] — DNS
    • host dns的地址
    • port 服务的端口号,如果设置了非安全模式,通常默认是80端口,如果设置安全模式,默认为443端口。
  • etcd:///appname — EGO(default)
    • appname 应用名称
  • etcd:///appname:port — EGO(k8s support)
    • name 应用名称
    • port 服务的端口号

目前gRPC官方并未加入etcd名字解析的具体实现,但官方声明了会加入该实现。目前我们主要以Beego的gRPC注册方式进行讲解.

7.3.2 Resolver

gRPC组件会根据scheme选择对应的resolver,并将名字传入到resolver中。resolver会与authority保持通信,并将内容反给gRPC组件。该通信流程如下所示。 grpc library — 名字信息 —> resolver —- 密码 —-> authority authority —- 内容 —-> rosolver —- 内容 —-> grpc library

其内容如下所示:

  • 列出ip列表,并且每个ip信息里都应该有kv键值对的服务元信息。resolver可以将这些信息传入到balancer,用于负载均衡。
  • 拿到服务配置信息(用于load balance策略)

插件api应该允许resolver持续监听某个节点,并根据需要更新解析的内容。

7.4 服务配置

服务配置是允许所有的服务所有者发布自己的参数,这些参数可以自动的被客户端接收到。

7.5 负载均衡

7.5.1 背景

gRPC是不是在连接的时候进行负载均衡而是在每次调用进行负载均衡。

7.5.2 负载均衡方式

  • 代理模式 低效、延时、消耗资源
  • 客户端内负载均衡 客户端采用sdk方式,可以进行多种负载均衡策略。例如,一个客户端可以使用多种负载均衡策略(RoundRobin、Random、etc)获取服务列表。通过这种模式,客户端可以通过名字服务和外部负载均衡器,将服务列表存储在客户端内存中,客户端可以在这些列表里选择对应的服务。 这种方式的缺点是需要同时维护多语言和多版本的客户端sdk代码。例如,有的负载均衡策略需要客户端与服务端保持通信,传递元数据信息、健康信息。这就导致客户端sdk代码变得更加复杂。 所以gRPC新的设计需要隐藏多层的负载均衡的复杂性,只将服务列表提供给客户端的使用。
  • 外部负载均衡服务 该模式,只需客户端实现简单的负载均衡算法(Roundrobin),就能够选择对应服务列表。外部负载均衡服务可以提供复杂的负载均衡算法。客户端通过负载均衡器提供负的载均衡配置和服务列表,决定像哪个服务器发送请求。当服务有不可用或者健康问题,负载均衡器可以更新这些服务列表。负载均衡器会把一些复杂均衡器告诉客户端、并且还可以与服务端进行通信,得到他们的负载和健康信息。

7.6 架构方式

gRPC中负载平衡的主要机制是外部负载平衡,其中外部负载平衡器为简单的客户端提供服务器的最新列表。 gRPC客户端应该支持内置负载均衡策略,这里只有少数的内置负载均衡策略(例如grpclb是实现了外部负载均衡策略)。gRPC官方不提倡用户扩展gRPC策略,一个新的策略应该在外部均衡器进行实现。

负载平衡策略在gRPC客户端的工作流程 img.png

  • 1 启动时,gRPC客户端会发出服务器名称的名称解析请求。该名称将解析为一个或多个IP地址,每个IP地址将指示它是服务器地址还是负载平衡器地址,以及一个服务配置,该服务配置告诉了客户端要使用哪种客户端负载平衡策略(例如,round_robin或grpclb )。
  • 2 客户端实例化负载均衡策略
    • 注意:如果解析程序返回的任何地址之一是平衡器地址,则客户端将使用grpclb策略,而不管服务配置请求哪种负载平衡策略。否则,客户端将使用服务配置请求的负载平衡策略。如果服务配置未请求任何负载平衡策略,则客户端将默认为选择第一个可用服务器地址的策略。

7.7 服务配置详解