1 项目架构演变过程
1.1 单体架构
单体架构所有模块和功能都集中在一个项目中 ,部署时也是将项目所有功能部整体署到服务器中
1.2 垂直架构
根据业务把项目垂直切割成多个项目,因此这种架构称之为垂直架构
1.3 分布式架构(SOA )
SOA全称为Service Oriented Architecture,即面向服务的架构 。它是在垂直划分的基础上,将每个项目 拆分出多个具备松耦合的服务,一个服务通常以独立的形式存在于操作系统进程中。各个服务之间通过网 络调用,这使得构建在各种各样的系统中的服务可以 以一种统一和通用的方式进行交互。
1.4 微服务架构
微服务架构是一种将单个应用程序 作为一套小型服务开发的方法,每种应用程序都在其自己的进程中独 立运行,并使用轻量级机制(通常是HTTP资源的API)进行通信。这些服务是围绕业务功能构建的,可以 通过全自动部署机制进行独立部署。这些服务的集中化管理非常少,它们可以用不同的编程语言编写, 并使用不同的数据存储技术。
微服务是在SOA上做的升华 , 粒度更加细致,微服务架构强调的一个重点是“业务需要彻底的组件化和服务化”。
2 Dubbo架构
2.1 Dubbo架构概述
Apache Dubbo是一款高性能的Java RPC框架。其前身是阿里巴巴公司开源的一个高性能、轻量级的开 源Java RPC框架,可以和Spring框架无缝集成。
服务治理(SOA governance),企业为了确保项目顺利完成而实施的过程,包括最佳实践、架构原 则、治理规程、规律以及其他决定性的因素。服务治理指的是用来管理SOA的采用和实现的过程。
2.2 Dubbo处理流程
2.3 服务注册中心Zookeeper
通过前面的Dubbo架构图可以看到,Registry(服务注册中心)在其中起着至关重要的作用。·Dubbo官 方推荐使用Zookeeper作为服务注册中心。Zookeeper 是 Apache Hadoop 的子项目,作为 Dubbo 服 务的注册中心,工业强度较高,可用于生产环境,并推荐使用 。
2.4 Dubbo管理控制台 dubbo-admin
主要包含:服务管理 、 路由规则、动态配置、服务降级、访问控制、权重调整、负载均衡等管理功能 如我们在开发时,需要知道Zookeeper注册中心都注册了哪些服务,有哪些消费者来消费这些服务。我 们可以通过部署一个管理中心来实现。其实管理中心就是一个web应用,原来是war(2.6版本以前)包需 要部署到tomcat即可。现在是jar包可以直接通过java命令运行。
2.5 Dubbo配置项说明
dubbo:application
dubbo:registry
dubbo:protocol
dubbo:service
dubbo:protocol
dubbo:service
dubbo:reference
dubbo:method
dubbo:service和dubbo:reference详解
其它配置 参考官网
3 Dubbo高级实战
3.1 SPI
SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制。
目前有不少框架用它
来做服务的扩展发现,简单来说,它就是一种动态替换发现的机制。使用SPI机制的优势是实现解耦, 使得第三方服务模块的装配控制逻辑与调用者的业务代码分离。
3.1.1 JDK中的SPI
3.1.2 Dubbo中的SPI
dubbo中大量的使用了SPI来作为扩展点,通过实现同一接口的前提下,可以进行定制自己的实现类。 比如比较常见的协议,负载均衡,都可以通过SPI的方式进行定制化,自己扩展。Dubbo中已经存在的 所有已经实现好的扩展点。
3.1.3 Dubbo中的Adaptive功能
主要解决的问题是如何动态的选择具体的扩展点。通过 getAdaptiveExtension统一对指定接口对应的所有扩展点进行封装,通过URL的方式对扩展点来进行动态选择。 (dubbo中所有的注册信息都是通过URL的 实现形式进行处理的)
3.1.4 Dubbo调用时拦截操作
与很多框架一样,Dubbo也存在拦截(过滤)机制,可以通过该机制在执行目标程序前后执行我们指定 的代码。
Dubbo的Filter机制,是专门为服务提供方和服务消费方调用过程进行拦截设计的,每次远程方法执
,该拦截都会被执行。这样就为开发者提供了非常方便的扩展性,比如为dubbo接口实现ip白名单功能、监控功能 、日志记录等。
3.2 负载均衡策略
3.2.1 负载均衡基本配置
负载均衡(Load Balance), 其实就是将请求分摊到多个操作单元上进行执行,从而共同完成工作任 务。
负载均衡策略主要用于客户端存在多个提供者时进行选择某个提供者。
在集群负载均衡时,Dubbo 提供了多种均衡策略(包括随机、轮询、最少活跃调用数、一致性 Hash),缺省为random随机调用。
3.2.2 自定义负载均衡器
负载均衡器在Dubbo中的SPI接口是 org.apache.dubbo.rpc.cluster.LoadBalance, 可以通过实现这 个接口来实现自定义的负载均衡规则。
3.3 异步调用
Dubbo不只提供了堵塞式的的同步调用,同时提供了异步调用的方式。这种方式主要应用于提供者接口
响应耗时明显,消费者端可以利用调用接口的时间去做一些其他的接口调用,利用Future模式来异步等
待和获取结果即可。这种方式可以大大的提升消费者端的利用率。 目前这种方式可以通过XML的方式进 行引入。
3.3.1 异步调用实现
3.3.2 异步调用特殊说明
需要特别说明的是,该方式的使用,请确保dubbo的版本在2.5.4及以后的版本使用。 原因在于在2.5.3
及之前的版本使用的时候,会出现异步状态传递问题。
比如我们的服务调用关系是 A -> B -> C, 这时候如果A向B发起了异步请求,在错误的版本时,B向C发 起的请求也会连带的产生异步请求。这是因为在底层实现层面,他是通过 RPCContext中的 attachment实现的。在A向B发起异步请求时,会在 attachment中增加一个异步标示字段来表明异步 等待结果。B在接受到A中的请求时,会通过该字段来判断是否是异步处理。但是由于值传递问题,B向 C发起时同样会将该值进行传递,导致C误以为需要异步结果,导致返回空。这个问题在2.5.4及以后的 版本进行了修正。
3.4 线程池
3.4.1 Dubbo已有线程池
dubbo在使用时,都是通过创建真实的业务线程池进行操作的。目前已知的线程池模型有两个和java中 的相互对应:
- fix: 表示创建固定大小的线程池。也是Dubbo默认的使用方式,默认创建的执行线程数为200,并 且是没有任何等待队列的。所以再极端的情况下可能会存在问题,比如某个操作大量执行时,可能 存在堵塞的情况。后面也会讲相关的处理办法。
- cache: 创建非固定大小的线程池,当线程不足时,会自动创建新的线程。但是使用这种的时候需 要注意,如果突然有高TPS的请求过来,方法没有及时完成,则会造成大量的线程创建,对系统的 CPU和负载都是压力,执行越多反而会拖慢整个系统。
3.4.2 自定义线程池
在真实的使用过程中可能会因为使用fix模式的线程池,导致具体某些业务场景因为线程池中的线程数量 不足而产生错误,而很多业务研发是对这些无感知的,只有当出现错误的时候才会去查看告警或者通过 客户反馈出现严重的问题才去查看,结果发现是线程池满了。所以可以在创建线程池的时,通过某些手 段对这个线程池进行监控,这样就可以进行及时的扩缩容机器或者告警。
3.5 路由规则
路由是决定一次请求中需要发往目标机器的重要判断,通过对其控制可以决定请求的目标机器。我们可 以通过创建这样的规则来决定一个请求会交给哪些服务器去处理。
3.5.1 路由规则快速入门
3.5.2 路由规则详解
通过上面的程序,我们实际本质上就是通过在zookeeper中保存一个节点数据,来记录路由规则。消费 者会通过监听这个服务的路径,来感知整个服务的路由规则配置,然后进行适配。这里主要介绍路由配 置的参数。具体请参考文档, 这里只对关键的参数做说明。
3.5.3 路由与上线系统结合
当公司到了一定的规模之后,一般都会有自己的上线系统,专门用于服务上线。方便后期进行维护和记 录的追查。我们去想象这样的一个场景,一个dubbo的提供者要准备进行上线,一般都提供多台提供者 来同时在线上提供服务。这时候一个请求刚到达一个提供者,提供者却进行了关闭操作。那么此次请求 就应该认定为失败了。所以基于这样的场景,我们可以通过路由的规则,把预发布(灰度)的机器进行从 机器列表中移除。并且等待一定的时间,让其把现有的请求处理完成之后再进行关闭服务。同时,在启 动时,同样需要等待一定的时间,以免因为尚未重启结束,就已经注册上去。等启动到达一定时间之后,再进行开启流量操作。
3.6 服务动态降级
服务降级,当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务有策略的降低服务级别, 以释放服务器资源,保证核心任务的正常运行。
而为什么要使用服务降级,这是防止分布式服务发生雪崩效应
什么是雪崩?
就是蝴蝶效应,当一个请 求发生超时,一直等待着服务响应,那么在高并发情况下,很多请求都是因为这样一直等着响应,直到 服务资源耗尽产生宕机,而宕机之后会导致分布式其他服务调用该宕机的服务也会出现资源耗尽宕机, 这样下去将导致整个分布式服务都瘫痪,这就是雪崩。
3.6.1 dubbo 服务降级实现方式
第一种 在 dubbo 管理控制台配置服务降级
屏蔽和容错
第二种 指定返回简单值或者null
如果是标注 则使用@Reference(mock=“return null”) @Reference(mock=“return 简单值”)
也支持 @Reference(mock=“force:return null”)
第三种 使用java代码 动态写入配置中心
第四种 整合整合 hystrix