远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC 协议假定某些传输协议的存在,如 TCP 或 UDP,为通信程序之间携带信息数据。在 OSI 网络通信模型中,RPC 跨越了传输层和应用层。RPC 使得开发包括网络分布式程序在内的应用程序更加容易。
RPC 采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。
在单机时代一台电脑运行多个进程,进程之间无法通讯,显然这会浪费很多资源,因此后来出现 IPC(Inter-process communication: 单机中运行的进程之间的相互通信 ),这样就能允许进程之间进行通讯,比如在一台计算机中的 A 进程写了一个吃饭的方法,那在以前如果在 B 进程中也要有一个吃饭的方法,必须要在 B 进程中进行创建,但有了 RPC 后 B 只需要调用 A 进程的程序即可完成,再到后来网络时代的出现, 大家电脑都连起来,这时可不可以调用其他电脑上的进程呢,当然可以,这样 RPC 框架就出现了。
严格意义上来讲:Unix的生态系统中 RPC 可以在同一台电脑上不同进程进行,也可以在不同电脑上进行;而在windows 里面同一台电脑上不同进程间的通讯还可以采用 LPC(本地访问)。综上:RPC 或 LPC是上层建筑,IPC 是底层基础。
RPC 框架有很多:比如 Thrift、dubbo、grpc 等。
TCP/UDP: 都是传输协议,主要区别是 tcp 协议连接需要 3 次握手,断开需要四次挥手,是通过流来传输的,就是确定连接后,一直发送信息,传完后断开。udp 不需要进行连接,直接把信息封装成多个报文,直接发送。所以 udp 的速度更快写,但是不保证数据的完整性。
HTTP: 超文本传输协议是一种应用层协议,建立在 TCP 协议之上
Socket: 是在应用程序层面上对 TCP/IP 协议的封装和应用。其实是一个调用接口,方便程序员使用 TCP/IP 协议栈而已。程序员通过 socket 来使用 tcp/ip 协议。但是 socket 并不是一定要使用 tcp/ip 协议,Socket 编程接口在设计的时候,就希望也能适应其他的网络协议。
小结: 我们把网络传输类比于一条公路,那 TCP/UDP 就是货车,HTTP 就是货物,而 socket就是发动机。
RPC 是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。所以 RPC 的实现可以通过不同的协议去实现比如可以使 http、RMI 等。
首先, 要解决通讯的问题,主要是通过在客户端和服务器之间建立 TCP 连接,远程过程调用的所有交换的数据都在这个连接里传输。连接可以是按需连接,调用结束后就断掉,也可以是长连接,多个远程过程调用共享同一个连接。
第二, 要解决寻址的问题,也就是说,A 服务器上的应用怎么告诉底层的 RPC 框架,如何连接到 B 服务器(如主机或 IP 地址)以及特定的端口,方法的名称名称是什么,这样才能完成调用。比如基于Web服务协议栈的RPC,就要提供一个endpoint URI,或者是从UDDI(一种目录服务,通过该目录服务进行服务注册与搜索)服务上查找。如果是 RMI 调用的话,还需要一个 RMI Registry 来注册服务的地址。
第三, 当 A 服务器上的应用发起远程过程调用时,方法的参数需要通过底层的网络协议如 TCP 传递到 B 服务器,由于网络协议是基于二进制的,内存中的参数的值要序列化成二进制的形式,也就是序列化(Serialize)或编组(marshal),通过寻址和传输将序列化的二进制发送给 B 服务器。
第四, B 服务器收到请求后,需要对参数进行反序列化(序列化的逆操作),恢复为内存中的表达方式,然后找到对应的方法(寻址的一部分)进行本地调用,然后得到返回值。
第五, 返回值还要发送回服务器 A 上的应用,也要经过序列化的方式发送,服务器 A 接到后,再反序列化,恢复为内存中的表达方式,交给 A 服务器上的应用
JAVAEE 里面的 stub 是为屏蔽客户调用远程主机上的对象,必须提供某种方式来模拟本地对象,这种本地对象称为存根(stub), 存根负责接收本地方法调用,并将它们委派给各自的具体实现对象
Skeleton:服务器的骨架
public class User implements Serializable {
private static final long serialVersionUID = 6290816946970912418L;
private Integer id;
private String userName;
private String userPwd;
public User(Integer id, String userName, String userPwd) {
this.id = id;
this.userName = userName;
this.userPwd = userPwd;
}
public User(){
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", userName='" + userName + '\'' +
", userPwd='" + userPwd + '\'' +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public static long getSerialVersionUID() {
return serialVersionUID;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPwd() {
return userPwd;
}
public void setUserPwd(String userPwd) {
this.userPwd = userPwd;
}
}
public interface UserService extends Remote { //规定继承Remote父类
public User queryUserById(Integer userId) throws RemoteException; //规定抛出异常
}
public class UserServiceImp extends UnicastRemoteObject implements UserService {
private Map<Integer, User> users = new HashMap<Integer, User>();
public UserServiceImp() throws RemoteException{
users.put(1,new User(1,"admin","123456"));
users.put(2,new User(2,"shsxt","123456"));
}
@Override
public User queryUserById(Integer userId) throws RemoteException {
return users.get(userId);
}
}
public class Publisher {
public static void main(String[] args) throws RemoteException, AlreadyBoundException, MalformedURLException {
//指定服务端口
LocateRegistry.createRegistry(8989);
//发布服务
Naming.bind("rmi://192.168.1.158:8989/userService", new UserServiceImp());
System.out.println("成功发布服务!!!");
}
}
public class App {
public static void main( String[] args ) throws RemoteException, NotBoundException, MalformedURLException {
UserService userService = (UserService) Naming.lookup("rmi://192.168.1.158:8989/userService");
System.out.println(userService.queryUserById(2));
}
}
官网: http://dubbo.apache.org/en-us/
A high performance Java RPC framework ----一个高效的远程调用框架
Dubbo 是由阿里巴巴开源的一个高性能、基于 Java 开源的远程调用框架。正如在许多RPC 系统中一样,dubbo 是基于定义服务的概念,指定可以通过参数和返回类型远程调用的方法。在服务器端,服务器实现这个接口,并运行一个 dubbo 服务器来处理客户端调用。在客户端,客户机有一个存根,它提供与服务器相同的方法。
dubbo的架构图:
Dubbo 提供三个核心功能:基于接口的远程调用、容错和负载均衡,以及服务的自动注
册与发现。Dubbo 框架广泛的在阿里巴巴内部使用,以及京东、当当、去哪儿、考拉等都在
使用。
这里也是从实战出发,搭建一个简单的远程调用小实例, 首先也是要创建一个maven的多模块项目, 结果图如下:
下面来一个模块一个模块的列出来:
大家不用像我建的那么深,我的错误; 里面的User与UserService与上面的rmi一样;
@Service
public class UserServiceImp implements UserService {
private Map<Integer, User> users = new HashMap<>();
public UserServiceImp(){
users.put(1,new User(1,"admin","123456"));
}
@Override
public User queryUserById(Integer userId) {
return users.get(userId);
}
}
public class Publisher {
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("provider.xml");
context.start();
System.out.println("服务发布成功!!!");
System.in.read(); //按任意键退出
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.shsxt.provider"/>
<!--
dubbo 环境配置
-->
<!--应用名称-->
<dubbo:application name="dubbo_provider"></dubbo:application>
<!--注册中心配置:广播地址-->
<dubbo:registry address="multicast://224.5.6.7:1234"></dubbo:registry>
<!--指定公布的服务使用的协议与端口号-->
<dubbo:protocol name="dubbo" port="20880"></dubbo:protocol>
<!--配置公布的服务-->
<dubbo:service interface="com.shsxt.api.service.UserService" ref="userServiceImp"></dubbo:service>
</beans>
@Controller
public class UserController {
@Resource
private UserService userService;
public User queryUserById(Integer userId){
return userService.queryUserById(userId);
}
}
public class App {
public static void main( String[] args ) {
ApplicationContext context = new ClassPathXmlApplicationContext("consumer.xml");
UserController userController = (UserController) context.getBean("userController");
System.out.println(userController.queryUserById(1));
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.shsxt.consumer"/>
<!--
dubbo 环境配置
-->
<!--配置应用名称-->
<dubbo:application name="dubbo_consumer"></dubbo:application>
<!--指定注册中心-->
<dubbo:registry address="multicast://224.5.6.7:1234"></dubbo:registry>
<!--配置订阅的服务列表-->
<dubbo:reference id="userService" interface="com.shsxt.api.service.UserService"></dubbo:reference>
</beans>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--引入dubbo依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.5.6</version>
</dependency>
</dependencies>
应⽤信息配置。对应的配置类:com.alibaba.dubbo.config.ApplicationConfig,下面是官网的大致配置介绍,详细介绍直接去官网查看: http://dubbo.apache.org/en-us/docs/user/references/xml/dubbo-service.html
标签 目的 介绍
dubbo:service 服务出口 用于导出服务,定义服务元数据,使用多个协议导出服务,向多个注册表注册服务
dubbo:reference 服务参考 用于创建远程代理,订阅多个注册表
dubbo:protocol 协议配置 在供应商方面配置服务协议,消费者方面如下。
dubbo:application 应用程序配置 适用于提供者和消费者。
dubbo:module 模块配置 可选的。
dubbo:registry 注册中心 注册表信息:地址,协议等
dubbo:monitor 监控中心 监控信息:地址,地址等。可选。
dubbo:provider 提供商的默认配置 ServiceConfigs的默认配置。可选的。
dubbo:consumer 消费者的默认配置 ReferenceConfigs的默认配置。可选的。
dubbo:method 方法级别配置 ServiceConfig和ReferenceConfig的方法级别配置。
dubbo:argument 参数配置 用于指定方法参数配置。
注册中⼼配置。对应的配置类: com.alibaba.dubbo.config.RegistryConfig。同时如果有多个不 同的注册 中⼼, 可以声 明多个 dubbo:registry 标签 ,并在 dubbo:service 或dubbo:reference 的 registry 属性指定使⽤的注册⼼。
服务提供者协议配置。对应的配置类:com.alibaba.dubbo.config.ProtocolConfig,同时, 如果需要⽀持多协议, 可以声明多个 dubbo:protocol 标签, 并在 dubbo:service 中通过protocol 属性指定使⽤的协议
服务提供者暴露服务配置。对应的配置类:com.alibaba.dubbo.config.ServiceConfig
服务消费者引⽤服务配置。对应的配置类: com.alibaba.dubbo.config.ReferenceConfig
为啥是linux呢? 简单+不卡啊!
在你认为合适的位置建一个文件夹: mkdir + 文件夹名
进入该目录进行下载操作: wget http://mirrors.hust.edu.cn/apache/zookeeper/zookeeper-3.4.10/zookeeper-3.4.10.tar.gz
tar -zvxf + 你要解压的压缩包
如果你直接去bin目录启动zookeeper服务器的话会报错, 错误为:不能在conf中找到zoo.cfg这个配置文件, 因为一开始conf里面只有一个zoo_sample_cfg , 所以我们先在conf目录下赋值一份, 名为zoo.cfg
cp zoo_sample_cfg zoo.cfg
用vim命令打开zoo.cfg文件, vim zoo.cfg 内容如下:
每个配置对应的解释详细也能看懂,就不介绍了,可以不用改就可以跑去bin目录下启动啦!
./zkServer.sh start (注意是要加start的) 启动服务端
./zkCli.sh 为启动客户端
<!--zookeeper配置-->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.3.3</version>
</dependency>
<!--zkclient客户端-->
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
上面使用了zkclient客户端连接,除了这个还可以使用curator客户端连接, 相应的依赖为:
<dependency>
<groupId>com.netflix.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>1.1.10</version>
</dependency>
就是改对应的provider与consumer模块的xml配置即可
<dubbo:registry address="zookeeper://10.20.153.10:2181" />
<dubbo:registry protocol="zookeeper" address="10.20.153.10:2181" />
不同的ip用逗号隔开
<dubbo:registry address="zookeeper://10.20.153.10:2181?backup=10.20.153.11:2181,10.20.153.12:2181" />
<dubbo:registry protocol="zookeeper" address="10.20.153.10:2181,10.20.153.11:2181,10.20.153.12:2181" />
<dubbo:registry id="chinaRegistry" protocol="zookeeper" address="10.20.153.10:2181" group="china" />
<dubbo:registry id="intlRegistry" protocol="zookeeper" address="10.20.153.10:2181" group="intl" />
我们上面的为单机版的就行,然后启动java里面的服务端与客户程序的代码就行了, 因为zookeeper管理dubbo为树形结构,使用可以查看注册中心的服务情况, 如下用ls 命令查看就行, 查看根节点为:
ls /dubbo (记得前面加/) 想查看哪一级的进哪一级查看就行