一、什么是Dubbo
Dubbo是阿里巴巴2011年开源的一个基于Java的RPC框架,中间沉寂了一段时间,不过其他一些企业还在用Dubbo并自己做了扩展,比如当当网的Dubbox,还有网易考拉的Dubbok。
但是在2017年阿里巴巴又重启了对Dubbo维护,此后这款软件还跻身开源中国(https://www.oschina.net/)2017最受欢迎的中国开源软件Top10。
在2018年Dubbo和Dubbox进行了合并,并且进入Apache孵化器,在2019年毕业正式成为Apache顶级项目。
目前Dubbo社区主力维护的是2.6.x和2.7.x两大版本,2.6.x版本主要是bug修复和少量功能增强为准,是稳定版本。
而2.7.x是主要开发版本,更新、新增feature和优化,并且2.7.5版本的发布被Dubbo认为是里程碑式的版本发布,之后我们再做分析。
它实现了面向接口的代理RPC调用,并且可以配合ZooKeeper等组件实现服务注册和发现功能,并且拥有负载均衡、容错机制等。
二、什么是RPC
RPC(RemoteProcedureCall)远程过程调用,简单的理解是一个节点请求另一个节点提供的服务。
本地过程调用:如果需要将本地student对象的age+1,可以实现一个addAge()方法,将student对象传入,对年龄进行更新之后返回即可,本地方法调用的函数体通过函数指针来指定。
远程过程调用:上述操作的过程中,如果addAge()这个方法在服务端,执行函数的函数体在远程机器上,如何实现age+1?
1、首先客户端需要告诉服务器,需要调用的函数,这里函数和进程ID存在一个映射,客户端远程调用时,需要查一下函数,找到对应的ID,然后执行函数的代码。
2、客户端需要把本地参数传给远程函数,本地调用的过程中,直接压栈即可,但是在远程调用过程中不再同一个内存里,无法直接传递函数的参数,因此需要客户端把参数转换成字节流,传给服务端,然后服务端将字节流转换成自身能读取的格式,是一个序列化和反序列化的过程。
3、数据准备好了之后,网络传输层需要把调用的ID和序列化后的参数传给服务端,然后把计算好的结果序列化传给客户端,因此TCP层即可完成上述过程。
三、实现简单RCP框架
1、首先定义一个接口和具体实现
public interface AobingService {
int addAge(int age);
}
public class AobingServiceImpl implements AobingService {
public int addAge(int age) {
return age+1;
}
}
2、RPC框架主体——服务提供者暴露服务
public class AobingRpcFramework {
public static void export(Object service, int port) throws Exception {
ServerSocket server = new ServerSocket(port);
while(true) {
Socket socket = server.accept();
new Thread(new Runnable() {
//反序列化
ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
String methodName = input.read(); //读取方法名
Class<?>[] parameterTypes = (Class<?>[]) input.readObject(); //参数类型
Object[] arguments = (Object[]) input.readObject(); //参数
Method method = service.getClass().getMethod(methodName, parameterTypes); //找到方法
Object result = method.invoke(service, arguments); //调用方法
// 返回结果
ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
output.writeObject(result);
}).start();
}
}
public static <T> T refer (Class<T> interfaceClass, String host, int port) throws Exception {
return (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class<?>[] {interfaceClass},
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] arguments) throws Throwable {
Socket socket = new Socket(host, port); //指定 provider 的 ip 和端口
ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
output.write(method.getName()); //传方法名
output.writeObject(method.getParameterTypes()); //传参数类型
output.writeObject(arguments); //传参数值
ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
Object result = input.readObject(); //读取结果
return result;
}
});
}
}
3、通过RPC实现远程调用
//服务提供者只需要暴露出接口
AobingService service = new AobingServiceImpl ();
AobingRpcFramework.export(service, 2333);
//服务调用者只需要设置依赖
AobingService service = AobingRpcFramework.refer(AobingService.class, "127.0.0.1", 2333);
service.addAge();
四、Dubbo总体架构
Consumer:需要调用远程服务的服务消费方
Registry:注册中心
Provider:服务提供方
Container:服务运行的容器
Monitor:监控中心
如上图,首先服务提供者Provider启动,然后向注册中心注册自己所能提供的服务。服务消费者Consumer启动并向注册中心订阅自己所需要的服务。然后注册中心将提供者的信息通知给Consumer,之后Consumer因为已经从注册中心获取提供者的地址,因此可以通过负载均衡选择一个Provider直接调用。
关于Dubbo的详细内容后续将持续更新~