当前位置:网站首页>Understanding of RPC core concepts

Understanding of RPC core concepts

2022-04-23 17:09:00 Handsome that handsome

Introduce
This paper mainly introduces RPC What is it? , Why use RPC, Use RPC Problems to be solved and RPC Using examples

RPC What is it?
RPC(Remote Procedure Call) Remote procedure call protocol , A way to request services from a remote computer over a network , You don't need to know the protocols of the underlying network technology .RPC It assumes the existence of certain agreements , for example TPC/UDP etc. , Carry information data between communication programs . stay OSI In the seven layer network model ,RPC Across the transport and application layers ,RPC Make development , Applications, including network distributed multiprogramming, are easier .

In a nutshell : Is to send a request to a remote server , Do business processing or task calculation, etc ( I.e. procedure ), I want to make the process of calling methods in the remote server as simple as calling local methods .

Why use RPC
We can't be in a process , Even when our needs are met by local calls , For example, our communication system , Even communication between different organizations , Because computing power needs to scale out , You need to deploy applications on a cluster of multiple machines , Only in this way can we communicate remotely ; Or e-commerce system , We can't rely on local calls to meet our needs , For example, the processing method of submitting orders , The inventory processing method is called locally , It must not work in , This is when the user initiates the corresponding request and our remote server does business processing and calculation . therefore RPC It seems so important .

Use RPC Need to solve the problem
Let's look at , Let's imagine when we call... Remotely ( That is to use RPC) In the process of , The functions or methods we need to execute are on the remote machine , For example, we want to call the remote computer's add Method , Here are some questions :

  1. Call ID mapping . How do we tell the remote computer that what we need to call is add Method , instead of reduce Method ,mult Method ,divi Such method , In a local call , The function body is specified directly through the function pointer , When we call local add When the method is used , The compiler will automatically call us to its corresponding function pointer , In remote calls , It's obviously not possible to use pointers , Because the addresses of the two processes are different . therefore , stay RPC in , All functions must have a unique ID, This ID It's the only certainty in all processes , The client must attach this when calling ID, Then we need to maintain one on the client and one on the server { function <—–> Call ID } Corresponding table , The tables don't have to be exactly the same , But the same function corresponds to Call ID It has to be the same , When the client needs to make a remote call , It just looks up this table , Find out the corresponding Call ID, And then pass it to the server , The server also looks up tables , To determine the functions that the client needs to call , Then execute the code of the corresponding function .
  2. Serialization and deserialization . How can the client pass parameter values to remote functions ? In a local call , We just need to push the parameters onto the stack , Then let the function itself read in the stack . But in remote procedure calls , The client and the server are different processes , You can't pass parameters through memory . Even sometimes the client and server are not in the same language ( For example, the server uses C++, The client with Java perhaps Go). At this time, the client needs to convert the parameters into a byte stream first , After passing it to the server , Then transfer the byte to a format that you can read . This process is called serialization and deserialization . Empathy , The value returned from the server also needs the process of serialization and deserialization

The whole process is as follows :
 Insert picture description here
3. Network transmission . Remote calls are often used on the network , The client and the server are connected through the network . All data needs to be transmitted through the network , So there needs to be a network transport layer . The network transport layer needs to put Call ID And the serialized parameter bytes are passed to the server , Then the serialized call result is sent back to the client . As long as you can do both , Can be used as a transport layer . therefore , The protocols it uses are actually unlimited , Just complete the transmission . Although most of RPC All frameworks use TCP agreement , But in fact UDP It's fine too , and gRPC Just use it HTTP2.Java Of Netty Things that also belong to this layer .

Solved the above three problems , We can achieve RPC 了 , Now let's look at , The client and server are in RPC What is the job in :

client (client):

1.  Map this call to Call ID. Let's assume that the simplest string is used as Call ID Methods , For example, here you can :http://127.0.0.1:8080/add?a=1&b=1, I.e. direct use add As path, Or, http://127.0.0.1:8080/?method=add&a=1&b=1 etc. 

