Narration of a function call in net/rpc

Identity introduction

Hello everyone, my name is Xiao R, and you can also call my full name: RPC request, I have been carrying the hope of the whole village since I was born, but I know that waiting for me will be a long link , Although in the entire link, there will be many elders ( Call, Method, Client, etc. ) escorting me, but I will still go through a lot of training ( serialization + deserialization ) until my spirit (Request parameters) are communicated to the central (server). At this point, my task is over, but I know that there will be someone ( response ) who will send the results of my body transformation ( response results ) back to my village ( client ). In any case, I will tell my story here.

Theme

RPC, the full name of remote procedure call, is called remote function call in Chinese. What it does is very simple. It is remote. The remote here can refer to other local functions, or other machines, clusters, or computer rooms, but in the final analysis, It is a communication between the client and the server. There are many such communications, such as master-slave design and separation of computing and storage in database design, which are similar to RPC.

income

In fact, the biggest benefit of RPC is: since the client does not need to care about how the server function is implemented (the whole process is a black box for the client), from the perspective of expansion, the server can support unlimited horizontal expansion. From the perspective of business-side development, it also greatly reduces the cost of business-side development.

harm

As mentioned above, the client does not need to care about how the server is implemented. Especially in enterprise-level projects, RPC is often used as the communication basis of the microservice architecture. In fact, if the server wants to ensure high availability + high stability, it must To do the following:

  • Powerful load balancing + efficient service discovery
  • Corresponding fusing and current limiting measures, elegant retry mechanism
  • Flexible expansion and shrinkage mechanism
    Compared with the monolithic micro-service architecture, the impact of the above points will be maximized, and accordingly it will increase the difficulty of the development of the micro-service level structure such as the underlying load balancing.

Net/RPC source code analysis

Main terms explained

  • Client:
    • Request: is a linked list structure , essentially a request header write , here is only used to record the calling method name, seq (seq is similar to the concept of a timestamp, each call will be assigned a seq number, and then call RPC seq number is always greater than the first called) and the next request. It is similar to the log in the database. The function here is to trace the request record, customize the reporting point, or analyze the network status, etc.
    • ClientCodec: The encoding and decoding library in the Client-Server link transmission. The integrated RPC will be encoded into the corresponding stream and written into the RPC Session for the server to read. At the same time, it decodes the response body returned by the server for the client to read .
    • Call: An RPC call being executed.
  • Server:
    • serviceMap: A thread-safe map, which records the mapping between different service names and the service itself.
    • freeReq: Same as the Request explanation on the Client side.
    • freeResp: The function is basically the same as Request, so I won't repeat it.

Below I will use a picture to describe the execution flow of the RPC call function in the link
Insert picture description here

Client process explanation:

  1. Call the Call function:, the func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) errorcall function is the interface that is exposed to the client to call. The
    serviceMethodservice + method name is a string type with case checking. For example, if I want to call the Get method in Service A, then I A.Get
    argscall the RPC method parameters, generally For the structure,
    replygenerally return, create the corresponding structure according to the expected return value
  2. The Call function will call the Go function. The main function is to create a channel to ensure the orderly execution of the request (there may also be a purpose to prevent flooding attacks against RPC by setting the size of the channel). The type of the channel is the Call type. , The default size is 1, the main function is to pass the Call and receive the Call returned from the server.
    In the Go() method, it mainly does several things
    • The serviceMethod, args, reply, channelencapsulated inside Call
    • transfersend(call *Call)
  3. func (client *Client) send(call *Call)
    The main function of Send() is
    1. Further create request for link tracking and backtracking and
    2. Write request and args to session

So far, all the information of the request for a remote call has been assembled . The operation to write to the session is: call the flush() function to write the assembled request+call to the I/O writer, wait for the server to read, and the corresponding steps The functions involved are as follows:
* err := client.codec.WriteRequest(&client.request, call.Args)
*c.encBuf.Flush() // Flush writes any buffered data to the underlying io.Writer.

Server process explanation:

initialization

We will manually initialize the server-side listening thread in the code (this process may be started locally, or it can be started in the form of opening ip+port using http protocol)

Register(new(Service))
rpc.HandleHTTP()
l, e := net.Listen("tcp", ":1234")
if e != nil {
    
    
	log.Fatal("listen error:", e)
}
go http.Serve(l, nil)

So in fact, it is very clear (low). Although RPC uses the tcp protocol, it essentially sets an http shell, creates a TCP connection, and uses http scheduling to listen to the TCP listener, so I personally feel that RPC actually It is a special kind of http , or it can be said that the application layer of RPC is based on http

start up

Our remote RPC calls are usually executed in this order

  1. func (server *Server) ServeHTTP(w http.ResponseWriter, req *http.Request)
  2. func (server *Server) ServeConn(conn io.ReadWriteCloser)
  3. func (server *Server) ServeCodec(codec ServerCodec)
  4. func (s *service) call(server *Server, sending *sync.Mutex, wg *sync.WaitGroup, mtype *methodType, req *Request, argv, replyv reflect.Value, codec ServerCodec)

Call ServeHTTPtime creates a connection (as the name suggests, to accept http packets is), this connection will be treated as the parameters passed to ServeConn, the ServeConncreation will be a gobServerCodecstructure, and as the parameter passed to ServeCodec, ServeCodecIt is mainly for decoding request and encoding response. After the request is decoded, the Call function will be called to execute the corresponding code and return the Response. The response is similar to the coding and writing logic of the Request in the client, so I will not repeat it.

Understanding the design of net/rpc source code from the perspective of design patterns

If you let me start from zero and don’t use any information, I can’t design such a code with high cohesion and low coupling. In fact, it’s only the first step to understand other people’s code. The most important thing is to learn this code. Design ideas, sometimes good code can pass only one more parameter than you , but write dozens of lines less compatible.
Let me list any code blocks that I have better designed.
At the same time, I hope you can discuss in the message area

  1. ServeCodeCAnd ServeConnsplit: The reason for this split is to ensure that the upper layer ServeConn, it does not need to be concerned about the underlying logic decoding and encoding, while if the underlying for a set of this logic, we do not need too many changes to the top , To sum up: when designing code, we need to consider how much the cost of changing the upper layer is when there is a subversive change in the execution logic of the lower-level code, and the lower the coupling degree, the lower the cost of the change.
  2. RequestThe design of the request: At first I thought the design of the request was a basic unit in the link transmission, but later I found that it was not. The Requestmore function of the linked list structure is the monitoring and tracking of the link , which can better monitor the network. The situation, with this Request, we can do more custom monitoring mechanisms based on it, providing an idea and basis for upper-level business and disaster tolerance design.

Guess you like

Origin blog.csdn.net/weixin_38683995/article/details/113665516