dubbo详解
1、dubbo是什么dubbo是一个分布式的服务框架,致力于提高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。
简言之,dubbo就是一个服务框架,如果没有分布式的需求,其实不需要用的,只有分布式的时候,才需要dubbo这样的分布式框架
本质里,dubbo就是个服务调用的东东。。
说白了就是个远程服务调用的分布式框架(告别webservice模式中的wsdl,以服务者与消费者的方式在dubbo上注册)
dubbo可以和spring无缝集成
2、dubbo能干什么
1)透明化的远程方法调用,就像调用本地方法一样,只需简单配置,没有任何API侵入
2)软负载均衡及容错机制,可在内网替代F5等硬件负载均衡器,降低成本,减少单点
3)服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且能够平滑添加或删除服务提供者
4)dubbo采用全spring配置方式,透明化接入应用,对应用没有任何API侵入,只需spring加载dubbo的配置即可,dubbo基于spring的schema扩展进行加载
3、dubbo怎么用——即dubbo工作原理
dubbo的核心:
1)远程通讯:提供多种基于长连接的NIO框架封装,包括多线程模型,序列号,以及“请求-响应”模式的信息交换方式
2)集群容错:提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持
3)自动发现:基于注册中心目录服务,使服务消费方能够动态查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器
dubbo主要核心部件
Remoting:网络通信框架,实现了sync-over-async和request-response消息机制。
RPC:一个远程过程调用的抽象,支持负载均衡、容灾和集群功能。
Registry:服务目录框架用于服务的注册和服务事件发布和订阅。
dubbo核心架构图:
角色说明:
provider:服务提供方
consumer:服务消费方
registry:服务注册与发现的注册中心
monitor:统计服务的调用次数和调用时间的监控中心
container:服务运行容器
调用关系说明:
0.服务器负责启动、加载、运行服务提供者
1.服务提供者在启动时,向注册中心注册自己提供的服务
2.服务消费者在启动时,向注册中心订阅自己所需的服务
3.注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者
4.服务消费者,从提供者列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,更换另一台调用
5.服务消费者和服务提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心
4、dubbo怎么用
dubbo基于spring的schema扩展进行加载
服务提供者:
1)下载zookeeper注册中心
2)定义服务接口(该接口需单独打包,在服务提供方和消费方共享)
3)spring配置声明暴露服务
<bean id="demoSevice" class="..."/> //具体的实现Bean
<dubbo:application name="x_provider" /> //提供方信息
<dubbo:egister address="multicast://ip" />//multicast广播注册中心,暴露服务地址
<dubbo:register address="zookeeper://ip:2181" />//zookeeper注册中心暴露服务地址
<dubbo:protocol name="dubbo" port="20880" />//用dubbo协议在20880端口暴露服务
<dubbo:service interface="..." ref="demoService"/>//声明需暴露的服务接口
服务消费者:
applicationContext-dubbo.xml:注册自己需要调用的接口(业务多了,按照业务将拆分成N多个applicationContext-dubbo-xxx.xml)
通过spring配置引用远程服务
<dubbo:application name=".._consumer"/>//消费方应用名
<dubbo:register address="zookeeper://ip:2181"/>//使用zookeeper注册中心暴露服务地址
<dubbo:reference id="demoService" interface="..demoService"/>//生成远程服务代理,可以像使用本地bean一样使用demoService
服务保护:
服务保护的原则上是避免发生类似雪崩效应,尽量将异常控制在服务周围,不要扩散开。
说到雪崩效应,还得提下dubbo自身的重试机制,默认3次,当失败时会进行重试,这样在某个时间点出现性能问题,然后调用方再连续重复调用,很容易引起雪崩,建议的话还是很据业务情况规划好如何进行异常处理,何时进行重试。
服务保护的话,目前我们主要从以下几个方面来实施,也不成熟,还在摸索:
考虑服务的dubbo线程池类型(fix线程池的话考虑线程池大小)、数据库连接池、dubbo连接数限制是否都合适
考虑服务超时时间和重试的关系,设置合适的值
一定时间内服务异常数较大,则可考虑使用failfast让客户端请求直接返回或者让客户端不再请求
zkclient问题
前文已经提到过zkclient有两个问题,修改服务器时间会导致容器挂掉;dubbo使用zkclient没有传超时时间导致zookeeper无法连接的时候,直接阻塞Integer.MAX_VALUE。
正在调研curator,目前只能说curator不会在无法连接的时候直接阻塞。
另外zkclient和curator的jar包应该都是jdk1.6编译的,所以系统还在jdk1.5以下的话无法使用。
注册中心的分组group和服务的不同实现group
这两个东西完全不同的概念,使用的时候不要弄混了。
registry上可以配置group,用于区分不同分组的注册中心,比如在同一个注册中心下,有一部分注册信息是要给开发环境用的,有一部分注册信息时要给测试环境用的,可以分别用不同的group区分开,目前对这个理解还不透彻,大致就是用于区分不同环境。
service和reference上也可以配置group,这个用于区分同一个接口的不同实现,只有在reference上指定与service相同的group才会被发现,还有前文提到的分组合并结果也是用的这个。
5、dubbo的容错方案
当我们的系统中用到Dubbo的集群环境,因为各种原因在集群调用失败时,Dubbo提供了多种容错方案,缺省为failover重试。
Dubbo的集群容错在这里想说说他是因为我们实际的项目中出现了此类的问题,因为依赖的第三方项目出现异常,导致dubbo调用超时,此时使用的是默认的集群容错方式,而配置的reties='3',这样前段系统连续掉用了三次服务,结果可想而知.
先说一下各节点关系:
这里的Invoker是Provider的一个可调用Service的抽象,Invoker封装了Provider地址及Service接口信息。
Directory代表多个Invoker,可以把它看成List<Invoker>,但与List不同的是,它的值可能是动态变化的,比如注册中心推送变更。
Cluster将Directory中的多个Invoker伪装成一个Invoker,对上层透明,伪装过程包含了容错逻辑,调用失败后,重试另一个。
Router负责从多个Invoker中按路由规则选出子集,比如读写分离,应用隔离等。
LoadBalance负责从多个Invoker中选出具体的一个用于本次调用,选的过程包含了负载均衡算法,调用失败后,需要重选。
集群容错模式: Failover Cluster
失败自动切换,当出现失败,重试其它服务器。(缺省)
通常用于读操作,但重试会带来更长延迟。
可通过retries="2"来设置重试次数(不含第一次)。正是文章刚开始说的那种情况.
Failfast Cluster
快速失败,只发起一次调用,失败立即报错。
通常用于非幂等性的写操作,比如新增记录。
Failsafe Cluster
失败安全,出现异常时,直接忽略。
通常用于写入审计日志等操作。
Failback Cluster
失败自动恢复,后台记录失败请求,定时重发。
通常用于消息通知操作。
Forking Cluster
并行调用多个服务器,只要一个成功即返回。
通常用于实时性要求较高的读操作,但需要浪费更多服务资源。
可通过forks="2"来设置最大并行数。
Broadcast Cluster
广播调用所有提供者,逐个调用,任意一台报错则报错。(2.1.0开始支持)
通常用于通知所有提供者更新缓存或日志等本地资源信息。
重试次数配置如:(failover集群模式生效)
<dubbo:serviceretries="2"/>
或:<dubbo:referenceretries="2"/>
或:<dubbo:reference>
<dubbo:methodname="findFoo"retries="2"/>
</dubbo:reference>
集群模式配置如:
<dubbo:servicecluster="failsafe"/>
或:<dubbo:referencecluster="failsafe"/>
6、dubbo负载均衡策略
在集群负载均衡时,Dubbo提供了多种均衡策略,缺省为random随机调用。
RandomLoadBalance
随机,按权重设置随机概率。
在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。
RoundRobinLoadBalance
轮循,按公约后的权重设置轮循比率。
存在慢的提供者累积请求问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。
LeastActiveLoadBalance
最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。
ConsistentHashLoadBalance
一致性Hash,相同参数的请求总是发到同一提供者。
当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。
Dubbo的集群容错和负载均衡同样也是Dubbo本身的高级特性.正如我们在说自定义扩展的时候一样,这两个特征同样也可以进行自定义扩展,用户可以根据自己实际的需求来扩展他们从而满足项目的实际需求。
7、服务之间如何实现通信
1)同步调用
REST(JAX-RS,Spring Boot)
RPC(Thrift,Dubbo,HSF)
2)异步消息调用(kafka,Notify,NetaQ)
RESTFUL和RPC比较:
restful基于HTTP,更易实现,服务端技术更灵活,各语言都支持,跨客户端,对客户端无特殊要求,只需封装HTTP的SDK就能调用
RPC:传输协议更高效,安全更可控
特别在一个公司内部,如果有统一的开发规范和统一的服务框架时,开发效率优势更明显
同步:调用问题,性能差(特别是层次多时)
异步:减低调用服务之间的耦合,调用之间的缓冲,确保消息挤压不会冲垮被调用方,同时保证调用方的服务体验,继续干自己该干的活,不至于被后台性能拖慢,付出的代价是一致性的减弱,需要接受数据最终一致性,后台服务一般要实现幂等性,因为消息发送处于性能的考虑一般会有重复;必须引入一个独立的broker。