trpc.group/trpc-go/trpc-go@v1.0.3/naming/README.zh_CN.md (about)

     1  [English](README.md) | 中文
     2  
     3  ## 背景
     4  
     5  名字服务模块可以将节点注册到对应的服务名下。注册信息除了 `ip:port` 外,还会包含运行环境、容器以及其他自定义的元数据信息。调用方根据服务名获取到所有节点后,路由模块再根据元数据信息对节点进行筛选,最后,负载均衡算法从满足要求的节点中选出一个节点来进行最终请求。名字提供了服务管理的统一抽象,避免了直接使用 `ip:port` 带来的运维困难。
     6  
     7  在 tRPC-Go 中,`register` 包定义了服务端的注册规范,`discovery`、`servicerouter`、`loadbalance`、`circuitebreaker` 则一起组成 `slector` 包并定义了客户端的服务发现规范。
     8  
     9  ## 原理
    10  
    11  先来看下naming的整体设计:
    12  
    13  ![naming design](/.resources/naming/naming.png)
    14  
    15  结合上图,我们来简单介绍下大致的设计、实现。
    16  
    17  ## 实现
    18  
    19  ### Discovery
    20  
    21  Discovery 定义了服务发现类的通用接口,基于给定的服务名返回服务的地址列表。
    22  
    23  Discovery 支持业务自定义实现。框架默认提供一个基于配置文件指定返回 ip 列表的 IpDiscovery。
    24  
    25  ### Node
    26  
    27  Node 定义了单个服务节点的数据结构。
    28  
    29  ### Registry
    30  
    31  Registry 定义了服务注册的通用接口,支持业务自定义实现 `Register`、`Deregister`。
    32  
    33  ### LoadBalancer
    34  
    35  LoadBalancer 定义了负载均衡类的通用接口,从一组节点中选一个节点出来。
    36  
    37  trpc-go 默认提供了轮询和加权轮询算法的负载均衡实现。业务可以自定义实现其他负载均衡算法。
    38  
    39  - [一致性哈希](/naming/loadbalance/consistenthash)
    40  - [轮询](/naming/loadbalance/roundrobin)
    41  - [加权轮询](/naming/loadbalance/weightroundrobin)
    42  
    43  ### ServiceRouter
    44  
    45  ServiceRouter 定义了对服务Node列表做路由过滤的接口。 例如根据Set配置路由、Namespace/Env环境路由等。
    46  
    47  ### Selector
    48  
    49  Selector 提供通过服务名获取一个服务节点的通用接口。Selector 调用了服务发现,负载均衡,熔断隔离,可以说是这些能力的一个组装。
    50  
    51  tRPC-Go 提供了 selector 的默认实现,使用默认的服务发现、负载均衡和熔断器。详见:[./selector/trpc_selector.go](/naming/selector/trpc_selector.go)
    52  
    53  默认 selector 逻辑: Discovery->ServiceRouter->LoadBalance->Node->业务使用->CircuitBreaker.Report
    54  
    55  ### CircuitBreaker
    56  
    57  CircuitBreaker 提供了判断服务节点是否可用的通用接口,同时提供上报当前服务节点成功/失败的能力。
    58  
    59  ### 如何使用
    60  
    61  tRPC-Go 支持[北极星](https://github.com/trpc-ecosystem/go-naming-polarismesh),可以根据服务名进行服务发现。假如业务方在调用时需要设置 Target,会根据 target 的 endpoint 去进行服务发现。
    62  
    63  ```go
    64  client.WithTarget(fmt.Sprintf("%s://%s", exampleScheme, exampleServiceName)),
    65  ```
    66  
    67  
    68  Target 是后端服务地址 ,格式为 `name://endpoint`。比如,`ip://127.0.0.1:80` 会直接按 `ip:port` 访问 `127.0.0.1:80`;`polaris://service_name` 会通过北极星插件对服务名 `service_name` 进行寻址。
    69  
    70  下面例子给出了一个业务自定义的服务发现的实现。
    71  
    72  1、实现 Selector 接口
    73  
    74  ```go
    75  type exampleSelector struct{}
    76  // Select 通过 service name 获取一个后端节点
    77  func (s *exampleSelector) Select(serviceName string, opt ...selector.Option) (*registry.Node, error) {
    78      fmt.Println(serviceName)
    79      if serviceName == exampleServiceName {
    80          return &registry.Node{
    81              Address: "127.0.0.1:8000",
    82          }, nil
    83      }
    84      return nil, errors.New("no available node")
    85  }
    86  // Report 上报当前请求成功或失败
    87  func (s *exampleSelector) Report(node *registry.Node, cost time.Duration, success error) error {
    88      return nil
    89  }
    90  ```
    91  
    92  2、注册自定义 selector
    93  
    94  ```go
    95  var exampleScheme = "example"
    96  func init() {
    97      selector.Register(exampleScheme, &exampleSelector{})
    98  }
    99  ```
   100  
   101  3、设置服务名
   102  
   103  ```go
   104  var exampleServiceName = "selector.example.trpc.test"
   105  client.WithTarget(fmt.Sprintf("%s://%s", exampleScheme, exampleServiceName))
   106  ```
   107  
   108  
   109  具体可参考 [selector demo](/examples/features/selector)。