我现阶段接触的分布式微服务的架构主要就是Zookeeper+Dubbo的框架模式,前面已经有一篇文章关于Zookeeper的文章《Zookeeper的学习理解》,那么这篇文章就主要介绍Dubbo吧!
官网地址:https://dubbo.apache.org/
一、概述
Apache Dubbo是一款高性能、轻量级的开源 Java RPC 分布式服务框架。
它提供了六大核心能力:
(1)面向接口代理的高性能RPC调用:提供高性能的基于代理的远程调用能力,服务以接口为粒度,为开发者屏蔽远程调用底层细节。提供对多种NIO框架抽象封装,包括“同步转异步”和“请求-响应”模式的信息交换方式。
(2)智能容错和负载均衡:内置多种负载均衡策略,智能感知下游节点健康状况,显著减少调用延迟,提高系统吞吐量。
(3)服务自动注册和发现:支持多种注册中心服务,服务实例上下线实时感知。
(4)高度可扩展能力:遵循微内核+插件的设计原则,所有核心能力如Protocol、Transport、Serialization被设计为扩展点,平等对待内置实现和第三方实现。
(5)运行期流量调度:内置条件、脚本等路由策略,通过配置不同的路由规则,轻松实现灰度发布,同机房优先等功能。
(6)可视化的服务治理与运维:提供丰富服务治理、运维工具:随时查询服务元数据、服务健康状态及调用统计,实时下发路由策略、调整配置参数。
Dubbo 采用全 Spring 配置方式,透明化接入应用,对应用没有任何 API 侵入,只需用 Spring 加载 Dubbo 的配置即可,Dubbo 基于 Spring 的 Schema 扩展 进行加载。如果不想使用 Spring 配置,可以通过 API 的方式 进行调用。
附录:
Java中的I/O通信机制模型:
BIO 同步并阻塞
NIO 同步非阻塞—dubbo用的NIO框架的抽象封装(Netty),游戏服务器,物联网服务器
AIO 异步非阻塞
上面三种通信机制对比可参考:https://www.pianshen.com/article/3988449788/
阻塞、非阻塞(相对数据而言):
概念:程序等待调用结果时的状态。进程访问数据的时候,数据是否就绪的一种处理状态。
解释:涉及到CPU线程调度;所谓阻塞,就是调用结果返回之前,该执行线程会被挂起,不释放CPU执行权,线程不能做其它事情,只能等待,只有等到调用结果返回了,才能接着往下执行;所谓非阻塞,就是在没有获取调用结果时,不是一直等待。
同步、异步:
概念:消息的通知机制
解释:涉及到IO通知机制;所谓同步,就是发起调用后,被调用者处理消息,必须等处理完才直接返回结果,没处理完之前是不返回的,调用者主动等待结果;所谓异步,就是发起调用后,被调用者直接返回,但是并没有返回结果,等处理完消息后,通过状态、通知或者回调函数来通知调用者,调用者被动接收结果。
疑问:NIO与BIO最大的区别就是只需要开启一个线程就可以处理来自多个客户端的IO事件,这是怎么做到的呢?
就是多路复用器,可以监听来自多个客户端的IO事件:
A. 若服务端监听到客户端连接请求,便为其建立通信套接字(java中就是通道),然后返回继续监听,若同时有多个客户端连接请求到来也可以全部收到,依次为它们都建立通信套接字。
B. 若服务端监听到来自已经创建了通信套接字的客户端发送来的数据,就会调用对应接口处理接收到的数据,若同时有多个客户端发来数据也可以依次进行处理。
C. 监听多个客户端的连接请求和接收数据请求同时还能监听自己时候有数据要发送。
二、Dubbo的组件角色
1.架构
2.组件角色
Provider:暴露服务的服务提供方
Consumer:调用远程服务的服务消费方
Registry:服务注册与发现的注册中心
Monitor:统计服务的调用次调和调用时间的监控中心
Container:服务运行容器
3.调用关系说明
注意:下面的序号对应着上面架构图中的序号。
(0)服务容器 Container 负责启动,加载,运行服务提供者。(init)
(1)服务提供者 Provider 在启动时,向注册中心注册自己提供的服务。(init)
(2)服务消费者 Consumer 在启动时,向注册中心订阅自己所需的服务。(init)
(3)注册中心 Registry 返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。(async)
(4)服务消费者 Consumer,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。(sync)
(5)服务消费者 Consumer 和提供者 Provider,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心 Monitor。(async)
三、Dubbo Admin 管理控制台
管理控制台为内部裁剪版本,开源部分主要包含:路由规则,动态配置,服务降级,访问控制,权重调整,负载均衡,等管理功能。我们需要自己配置,可以通过控制台观察相关信息。
GitHub:https://github.com/apache/incubator-dubbo-ops
参考:https://www.funtl.com/zh/apache-dubbo-rpc/Dubbo-Admin-%E7%AE%A1%E7%90%86%E6%8E%A7%E5%88%B6%E5%8F%B0.html
、
四、Dubbo 的负载均衡
在集群负载均衡时,Dubbo 提供了多种均衡策略,缺省为 random 随机调用。
(1)Random LoadBalance
随机,按权重设置随机概率。
在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
(2)RoundRobin LoadBalance
轮询,按公约后的权重设置轮询比率。
存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。
(3)LeastActive LoadBalance
最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
(4)ConsistentHash LoadBalance
一致性 Hash,相同参数的请求总是发到同一提供者。
当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
算法参见:http://en.wikipedia.org/wiki/Consistent_hashing
缺省只对第一个参数 Hash,如果要修改,请配置 <dubbo:parameter key="hash.arguments" value="0,1" />
缺省用 160 份虚拟节点,如果要修改,请配置 <dubbo:parameter key="hash.nodes" value="320" />
配置实例如下:
#服务端服务级别
dubbo:
provider:
loadbalance: leastactive
#客户端服务级别
dubbo:
consumer:
loadbalance: leastactive
五、Dubbo 中的序列化
Dubbo RPC 是 Dubbo 体系中最核心的一种高性能、高吞吐量的远程调用方式,可以称之为多路复用的 TCP 长连接调用:
长连接:避免了每次调用新建 TCP 连接,提高了调用的响应速度。
多路复用:单个 TCP 连接可交替传输多个请求和响应的消息,降低了连接的等待闲置时间,从而减少了同样并发数下的网络连接数,提高了系统吞吐量。
Dubbo RPC 主要用于两个 Dubbo 系统之间的远程调用,特别适合高并发、小数据的互联网场景。而序列化对于远程调用的响应速度、吞吐量、网络带宽消耗等同样也起着至关重要的作用,是我们提升分布式系统性能的最关键因素之一。
Dubbo 中支持的序列化方式:
(1)dubbo 序列化:阿里尚未开发成熟的高效 java 序列化实现,阿里不建议在生产环境使用它
(2)hessian2 序列化:hessian 是一种跨语言的高效二进制序列化方式。但这里实际不是原生的 hessian2 序列化,而是阿里修改过的 hessian lite,它是 dubbo RPC 默认启用的序列化方式
(3)json 序列化:目前有两种实现,一种是采用的阿里的 fastjson 库,另一种是采用 dubbo 中自己实现的简单 json 库,但其实现都不是特别成熟,而且 json 这种文本序列化性能一般不如上面两种二进制序列化。
(4)java 序列化:主要是采用 JDK 自带的 Java 序列化实现,性能很不理想。
在通常情况下,这四种主要序列化方式的性能从上到下依次递减。对于 dubbo RPC 这种追求高性能的远程调用方式来说,实际上只有 1、2 两种高效序列化方式比较般配,而第 1 个 dubbo 序列化由于还不成熟,所以实际只剩下 2 可用,所以 dubbo RPC 默认采用 hessian2 序列化。
但 hessian 是一个比较老的序列化实现了,而且它是跨语言的,所以不是单独针对 Java 进行优化的。而 dubbo RPC 实际上完全是一种 Java to Java 的远程调用,其实没有必要采用跨语言的序列化方式(当然肯定也不排斥跨语言的序列化)。
最近几年,各种新的高效序列化方式层出不穷,不断刷新序列化性能的上限,最典型的包括:
(1)专门针对 Java 语言的:Kryo,FST 等等
(2)跨语言的:Protostuff,ProtoBuf,Thrift,Avro,MsgPack 等等
有鉴于此,我们为 dubbo 引入 Kryo 和 FST 这两种高效 Java 序列化实现,来逐步取代 hessian2。
其中,Kryo 是一种非常成熟的序列化实现,已经在 Twitter、Groupon、Yahoo 以及多个著名开源项目(如 Hive、Storm)中广泛的使用。而 FST 是一种较新的序列化实现,目前还缺乏足够多的成熟使用案例。
在面向生产环境的应用中,目前更优先选择 Kryo。
如何启用 Kryo??
推荐参考:启用Kryo
六、服务熔断
Dubbo + Hystrix实现熔断器模型,熔断器打开后,为了避免连锁故障,通过 fallback 方法可以直接返回一个固定值。
具体后续补充。