Now that you understand what RPC is, let’s take a look at dubbo-Go’s RPC flow. Next, I’ll use Dubo-Go-samples/HelloWorld as an example for analysis.

The following figure shows the dubo-Go RPC process overview. From the request initiator (hereafter referred to as Consumer) through six modules, the information is sent to the server (hereafter referred to as Provider), and then through five modules, finally the whole process of invoking remote methods.

Figure 2: Dubo-go RPC flow

Start by explaining how a Consumer can process RPC through six modules.

How do I start Conusmer

How the Consumer does RPC in Dubo-go-samples/HelloWorld. At the code level, you can see that the GetUser property of the userProvider is called in the main method. But why does calling a property make RPC work correctly? For an example, the code looks like this:

`func init() {` `config.SetConsumerService(userProvider` `hessian.RegisterPOJO(&pkg.User{}` `}` `func main() {` 'config.load (' user := &pkg. user') // Calls the local method, Provider RPC ' 'err := userprovider.getUser (context.todo (), []interface{}{"A001"}, user)' '} 'Copy the code

 


Proxy

After RPC is initiated, the proxy layer proxy method is executed. The key to initiating RPC correctly through attributes is config.load (). Loaded into the consumer configuration loadConsumerConfig (), the References of Dubbo – go read consumerConfig attributes with config. SetConsumerService (corresponding) information, Refer method in the following code), such as the URL to be registered in the organization, obtaining cluster management policies, and obtaining proxy classes.

Func loadConsumerConfig() {' '... ` `for key, ref := range consumerConfig.References {` `... ' 'ref.Refer(rpcService) <------ Initializes references Provider related information' '// proxy related attributes'' ref.implement (rpcService) ' '... ` ` `}Copy the code

Proxy class Proxy local call property (userprovider.getUser), transfers the call property to proxy, executes RPC-related methods, and transparently achieves RPC effect for users. Proxy classes organize the information needed for RPC and invoke Invoker to initiate RPC calls. When called, the result of the response is returned.

Func loadConsumerConfig() {' '... ` `for key, ref := range consumerConfig.References {` `... ' 'ref.Refer(rpcService) <------ Initializes references Provider related information' '// proxy related attributes'' ref.implement (rpcService) ' '... ` ` `}Copy the code

After the proxy layer has processed it, it needs to make a remote call to the Provider. To make a remote call, you need to support the network protocol. Next, go to the call layer and see how Dubbo-Go does this.

Invoker

The invocation layer, which implements the interface for the Consumer to invoke the Provider approach (as shown in the code below). At present, Dubo-Go implements several commonly used communication protocols in the industry, such as: Native Dubbo protocol (supporting Hessian2 data serialization), gRPC protocol (supporting Protobuffer data serialization), JSONRPC, etc., allowing users to choose to use according to the actual situation, or to achieve a custom protocol.

'// Implement Consumer invoke Provider type Invoker interface {'' common.nod ' '// invoke remote method and return result' '// context.context: Invocation: Invoke(Context.Context, Invocation) Resul '} 'for each remote InvocationCopy the code

The main concern in this example is the Dubbo protocol (shown in the code below). Determine what form of request to initiate is the primary processing logic of this method. Dubbo supports multiple request modes, including one-way, two-way, and asynchronous processing. Conveniently meet the needs of users in different scenarios.

Func (DI *DubboInvoker) Invoke(CTX Context.Context, Invocation Protocol.Invocation) protocol.Result {'.. ' 'if async {'' // async ' 'if callBack, ok := inv.callback ().(func(response common.callbackResponse)); ok {` `result.Err = di.client.AsyncRequest(&invocation, url, timeout, callBack, rest` `} else {` `// one-way` `result.Err = di.client.Send(&invocation, url, timeout` `} else {` `.. ` `// two-way` `result.Err = di.client.Request(&invocation, url, timeout, rest` `.. ` `.. ` ` `}Copy the code

After passing through the invocation layer, the information is passed to the exchange layer, which organizes and collects all information provided by consumers in a unified manner.

Exchange

Enter di.client.Request to analyze how to implement two-way communication. Use provider-related information to instantiate Consumer connection information, such as the connection pool and data serialization method.

  • Invocation Provider Specifies information about the invocation method, including the method name and parameter list.

  • Url: Information about the Provider connection, including the IP address, port, and application name.

  • Timeout: the request timeout, through a configuration file references. The methods. The timeout configuration.

  • Result: the result returned by RPC is converted into this object,

The entire interchange layer is analyzed in more detailed sections later.

'// Two way Request' func (Client *ExchangeClient) Request(Invocation *protocol.Invocation, URL * common.url, Timeout time.Duration, ' 'result *protocol.RPCResult) error {'' // Initializes connection information, such as connection pool and data serialization method, according to the Provider URL. ` `if er := client.doInit(url); er ! = nil {` `return er` `}` `... Err := client.client.Request(Request, timeout, RSP... ` ` `}Copy the code

After collation and collection by the exchange layer, the data is transferred to the serialization layer, and all the data is serialized through the data serialization protocol.

Codec

The data serialization protocol of the serialization layer can be implemented by the user, but in this chapter, it is mainly Hessian2 (the native protocol of Dubbo and Dubbo-Go). There are two main steps:

  • First, the Request object is converted to a DubboPackage object;

  • After the conversion is complete, Serializer.Marshal is called to serialize the data into the Hessian2 protocol content, which is used for information sent to the server through RPC. The entire serialization layer is analyzed in more detail in subsequent sections.

EncodeRequest(request * request) (* bytes.buffer, Error ' '// encode response content EncodeResponse(response * response) (* bytes.buffer, Error ' '// decode request/response contents'' decode (data []byte) (DecodeResult, int, Error) ' '} ' '// Serializer interface {'' // Serialize the DubboPackage object into []byte ' 'Marshal(p DubboPackage) ([]byte, Unmarshal([]byte, *DubboPackage) error ' '} 'Copy the code

After the data is serialized, it can enter the transport layer, which is responsible for the data transport level.

Transport

Finally, there is the transport layer, where Dubbo-Go uses apache/ Dubbo-Getty components for TCP communication and data transmission. The Connection interface is the key to support multiple transmission protocols, which supports UDP, TCP and WebSocket. The entire transport layer is analyzed in more detail in the following sections.

`package getty` `.... ` `type Connection interface {` `.... Send (interface{}) (int, error).... ` `} ` `... `Copy the code

The Consumer now serializes the data, initiates the network connection to the Provider, and transfers the data. What happens to the Provider when the data arrives? Don’t worry, we’ll continue.

conclusion

You’ve seen how Dubbo-Go encodes information layer by layer and sends it to the Provider when calling Consumer’s native methods.

About it, there are a lot of deep knowledge worth exploring and learning, such as:

  • In what way does Dubo-Go go over the network?

  • How does Dubo-Go sequence and deserialize data?

The answers to these questions need to be found in subsequent articles.

Welcome to the community

Pay attention to the public account [minister technology road], in the public account background reply keyword [dubbogo] to join the community.