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 := &registry.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).