trpc.group/trpc-go/trpc-go@v1.0.3/docs/user_guide/client/overview.md (about) 1 English | [中文](overview.zh_CN.md) 2 3 tRPC-Go Client Development Guide 4 5 6 # Introduction 7 8 The tRPC-Go framework and plugins provide interface calls for services, allowing users to call downstream services as if they were calling local functions without worrying about the underlying implementation details. This article first introduces the capabilities that the framework can provide for service calls and the means that users can use to control the behavior of each link in the service call by sorting out the entire processing flow of service calls. Next, this article will explain how to develop and configure a client call from key links such as service calls, configuration, addressing, interceptors, and protocol selection. The article will provide development guidance for typical scenarios of service calls, especially for scenarios where the program serves as both a server and a client. 9 10 # Framework Capabilities 11 12 This section first introduces the types of service calls supported by the framework. Then, by sorting out the entire processing flow of service calls, we can understand what capabilities the framework provides for service calls and which key link behaviors can be customized. This provides a knowledge foundation for the development of clients later. 13 14 ## Call Types 15 16 The tRPC-Go framework provides multiple types of service calls. We roughly divide service calls into four categories according to the protocol: built-in protocol calls, third-party protocol calls, storage protocol calls, and message queue producer calls. The interfaces for calling these protocols are all different. For example, the tRPC protocol provides a service interface defined by PB files, and the interface provided by MySQL is "query(), exec(), transaction()". When developing a client, users need to refer to the protocol documentation to obtain interface information. You can refer to the following development guide documents: 17 18 **Built-in protocols**: 19 tRPC-Go provides service calls for the following built-in protocols: 20 21 - [Calling the tRPC service](/docs/quick_start.md) 22 23 **Third-party protocols**: 24 tRPC-Go provides a rich set of protocol plugins for clients to integrate with third-party protocol services. At the same time, the framework also supports user-defined protocol plugins. For protocol plugin development, please refer to [here](/docs/developer_guide/develop_plugins/protocol.md). Common third-party protocols refer to [trpc-ecosystem/go-codec](https://github.com/trpc-ecosystem/go-codec). 25 26 **Storage protocols**: 27 tRPC-Go encapsulates access to common databases by performing database operations through service access. For details, please refer to [tRPC-Go call the Storage Service](/docs/developer_guide/develop_plugins/storage.md)。 28 29 **Message Queue**: 30 tRPC-Go encapsulates the producer operations of common message queues by producing messages through service access. 31 32 - [kafka](https://github.com/trpc-ecosystem/go-database/tree/main/kafka) 33 34 Although the interfaces for calling each protocol are different, the framework adopts a unified service call process, allowing all service calls to reuse the same service governance capabilities, including interceptor, service addressing, monitoring reporting, and other capabilities. 35 36 ## Calling Flow 37 38 Next, let's take a look at what a complete service call process looks like. The following figure shows the entire process from when the client initiates a service call request to when it receives a service response. The first row from left to right represents the process of the service request. The second row from right to left represents the process of the client processing the service response message. 39 40 ![call_flow](/.resources/user_guide/client/overview/call_flow.png) 41 42 The framework provides a service call proxy (also known as "ClientProxy") for each service, which encapsulates the interface functions ("stub functions") of the service call, including the input parameters, output parameters, and error return codes of the interface. From the user's perspective, calling the stub function is the same as calling a local function. 43 44 As described in the tRPC framework overview, the framework adopts the idea of interface-based programming. The framework only provides standard interfaces, and plugins implement specific functions. As can be seen from the flowchart, the core process of service calls includes interceptor execution, service addressing, protocol processing, and network connection. Each part is implemented through plugins, and users need to select and configure plugins to complete the entire call process. 45 46 Users can choose and configure plugins through the framework configuration file and Option function options. At the same time, the framework also supports users to develop plugins to customize service call behavior. Interceptors are the most typical use case, such as custom interceptors to implement service call authentication and authorization, call quality monitoring and reporting, etc. 47 48 Service addressing is a very important part of the service call process. The addressing plugin (selector) provides service instance strategy routing selection, load balancing, and circuit breaker processing capabilities in scenarios where services are used on a large scale. It is a part that needs special attention in client development. 49 50 ## Governance Capabilities 51 52 In addition to providing interface calls for various protocols, tRPC-Go also provides rich service governance capabilities for service calls, realizing integration with service governance components. Developers only need to focus on the business logic itself. The framework can implement the following service governance capabilities through plugins: 53 54 - Service addressing 55 - [Timeout control](/docs/user_guide/timeout_control.md) 56 - [Filter mechanism](/docs/developer_guide/develop_plugins/interceptor.md), implementing functions such as tracing, monitoring, [retry hedging](https://github.com/trpc-ecosystem/go-filter/tree/main/slime), etc. 57 - [Remote logging](/log/README.md) 58 - [Configuration center](/config/README.md) 59 - ... 60 61 # Client Development 62 63 This section mainly explains from the perspective of code development how to initialize the client, how to call service interfaces, and how to control the behavior of service calls through parameter configuration. 64 65 ## Development Modes 66 67 Client development is mainly divided into the following two modes: 68 69 - Mode 1: The program serves as both a server and a client. tRPC-Go service calls downstream client requests are the most common scenario. 70 - Mode 2: Non-service pure client small tools requests, commonly used in the development and operation and maintenance of small tools scenarios. 71 72 ### Service Calls Client Internally 73 74 For Mode 1, when creating and starting the service, the framework configuration file will be read, and the initialization of all configured plugins will be automatically completed in trpc.NewServer(). The code example is as follows: 75 76 ```go 77 import ( 78 "trpc.group/trpc-go/trpc-go/errs" 79 // The Git address for the generated protocol file pb.go of the called service and the protocol interface management can be found here: todo 80 pb "github.com/trpcprotocol/app/server" 81 ) 82 83 // SayHello is the entry function for server requests. Generally, client calls are made within a service to call downstream services 84 // SayHello carries ctx information, and when calling downstream services within this function, ctx needs to be passed through all the way 85 func (s *greeterServerImpl) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloReply, error) { 86 // Create a client call proxy. This operation is lightweight and does not create a connection. It can be created for each request or a global proxy can be initialized. It is recommended to put it in the service impl struct for easy mock testing. For detailed demos, please refer to the framework source code examples/helloworld. 87 proxy := pb.NewGreeterClientProxy() 88 // In normal cases, do not specify any option parameters in the code. Use configuration for greater flexibility. If you specify options, the options have the highest priority 89 reply, err := proxy.SayHi(ctx, req) 90 if err != nil { 91 log.ErrorContextf(ctx, "say hi fail:%v", err) 92 return nil, errs.New(10000, "xxxxx") 93 } 94 return &pb.HelloReply{Xxx: reply.Xxx} nil 95 } 96 97 func main(){ 98 // Create a service object, which will automatically read the service configuration and initialize the plugins. It must be placed at the beginning of the main function. The business initialization logic must be placed after NewServer 99 s := trpc.NewServer() 100 // Register the current implementation to the service object 101 pb.RegisterService(s, &greeterServerImpl{}) 102 // Start the service and block here 103 if err := s.Serve(); err != nil { 104 panic(err) 105 } 106 } 107 ``` 108 109 ### Pure Small Client Tools 110 111 For Mode 2, client small tools do not have configuration files and need to set options to initiate backend calls. Also, there is no ctx, so trpc.BackgroundContext() must be used. Since there is no initialization of plugins through configuration files, some addressing methods need to be manually registered, such as the North Star. The code sample is as follows: 112 113 ```go 114 import ( 115 "trpc.group/trpc-go/trpc-go/client" 116 pb "github.com/trpcprotocol/app/server" 117 pselector "trpc.group/trpc-go/trpc-naming-polarismesh/selector" // You need to import the required naming service plugin code yourself 118 trpc "trpc.group/trpc-go/trpc-go" 119 ) 120 121 // Generally, small tools start from the main function 122 func main { 123 // Since there is no configuration file to help initialize the plugin, you need to manually initialize the North Star 124 pselector.RegisterDefault() 125 // Create a client call proxy 126 proxy := pb.NewGreeterClientProxy() 127 // You must create ctx yourself through trpc.BackgroundContext() and pass in option parameters through code. 128 rsp, err := proxy.SayHi(trpc.BackgroundContext(), req, client.WithTarget("ip://ip:port")) 129 if err != nil { 130 log.Errorf("say hi fail:%v", err) 131 return 132 } 133 return 134 } 135 ``` 136 137 Actually, most small tools can be executed using the timer mode, so it is recommended to use the timer to implement them and execute the tools in Mode 1. This way, all server functions will be automatically equipped. 138 139 ## Interface Call 140 141 In the client, the framework defines a "ClientProxy" for each service, which provides stub functions for service invocation. Users can call the stub functions just like calling ordinary functions. The proxy is a lightweight structure that does not create any connection or other resources internally. The proxy call is thread-safe, and users can initialize a global proxy for each service or generate a proxy for each service call. 142 143 For different protocols, the services they provide are different. Users need to refer to the client development documentation of their respective protocols during the specific development process (see the Service Type section). Although the definitions of the interfaces are different, they all have common parts: "ClientProxy" and "Option function options". Based on the protocol type and the way the stub code is generated, they are divided into two categories: "IDL type service invocation" and "non-IDL type service invocation". 144 145 **1. IDL type service call** 146 147 For IDL-type services (such as tRPC services and generic HTTP RPC services), tools are usually used to generate client stub functions, including "ClientProxy creation function" and "interface invocation function". The function definition is roughly as follows: 148 149 ```go 150 // Initialization function of ClientProxy. 151 var NewHelloClientProxy = func(opts ...client.Option) HelloClientProxy{...} 152 153 // Service interface definition. 154 type HelloClientProxy interface { 155 SayHello(ctx context.Context, req *HelloRequest, opts ...client.Option) (rsp *HelloReply, err error) 156 } 157 ``` 158 159 The stub code provides users with the ClientProxy creation function, service interface function, and corresponding parameter definitions. Users can use these two sets of functions to call downstream services. The interface call is completed using synchronous calls. The option parameter can configure the behavior of the service call, which will be introduced in later sections. An example of a complete service call is as follows: 160 161 ```go 162 import ( 163 "context" 164 165 "trpc.group/trpc-go/trpc-go/client" 166 "trpc.group/trpc-go/trpc-go/log" 167 pb "github.com/trpcprotocol/test/helloworld" 168 ) 169 170 func main() { 171 // Create ClientProxy. 172 proxy := pb.NewGreeterClientProxy() 173 // Fill in the request parameters. 174 req := &pb.HelloRequest{Msg: "Hello, I am tRPC-Go client."} 175 // Call the service request interface. 176 rsp, err := proxy.SayHello(context.Background(), req, client.WithTarget("ip://127.0.0.1:8000")) 177 if err != nil { 178 return 179 } 180 // Get the request response data. 181 log.Debugf("response: %v", rsp) 182 } 183 ``` 184 185 **2. non-IDL type service call** 186 187 For non-IDL type services, the "ClientProxy" is also used to encapsulate the service invocation interface. The ClientProxy creation function and interface invocation function are usually provided by the protocol plugin. Different plugins have slightly different encapsulations of functions, and developers need to follow the usage documentation of their respective protocols. Taking the generic HTTP standard service as an example, the interface is defined as follows: 188 189 ```go 190 // NewClientProxy creates a new ClientProrxy, with the http service name as a required parameter 191 var NewClientProxy = func(name string, opts ...client.Option) Client 192 193 // Generic HTTP standard service, providing four common interfaces: get, put, delete, and post 194 type Client interface { 195 Get(ctx context.Context, path string, rspbody interface{}, opts ...client.Option) error 196 Post(ctx context.Context, path string, reqbody interface{}, rspbody interface{}, opts ...client.Option) error 197 Put(ctx context.Context, path string, reqbody interface{}, rspbody interface{}, opts ...client.Option) error 198 Delete(ctx context.Context, path string, reqbody interface{}, rspbody interface{}, opts ...client.Option) error 199 } 200 ``` 201 202 An example of a complete service call is as follows: 203 204 ```go 205 import ( 206 "trpc.group/trpc-go/trpc-go/client" 207 "trpc.group/trpc-go/trpc-go/codec" 208 "trpc.group/trpc-go/trpc-go/http" 209 ) 210 211 func main() { 212 // Create ClientProxy 213 httpCli := http.NewClientProxy("trpc.http.inews_importable", 214 client.WithSerializationType(codec.SerializationTypeForm)) 215 // Fill in the request parameters 216 req := url.Values{} // Set form parameters 217 req.Add("certify", "1") 218 req.Add("clientIP", ip) 219 // Call the service request interface 220 rsp: = &A{} 221 if err := httpCli.Post(ctx, "/i/getUserUid", req, rsp); err != nil { 222 return 223 } 224 // Get the request response data 225 log.Debugf("response: %v", rsp) 226 } 227 ``` 228 229 ## Option 230 231 The tRPC-Go framework provides two levels of Option function options to set Client parameters, which are "ClientProxy-level configuration" and "interface invocation-level configuration". The Option implementation uses the Functional Options Pattern design pattern. Option configuration is usually used as a pure client-side tool. 232 233 ```go 234 // ClientProxy-level Option setting, the configuration takes effect every time the clientProxy is used to call the service. 235 clientProxy := NewXxxClientProxy(option1, option2...) 236 // Interface invocation-level Option setting, the configuration only takes effect for this service call. 237 rsp, err := proxy.SayHello(ctx, req, option1, option2...) 238 ``` 239 240 For scenarios where the program is both a server and a client, the system recommends using the framework configuration file to configure the Client. This can achieve decoupling of configuration and program, and facilitate configuration management. For scenarios where Option and configuration files are used in combination, the priority of configuration settings is: `interface invocation-level Option` > `ClientProxy-level Option` > `framework configuration file`. 241 242 The framework provides rich Option parameters. This article focuses on some configurations that are often used in development. 243 244 **1. We can set the protocol, serialization type, compression method, and service address of the service using the following parameters:** 245 246 ```go 247 proxy.SayHello(ctx, req, 248 client.WithProtocol("http"), 249 client.WithSerializationType(codec.SerializationTypeJSON), 250 client.WithCompressType(codec.CompressTypeGzip), 251 client.WithTLS(certFile, keyFile, caFile, serverName), 252 client.WithTarget("ip://127.0.0.1:8000")) 253 ``` 254 255 **2. We can get the call address of the downstream called service using the following parameters:** 256 257 ```go 258 node := ®istry.Node{} 259 proxy.SayHello(ctx, req, client.WithSelectorNode(node)) 260 ``` 261 262 **3. We can set the pass-through information using the following parameters:** 263 264 ```go 265 proxy.SayHello(ctx, req, client.WithMetaData(version.Header, []byte(version.Version))) 266 ``` 267 268 **4. We can get the pass-through information returned by the downstream service using the following parameters:** 269 270 ```go 271 trpcRspHead := &trpc.ResponseProtocol{} // Different protocols correspond to different head structures 272 proxy.SayHello(ctx, req, client.WithRspHead(trpcRspHead)) 273 // trpcRspHead.TransInfo is the pass-through information returned by the downstream service 274 ``` 275 276 **5. We can set the service call to be a one-way call using the following parameters:** 277 278 ```go 279 proxy.SayHello(ctx, req, client.WithSendOnly()) 280 ``` 281 282 ## Commonly Used APIs 283 284 tRPC-Go uses GoDoc to manage the tRPC-Go framework API documentation. By consulting the [tRPC-Go API documentation](https://pkg.go.dev/github.com/trpc.group/trpc-go), you can obtain the interface specifications, parameter meanings, and usage examples of the APIs. 285 286 For log, metrics, and config, the framework provides standard calling interfaces. Service development can only interface with the service governance system by using these standard interfaces. For example, for logs, if the standard log interface is not used and "fmt.Printf()" is used directly, log information cannot be reported to the remote log center. 287 288 ## Error codes 289 290 tRPC-Go has planned the data type and meaning of error codes, and has also explained the problem of common error codes. Please refer to the [tRPC-Go error code manual](/docs/user_guide/error_codes.md) for details. 291 292 # Client Configuration 293 294 The client configuration can be configured through the "client" section in the framework configuration file, and the configuration is divided into "global service configuration" and "specified service configuration". For the specific meanings, value ranges, and default values of the configuration, please refer to [tRPC-Go Framework Configuration](/docs/user_guide/framework_conf.md)。 295 296 The following is a typical example of client configuration: 297 298 ```yaml 299 client: # Client-side backend configuration 300 timeout: 1000 # The longest processing time for requests for all backends, in ms 301 namespace: Development # The environment for all backends, Production for production environment, Development for testing environment 302 filter: # An array of interceptor configurations for all backends 303 - debuglog # It is strongly recommended to use this debuglog to print logs, which is very convenient for troubleshooting. For details, please refer to: https://github.com/trpc-ecosystem/go-filter/tree/main/debuglog 304 service: # Configuration for a single backend, default values are available and can be completely unconfigured 305 - callee: trpc.test.helloworld.Greeter # The service name of the backend service protocol file. If callee is the same as the name below, only one needs to be configured 306 name: trpc.test.helloworld.Greeter1 # The service name of the backend service name routing. If it is registered with the Polaris name service, the target below does not need to be configured 307 target: ip://127.0.0.1:8000 # The address of the backend service, ip://ip:port polaris://servicename 308 network: tcp # The network type of the backend service, tcp udp, default tcp 309 protocol: trpc # Application layer protocol trpc http..., default trpc 310 timeout: 800 # The longest processing time for the current request, default 0 is not timed out 311 serialization: 0 # Serialization method 0-pb 1-jce 2-json 3-flatbuffer, do not configure by default 312 compression: 1 # Compression method 1-gzip 2-snappy 3-zlib, do not configure by default 313 filter: # An array of interceptor configurations for a single backend 314 - debug # Only use debuglog for the current backend 315 ``` 316 317 The configuration items that need to be focused on are: 318 319 **1. The difference between "callee" and "name":** 320 321 "Callee" represents the Proto Service of the downstream service, in the format of "{package}.{proto service}". "Name" represents the Naming Service of the downstream service, used for service addressing. 322 323 According to the tRPC-Go development specification, in most cases, "callee" and "name" are the same, and users can only configure "name". For the scenario where a Proto Service is mapped to multiple Naming Services, users need to set both "callee" and "name". 324 325 **2. Setting of "target":** 326 327 tRPC-Go provides two sets of addressing configurations: "Naming Service-based addressing" and "Target-based addressing". The "target" configuration can be left unconfigured, and the framework defaults to using name addressing. When "target" is configured, the framework will use Target-based addressing. The format of "target" is:`selector://service_identifier`, such as `ip://127.0.0.1:1000`. 328 329 **3. Configuration of the protocol** 330 331 The configuration of the service protocol mainly includes the fields of "network", "protocol", "serialization", and "compression". "Network" and "protocol" should be based on the server configuration. 332 333 **4. Configuration of TLS** 334 335 For the tRPC protocol, the https, http2, and http3 protocols all support TLS configuration. A typical TLS configuration example is as follows: 336 337 ```yaml 338 client: 339 service: # Service of the downstream service 340 - name: trpc.test.helloworld.Greeter # Routing name of the service 341 network: tcp # Network listening type tcp udp 342 protocol: trpc # Application layer protocol trpc http 343 timeout: 1000 # The longest processing time for requests, in milliseconds 344 tls_key: client.pem # Client key file address path. The key file should not be directly submitted to git. It should be pulled from the configuration center and stored locally at the specified path when the program starts. 345 tls_cert: client.cert # Client certificate file address path 346 ca_cert: ca.cert # CA certificate file address path, used to verify the server certificate, call the TLS service, such as https server 347 tls_server_name: xxx # Client verifies the server service name. When calling https, it defaults to hostname 348 ``` 349 350 For pure client tools, it needs to be specified through options: 351 352 353 ```go 354 proxy.SayHello(ctx, req, client.WithTLS(certFile, keyFile, caFile, serverName)) 355 ``` 356 357 **5. Configuration of Filter** 358 359 The framework supports two-level filter configuration: global configuration and single service configuration, and the execution priority is: global setting > single service configuration. If there are duplicate filter between the two, only the one with the highest priority will be executed. A specific example is as follows: 360 361 ```yaml 362 client: # Client-side backend configuration 363 timeout: 1000 # The longest processing time for requests for all backends, in ms 364 namespace: Development # The environment for all backends, Production for production environment, Development for testing environment 365 filter: # An array of filter configurations for all backends 366 - debuglog # debuglog prints logs 367 service: # Configuration for a single backend, default values are available and can be completely unconfigured 368 - name: trpc.test.helloworld.Greeter1 # The service name of the backend service name routing. If it is registered with the Polaris name service, the target below does not need to be configured 369 network: tcp # The network type of the backend service, tcp udp, default tcp 370 protocol: trpc # Application layer protocol trpc http tars oidb ..., default trpc 371 timeout: 800 # The longest processing time for the current request, default 0 is not timed out 372 filter: # An array of filter configurations for a single backend 373 - debuglog 374 ``` 375 376 # Service Addressing 377 378 Service addressing is a very important part of service invocation. The framework implements service discovery, strategy routing, load balancing, and circuit breakers through plugins. The framework does not include any specific implementation, and users can introduce corresponding plugins as needed. Many functions of service addressing are closely related to the functions provided by the naming service. Users need to combine the naming service documentation and the corresponding plugin documentation to obtain detailed information. The following descriptions in this section are based on the Polaris plugin. 379 380 ## Namespace and Environment 381 382 The framework uses two concepts, namespace and env_name, to implement the isolation of service invocation. Namespace is usually used to distinguish between production and non-production environments, and services in two namespaces are completely isolated. env_name is only used in non-production environments to provide users with personal test environments. 383 384 The system recommends setting the client's namespace and env_name through the framework configuration file, and using the client's namespace and env_name by default when calling services. 385 386 ```yaml 387 global: 388 # Required, usually use Production or Development 389 namespace: String 390 # Optional, environment name 391 env_name: String 392 ``` 393 394 The framework also supports specifying the namespace and env_name of the service when calling the service. We call it specified environment service invocation. Specified environment service invocation requires turning off the service routing function (which is turned on by default). It can be set through the Option function: 395 396 ```go 397 opts := []client.Option{ 398 // Namespace, if not filled in, the namespace of the environment where this service is located is used by default 399 client.WithNamespace("Development"), 400 // Service name 401 client.WithServiceName("trpc.test.helloworld.Greeter"), 402 // Set the environment of the called service 403 client.WithCalleeEnvName("62a30eec"), 404 // Turn off service routing 405 client.WithDisableServiceRouter() 406 } 407 ``` 408 409 It can also be set through the framework configuration file: 410 411 ```yaml 412 client: # Client-side backend configuration 413 namespace: Development # The environment for all backends 414 service: # Configuration for a single backend 415 - name: trpc.test.helloworld.Greeter1 # The service name of the backend service name routing 416 disable_servicerouter: true # Whether to disable service routing for a single client 417 env_name: eef23fdab # Set the environment name of the downstream service in multiple environments. It only takes effect when disable_servicerouter is true 418 namespace: Development # The environment of the peer service 419 ``` 420 421 ## Addressing Methods 422 423 The framework provides two sets of addressing configurations: "Naming Service-based addressing" and "Target-based addressing". It can be set through the Option function option, and the system defaults to and recommends "Naming Service-based addressing". The Option function definition and example of Naming Service-based addressing are as follows: 424 425 ### Addressing based on Naming Service 426 427 ```go 428 // Definition of the Naming Service-based addressing interface 429 func WithServiceName(s string) Option 430 431 // Example code 432 func main() { 433 opts := []client.Option{ 434 client.WithServiceName("trpc.app.server.service"), 435 } 436 rsp, err := clientProxy.SayHello(ctx, req, opts...) 437 } 438 ``` 439 440 ### Addressing based on Target 441 442 The Option function definition and example are as follows: 443 444 ```go 445 // Definition of the Target-based addressing interface, target format: selector://service identifier 446 func WithTarget(t string) Option 447 448 // Example code 449 func main() { 450 opts := []client.Option{ 451 client.WithNamespace("Development"), 452 client.WithTarget("ip://127.0.0.1:8000"), 453 } 454 rsp, err := clientProxy.SayHello(ctx, req, opts...) 455 } 456 ``` 457 458 "ip" and "dns" are commonly used selectors in tool-type clients, and the format of the target is: `ip://ip1:port1,ip2:port2`, which supports IP lists. The IP selector randomly selects an IP from the IP list for service invocation. The IP and DNS selectors do not depend on external naming services. 459 460 #### `ip://<ip>:<port>` 461 462 Specifies direct IP addressing, such as ip://127.1.1.1:8080. Multiple IPs can also be set, and the format is ip://ip1:port1,ip2:port2. 463 464 #### `dns://<domain>:<port>` 465 466 Specifies domain name addressing, which is commonly used for HTTP requests, such as dns://www.qq.com:80. 467 468 ## Plugin Design 469 470 Service addressing includes service discovery, load balancing, service routing, circuit breakers, and other parts. The service discovery process can be simplified as follows: 471 472 ![server_discovery](/.resources/user_guide/client/overview/server_discovery.png) 473 474 The framework combines these four modules through the "selector" and provides two plugin methods to implement service addressing: 475 476 - Overall interface: The name service is registered as a whole to the framework as a selector plugin. The advantage of the overall interface is that it is relatively simple to register with the framework. The framework does not care about the specific implementation of each module in the name service process. The plugin can control the entire process of name service addressing as a whole, which is convenient for performance optimization and logic control. 477 - Modular interface: Use the selector provided by the framework by default, and register service discovery, load balancing, service routing, circuit breakers, etc. to the framework, and the framework combines these modules. The advantage of the modular interface is that it is more flexible. Users can choose different modules according to their needs and freely combine them, but it will increase the complexity of plugin implementation. 478 479 The framework supports users to develop new name service plugins. Please refer to [tRPC-Go Development Name Service Plugin](/docs/developer_guide/develop_plugins/naming.md) for the development of name service plugins. 480 481 # Plugin Selection 482 483 For the use of plugins, we need to import the plugin in the main file and configure the plugin in the framework configuration file at the same time. Please refer to the example in [Polaris Naming Service](https://trpc.group/trpc-go/trpc-naming-polarismesh) for how to use plugins. 484 485 The tRPC plugin ecosystem provides a rich set of plugins. How can programs choose the appropriate plugins? Here we provide some ideas for reference. We can roughly divide plugins into three categories: independent plugins, service governance plugins, and storage interface plugins. 486 487 - Independent plugins: For example, protocol, compression, serialization, local memory cache, and other plugins, their operation does not depend on external system components. The idea of this type of plugin is relatively simple, mainly based on the needs of business functions and the maturity of the plugin to make choices. 488 - Service governance plugins: Most service governance plugins, such as remote logs, naming services, configuration centers, etc., need to interface with external systems and have a great dependence on the microservice governance system. For the selection of these plugins, we need to clarify on what operating platform the service will ultimately run, what governance components the platform provides, which capabilities the service must interface with the platform, and which ones do not. 489 - Storage interface plugins: Storage plugins mainly encapsulate the interface calls of mature databases, message queues, and other components in the industry and within the company. For this part of the plugin, we first need to consider the technical selection of the business, which database is more suitable for the needs of the business. Then, based on the technical selection, we can see if tRPC supports it. If not, we can choose to use the native SDK of the database or recommend that everyone contribute plugins to the tRPC community. 490 491 # Filter 492 493 tRPC-Go provides a filter mechanism, which sets up points in the context of service requests and responses, allowing businesses to insert custom processing logic at these points. The tRPC-Go [Plugin Ecosystem](https://github.com/trpc-ecosystem) provides a rich set of filters, including call chain and monitoring plugins, which are also implemented through filters. 494 495 For the principle, triggering timing, execution order, and example code of custom filters, please refer to [Developing Filter Plugins in tRPC-Go](/filter)。 496 497 # Calling Scenarios 498 499 For scenarios where the program is purely a client, the service invocation method is relatively simple. Usually, synchronous invocation is used to wait for the invocation to return directly, or a goroutine is created to synchronously invoke and wait for the return result in the goroutine. This will not be discussed here. 500 501 For scenarios where the program is both a server and a client (when the service receives an upstream request, it needs to call downstream services), it will be relatively more complex. This article provides ideas for user development according to three methods: synchronous processing, asynchronous processing, and multi-concurrency processing. 502 503 ## Synchronous Processing 504 505 The typical scenario for synchronous processing is that when a service receives an upstream service request, it needs to call a downstream service and wait for the downstream service to complete the call before returning the response to the upstream. 506 507 For synchronous processing, the program can use the ctx of the downstream service call, which supports functions such as ctx logging and full-link timeout control. The code example is as follows: 508 509 ```go 510 func (s *serverImpl) Call(ctx context.Context, req *pb.Req) (*pb.Rsp, error) { 511 .... 512 513 // Synchronously process subsequent service calls, you can use the ctx in the service request 514 proxy := redis.NewClientProxy("trpc.redis.test.service") // proxy should not be created every time, this is just an example 515 val1, err := redis.String(proxy.Do(ctx, "GET", "key1")) 516 .... 517 } 518 ``` 519 520 ## Asynchronous Processing 521 522 The typical scenario for asynchronous processing is that when a service receives an upstream service request, it needs to return the response to the upstream first and then slowly process the downstream service call. 523 524 For asynchronous processing, the program can start a goroutine to execute subsequent service calls, but the subsequent service calls cannot use the ctx of the original service request because the original ctx will be automatically canceled after the response is returned. The subsequent service call can use trpc.BackgroundContext() to create a new ctx, or directly use the trpc.Go utility function provided by trpc: 525 526 ```go 527 func (s *serverImpl) Call(ctx context.Context, req *pb.Req) (*pb.Rsp, error) { 528 .... 529 530 trpc.Go(ctx, time.Minute, func(ctx context.Context) { // Here you can directly pass in the ctx of the request entry. trpc.Go will first clone the context and then go and recover. It will include logging, monitoring, recover, and timeout control internally. 531 proxy := redis.NewClientProxy("trpc.redis.test.service") // proxy should not be created every time, this is just an example 532 val1, err := redis.String(proxy.Do(ctx, "GET", "key1")) 533 }) 534 535 // Do not wait for the downstream response, return the response directly. The ctx will be automatically canceled after the response is returned. 536 .... 537 } 538 ``` 539 540 ## Multi-Concurrency Processing 541 542 The typical scenario for multi-concurrency calls is that when an online service receives an upstream service request, it needs to call multiple downstream services at the same time and wait for the response of all downstream services. 543 544 In this scenario, the business can start multiple goroutines to initiate requests by itself, but this is more troublesome, requiring its own waitgroup and recover. If there is no recover, the goroutines started by itself are easy to cause the service to crash. The framework encapsulates a simple multi-concurrency function GoAndWait() for users to use. 545 546 ```go 547 // GoAndWait encapsulates a safer multi-concurrency call, starts a goroutine and waits for all processing flows to complete, and automatically recovers. 548 // Return value error: the first non-nil error returned in the multi-concurrency goroutine. 549 func GoAndWait(handlers ...func() error) error 550 ``` 551 552 Example: Assuming that the service receives a Call() request, the service needs to get the values of key1 and key2 from two backend services redis. Only after the downstream service call is completed, will the response be returned to the upstream. 553 554 ```go 555 func (s *serverImpl) Call(ctx context.Context, req *pb.Req) (*pb.Rsp, error) { 556 var value [2]string 557 proxy := redis.NewClientProxy("trpc.redis.test.service") 558 if err := trpc.GoAndWait( 559 func() error { 560 // Assuming that the first downstream service call is to get the value of key1 from redis, since GoAndWait will wait for all goroutines to complete before exiting, ctx will not be canceled, so the ctx of the request entry can be used here. If you want to copy a new ctx, you can use `newCtx := trpc.CloneContext(ctx)` before GoAndWait 561 val1, err := redis.String(proxy.Do(ctx, "GET", "key1")) 562 if err != nil { 563 // key1 is not critical data, it doesn't matter if it fails, you can use a fake data as a backup and return success 564 value[0] = "fake1" 565 return nil 566 } 567 log.DebugContextf(ctx, "get key1, val1:%s", val1) 568 value[0] = val1 569 return nil 570 }, 571 func() error { 572 // Assuming that the second downstream service call is to get the value of key2 from redis 573 val2, err := redis.String(proxy.Do(ctx, "GET", "key2")) 574 if err != nil { 575 // key2 is critical data. If it cannot be obtained, the logic needs to be terminated in advance, so return failure here 576 return errs.New(10000, "get key2 fail: "+err.Error()) 577 } 578 log.DebugContextf(ctx, "get key2, val2:%s", val2) 579 580 value[1] = val2 581 return nil 582 }, 583 ); err != nil { // If there is a failure in the multi-concurrency request, return the error code to the upstream service 584 return nil, err 585 } 586 // ... 587 } 588 ``` 589 590 # Advanced Features 591 592 ## Timeout control 593 594 The tRPC-Go framework provides a call timeout mechanism for service calls. For an introduction to the call timeout mechanism and related configurations, please refer to [tRPC-Go Timeout Control](/docs/user_guide/timeout_control.md) 。 595 596 ## Link transmission 597 598 The tRPC-Go framework provides a mechanism for passing fields between the client and server and passing them down the entire call chain. For the mechanism and usage of link transmission, please refer to [tRPC-Go Link Transmission](/docs/user_guide/metadata_transmission.md). This feature requires protocol support for metadata distribution. The tRPC protocol, generic HTTP RPC protocol, and TAF protocol all support link transmission. For other protocols, please contact the respective protocol responsible person. 599 600 ## Custom compression 601 602 The tRPC-Go framework supports businesses to define their own compression and decompression methods. For details, please refer to [here](/codec/compress_gzip.go). 603 604 ## Custom serialization 605 606 The tRPC-Go framework allows businesses to define their own serialization and deserialization types. For specific examples, please refer to [here](/codec/serialization_json.go).