2023-01-16 Dubbo+Zookeeper集成
Dubbo+Zookeeper
文章目录
- Dubbo+Zookeeper
- 1. Dubbo作用
- 连通性
- 健壮性
- 伸缩性
- dubbo支持的协议
- dubbo协议(默认)
- 注册中心
- Dubbo支持的注册中心
- Zookeeper注册中心(推荐)
- 2. Dubbo服务治理
- Dubbo启动检查
- 3. Dubbo架构
- 4. Dubbo集群容错方案
- 5. Zookeeper安装
- 1.安装
- 2.集群搭建
- 6. Spring整合Dubbo
- 6.1 Provider生产者
- 6.2 Consumer消费者
- 7. SpringBoot整合Dubbo
- 7.1 Provider生产者
- 7.2 Consumer消费者
- 8.Dubbo的Spi机制的过滤器扩展
Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案
1. Dubbo作用
1.透明化的远程方法调用,就像调用本地方法一样调用远程方法,只需简单配置,没有任何API侵入。
2.软负载均衡及容错机制,可在内网替代F5等硬件负载均衡器,降低成本,减少单点。
3.服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且能够平滑添加或删除服务提供者。
节点 | 角色说明 |
---|---|
Provider | 暴露服务的服务提供方 |
Consumer | 调用远程服务的服务消费方 |
Registry | 服务注册与发现的注册中心 |
Monitor | 统计服务的调用次数和调用时间的监控中心 |
Container | 服务运行容器 |
- 服务容器负责启动,加载,运行服务提供者。
- 服务提供者在启动时,向注册中心注册自己提供的服务。
- 服务消费者在启动时,向注册中心订阅自己所需的服务。
- 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
- 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
dubbo默认服务间调用使用的是同步方式调用
连通性
- 注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,压力较小
- 监控中心负责统计各服务调用次数,调用时间等,统计先在内存汇总后每分钟一次发送到监控中心服务器,并以报表展示
- 服务提供者向注册中心注册其提供的服务,并汇报调用时间到监控中心,此时间不包含网络开销
- 服务消费者向注册中心获取服务提供者地址列表,并根据负载算法直接调用提供者,同时汇报调用时间到监控中心,此时间包含网络开销
- 注册中心,服务提供者,服务消费者三者之间均为长连接,监控中心除外
- 注册中心通过长连接感知服务提供者的存在,服务提供者宕机,注册中心将立即推送事件通知消费者
- 注册中心和监控中心全部宕机,不影响已运行的提供者和消费者,消费者在本地缓存了提供者列表
- 注册中心和监控中心都是可选的,服务消费者可以直连服务提供者
健壮性
- 监控中心宕掉不影响使用,只是丢失部分采样数据
- 数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务
- 注册中心对等集群,任意一台宕掉后,将自动切换到另一台
- 注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯
- 服务提供者无状态,任意一台宕掉后,不影响使用
- 服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复
伸缩性
- 注册中心为对等集群,可动态增加机器部署实例,所有客户端将自动发现新的注册中心
- 服务提供者无状态,可动态增加机器部署实例,注册中心将推送新的服务提供者信息给消费者
dubbo支持的协议
协议是两个网络实体进行通信的基础,数据在网络上从一个实体传输到另一个实体,以字节流的形式传递到对端。在这个字节流的世界里,如果没有协议,就无法将这个一维的字节流重塑成为二维或者多维的数据结构以及领域对象.
序列化方式将对象数据进行转换
Dubbo对于数据之间传输的序列化也支持多种形式:
JDk方式序列化
hessian方式序列化 (dubbo 默认)
Json方式序列化
协议名称 |
---|
dubbo协议(默认) |
rest协议 |
HTTP协议 |
Hessian协议 |
Redis协议 |
Thrift协议 |
gRpc协议 |
memcached协议 |
RMI协议 |
WebService协议 |
dubbo协议(默认)
Dubbo 缺省协议采用单一长连接和 NIO 异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况。反之,Dubbo 缺省协议不适合传送大数据量的服务,比如传文件,传视频等,除非请求量很低。
特性:
缺省协议,使用基于 mina 1.1.7
和 hessian 3.2.1
的 tbremoting 交互。
- 连接个数:单连接
- 连接方式:长连接
- 传输协议:TCP
- 传输方式:NIO 异步传输
- 序列化:Hessian 二进制序列化
- 适用范围:传入传出参数数据包较小(建议小于100K),消费者比提供者个数多,单一消费者无法压满提供者,尽量不要用 dubbo 协议传输大文件或超大字符串。
- 适用场景:常规远程服务方法调用
约束:
- 参数及返回值需实现
Serializable
接口 - 参数及返回值不能自定义实现
List
,Map
,Number
,Date
,Calendar
等接口,只能用 JDK 自带的实现,因为 hessian 会做特殊处理,自定义实现类中的属性值都会丢失。 - Hessian 序列化,只传成员属性值和值的类型,不传方法或静态变量
注册中心
对于服务提供方,它需要发布服务,而且由于应用系统的复杂性,服务的数量、类型也不断膨胀,对于服务消费方,它最关心如何获取到它所需要的服务,而面对复杂的应用系统,需要管理大量的服务调用。而且,对于服务提供方和服务消费方来说,他们还有可能兼具这两种角色,即既需要提供服务,有需要消费服务。
通过将服务统一管理起来,可以有效地优化内部应用对服务发布/使用的流程和管理。服务注册中心可以通过特定协议来完成服务对外的统一.
Dubbo支持的注册中心
在dubbo2.7版本中支持5种注册中心
注册中心名称 |
---|
Nacos注册中心(新dubbo之后) alibaba cloud 的 官方 注册和配置中心 eureka(可用性) |
Zookeeper注册中心(推荐) 分布式一致性协调服务器系统 (一致性) |
Multicast 注册中心 |
Redis 注册中心 |
Simple 注册中心 |
Zookeeper注册中心(推荐)
Zookeeper 是 Apache Hadoop 的子项目,是一个树型的目录服务,支持变更推送,适合作为 Dubbo 服务的注册中心,工业强度较高,可用于生产环境,并推荐使用
2. Dubbo服务治理
Dubbo启动检查
Dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,以便上线时,能及早发现问题,默认 check="true"
。
可以通过 check="false"
关闭检查,比如,测试时,有些服务不关心,或者出现了循环依赖
,必须有一方先启动。
另外,如果你的 Spring 容器是懒加载的,或者通过 API 编程延迟引用服务,请关闭 check,否则服务临时不可用时,会抛出异常,拿到 null 引用,如果 check="false"
,总是会返回引用,当服务恢复时,能自动连上。
3. Dubbo架构
- 服务接口层(Service):该层是与实际业务逻辑相关的,根据服务提供方和服务消费方的业务设计对应的接口和实现。
- 配置层(Config):对外配置接口,以ServiceConfig和ReferenceConfig为中心,可以直接new配置类,也可以通过spring解析配置生成配置类。
- 服务代理层(Proxy):服务接口透明代理,生成服务的客户端Stub和服务器端Skeleton,以ServiceProxy为中心,扩展接口为ProxyFactory。
- 服务注册层(Registry):封装服务地址的注册与发现,以服务URL为中心,扩展接口为RegistryFactory、Registry和RegistryService。可能没有服务注册中心,此时服务提供方直接暴露服务。
- 集群层(Cluster):封装多个提供者的路由及负载均衡,并桥接注册中心,以Invoker为中心,扩展接口为Cluster、Directory、Router和LoadBalance。将多个服务提供方组合为一个服务提供方,实现对服务消费方来透明,只需要与一个服务提供方进行交互。
- 监控层(Monitor):RPC调用次数和调用时间监控,以Statistics为中心,扩展接口为MonitorFactory、Monitor和MonitorService。
- 远程调用层(Protocol):封将RPC调用,以Invocation和Result为中心,扩展接口为Protocol、Invoker和Exporter。Protocol是服务域,它是Invoker暴露和引用的主功能入口,它负责Invoker的生命周期管理。Invoker是实体域,它是Dubbo的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起invoke调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。
- 信息交换层(Exchange):封装请求响应模式,同步转异步,以Request和Response为中心,扩展接口为Exchanger、ExchangeChannel、ExchangeClient和ExchangeServer。
- 网络传输层(Transport):抽象mina和netty为统一接口,以Message为中心,扩展接口为Channel、Transporter、Client、Server和Codec。
- 数据序列化层(Serialize):可复用的一些工具,扩展接口为`、 ObjectInput、ObjectOutput和ThreadPool。
4. Dubbo集群容错方案
在微服务应用中都是多实例部署,也就是说同一份代码部署多台机器或容器中,这样做的好处是提高服务处理能力。同时由于集群部署,所以整个集群也有容错的能力。当我们在调用集群中一个实例时出错,我们可以重试另外一个实例这样大大提高了应用的可靠性。假设系统没有容错处理能力那么即使有集群的部署在调用应用失败情况下不能重试其他实例,这样可靠性大大降低,并极大的浪费系统资源.
在Dubbo中有6种容错模式分别是:
Failover Cluster
失败自动切换:当我们在调用Dubbo服务时出现失败,容错策略会重试其它服务器 。
使用场景:对于一些必达性要求高的服务调用,但是服务提供方要求做幂等处理 。
Failfast Cluster
快速失败:只发起一次调用,如果调用Dubbo服务失败立即报错。
使用场景:通常用于非幂等性的写操作,比如新增记录。
Failsafe Cluster
失败安全:当调用Dubbo服务出现异常时,直接忽略。
使用场景:通常用于运行数据丢失常见,例如:日志记录等操作。
Failback Cluster
失败自动恢复:当调用Dubbo服务失败,后台记录失败请求并定时重发。
使用场景:通常用于必达通知场景,例如:消息通知操作。
Forking Cluster
集群并行:并行调用多个Dubbo服务,只要其中有一个成功即返回。
使用场景:通常用于从多个源获取相同数据,以获取最快的响应速度,例如:同时从多个备库查询数据。
Broadcast Cluster
集群广播:循环调用所有Dubbo服务提供者,任意一台报错则报错。
使用场景:通用用于向多个实例通知消息,例如:更新集群中所有应用缓存或日志。
5. Zookeeper安装
1.安装
1.在local下创建zookeeper文件夹
2.上传zookeeper文件到创建的文件夹
3.使用 tar -xzvf解压zookeeper
4.进入zookeeper的conf文件夹,复制zoo_sample.cfg为zoo.cfg,因为启动时默认会去找这个文件名
5.在解压后的目录中创建data文件夹
6.设置zoo.cfg文件,设置dataDir为创建的data文件夹路径
7.进入bin目录,使用./zkServer.sh start启动zookeeper服务
2.集群搭建
修改各个linux下的zoo.cfg配置文件,向文件中添加
server.1=192.168.25.100:2888:3888
server.2=192.168.25.101:2888:3888
server.3=192.168.25.102:2888:3888
其中1,2,3为各集群节点的id,需要在data目录下创建myid文件并设置文件里面内容为各个节点的id。
6. Spring整合Dubbo
6.1 Provider生产者
1.pom依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.38</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
2.spring整合dubbo配置文件
<?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">
<!--修改后必须重新install打包部署-->
<!--dubbo直连方式-->
<!--配置dubbo服务名称-->
<!--不同的服务名称不能一致,不同服务需要独立,如果做负载均衡,同一服务的负载均衡可以一致-->
<dubbo:application name="goodsProvider"/>
<!--注册应用服务地址:直连方式N/A-->
<!-- <dubbo:registry address="N/A" />-->
<!--使用zookeeper注册中心注册-->
<dubbo:registry address="zookeeper://192.168.25.100:2181?backup=192.168.25.101:2181,192.168.25.102:2181"/>
<!--暴露要提供的服务接口-->
<!--<dubbo:service interface="com.li.service.GoodsService" ref="goodsService"/>-->
<dubbo:annotation package="com.li.service" />
<!--设置dubbo服务的协议名称和端口号,默认dubbo和20880-->
<dubbo:protocol name="dubbo" port="20880" threads="300" threadpool="fixed"></dubbo:protocol>
<!--注册服务接口-->
<bean id="goodsService" class="com.li.service.GoodsServiceImpl"/>
</beans>
服务接口暴露注册时,可采用dubbo的**@Service**注解进行服务接口注册
6.2 Consumer消费者
1.pom依赖
<!--导入服务提供者的依赖-->
<dependency>
<groupId>org.example</groupId>
<artifactId>dubbo-provider</artifactId>
<version>1.0-SNAPSHOT</version>
<!--排除重复依赖-->
<exclusions>
<exclusion>
<groupId>com.alibaba</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.38</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
2.spring整合dubbo消费端配置文件
<?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:application name="goodsConsumer"/>
<!--在注册中心注册-->
<dubbo:registry address="zookeeper://192.168.25.100:2181?backup=192.168.25.101:2181,192.168.25.102:2181"/>
<!--直连方式远程服务调用,将这个接口注册bean-->
<!--默认使用dubbo通信协议,hessian序列化协议,所以调用对象返回数据对象必须序列化-->
<!--<dubbo:reference id="goodsService" interface="com.li.service.GoodsService" url="dubbo://127.0.0.1:20880"/>-->
<!--使用注册中心后,就不用使用url来连接dubbo,而是通过注册中心止获取-->
<dubbo:reference id="goodsService" interface="com.li.service.GoodsService"/>
</beans>
7. SpringBoot整合Dubbo
7.1 Provider生产者
1.pom依赖
<?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>org.example</groupId>
<artifactId>springboot-dubbo-provider</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.5</version>
</dependency>
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.38</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.1.0</version>
</dependency>
</dependencies>
</project>
2.yml核心配置文件
dubbo:
application:
name: dubbo_provider
protocol:
name: dubbo
port: 20880
registry:
address: zookeeper://192.168.25.100:2181
protocol: zookeeper
scan:
base-packages: com.li.service
spring:
application:
name: dubbo_provider
server:
port: 8084
3.服务暴露注册
package com.li.service.impl;
import com.alibaba.dubbo.config.annotation.Service;
import com.li.pojo.Goods;
import com.li.service.GoodsService;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
@Service
@Component
public class GoodsServiceImpl implements GoodsService {
@Override
public void save() {
System.out.println("save方法被远程调用了");
}
@Override
public String get() {
return "远程调用get方法";
}
@Override
public Goods findGoods() {
Goods goods = new Goods(1,"小米2",new BigDecimal(2333));
return goods;
}
}
7.2 Consumer消费者
1.pom依赖
<?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>org.example</groupId>
<artifactId>springboot-dubbo-consumer</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.6.5</version>
</dependency>
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.38</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.6</version>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>4.1.0</version>
</dependency>
</dependencies>
</project>
2.yml核心配置文件
dubbo:
application:
name: dubbo_consumer
protocol:
name: dubbo
port: 20881
registry:
address: zookeeper://192.168.25.100:2181
protocol: zookeeper
spring:
application:
name: dubbo_consumer
server:
port: 8083
3.服务消费
package com.li.controller;
import com.alibaba.dubbo.config.annotation.Reference;
import com.li.service.GoodsService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test")
public class TestController {
@Reference
private GoodsService goodsService;
@RequestMapping("/aaa")
public void test01(){
String s = goodsService.get();
System.out.println(s);
}
}
8.Dubbo的Spi机制的过滤器扩展
应用:系统参数的过滤器校验
1.方法调用时添加对应的接口验证参数
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
if(servletContext!=null&&contextRefreshedEvent.getApplicationContext().getParent()==null){
servletContext.setAttribute("root",servletContext.getContextPath());
//由于系统参数需要防止恶意调用修改,所以需要存一个令牌来进行进行验证,当调用放调用接口时,
// 通过dubbo过滤器来验证是否正确,正确则调用,否则抛出异常
//获取RPC上下文对象
RpcContext context = RpcContext.getContext();
context.setAttachment("systemConfigToken","dugasud78dt67q6d");
//获取数据库系统参数赋值给配置文件
List<ConfigVo> configList = systemConfigService.findAllConfig();
for (ConfigVo config : configList) {
PropertiesUtils.setProp(config.getConfigname(),config.getConfigvalue().toString());
}
}
}
2.被调用接口的接口拦截验证
//dubbo过滤器,需要手动在xml中添加,不能使用@Component注解交给Spring,不生效,且不写全包名
@Activate(group = "provider")
public class RequestAuthFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
//获取上下文对象,判断传过来的令牌是否正确
RpcContext context = RpcContext.getContext();
String tokenValue = context.getAttachment("systemConfigToken");
if(!"dugasud78dt67q6d".equals(tokenValue)){
//不相等抛异常
throw new RpcException("非法调用请求");
}
//调用
return invoker.invoke(invocation);
}
}
3.验证接口的配置
/META-INF/dubbo/com.alibaba.dubbo.rpc.Filter
requestAuthFilter=com.li.config.service.impl.RequestAuthFilter