一 什么是RPC
维基百科是这么定义RPC的:
在分布式计算,远程过程调用(英语:Remote Procedure Call,缩写为 RPC)是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一个地址空间(通常为一个开放网络的一台计算机)的子程序,而程序员就像调用本地程序一样,无需额外地为这个交互作用编程(无需关注细节)。RPC是一种服务器-客户端(Client/Server)模式,经典实现是一个通过发送请求-接受回应进行信息交互的系统。
如果涉及的软件采用面向对象编程,那么远程过程调用亦可称作远程调用或远程方法调用,例:Java RMI。
所以,对于Java程序员而言,RPC就是远程方法调用。
远程方法调用和本地方法调用是相对的两个概念,本地方法调用指的是进程内部的方法调用,而远程方法调用指的是两个进程内的方法相互调用。
要实现远程方法调用,基本的就是通过网络,通过传输数据来进行调用。
所以就有了:
- RPC over Http:基于Http协议来传输数据
- PRC over Tcp:基于Tcp协议来传输数据
对于所传输的数据,可以交由RPC的双方来协商定义,但基本都会包括:
- 调用的是哪个类或接口
- 调用的是哪个方法,方法名和方法参数类型(考虑方法重载)
- 调用方法的入参
所以,我们其实可以看到RPC的自定义性是很高的,各个公司内部都可以实现自己的一套RPC框架,而Dubbo就是阿里所开源出来的一套RPC框架。
二 什么是Dubbo
官网地址:http://dubbo.apache.org/zh/
目前,官网上是这么介绍的:Apache Dubbo 是一款高性能、轻量级的开源 Java 服务框架
在不久前,官网的介绍是:Apache Dubbo 是一款高性能、轻量级的开源 Java RPC框架
为什么会将RPC改为服务?
Dubbo一开始的定位就是RPC,专注于两个服务之间的调用。但随着微服务的盛行,除开服务调用之外,Dubbo也在逐步的涉猎服务治理、服务监控、服务网关等等,所以现在的Dubbo目标已经不止是RPC框架了,而是和Spring Cloud类似想成为了一个服务框架。
Dubbo网关参考:https://github.com/apache/dubbo-proxy(社区不是很活跃)
2.1 基本原理
2.2 开源RPC框架对比
网上截图,仅作为参考(数据需要更新)
手写模拟Dubbo代码地址:https://gitee.com/archguide/rpc
git clone地址:https://gitee.com/archguide/rpc.git
三 Dubbo与直接远程调用Controller区别
如果是使用Httpclient或者restTemplate直接调用远程Controller的话,存在以下问题
- 调用服务方在调用时,在代码里把服务提供者的地址可能写错
- get/post等请求方式也可能写错
- 消费者获取到String类型的返回值后还需要手动转换为对象
总之,使用远程直接调用会有很大概率出各种错误
而使用dubbo的话,对于服务提供者,只需要写一个service/serviceImpl类即可,如下
public interface DemoService {
public String sayHello(String name) ;
}
import org.apache.dubbo.demo.DemoService;
import org.apache.dubbo.rpc.RpcContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
public class DemoServiceImpl implements DemoService {
// 服务
private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class);
@Override
public String sayHello(String name) {
logger.info("Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress());
return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress();
}
}
对于服务消费者,只需要定义与服务提供者同样的接口即可,而接口体量非常小,所以消费者依赖的其他代码就会非常少
import org.apache.dubbo.demo.DemoService;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.concurrent.CompletableFuture;
public class Application {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-consumer.xml");
context.start();
// 接口的代理对象
DemoService demoService = context.getBean("demoService", DemoService.class);
String hello = demoService.sayHello("world"); // 执行服务
System.out.println("result周瑜: " + hello);
}
}
四 spring整合dubbo
spring整合dubbo有两种方式:xml配置文件与注解
4.1 xml配置文件整合dubbo
服务提供者
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!--应用名字-->
<dubbo:application name="demo-provider"/>
<!--注册中心,可以不使用注册中心-->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<!--服务协议,这里也可以配置为http-->
<dubbo:protocol name="dubbo"/>
<!--服务协议是http的话,默认是tomcat,这里可以手动改为jetty-->
<!--<dubbo:protocol name="http" server="jetty"/>-->
<!--定义springBean-->
<bean id="demoService" class="org.apache.dubbo.demo.provider.DemoServiceImpl"/>
<!--定义dubbo服务 interface:接口 ref:接口的具体实现-->
<dubbo:service interface="org.apache.dubbo.demo.DemoService" ref="demoService" />
</beans>
服务消费者
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!--应用名字-->
<dubbo:application name="demo-consumer"/>
<!--注册中心-->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<!--定义dubbo服务 reference:引入服务 id:bean名字(代码里要用这个bean) interface:要使用哪个服务-->
<dubbo:reference id="demoService" check="false" interface="org.apache.dubbo.demo.DemoService"/>
</beans>
4.2 Dubbo 中 zookeeper做注册中心,如果注册中心集群都挂掉,发布者和订阅者之间还能通信么?
可以通信的,启动 dubbo 时,消费者会从 zk 拉取注册的生产者的地址接口等数据,缓存在本地。每次调用时,按照本地存储的地址进行调用;
注册中心对等集群,任意一台宕机后,将会切换到另一台;注册中心全部宕机后,服务的提供者和消费者仍能通过本地缓存通讯。服务提供者无状态,任一台宕机后,不影响使用;服务提供者全部宕机,服务消费者会无法使用,并无限次重连等待服务者恢复;
挂掉是不要紧的,但前提是你没有增加新的服务,如果你要调用新的服务,则是不能办到的。