1、RPC 基础知识
1.1、软件架构
单一应用架构
单一应用架构:就是之前练习的系统,将所有的功能都部署在一起,只需一个应用
当网站流量很小时,应用规模小时,只需一个应用,将所有功能都部署在一起,以减少部署服务器数量和成本
适合小型系统,小型网站,或者企业的内部系统,用户较少,请求量不 大,对请求的处理时间没有太高的要求
缺点: 1、性能扩展比较困难 2、不利于多人同时开发 3、不利于升级维护 4、整个系统的空间占用比较大
分布式服务架构
将核心业务抽取出来,作为独立的服务
1.2、分布式系统
分布式系统中的计算机可以使用不同的操作系统,可以运行不同应用程序提供服务,将 服务分散部署到多个计算机服务器上
1.2.1、RPC
RPC 【Remote Procedure Call】是指远程过程调用,是一种进程间通信方式,是一种技 术思想,而不是规范
它允许程序调用另一个地址空间(网络的另一台机器上)的过程或函 数,而不用开发人员显式编码这个调用的细节
RPC 的特点
- 简单:使用简单,建立分布式应用更容易
- 高效:调用过程看起来十分清晰,效率高
- 通用:进程间通讯的方式,有通用的规则
rpc 通讯是基于 tcp 或 udp 议
序列化方式(xml/json/二进制)
1.2.2、RPC 基本原理
2、dubbo 框架
一般服务器与服务器之间使用的是长连接方式,用户与服务器之间使用短连接方式访问
面向接口代理:
调用接口的方法,在 A 服务器调用 B 服务器的方法,由 dubbo 实现对 B 的 调用,无需关心实现的细节,就像 MyBatis 访问 Dao 的接口,可以操作数据库一样。不用关心 Dao 接口方法的实现
动态代理对象
2.1、dubbo 支持的协议
支持多种协议:dubbo , hessian , rmi , http, webservice , thrift , memcached , redis。 dubbo 官方推荐使用 dubbo 协议
dubbo 协议默认端口 20880
dubbo 协议采用单一长连接和异步通讯,适用于小数据量大并发的服务调用,不适合于大数据量的服务(比如文件、视频等)
一般服务器与服务器之间使用的是长连接方式,用户与服务器之间使用短连接方式访问
使用 dubbo 协议,spring 配置文件加入:
<dubbo:protocol name="dubbo" port="20880"/>
2.2、基本架构
服务提供者(Provider):暴露服务的服务提供方,服务提供者在启动时,向注册中心注 册自己提供的服务
服务消费者(Consumer): 调用远程服务的服务消费方,服务消费者在启动时,向注册 中心订阅自己所需的服务,服务消费者,从提供者地址列表中,基于软负载均衡算法,选一 台提供者进行调用,如果调用失败,再选另一台调用
注册中心(Registry):注册中心返回服务提供者地址列表给消费者,如果有变更,注册 中心将基于长连接推送变更数据给消费者
监控中心(Monitor):服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心(可以没有)
调用关系说明:
- 服务容器负责启动,加载,运行服务提供者
- 服务提供者在启动时,向注册中心注册自己提供的服务
- 服务消费者在启动时,向注册中心订阅自己所需的服务
- 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推 送变更数据给消费者
- 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用, 如果调用失败,再选另一台调用
- 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计 数据到监控中心
2.3、使用 Dubbo 的第一个项目
先写的简单一点,使用 点对点的直连方式
点对点的直连项目:消费者直接访问服务提供者,没有注册中心
消费者必须指定服务提供者的访问地址(url),消费者直接通过 url 地址访问固定的服务提供者,这个 url 地址是不变的
2.3.1、服务提供者
步骤:
-
新建 maven web 工程
-
创建实体类,保存在网络中传输的数据
注意此类需要实现序列化接口,否则后面启动项目会报错
-
定义服务接口和实现类:UserService
-
定义 spring 配置文件
- 声明 Dubbo 服务名称:保证唯一
- 声明 Dubbo 使用的协议和端口号
- 暴露服务接口,使用直连方式
- 声明服务接口的实现类对象
-
测试配置文件是否有效
-
添加监听器(创建spring容器对象)
-
将项目打包成 jar 包
-
消费者怎么知道提供者暴露了哪些接口呢?
这里需要将提供者的工程打包成一个 jar 包,并放入本地仓库,作为消费者 maven 的一个依赖
-
将打包方式改为 jar ,然后进行打包,放入本地仓库
-
然后再将打包方式改回 war
-
在消费者项目中,引入此依赖
<!--依赖服务提供者--> <dependency> <groupId>com.afei</groupId> <artifactId>001_test</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
-
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.afei</groupId>
<artifactId>001_test</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!--Spring依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.16.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.16.RELEASE</version>
</dependency>
<!--dubbo 依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.2</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<!-- 插件 Tomcat7 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>8080</port> <!-- 端口 -->
<path>/</path> <!-- 上下路径 -->
<uriEncoding>UTF-8</uriEncoding> <!-- 针对 GET 方式乱码处理 -->
</configuration>
</plugin>
</plugins>
</build>
</project>
实体类
自定义类,使用 idea 自动生成序列化版本号
在类名上 Alt + Enter ,生成序列化版本号
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
private Integer id;
private String username;
private Integer age;
}
service 接口及实现类
public interface UserService {
User queryUserById(Integer id);
}
public class UserServiceImpl implements UserService {
@Override
public User queryUserById(Integer id) {
User user = new User(1001, "lisi", 20);
return user;
}
}
spring配置文件
<?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"
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">
<!-- dubbo 提供者的配置文件-->
<!--声明服务的名称,自定义名字表示当前服务提供者
name:自定义服务名称,一般使用项目名称,使用唯一值
服务名称是 Dubbo 内部使用标识服务的
-->
<dubbo:application name="001-link-userservice-provider"/>
<!--访问服务协议的名称、端口
name:指定协议名称,官方推荐使用 dubbo 协议
port:指定协议端口号,默认20880
-->
<dubbo:protocol name="dubbo" port="20880"/>
<!--暴露服务接口
interface:接口全限定名称
ref:指定接口实现类的bean的id
registry:指定使用注册中心。这里是点对点直连方式,不使用注册中心,赋值为N/A:不使用注册中心
-->
<dubbo:service interface="com.service.UserService" ref="userServiceImpl" registry="N/A"/>
<!--声明服务接口的实现类对象,真正提供接口的功能实现-->
<bean id="userServiceImpl" class="com.service.impl.UserServiceImpl"/>
</beans>
第二、三步可以合并为一个标签
<dubbo:service interface="com.service.UserService"
ref="userServiceImpl"
protocol="dubbo"
registry="N/A"/>
写完配置文件可以进行简单测试,如果没有报错,验证读取是否成功、配置是否有效
public static void main(String[] args) {
//创建spring容器对象
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("dubbo-userservice-provider.xml");
ctx.start();
}
web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<!--声明监听器
1、默认监听器:创建容器对象是,读取配置文件:/WEB_INF/applicationContext.xml
2、自定义日期使用配置文件的路径:使用 context-param 标签
-->
<!--自定义spring容器使用的配置文件路径
context-param 叫做上下文路径,给监听器提供参数的
-->
<context-param>
<!-- contextConfigLocation:固定名称,表示自定义spring配置文件路径 -->
<param-name>contextConfigLocation</param-name>
<!-- 自定义配置文件路径 -->
<param-value>classpath:dubbo-userservice-provider.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
2.3.2、服务消费者
步骤:
- 新建 maven 项目
- 定义 spring 配置文件
- 声明服务的名称
- 声明要使用的服务,引用服务提供者
- 定义使用者类,调用服务提供者的功能吗,这是一个远程调用
消费者怎么知道提供者暴露了哪些接口呢?
这里需要将提供者的工程打包成一个 jar 包,然后放入本地仓库,作为消费者 maven 的一个依赖
pom.xml
<!--Spring依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.16.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.16.RELEASE</version>
</dependency>
<!--dubbo 依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.2</version>
</dependency>
<!--依赖服务提供者-->
<dependency>
<groupId>com.afei</groupId>
<artifactId>001_test</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
spring配置文件
<?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://dubbo.apache.org/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- dubbo 消费者的配置文件-->
<!--声明服务的名称(声明服务的操作是一样的)-->
<!--声明服务的名称,自定义名字表示当前服务提供者
name:自定义服务名称,一般使用项目名称,使用唯一值
服务名称是 Dubbo 内部使用标识服务的
-->
<dubbo:application name="002-link-consumer"/>
<!--引用远程服务接口
interface:dubbo服务接口全限定名称
id:dubbo创建的代理对象的id,使用这个id访问代理对象
url:点对点方式中,访问远程服务的地址
dubbo://localhost:20880
-->
<dubbo:reference interface="com.service.UserService"
id="remoteUserService"
url="dubbo://localhost:20880" registry="N/A"/>
<bean id="invokeService" class="com.service.InvokeService">
<property name="service" ref="remoteUserService"/>
</bean>
</beans>
定义使用者类
public class MyClient {
public static void main(String[] args) {
//创建 spring 容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("dubbo-consumer.xml");
//从容器中获取远程的代理对象
UserService service = (UserService) ctx.getBean("remoteUserService");
System.out.println(service); //com.alibaba.dubbo.common.bytecode.proxy0@776aec5c 说明是生成的代理对象
//通过代理对象执行方法的调用,就像调用自己的方法一样
User user = service.queryUserById(1001);
System.out.println("通过代理对象执行方法的调用结果" + user);
}
}
2.3.3、运行项目
直接输出代理对象,执行方法调用
需要启动服务提供者的 Tomcat 服务,然后执行 消费者中使用者类的 main 方法
当执行 service.queryUserById(1001);
,方法传入参数之后,进行序列化,传递到 001提供者 项目中
该项目执行得到 user 对象,然后经过序列化传递回 002 消费者项目
002经过反序列化得到结果 user 对象,赋值给 User user
代理对象作为业务类的属性
(也可以创建 springmvc 配置文件,使用注解方式,定义controller类,来调用业务类对象执行方法)
定义业务类
@Setter
public class InvokeService {
private UserService service;
public void printService(){
User user = service.queryUserById(1001);
System.out.println("通过代理对象执行方法的调用结果" + user);
}
配置文件中声明 bean 对象
<bean id="invokeService" class="com.service.InvokeService">
<property name="service" ref="remoteUserService"/>
</bean>
使用者类创建业务类对象,执行方法
public class MyClient {
public static void main(String[] args) {
//创建 spring 容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("dubbo-consumer.xml");
//从容器中获取 Service 对象
InvokeService service = (InvokeService) ctx.getBean("invokeService");
service.printService();
}
}
需要启动服务提供者项目的 Tomcat 服务,然后执行消费者项目中使用者类的 main 方法
2.4、使用接口作为独立项目
假如此时有多个功能提供者,消费者需要使用查看用户信息、获取天气状况、查看电影信息三个功能
因为消费者项目中需要:
- 导入提供者 jar 包(多个功能就有多个jar包,麻烦)
- 使用提供者暴露的接口
此处多个功能就有多个jar包,麻烦,所以规范化应该是如下结构:
- 定义一个公共接口项目:
- 定义实体类
- 定义接口
- 多个服务器ABC,实现提供者功能
- 引入公共接口项目的 jar 包
- 定义公共接口项目中的接口的实现类
- 定义spring配置文件,内容不需要变化,仍然是 4 步
- 添加监听器(创建spring容器对象),内容不需要变化
- 消费者项目:
- 现在只需要引入公共接口项目的 jar 包,就不需要引用多个 jar 包
- 定义spring配置文件,内容不需要变化,仍然是 2 步
2.5、dubbo 常用标签
Dubbo 中常用标签。分为三个类别:公用标签,服务提供者标签,服务消费者标签
2.5.1、公用标签
<dubbo:application/> 和 <dubbo:registry/>
-
配置应用信息
<dubbo:application name="服务的名称/>
-
配置注册中心
<dubbo:registry address="ip:port" protocol="协议"/>
2.5.2、提供者标签
配置访问服务提供者的协议信息
<dubbo:protocol name="dubbo" port="20880"/>
配置暴露的服务
<dubbo:service interface="服务接口名" ref="服务实现对象 bean"/>
2.5.3、消费者标签
配置服务消费者引用远程服务
<dubbo:reference id="服务引用 bean 的 id" interface="服务接口名"/>
2.5.4、关闭检查 check
服务启动时,会检查相关的依赖是否可用,如不可用则会抛出异常(比如此处必须先运行提供者的 Tomcat,否则报错)
关闭这个启动时检查:(比如先运行消费者,再运行的提供者,就需要关闭检查)
<dubbo:reference interface="com.service.UserService" check="false"/>
关闭注册中心启动时检查:
<dubbo:registry check="false"/>
2.5.5、请求重试 retries
远程服务调用重试次数,不包括第一次调用,默认是 2 次,加上第一次共 3 次
<dubbo:reference retries="5" />
3、注册中心-Zookeeper
现在在消费者项目的配置文件中,对于 引用远程服务接口 中的访问地址,是写死的,现在使用注册中心可以使其动态化,防止出现链接崩坏而导致的项目问题
服务注册中心可以通过特定协议来完成服务对外的统一
Dubbo 提供 的注册中心有如下几种类型可供选:
- Multicast 注册中心:组播方式 (类似于广播,需要频道)
- Redis 注册中心:使用 Redis 作为注册中心 (存入redis数据库)
- Simple 注册中心:就是一个 dubbo 服务。作为注册中心。提供查找服务的功能。
- Zookeeper 注册中心:使用 Zookeeper 作为注册中心
Zookeeper 是一个高性能的,分布式的,开放源码的分布式应用程序协调服务,简称 zk
Zookeeper 是翻译管理是动物管理员,可以理解为 windows 中的资源管理器或者注册表
他是一个树形结构,这种树形结构和标准文件系统相似,ZooKeeper 树中的每个节点被称为 Znode,和文件系统的目录树一样,ZooKeeper 树中的每个节点可以拥有子节点,每个节点表 示一个唯一服务资源
Zookeeper 运行需要 java 环境
3.1、安装配置 Zookeeper
3.1.1、Windows 平台 Zookeeper 安装,配置
下载的文件 zookeeper-3.5.4-beta.tar.gz 解压后到目录就可以了,例如 d:/servers/ zookeeper-3.5.4
修改 zookeeper-3.5.4/conf/ 目录下配置文件
复制一份 zoo-sample.cfg ,并改名为 zoo.cfg
文件内容:
-
tickTime:心跳的时间,单位毫秒
Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳,表明存活状态
-
dataDir:数据目录,可以是任意目录
存储 zookeeper 的快照文件、pid 文件,默认为 /tmp/zookeeper,建议在 zookeeper 安装目录下创建 data 目录,将 dataDir 配置改为
/usr/local/zookeeper-3.4.10/data
-
clientPort:客户端连接 zookeeper 的端口,即 zookeeper 对外的服务端口,默认为 2181
配置内容:
-
dataDir :zookeeper 数据的存放目录
-
admin.serverPort=8888
原因:zookeeper 3.5.x 占用 8080
启动:
打开解压目录的 bin 目录,双击 zkServer.cmd ,启动服务器
zkCli.cmd 启动命令客户端
3.1.2、 Linux 平台 Zookeeper 安装、配置
Zookeeper 的运行需要 jdk。使用前 Linux 系统要安装好 jdk
①:上传 zookeeper-3.5.4-beta.tar.gz 并解压
解压文件执行命令:tar -zxvf zookeeper-3.5.4-beta.tar.gz -C /usr/local/
②:配置文件
在 zookeeper 的 conf 目录下,拷贝样例文件 zoo-sample.cfg 为 zoo.cfg,cp zoo_sample.cfg zoo.cfg
zookeeper 启动时会读取该文件作为默认配置文件
③:启动 Zookeeper
启动(切换到安装目录的 bin 目录下):./zkServer.sh start
④:关闭 Zookeeper
关闭(切换到安装目录的 bin 目录下):./zkServer.sh stop
3.2、使用 Zookeeper
-
将服务提供者注册到注册中心(暴露服务)
- 导入 dubbo 依赖、操作 ZooKeeper 的客户端 curator 依赖
- 配置服务提供者(spring配置文件)
- 声明服务的名称
- 声明ZooKeeper注册中心的地址
- 指定通信规则
- 暴露服务接口,ref指向真正的实现对象
-
让服务消费者去注册中心订阅服务提供者的服务地址
-
消费者需要引入和提供者一样的依赖
-
配置文件
- 声明服务的名称
- 声明ZooKeeper注册中心
- 引用远程服务接口
-
3.2.1、公共接口
仅提供实体类、需要暴露的公共接口
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.afei</groupId>
<artifactId>dubbo-public-interface</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!--Spring依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.16.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.16.RELEASE</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
实体类、接口
注意实体类要实现序列化接口
@Data
public class User implements Serializable {
private Integer id;
private String username;
private Integer age;
}
public interface UserService {
User queryUser(Integer id);
}
结构
3.2.2、服务提供者
需要引入公共接口项目打包为 jar 包,放入maven本地仓库作为依赖
怎么将项目打包为 jar ?并且打包同时放入maven本地仓库
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.afei</groupId>
<artifactId>user-provider</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!--Spring依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.16.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.16.RELEASE</version>
</dependency>
<!--dubbo 依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.2</version>
</dependency>
<!--curator-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.0</version>
</dependency>
<!--引入公共接口依赖-->
<dependency>
<groupId>com.afei</groupId>
<artifactId>dubbo-public-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
接口实现类
public class UserServiceImpl implements UserService {
@Override
public User queryUser(Integer id) {
User user = new User();
user.setId(id);
user.setUsername("lisi");
user.setAge(id + 1);
return user;
}
}
配置文件
<?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://dubbo.apache.org/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- dubbo 提供者的配置文件-->
<!--声明服务的名称,自定义名字表示当前服务提供者
name:自定义服务名称,一般使用项目名称,使用唯一值
服务名称是 Dubbo 内部使用标识服务的
-->
<dubbo:application name="user-provider"/>
<!--声明ZooKeeper注册中心的地址
连接到本机,因为使用的是 Linux,使用IP地址,如果是Windows,使用localhost
或者用<dubbo:registry protocol="zookeeper" address="192.168.162.128:2181"/>
-->
<dubbo:registry address="zookeeper://192.168.162.128:2181"/>
<!-- 指定通信规则,访问服务协议的名称、端口 -->
<dubbo:protocol name="dubbo" port="20880"/>
<!--暴露服务接口
interface:接口全限定名称
ref:指定接口实现类的bean的id
-->
<dubbo:service interface="com.service.UserService" ref="userServiceImpl"/>
<!--
如果还有其他实现类,那么可以通过 version 来解决消费者想要调用哪个实现类的问题
<dubbo:service interface="com.service.UserService" ref="userServiceImpl"
version="2.0.0"/>
-->
<!--声明服务接口的实现类对象,真正提供接口的功能实现-->
<bean id="userServiceImpl" class="com.serviceImpl.UserServiceImpl"/>
</beans>
对应着xml配置的 <dubbo:service> 和<dubbo:reference>
,注解是 @DubboService 和 @DubboReference
注:2.7.7 开始才增加这两个注解,之前使用的是@Service和@Reference
- @Service 只能定义在一个类上,表示一个服务的具体实现
- interfaceClass:指定服务提供方实现的 interface 的类
- interfaceName:指定服务提供方实现的 interface 的类名
- version:指定服务的版本号
- group:指定服务的分组
- export:是否暴露服务
- registry:是否向注册中心注册服务
- application:应用配置
- module:模块配置
- provider:服务提供方配置
- protocol:协议配置
- monitor:监控中心配置
- registry:注册中心配置
(从 8 到 13)需要提供的是对应的 spring bean 的名字
①、启动提供者一
注意:
关闭 Linux 防火墙、启动ZooKeeper服务、启动监控中心(运行 jar 包并访问 7001 端口)
第一种方式:在上面配置的基础上,仅需要创建一个类,来加载 spring 配置生成容器对象,并执行 start() 方法
加载 spring 配置
public class MainApplication {
//必须保证此方法在运行,没有停止,注册中心中才可以有提供者存在
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext appc = new ClassPathXmlApplicationContext("provider.xml");
appc.start();
System.in.read(); //此句不可省
}
}
结构
②、启动提供者二
注意:
关闭 Linux 防火墙、启动ZooKeeper服务、启动监控中心(运行 jar 包并访问 7001 端口)
第二种方式:在上面配置的基础上
-
配置 web.xml 方式,配置监听器,来生成 Spring 容器对象
-
配置 pom.xml 文件,添加 Tomcat 插件,启动 tomcat来启动 提供者服务
注意更改端口号,将打包方式改成 war
web.xml文件
配置 spring 容器监听器
<!--声明监听器-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:provider.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
pom.xml 文件新增
<packaging>war</packaging>
<build>
<plugins>
<!-- 插件 Tomcat7 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>8081</port> <!-- 端口 -->
<path>/</path> <!-- 上下路径 -->
<uriEncoding>UTF-8</uriEncoding> <!-- 针对 GET 方式乱码处理 -->
</configuration>
</plugin>
</plugins>
</build>
结构
3.2.3、服务消费者
需要引入公共接口项目打包为 jar 包,放入maven本地仓库作为依赖
pom.xml
文件内容与提供者的内容一致
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.afei</groupId>
<artifactId>consumer</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!--Spring依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.16.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.16.RELEASE</version>
</dependency>
<!--dubbo 依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.2</version>
</dependency>
<!--curator-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.0.0</version>
</dependency>
<!--引入公共接口依赖-->
<dependency>
<groupId>com.afei</groupId>
<artifactId>dubbo-public-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 插件 Tomcat7 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>8080</port> <!-- 端口 -->
<path>/</path> <!-- 上下路径 -->
<uriEncoding>UTF-8</uriEncoding> <!-- 针对 GET 方式乱码处理 -->
</configuration>
</plugin>
</plugins>
</build>
</project>
配置文件
<?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://dubbo.apache.org/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://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- dubbo 消费者的配置文件-->
<!--声明服务的名称(声明服务的操作是一样的)-->
<!--声明服务的名称,自定义名字表示当前服务提供者
name:自定义服务名称,一般使用项目名称,使用唯一值
服务名称是 Dubbo 内部使用标识服务的
-->
<dubbo:application name="consumer"/>
<!--声明ZooKeeper注册中心-->
<dubbo:registry address="zookeeper://192.168.162.128:2181"/>
<!--引用远程服务接口
interface:dubbo服务接口全限定名称
id:dubbo创建的代理对象的id,使用这个id访问代理对象
-->
<dubbo:reference interface="com.service.UserService" id="remoteUserService"/>
</beans>
对应着xml配置的 <dubbo:service> 和<dubbo:reference>
,注解是 @DubboService 和 @DubboReference
注:2.7.7开始才增加这两个注解,之前使用的是@Service和@Reference
- @Reference 可以定义在类中的一个字段上,也可以定义在一个方法上,甚至可以用来修饰另一个 annotation,表示一个服务的引用。通常 @Reference 定义在一个字段上
- interfaceClass:指定服务的 interface 的类
- interfaceName:指定服务的 interface 的类名
- version:指定服务的版本号
- group:指定服务的分组
- url:通过指定服务提供方的 URL 地址直接绕过注册中心发起调用
- application:应用配置
- module:模块配置
- consumer:服务消费方配置
- protocol:协议配置
- monitor:监控中心配置
- registry:注册中心配置
(从 7 到 12)需要提供的是对应的 spring bean 的名字
启动类就要使用 @EnableDubbo: 开启注解Dubbo功能 ,其中可以加入scanBasePackages属性配置包扫描的路径,用于扫描并注册bean
通过 @EnableDubbo
可以在指定的包名下(通过 scanBasePackages
),或者指定的类中(通过 scanBasePackageClasses
)扫描 Dubbo 的服务提供者(以 @Service
标注)以及 Dubbo 的服务消费者(以 Reference
标注)
SpringMVC 配置文件
<?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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.service"/>
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<!--声明中央调度器-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml,classpath:consumer.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
service、controller
@Component
public class ConsumerService {
@Resource
private UserService userService;
public void printTest(Integer userid){
User user = userService.queryUser(userid);
System.out.println(user);
}
}
@Controller
public class MyController {
@Resource
private ConsumerService service;
@RequestMapping("/test")
public String tt(Integer id){
service.printTest(id);
return "hello";
}
}
结构
4、监控中心
4.1、什么是监控中心
dubbo 的使用,其实只需要有注册中心,消费者,提供者这三个就可以使用了,但是并不能看到有哪些消费者和提供者,为了更好的调试,发现问题,解决问题,因此引入 dubbo-admin
通过 dubbo-admin 可以对消费者和提供者进行管理。可以在 dubbo 应用部署做动态的调整, 服务的管理
- dubbo-admin:图形化的服务管理页面;安装时需要指定注册中心地址,即可从注册中心中获取到所有的提供者 / 消费者进行配置管理
- dubbo-monitor-simple:简单的监控中心
4.2、发布配置中心
1、下载监控中心,https://github.com/alibaba/dubbo
到官网的 GitHub页面,拉到最下面,点击 dubbo admin
这里下载的是源代码,需要手工编译才能使用
下载
2、 进入目录,修改dubbo-admin配置
修改 src\main\resources\application.properties 指定zookeeper地址
如果启动的 ZooKeeper 是 Windows 版本的,地址就如下图:
如果启动的 ZooKeeper 是 Linux 版本的,地址就填虚拟机地址:
3、 打包dubbo-admin
进入 pom.xml 文件所在的目录。在目录栏使用 cmd ,打开命令窗口
执行命令: mvn clean package
清理并打包
打包好后,会在 target 目录下出现 jar 包
4、运行dubbo-admin
将jar包挪出来,然后在 jar 包所在目录位置 cmd
注意:
- jdk版本时 1.8
- 要保证 ZooKeeper 在 jdk1.8版本下运行
执行命令:java -jar dubbo-admin-0.0.1-SNAPSHOT.jar
启动后不关闭窗口,在浏览器访问端口 7001
默认使用root/root 登陆
5、负载均衡
负载均衡是以集群为前提,将工作任务进行平衡、分摊到多个操作单元上进行执行
负载均衡有两个方面的含义:
- 单个重负载的工作分配到多台服务器做并行处理,每个服务器处理之后将结果汇总,返回给用户,系统处理能力增强
- 大量的并发访问或数据流量分摊到多台服务器处理,减少用户等待响应时间
5.1、负载策略
RandomLoadBalance(默认)
随机,按权重设置随机概率
RoundRobinLoadBalance
轮循,按公约后的权重设置轮循比率
存在慢的提供者累计请求问题,服务器性能相近时使用
LeastActiveLoadBalance
最少活跃调用书,系统活跃数的随机,活跃数指调用前后计数差
服务器性能相差较大时使用
ConsistentHashLoadBalance
一致性 Hash,相同参数的请求总是发到同一提供者,当某一提供者挂是,将需求会平摊到其他提供者
对故障的处理波动较小
5.2、代码实现
需要是集群环境中实现
配置方式:
<dubbo:reference interface="..." loadbalance="roundrobin"/>
或
<dubbo:service interface="..." loadbalance="roundrobin"/>