1、为什么要有rpc?
因为微服务之间需要进行服务间的通信,不同服务之间的接口要互相调用。而常见的通信协议主要有 RPC 和 REST 协议
使用rpc的好处是:
引入RPC框架对我们现有的代码影响最小,同时又可以帮我们实现架构上的扩展
两者对比
2、什么是Rpc
Remote Procdeure Call ,即远程过程调用,是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络实现的技术。
RPC 是一种进程间通信方式,允许像调用本地服务一样调用远程服务
例如微服务中有订单服务需要调用用户服务获取用户信息,之前的方法可能是通过http请求来访问接口,获取信息,现在调用时,只需要知道获取用户信息的接口的类名、方法名,传入相应参数,就可以获取到对应的用户信息。
3、Rpc流程
- 客户端以本地调用方式发起请求,请求内容包括:远程方法在本地的模拟对象,方法名,方法参数,将请求内容包装后的信息通过网络发送到服务端。
- 服务端收到消息后,进行解码为实际的方法名和参数
- 服务端本地服务执行并将结果返回
- 服务端将返回结果打包成消息并发送至客户端
- 客户端收到消息后,解码,获取响应内容
4、Rpc使用到的核心技术
- 代理,为什么要有代理,因为客户端只管发送请求,获取响应,至于过程如何不关心,所以需要一个代理来进行中间过程的封装。
- 反射,服务端收到请求后,需要通过反射机制来获取要调用的方法的对象,执行对应的方法
- 序列化 ,网络传输过程中需要先将数据进行序列化才能进行传输,接收到数据后需要将数据进行反序列化才能进行下一步操作。
5、一个简单的RpcDemo
发起服务端
package com.ljx.splearn.RpcDemo;
public class Main{
public static void main(String[] args) throws Exception{
//RPC调用,客户端获取要调用的服务并发起调用
UserService service=(UserService)Client.getStub(UserService.class);
User user = service.findUserByID(222);
System.out.println(user.getName());
}
}
client实现,重要类
package com.ljx.splearn.RpcDemo;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.Socket;
public class Client{
//远程调用类
public static Object getStub(final Class clazz) throws Exception{
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//通过socket将请求发送到服务方
Socket socket = new Socket("127.0.0.1", 8888);
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
String className = clazz.getName();
String methodName = method.getName();
Class[] parametersTypes = method.getParameterTypes();
oos.writeUTF(className);
oos.writeUTF(methodName);
oos.writeObject(parametersTypes);
oos.writeObject(args);
oos.flush();
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Object o = ois.readObject();
oos.close();
socket.close();
return o ;
}
};
//通过代理实现方法调用
Object o = Proxy.newProxyInstance(clazz.getClassLoader(),
new Class[]{clazz},handler);
return o;
}
}
服务端启动一个socket,接收传递过来的请求数据,通过反射获取方法名和参数,并调用方法返回结果
package com.ljx.splearn.RpcDemo;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 服务端
*/
public class Server {
private static boolean running = true;
public static void main(String[] args) throws Exception{
//启动一个socket方法
ServerSocket serverSocket = new ServerSocket(8888);
while (running){
Socket socket = serverSocket.accept();
process(socket);
socket.close();
}
serverSocket.close();
}
private static void process(Socket socket) throws Exception{
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
ObjectInputStream ois = new ObjectInputStream(in);
// 拿到客户端传递过来的class
String clazzName =ois.readUTF();
String methodName =ois.readUTF();
Class[] parameterTypes = (Class[])ois.readObject();
Object[] args =(Object[])ois.readObject();
//反射拿到class
//通过反射可以获取所有的接口类
Class clazz =Class.forName(clazzName);
if(clazz.isInterface()){
if(clazzName.equals("com.ljx.splearn.RpcDemo.UserService")){
clazz = UserServiceImpl.class;
}
}
//使用反射获取结果
Method method = clazz.getMethod(methodName,parameterTypes);
Object object = method.invoke(clazz.newInstance(),args);
//通过socket将结果返回
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(object);
oos.flush();
}
}
服务调用的接口和实体类
package com.ljx.splearn.RpcDemo;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.io.Serializable;
/**
* @author lijianxi
* @date 2023年01月16日 10:40 上午
*/
@Data
@AllArgsConstructor
public class User implements Serializable {
Integer id;
String name;
}
package com.ljx.splearn.RpcDemo;
public interface UserService {
public User findUserByID(Integer id);
}
package com.ljx.splearn.RpcDemo;
public class UserServiceImpl implements UserService {
@Override
public User findUserByID(Integer id) {
return new User(id, "ljx");
}
}
启动server,调用main
结果如下
6、RPC和HTTP
1、RPC是远程过程调用,只是对不同应用间相互调用的一种描述,它是一种思想。具体怎么调用?实现方式可以是最直接的TCP通信,也可以是HTTP方式。
2、HTTP是应用层的一种协议,负责服务之间的通信操作。
3、dubbo是基于tcp通信的,gRPC是Google公布的开源软件,基于最新的HTTP2.0协议,底层使用到了Netty框架的支持。