仙桃网站定制,网站建设项目验收方案,html5鱼缸,网站备案注销说起RPC#xff0c;博主使用CPP手搓了一个RPC项目#xff0c;RPC简单来说#xff0c;就是远程过程调用#xff1a;我们一般在本地传入数据进行执行函数#xff0c;然后返回一个结果#xff1b;当我们使用RPC之后#xff0c;我们可以将函数的执行过程放到另外一个服务器上… 说起RPC博主使用CPP手搓了一个RPC项目RPC简单来说就是远程过程调用我们一般在本地传入数据进行执行函数然后返回一个结果当我们使用RPC之后我们可以将函数的执行过程放到另外一个服务器上而不是在本地创建一个函数栈帧将函数执行所需要的一些东西压入到栈中。下面我们来学习RPC!!!
一、远程过程调用带来的问题 在远程调用时我们需要执行的函数体是在远程的机器上也就是说add是在另一个进程中执行的。这就带来了几个问题
1.1 Caller ID 映射 我们怎么告诉远程机器我们要调用add而不是sub或者 Foo呢在本地调用中直接通过函数指针来指定的我们调用add编译器就自动帮我们调用它相应的函数指针。但是在远程调用中指针是不行的因为两个进程的地址空间是完全不一样的。所以在RPC中所有的函数都必须有自己的一个ID。 这个ID在所有进程中都是唯一确定的。客户端在做远程调用时必须附上这个ID。然后我们还需要在客户端和服务端中分别维护一个 【函数 ---- Call ID】的对应表。两者的表不一定需要完全相同但是相同的函数对应的 Call ID 必须相同。当客户端需要进行远程调用时他就查一下这个表找出相应的 Call ID 然后将他传入到服务端服务端也通过查表来确定客户端需要调用的函数然后执行相应函数的代码。
1.2 序列化和反序列化 客户端怎么把参数值传给远程的函数呢在本地调用中我们只需要把参数压入到栈中然后让函数自己去栈萝莉读就行。但是在远程过程调用时客户端根服务端是不同的进程不能通过内存来传递参数。甚至有时候客户端和服务端使用的都不是同一种语言比如服务端用C客户端使用 Java 或者 python。这时候就需要客户端把参数先转成一个字节流传给服务端后再把字节流转成自己能读取的格式。这个过程叫做序列化和反序列化。同理从服务端返回的值夜需要通过序列化和反序列化的过程。
1.3 网络传输 远程调用往往用在网络中客户端和服务端是通过网络连接的。所有的数据都需要通过网络传输因此就需要有一个网络传输层。网络传输层需要把 Call ID 和序列化后的参数字节流传给服务端然后再把序列化后的调用结果传回给客户端。只要能完成这两者的都可以用作为传输层使用。因此他所使用的协议其实是不限的只要可以完成传输就行了。尽管大部分RPC框架都使用TCP协议但是其实UDP也是可以的而gRPC干脆就使用HTTP2。
二、上述三个机制的解决方法
当我们解决了上述的三个问题就可以实现RPC了具体过程如下
2.1 client 端可以解决的问题
将这个调用映射为 Call ID 这里假设使用最简单的字符串当 Call ID 的方法将 Call ID a 和 b序列化。可以直接将他们的值以二进制形式打包将2中得到的数据包发送给 ServerAddr这就需要使用网络传输层等待服务器调用成功那么就将结果反序列化并赋值给total
2.2 server 端可以解决的问题
在本地维护一个 Call ID 到函数指针的映射 call_id_map我们可以使用dict来完成等待请求包括多线程的并发处理能力得到一个请求后将其数据包反序列化得到相应的函数指针将 a 和 rb 反序列化后在本地调用 add 函数得到结果将结果序列化后通过网络返回给 Client 在上面的整个流程中其中 Call ID 映射可以直接使用函数字符串也可以使用整数ID。映射表一般就是一个哈希表序列化和反序列化可以自己写也可以使用 protobuf 或者 FlatBuffers 之类的网络传输库可以自己写 socket 或者使用 asioZeroMQ、Netty 之类的 实际上真正的开发过程中除了上面的基本功能之外还需要更多的细节网络错误流量控制超时和重传。 三、最后如何将远程的这些过程写出本地函数调用的感觉
下面我们可以使用 go 语言来进行实现这个问题因为在 go 语言中提供的包还是很全的。
我们分为服务端和客户端来进行编写代码我们先来看一看服务端的代码
package mainimport (encoding/jsonfmtnet/httpstrconv
)func main() {// http// 返回的格式化为json{ data3 }// 1. callID 的问题 r.URL.Path 2. 数据的传输协议 url 的参数传递协议 3. 网络传输协议 httphttp.HandleFunc(/add, func(w http.ResponseWriter, r *http.Request) {_ r.ParseForm() // 解析参数fmt.Println(Path: , r.URL.Path)a, _ : strconv.Atoi(r.Form[a][0])b, _ : strconv.Atoi(r.Form[b][0])w.Header().Set(Content-Type, application/json; charsetutf-8)jData, _ : json.Marshal(map[string]interface{}{data: a b,})_, _ w.Write(jData)})_ http.ListenAndServe(:8080, nil)
}
客户端中的代码如下
package mainimport (encoding/jsonfmtgithub.com/kirinlabs/HttpRequest
)type ResponseData struct {Data int json:data
}func add(a, b int) int {// 传输协议req : HttpRequest.NewRequest() // 创建一个requestres, _ : req.Get(fmt.Sprintf(http://127.0.0.1:8080/%s?a%db%d, add, a, b))body, _ : res.Body()rspData : ResponseData{}_ json.Unmarshal(body, rspData)return rspData.Data
}func main() {// 实现 rpcadd(1, 2)
}
四、RPC开发的要素分析
4.1 RPC开发的四大要素 RPC技术在架构设计上有四个部分组成分别是客户端客户端存根服务端。服务端存根。下面我们来一一介绍
客户端服务调用发起方也称为服务消费者客户端存根该程序运行在客户端所在的计算机机器上主要用来存储要调用的服务器的地址另外该程序还负责将客户端请求远端服务器程序的数据信息打包成数据包通过网络发送给服务端Stub程序其次还要接受服务器Stub程序发送的调用结果数据包并解析返回给客户端。服务端远端的计算机机器上运行的程序其中有客户端要调用的方法服务端存根接收客户Stub程序通过网络发送的请求消息数据包并调用服务端中真正的程序功能方法完成功能调用其次将服务端执行调用的结果进行数据处理打包发送给客户端Stub程序。 了解完了RPC技术的组成结构我们来看一下具体是如何实现客户端到服务端的调用的。实际上如果我们想要在网络中的任意两台计算机上实现进程调用进程需要解决很多问题比如
两台物理机器在网络中要建立稳定可靠的通信连接两台服务器的通信协议的定义问题即两台服务器上的程序如何识别对方的请求和返回结果。也就是说两台计算机必须能够识别对方发来的信息并且能够识别出其中的请求含义和返回含义然后才能进行处理这其实就是通信协议要完成的工作。 在上图中通过10步完成了RPC下面我们来具体描述一下RPC每一步的调用过程
客户端想要发起一个远程过程调用首先要通过调用本地客户端Stub程序的方式调用想要使用的功能方法名客户端Stub程序接收到了客户端的功能调用请求将客户端请求调用的方法名携带的参数等信息做序列化操作并打包成数据包客户端Stub查找到远程服务器程序的IP地址调用Socket通信协议通过网络发送给服务端服务端Stub程序接收到客户端发送的数据包信息并通过约定好的协议将数据进行反序列化得到请求的方法名和请求参数等信息服务端Stub程序准备相关数据调用本地的Server对应的功能方法进行并存入相应的参数进行业务处理服务端程序根据已有的业务逻辑执行调用过程等到业务执行结束之后将执行结果返回给服务端Stub程序服务端Stub程序将程序调用结果按照约定的协议进行序列化并通过网络发送回给客户端Stub程序客户端Stub接收到服务端Server发送返回的数据对数据进行反序列化的操作并将调用返回的数据传递给客户端请求发送者客户端请求发起者得到调用结果整个RPC调用过程结束
五、RPC需要使用到的术语 通过上文一系列的文字描述和讲解我们已经了解了RPC的由来和整个RPC调用过程。我们可以看到RPC是一系列操作的集合其中涉及了很多对于数据的操作以及网络通信。因此我们对RPC中涉及到的技术做一个总结和分析
动态代理技术上文中我们提到的Client Stub 和Server Stub 程序在具体的编码和开发实践的过程中都是使用动态代理技术自动生成的一段程序序列化和反序列化在RPC调用的过程中我们可以看到数据需要在一台机器上传输到另一台机器上。在互联网中所有的数据都是以字节的形式进行传输的。而我们在编程的过程中往往都需要使用数据对象因此想要在网络上将对象和相关变量进行传输就需要对数据对象做序列化和反序列化的操作。