Java教程

Dubbo

本文主要是介绍Dubbo,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

1. 分布式架构(SOA )

在这里插入图片描述

  • 分层: 按照业务性质分层 每一层要求简单 和 容易维护
  • 应用层: 距离用户最近的一层 也称之为接入层 使用tomcat 作为web容器 接收用户请求 使用下游的dubbo提供的接口来返回数据并且该层禁止访问数据库
  • 业务服务层:根据具体的业务场景 演变而来的模块
  • 基础业务层:拉勾网招聘业务的核心
  • 基础服务层:这一层 是与业务无关的模块 是一些通用的服务 这类服务的特点:请求量大 逻辑简单 特性明显 功能独立 消息服务(发邮件 短信 微信) 附件解析
  • 存储层:不同的存储类型
  • 分级:按照业务性质分层 同一层的业务也要做好分级 依据业务的重要性进行分级 按照二八定律

网站80%的流量 都在核心功能上面 要优先保证核心业务的稳定。

  • 隔离:不同性质 不同重要性的业务做好隔离 包括 业务 缓存 DB 中间件 都要做好隔离 比如 核心业务的数据库 要和活动相关的数据库隔离
  • 调用 :总体上调用要单向 可以跨层调用 但不能出现逆向调用

优点

  • 服务以接口为粒度,为开发者屏蔽远程调用底层细节 使用Dubbo 面向接口远程方法调用,屏蔽了底层调用细节
  • 业务分层以后架构更加清晰 并且每个业务模块职责单一 扩展性更强
  • 数据隔离,权限回收,数据访问都通过接口 让系统更加稳定 安全
  • 服务应用本身无状态化 这里的无状态化指的是应用本身不做内存级缓存 而是把数据存入db
  • 服务责任易确定 每个服务可以确定责任人 这样更容易保证服务质量和稳定

缺点

  • 粒度控制复杂 如果没有控制好服务的粒度 服务的模块就会越来越多 就会引发 超时 分布式事务等问题
  • 服务接口数量不宜控制 容易引发接口爆炸 所以服务接口建议以业务场景进行单位划分 并对相近的业务做抽象 防止接口爆炸
  • 版本升级兼容困难 尽量不要删除方法 字段 枚举类型的新增字段也可能不兼容
  • 调用链路长 服务质量不可监控 调用链路变长 下游抖动可能会影响到上游业务 最终形成连
  • 锁反应 服务质量不稳定 同时链路的变成使得服务质量的监控变得困难

2. Dubbo架构

Apache Dubbo是一款高性能的Java RPC框架。其前身是阿里巴巴公司开源的一个高性能、轻量级的开源Java RPC框架,可以和Spring框架无缝集成。
在这里插入图片描述
调用关系说明:

虚线 代表异步调用
实线 代表同步访问
蓝色虚线 是在启动时完成的功能
红色虚线 是程序运行中执行的功能

在这里插入图片描述
在这里插入图片描述

  • 服务注册中心Zookeeper
    通过前面的Dubbo架构图可以看到,Registry(服务注册中心)在其中起着至关重要的作用。Dubbo官方推荐使用Zookeeper作为服务注册中心。Zookeeper 是 Apache Hadoop 的子项目,作为 Dubbo 服务的注册中心,工业强度较高,可用于生产环境,并推荐使用 。

3. Dubbo开发实战

在Dubbo中所有的的服务调用都是基于接口去进行双方交互的。双方协定好Dubbo调用中的接口,提供者来提供实现类并且注册到注册中心上。
调用方则只需要引入该接口,并且同样注册到相同的注册中心上(消费者)。即可利用注册中心来实现集群感知功能,之后消费者即可对提供者进行调用。
我们所有的项目都是基于Maven去进行创建,这样相互在引用的时候只需要以依赖的形式进行展现就可以了。
并且这里我们会通过maven的父工程来统一依赖的版本。

程序实现分为以下几步骤:

  1. 建立maven工程 并且 创建API模块: 用于规范双方接口协定
  2. 提供provider模块,引入API模块,并且对其中的服务进行实现。将其注册到注册中心上,对外来统一提供服务。
  3. 提供consumer模块,引入API模块,并且引入与提供者相同的注册中心。再进行服务调用。

3.1 配置方式

快速开始
注解方式
XML方式
配置项详细说明

4. Dubbo管理控制台 dubbo-admin

作用

  • 主要包含:服务管理 、 路由规则、动态配置、服务降级、访问控制、权重调整、负载均衡等管理功能。如我们在开发时,需要知道Zookeeper注册中心都注册了哪些服务,有哪些消费者来消费这些服务

控制台安装步骤

  1. 从git 上下载项目 https://github.com/apache/dubbo-admin
  2. 修改项目下的dubbo.properties文件 注意dubbo.registry.address对应的值需要对应当前使用的Zookeeper的ip地址和端口号
    dubbo.registry.address=zookeeper://zk所在机器ip:zk端口
    dubbo.admin.root.password=root
    dubbo.admin.guest.password=guest
  3. 切换到项目所在的路径 使用mvn 打包 mvn clean package -Dmaven.test.skip=true
  4. java 命令运行 java -jar 对应的jar包

使用控制台

  1. 访问http://IP:端口
  2. 输入用户名root,密码root
  3. 点击菜单查看服务提供者和服务消费者信息

5. SPI

SPI简介

  • SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制。 目前有不少框架用它来做服务的扩展发现,简单来说,它就是一种动态替换发现的机制。使用SPI机制的优势是实现解耦,使得第三方服务模块的装配控制逻辑与调用者的业务代码分离。

