Hey Dubbo
Living without an aim is like sailing without a compass.–生活没有目标,犹如航海没有罗盘.
在今天的blog开始之前,先和大家浅谈一下网站的发展架构发展历史.
随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,
分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进.
- 架构演进
单一应用架构
网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本.
此时,用于简化增删改查工作量的 数据访问框架(ORM) 是关键.
垂直应用架构
当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率.
此时,用于加速前端页面开发的 Web框架(MVC) 是关键.
分布式服务架构
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求.
此时,用于提高业务复用及整合的 分布式服务框架(RPC) 是关键.
流动计算架构
当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率.
此时,用于提高机器利用率的 资源调度和治理中心(SOA) 是关键.
那么我们面临的问题又是什么呢? 总结下来 无非几点:
1 多种调用传输方式:HTTP方式、WebService方式;
2 服务调用依赖关系:人工记录,查看代码分析;
3 服务调用性能监控:日志记录,人工查看时间;
4 服务与应用紧耦合:服务挂掉,应用无法可用;
5 服务集群负载配置:Nginx配置,存在单点问题;
那么有了问题,我们就会思考了,去追寻最佳解决方案了,我们选择什么技术来实现我们的需求呢?该技术首先要符合什么标准呢?
1 支持当前业务需求,这是最最基本的条件;
2 服务避免单点问题,去中心化;
3 服务高可用、高并发,解耦服务依赖;
4 服务通用化,支持异构系统调用服务;
5 服务依赖关系自维护,可视化;
6 服务性能监控自统计,可视化;
7 服务需自带注册、发现、健康检查、负载均衡等特性;
8 开发人员关注度高,上手快,简单轻量,低侵入;
有了问题,有了标准,那么我们就可以去选择哪种技术了.
回到我们今天的主题 Dubbo ,那么Dubbo 究竟有什么优点值得我们去使用呢?
1.远程通讯: 提供对多种基于长连接的NIO框架抽象封装,
包括多种线程模型,序列化,以及“请求-响应”模式的信息交换方式.
2.软负载均衡及容错机制: 提供基于接口方法的透明远程过程调用,
包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持,可在内网替代F5等硬件负载均衡器,降低成本,减少单点
3 服务自动注册与发现: 基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器 .
4.提供完善的管理控制台dubbo-admin与简单的控制中心dubbo-monitor
5 Dubbo提供了伸缩性很好的插件模型,很方便进行扩展(ExtensionLoader)
6 支持多协议
7 Dubbo采用全spring配置方式,透明化接入应用,对应用没有任何API侵入,只需用Spring加载Dubbo的配置即可,Dubbo基于Spring的Schema扩展进行加载.
了解了其种种优势,那么我们该去贴近它,去一看究竟了.
Dubbo 源码架构如下图所示:
各个模块的作用是什么呢?
1 dubbo-common 公共逻辑模块,包括Util类和通用模型.
2 dubbo-remoting 远程通讯模块,相当于Dubbo协议的实现,如果RPC用RMI协议则不需要使用此包.
3 dubbo-rpc 远程调用模块,抽象各种协议,以及动态代理,只包含一对一的调用,不关心集群的管理.
4 dubbo-cluster 集群模块,将多个服务提供方伪装为一个提供方,包括:负载均衡、容错、路由等,集群的地址列表可以是静态配置的,也可以是由注册中心下发.
5 dubbo-registry 注册中心模块,基于注册中心下发地址的集群方式,以及对各种注册中心的抽象.
6 dubbo-monitor 监控模块,统计服务调用次数,调用时间的,调用链跟踪的服务.
7 dubbo-config 配置模块,是Dubbo对外的API,用户通过Config使用Dubbo,隐藏Dubbo所有细节.
8 dubbo-container 容器模块,是一个Standalone的容器,以简单的Main加载Spring启动,因为服务通常不需要Tomcat/JBoss等Web容器的特性,没必要用Web容器去加载服务.
各个模块之间的联系是:
那么Dubbo 的工作流程是什么呢?
1、Provider:暴露服务的服务提供方. Consumer: 调用远程服务的服务消费方.
2、Registry:服务注册与发现的注册中心. Monitor: 统计服务的调用次调和调用时间的监控中心.
3、Container: 服务运行容器
根据上图的流程我们可以知道Dubbo之间的调用关系是:
1、服务容器负责启动,加载,运行服务提供者.
2、服务提供者在启动时,向注册中心注册自己提供的服务.
3、服务消费者在启动时,向注册中心订阅自己所需的服务.
4、注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者.
5、服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用.
6、服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心.
Dubbo 调用的方式 其实有两种 一种是 异步调用 ,另一种是 本地调用
异步调用
基于NIO的非阻塞实现并行调用,客户端不需要启动多线程即可完成并行调用多个远程服务,相对多线程开销较小
本地调用:
本地调用,使用了Injvm协议,是一个伪协议,它不开启端口,不发起远程调用,只在JVM内直接关联,但执行Dubbo的Filter链.
- Dubbo支持的注册中心
Multicast注册中心
不需要启动任何中心节点,只要广播地址一样,就可以互相发现
组播受网络结构限制,只适合小规模应用或开发阶段使用.
组播地址段: 224.0.0.0 - 239.255.255.255
Zookeeper注册中心
是Apacahe Hadoop的子项目,是一个树型的目录服务,支持变更推送,适合作为Dubbo服务的注册中心,工业强度较高
只需搭一个原生的Zookeeper服务器,
并将Provider和Consumer里的dubbo.properties中的dubbo.registry.addrss的值改为zookeeper://127.0.0.1:2181即可使用
阿里内部并没有采用Zookeeper做为注册中心,而是使用自己实现的基于数据库的注册中心,即:Zookeeper注册中心并没有在阿里
内部长时间运行的可靠性保障,其可靠性依赖于Zookeeper本身的可靠性.
ZooKeeper集群由一组Server节点组成,这一组Server节点中存在一个角色为Leader的节点,其他节点都为Follower.
当客户端Client连接到ZooKeeper集群,并且执行写请求时,这些请求会被发送到Leader节点上,然后Leader节点上数据变更会同步到集群中其他的Follower节点.
Redis注册中心
Simple注册中心
相信大家又会问了,每个框架一般都会有其设计模式来支撑框架的使用,那么Dubbo的设计模式是什么呢?
- 设计模式
工厂模式
在 package com.alibaba.dubbo.config; 包下的 ServiceConfig中有这么一局代码
public class ServiceConfig<T> extends AbstractServiceConfig {
private static final Protocol protocol = (Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
private static final ProxyFactory proxyFactory = (ProxyFactory)ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
private static final Map<String, Integer> RANDOM_PORT_MAP = new HashMap();
private static final ScheduledExecutorService delayExportExecutor = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("DubboServiceDelayExporter", true));
由此可以知道
private static final Protocol protocol = (Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
只是实现类的获取采用了jdkspi的机制完成了工厂模式.
装饰器模式
Dubbo在启动和调用阶段都大量使用了装饰器模式.以Provider提供的调用链为例,具
体的调用链代码是在ProtocolFilterWrapper的buildInvokerChain完成的,具体是将注解中含
有group=provider的Filter实现,按照order排序,最后的调用顺序是
EchoFilter-》ClassLoaderFilter-》GenericFilter-》ContextFilter-》ExceptionFilter-》
TimeoutFilter-》MonitorFilter-》TraceFilter
更确切地说,这里是装饰器和责任链模式的混合使用
观察者模式
Dubbo的provider启动时,需要与注册中心交互,先注册自己的服务,再订阅自己的服
务,订阅时,采用了观察者模式,开启一个listener.注册中心会每5秒定时检查是否有服
务更新,如果有更新,向该服务的提供者发送一个notify消息,provider接受到notify消息
后,即运行NotifyListener的notify方法,执行监听器方法.
动态代理模式
根据上述代码就可以知道private static final ProxyFactory proxyFactory = (ProxyFactory)ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
Dubbo扩展jdkspi的类ExtensionLoader的Adaptive实现是典型的动态代理实现.
好了,相信大家看到这里也已经对Dubbo有了更明确的认识了.如果还有什么疑问,可以随时留言哦.