trpc.group/trpc-go/trpc-go@v1.0.3/client/README.zh_CN.md (about) 1 [English](README.md) | 中文 2 3 # tRPC-Go Client 模块 4 5 6 ## 背景 7 8 客户端通过桩代码发起 RPC 请求,请求会经过框架的 client 模块,进行服务发现,执行拦截器,序列化,压缩等,最后通过 transport 模块发送到网络中;而接收到网络响应后,会执行解压缩,反序列化,执行拦截器,最终返回响应给用户。client 模块中的每个步骤都是可以自定义的,用户可以自定义服务发现方式,自定义拦截器,自定义序列化和压缩等。 9 10 ## 客户端选项 11 12 用户可以在发起 RPC 请求的时候传入不同的客户端选项,包括请求的目的地址,网络类型等;也可以通过选项指定各个步骤的具体实现,包括服务发现方式,序列化方式等。 13 14 ```golang 15 proxy := pb.NewGreeterClientProxy() 16 rsp, err := proxy.Hello( 17 context.Background(), 18 &pb.HelloRequest{Msg: "world"}, 19 client.WithTarget("ip://127.0.0.1:9000"), // 指定 client 选项 20 ) 21 ``` 22 23 常用的选项如下: 24 25 - `WithTarget(target string)` 设置服务端地址 26 27 - `WithNetwork(network string)` 设置网络类型 28 29 - `WithNamespace(ns string)` 设置服务端命名空间(Production/Development) 30 31 - `WithServiceName(name string)` 设置服务端服务名,服务名会直接在服务发现用于寻址 32 33 - `WithTimeout(timeout time.Duration)` 设置请求的超时时间 34 35 - `WithNamedFilter(name string, f filter.ClientFilter)` 设置拦截器 36 37 - `WithSerializationType(t int)` 设置序列化类型,内置的序列化方式有 protobuf,json,flatbuffer 等,自定义序列化类型需要先使用 `codec.RegisterSerializer` 注册序列化类型 38 39 - `WithCompressType(t int)` 设置压缩类型,内置的序列化方式有 gzip,snappy,zlib 等,自定义压缩类型需要先使用 `codec.RegisterCompressor` 注册压缩类型 40 41 - `WithProtocol(s string)` 设置自定义协议类型(默认是 trpc),需要先使用 `codec.Register` 注册协议类型 42 43 ## 客户端配置 44 45 用户不仅可以在发起 RPC 请求时传入不同的选项,还可以在配置文件中添加客户端的配置。客户端选项和客户端配置的功能是部分重合的,客户端选项的优先级高于客户端配置,如果同时添加了配置和选项的话,选项中的内容会覆盖配置。使用客户端配置的优点是方便修改配置内容,不需要频繁变更代码。 46 47 ```yaml 48 client: # 客户端配置 49 timeout: 1000 # 所有请求最长处理时间(ms) 50 namespace: Development # 所有请求服务端的环境 51 filter: # 所有请求的拦截器 52 - debuglog # 使用 debuglog 打印具体请求和响应数据 53 service: # 请求特定服务端的配置 54 - callee: trpc.test.helloworld.Greeter # 请求服务端协议文件的 service name, 如果 callee 和下面的 name 一样,那只需要配置其中之一即可 55 name: trpc.test.helloworld.Greeter1 # 请求服务名字路由的 service name 56 target: ip://127.0.0.1:8000 # 服务端地址,如果 name 可以直接用作服务发现,则可以不用配置,例如 ip://ip:port, polaris://servicename 57 network: tcp # 请求的网络类型 tcp udp 58 protocol: trpc # 应用层协议 trpc http 59 timeout: 800 # 请求超时时间(ms) 60 serialization: 0 # 序列化方式 0-pb 2-json 3-flatbuffer,默认不用配置 61 compression: 1 # 压缩方式 1-gzip 2-snappy 3-zlib,默认不用配置 62 ``` 63 64 配置中的 `callee` 和 `name` 的区别: 65 66 **`callee` 是指被调方的 pb 协议文件的 service name**,格式是 `pbpackage.service`。 67 68 如 pb 为: 69 70 ```protobuf 71 package trpc.a.b; 72 service Greeter { 73 rpc SayHello(request) returns reply 74 } 75 ``` 76 77 那么 `callee` 即为 `trpc.a.b.Greeter` 78 79 **`name` 是指被调方注册在名字服务上面的服务名**,也就是被调服务配置文件里面的 `server.service.name` 的字段值。 80 81 一般情况下,`callee` 和 `name` 是相同的,只需配置其中任何一个即可,但是有些场景下,如存储服务,同一份 pb 会部署多个实例,这个时候的名字服务的 service name 和 pb service name 就不一样了,此时配置文件就必须同时配置 `callee` 和 `name` 82 83 ```yaml 84 client: 85 service: 86 - callee: pbpackage.service # 必须同时配置 callee 和 name,callee 是 pb 的 service name,用于匹配 client proxy 和配置 87 name: polaris-service-name # 名字服务的 service name,用于寻址 88 protocol: trpc 89 ``` 90 91 通过 pb 生成的 client 桩代码,默认会把 pb servicename 填入到 client 中,所以 client 寻找配置时只会 `以 callee 为 key`(也就是 pb 的 service name)来匹配 92 93 而通过类似 `redis.NewClientProxy("trpc.a.b.c")` 等(包括 database 下面所有插件以及 http)生成的 client,默认 service name 就是用户自己输入的字符串,所以 client 寻找配置时**以 NewClientProxy 的输入参数为 key**(即以上的 `trpc.a.b.c`)来匹配 94 95 同时,框架还支持了同时以 `callee` 及 `name` 为 key 来寻找配置,比如以下两个客户端配置共享了相同的 `callee`, 但是 `name` 不同: 96 97 ```yaml 98 client: 99 service: 100 - callee: pbpackage.service # callee 是 pb 的 service name 101 name: polaris-service-name1 # 名字服务的 service name,用于寻址 102 network: tcp # 使用 TCP 103 - callee: pbpackage.service # callee 是 pb 的 service name 104 name: polaris-service-name2 # 另一个名字服务的 service name,用于寻址 105 network: udp # 使用 UDP 106 ``` 107 108 用户在代码中可以使用 `client.WithServiceName` 来同时用 `called` 以及 `name` 作为 key 进行配置的寻找: 109 110 ```golang 111 // proxy1 使用第一项配置,使用 TCP 112 proxy1 := pb.NewClientProxy(client.WithServiceName("polaris-service-name1")) 113 // proxy2 使用第二项配置,使用 UDP 114 proxy2 := pb.NewClientProxy(client.WithServiceName("polaris-service-name2")) 115 ``` 116 117 ## 客户端调用流程 118 119 1. 用户传入请求,在使用桩代码发起 RPC 调用 120 2. 进入 client 模块 121 3. 根据配置的 option 和配置文件信息完成客户端配置 122 4. 进行服务发现,根据服务名获取服务真实地址 123 5. 调用拦截器,执行拦截器前置阶段 124 6. 序列化请求体,得到二进制数据 125 7. 压缩请求体 126 8. 打包完整请请求,添加协议头 127 9. transport 模块发起网络请求 128 10. transport 模块接收网络响应 129 11. 解包响应,得到协议头和响应体 130 12. 解压响应体 131 13. 反序列化响应,得到响应结构 132 14. 调用拦截器,执行拦截器后置阶段 133 15. 将响应返回给用户