Dubbo中扩展点使用方式
我们使用三个项目来演示Dubbo中扩展点的使用方式
dubbo-spi-demo-api 服务接口项目api 在接口上 使用@SPI

dubbo-spi-demo-impl 服务实现项目impl

  1. 导入 api项目 的依赖
  2. 建立实现类。
  3. SPI进行声明操作,在resources 目录下创建目录META-INF/dubbo 目录,在目录下创建名称为接口的全限定类名的文件,文件内部配置实现类名称和对应的全限定名:

dubbo-spi-demo-main 主项目main。 dubbo 需要借助ExtensionLoader

dubbo自己做SPI的目的

  1. JDK标准的SPI会一次性实例化扩展点所有实现,如果有扩展实现初始化很耗时,但如果没用上也加载,会很浪费资源
  2. 如果有扩展点加载失败,则所有扩展点无法使用
  3. 提供了对扩展点包装的功能(Adaptive),并且还支持通过set的方式对其他的扩展点进行注入

Dubbo中的@Adaptive功能

  • @Adaptive注解主要解决的问题是如何动态的选择具体的扩展点。
  • 通过getAdaptiveExtension 统一对指定接口对应的所有扩展点进行封装,通过URL的方式对扩展点来进行动态选择。 (dubbo中所有的注册信息都是通过URL的形式进行处理的。)这里同样采用相同的方式进行实现。

通过SPI添加拦截机制

  1. 实现org.apache.dubbo.rpc.Filter 接口
  2. 使用@Activate对类进行注册。通过group可以指定生产端CommonConstants.CONSUMER、消费端CommonConstants.PROVIDER
  3. 在META-INF.dubbo 中新建org.apache.dubbo.rpc.Filter 文件,写入timerFilter=自定义过滤器的全限定类名

注意:一般类似于这样的功能都是单独开发依赖的,所以再使用方的项目中只需要引入依赖,在调用接口时,该方法便会自动拦截。

6. 负载均衡策略

负载均衡(Load Balance), 其实就是将请求分摊到多个操作单元上进行执行,从而共同完成工作任务。
负载均衡策略主要用于客户端存在多个提供者时进行选择某个提供者。
在集群负载均衡时,Dubbo 提供了多种均衡策略(包括随机、轮询、最少活跃调用数、一致性Hash),缺省为random随机调用。
官方负载均衡

在服务消费者一方配置负载均衡策略
@Reference(check = false,loadbalance = "random")

自定义负载均衡器

  1. 需要实现LoadBalance接口。自定义负载均衡算法。
  2. 配置负载均衡器SPI。在工程的META-INF/dubbo 目录下新建 org.apache.dubbo.rpc.cluster.LoadBalance 内容: 自定义均衡器名=自定义负载均衡器全类名
  3. 在使用方的项目中只需要引入依赖,就可以配置自定义的负载均衡器。
  4. 配置负载均衡策略 @Reference(check = false,loadbalance = “自定义”)

Dubbo异步调用

  • Dubbo不只提供了堵塞式的的同步调用,同时提供了异步调用的方式。这种方式主要应用于提供者接口响应耗时明显,消费者端可以利用调用接口的时间去做一些其他的接口调用,利用Future 模式来异步等待和获取结果即可。这种方式可以大大的提升消费者端的利用率。
  • 目前这种方式可以通过XML的方式进行引入。
  • 我们在消费方添加异步调用。由于异步只能XML的方式进行引入,所以consumer使用xml方式配置,provider使用注解
  • 异步方法在同步调用时的返回值是空,我们可以通过RpcContext.getContext().getFuture() 来进行获取Future对象来进行后续的结果等待操作。

线程池

  • dubbo在使用时,都是通过创建真实的业务线程池进行操作的。目前已知的线程池模型有两个和java中的相互对应:
  1. fix: 表示创建固定大小的线程池。也是Dubbo默认的使用方式,默认创建的执行线程数为200,并且是没有任何等待队列的。
    缺点:某个操作大量执行时,可能存在堵塞的情况
  2. cache: 创建非固定大小的线程池,当线程不足时,会自动创建新的线程。
    缺点:如果突然有高TPS的请求过来,方法没有及时完成,则会造成大量的线程创建,对系统的CPU和负载都是压力,执行越多反而会拖慢整个系统。

自定义线程池
在创建线程池的时,对这个线程池进行监控,这样就可以进行及时的扩缩容机器或者告警。

  • dubbo-spi-threadpool 自定义线程池相关内容写在此模块中
  1. 线程池实现(com.lagou.threadpool.WatchingThreadPool), 这里主要是基于对FixedThreadPool中的实现做扩展出线程监控的部分
  2. SPI声明,创建文件META-INF/dubbo/org.apache.dubbo.common.threadpool.ThreadPool
    内容:自定义线程池名=自定义线程池的全限定类名 自定义线程池名以后在服务提供方使用
  3. 在服务提供方项目pom.xml中引入该依赖
  4. 在服务提供方项目中设置使用该线程池生成器 dubbo.provider.threadpool=自定义线程池名
  • threadpoolService-provider 服务提供者模块,在此模块中引入自定义线程池模块的依赖。 在服务提供方项目中设置使用该线程池生成器,即dubbo-provider.properties文件。添加内容:dubbo.provider.threadpool=自定义线程池名
这篇关于Dubbo的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!