手写rpc都需要做什么呢?
要知道rpc是什么东西,rpc 的全称是 Remote Procedure Call,即远程过程调用。从字面上的来看,rpc就是通过网络通信访问另一台机器的应用程序接口。
目前的rpc组件的基本能力就是屏蔽网络编程细节,实现调用远程方法就跟调用本地(同一个项目中的方法)一样。
但一个合格的可以用于生产的rpc框架还应该具备负载均衡、优雅启停、链路追踪、灰度发布等等功能。在我的rpc中只实现了一部分。
那么如何使用rpc呢?‘
不知道大家是否熟悉dubbo、grpc、或者openFegin,那就会很清楚问题的答案。
以dubbo举例
在springboot中,服务提供者和消费者只要依赖相同接口,就可以使用如下的方式进行远程调用了。
1、服务端只需要使用 @DubboService 注解将对应接口的实现暴露出去
@DubboService
public class DemoServiceImpl implements DemoService {
@Override
public String sayHello(String name) {
return "Hello " + name;
}
}
2、客户端就可以直接使用 @DubboReference 直接注入使用了。
@Component
public class Task implements CommandLineRunner {
@DubboReference
private DemoService demoService;
@Override
public void run(String... args) throws Exception {
String result = demoService.sayHello("world");
System.out.println("Receive result ======> " + result);
new Thread(()-> {
while (true) {
try {
Thread.sleep(1000);
System.out.println(new Date() + " Receive result ======> " + demoService.sayHello("world"));
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
}).start();
}
}
这样就是实现了调用远程接口就和调用本地接口一样的能力。
那么rpc如何做到调用方和被调用方互相通信的呢?
rpc能实现调用远程方法就跟调用本地(同一个项目中的方法)一样,发起调用请求的那一方叫做调用方,被调用的一方叫做服务提供方。
发起远程调用的核心是网络通信,那我们手动实现rpc框架的核心就是封装通信细节,本小节我们主要和大家一起来思考整个调用过程中的一些流程和细节:
**1、传输协议:**既然 yrpc 存在的核心目的是为了实现远程调用,既然是远程调用那肯定就需要通过网络来传输数据,并且 yrpc 常用于业务系统之间的数据交互,需要保证其可靠性,所以 yrpc 一般默认采用 TCP 来传输。事实上。我们常用的 HTTP 协议也是建立在 TCP 之上的。选择tcp的核心原因还是因为他的效率要比很多应用层协议高很多。
**2、封装一个可用的协议:**选择了合适的传输层协议之后,我们需要基于此建立一个我们自己的通用协议,和http一样需要封装自己的应用层协议,详细的内容会在后边的课程里详细介绍。
**3、序列化:**网络传输的数据必须是二进制数据,但调用方请求的出入参数都是对象。对象是肯定没法直接在网络中传输的,需要提前把它转成可传输的二进制,并且要求转换算法是可逆的,这个过程我们一般叫做“序列化”。
**4、压缩:**如果我们觉得序列化后的字节数组体积比较大,我们还可以对他进行压缩,压缩后的字节数组体积更小,能在传输的过程中更加节省带宽和内存。
上述流程对rpc来说还是有缺憾的。
还需要做到让使用方只需要关注业务接口,像调用本地一样来调用远程。
接下来叙述一些rpc中的细节问题。