2.  take Call ID,a and b serialize . You can package their values directly in binary form 

3.  hold 2 The data packet obtained in is sent to ServerAddr, This requires the use of the network transport layer 

4.  Wait for the server to return results 

4.  If the server call succeeds , Then deserialize the result , And give it to total

Server side (service):

1.  Maintain one locally Call ID Mapping to function pointers call_id_map, It can be used dict complete 

2.  Wait for the request , Including the concurrent processing capability of multithreading 

3.  After getting a request , Deserialize its packets , obtain Call ID

4.  By means of call_id_map Search for , Get the corresponding function pointer 

5.  take a and rb After deserialization , Call... Locally add function , Get the results 

6.  Serialize the results and return them to Client

Be careful :

  1. Call ID Can be a string , It can also be an integer ID, The mapping is actually a hash table
  2. Serialization and deserialization can be written by yourself , You can also use it Protobuf perhaps FlatBuffers And so on. .
  3. The network transmission library can be implemented by itself socket, You can also use asio,ZeroMQ,Netty And so on .

RPC Using examples
Let's simply simulate RPC Call procedure for , introduces : The client needs to call the calculation method on the remote computer , Take addition as an example ( Of course, it can be very complex large-scale calculation )

There is no need to care about the remote server when calling the client add How is the method implemented , We only need to make remote calls on the client side add Method :

service:

Because it's a simple example , You won't do complete error handling

package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "strconv"
)

func main() {
    
    //http://127:0:0:1:8000/add?a=1&b=2
    //Call ID  Use request.URL.PATH
    http.HandleFunc("/add",
        func(writer http.ResponseWriter, request *http.Request) {
    
            // Analytical parameters 
            err := request.ParseForm()
            if err != nil {
    
                panic(" Decoding failed ")
            }
            fmt.Println("path:", request.URL.Path)
            // Take out the parameters , Do type conversion 
            a, err := strconv.Atoi(request.Form["a"][0])
            if err != nil {
    
                panic(" switch views ")
            }
            b, err := strconv.Atoi(request.Form["b"][0])
            if err != nil {
    
                panic(err)
            }
            // The format of the data returned :json{"data":3}
            // Use json code , Namely serialization 
            writer.Header().Set("Content-Type", "application/json")
            // serialize 
            jData, err := json.Marshal(map[string]int{
    
                "data": a + b,
            })
            if err != nil {
    
                panic(err)
            }
            _, err = writer.Write(jData)
            if err != nil {
    
                panic(" Write failure ")
            }
        })

    // Listening port 
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
    
        panic(" Monitoring failed ")
    }
}

Start server

client:

There is also no complete error handling here
Here we use a third-party package :github.com/kirinlabs/HttpRequest
Use the following command to get :

go get github.com/kirinlabs/HttpRequest

Of course, you can also use other related methods to connect our service

package main

import (
    "encoding/json"
    "fmt"

    "github.com/kirinlabs/HttpRequest"
)

// Analytical structure 
type ResponseData struct {
    
    data int `json:"data"`
}

// Yes add encapsulate 
func add(a, b int) int {
    
    // Generate an instance 
    req := HttpRequest.NewRequest()
    res, err := req.Get(fmt.Sprintf("http://127.0.0.1:8080/add?a=%d&b=%d", a, b))
    if err != nil {
    
        panic(" The connection fails ")
    }
    body, err := res.Body()
    if err != nil {
    
        panic(err)
    }

    var resData ResponseData
    err = json.Unmarshal(body, &resData)
    if err != nil {
    
        panic(" Decoding failed ")
    }
    return resData.data
}

func main() {
    
  fmt.Println(add(1, 4))
}

Print the results :

{
    "data":5}

Process finished with the exit code 0

Of course, we can also access it directly in the browser :
 Insert picture description here

版权声明
本文为[Handsome that handsome]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204231707235858.html