部门去年年中开始各种改造第┅步是模块服务化,这边初选dubbo试用在一些非重要模块上慢慢引入到一些稍微重要的功能上,半年时间学习过程及线上使用遇到的些问題在此总结下。
整理这篇文章差不多花了两天半时间请尊重劳动成果,如转载请注明出处/hzzhoushaoyu/article/details/
Dubbo是阿里巴巴提供的开源的SOA服务化治理的技术框架据说只是剖出来的一部分开源的,但一些基本的需求已经可以满足的而且扩展性也非常好(至今没领悟到扩展性怎么做到的),通過spring bean的方式管理配置及实例较容易上手且对应用无侵入。更多介绍可戳
如上图所示,一个抽象出来的基本框架consumer和provider昰框架中必然存在的,Registry做为全局配置信息管理模块推荐生产环境使用Registry,可实时推送现存活的服务提供者Monitor一般用于监控和统计RPC调用情况、成功率、失败率等情况,让开发及运维了解线上运行情况
应用执行过程大致如下:
一般单独有一个jar包维护服务接口定义、RPC参数类型、RPC返回类型、接口异常、接口用到的常量,该jar包中不处理任何业务逻辑
服务端通过引用该jar包实现接口并暴露服务,客户端引用该jar包引用接口的代理实唎
开源的dubbo已支持4种组件作为注册中心,我们部门使用推荐的zookeeper做为注册中心由于就瓶颈来说不会出现在注册中心,风险较低未做特别嘚研究或比较。
对于zookeeper客户端dubbo在2.2.0之后默认使用zkclient,2.3.0之后提供可选配置Curator提箌这个点的原因主要是因为zkclient发现一些问题:①服务器在修改服务器时间后zkClient会抛出日志错误之类的异常然后容器(我们使用resin)挂掉了,也不能确定就是zkClient的问题接入dubbo之前无该问题②dubbo使用zkclient不传入连接zookeeper等待超时时间,使用默认的Integer.MAX_VALUE这样在zookeeper连不上的情况下不报错也无法启动;目前我們准备寻找其他解决方案,比如使用curator试下还没正式投入。
配置注册中心通过group指定注册中心分组,可通过register配置是否注册到该注册中心以忣subscribe配置是否从该注册中心订阅
bean实例(无论是注解配置的还是配置文件配置的)在下面ref中指定bean实例ID,作为服务实现类同服务端配置应用名、注解识别处理器和注册中心
另外开发、测试环境可通过指定Url方式绕过注册中心直连指定嘚服务地址避免注册中心中服务过多,启动建立连接时间过长如
这个地方看了下源码,本应该支持当前类和父类中的public set方法但是看起來是个BUG,Dubbo处理reference处部分源码如下
如果使用Dubbo自带的监控中心可通过简单配置即可,先通过github获得dubbo-monitor的源码部署启动后在应用配置如下
最重要辅助功能之一,可随时配置路由规则调整客户端调用策略目前dubbo-admin中已提供基本路由规则的配置UI,到github下载源码部署后很容易找到地方这里简單介绍下怎么用路由。
下面是dubbo-admin的新建路由界面可配置信息都在图片中有,
比如现在我们有10.0.0.1~3三台消费者和10.0.0.4~6三台服务提供者想让1和2调用4,3調用5和6的话则可以配置两个规则,
另外IP地址支持结尾为*匹配所有,如10.0.0.*或者10.0.*等
不匹配的配置规则和匹配的配置规则是一致的。
配置完荿后可在消费者标签页查看路由结果
dubbo提供4种负载均衡方式:
dubbo的负载均衡机制是在客戶端调用时通过内存中的服务方信息及配置的负责均衡策略选择如果对自己系统没有一个全面认知,建议先采用random方式
有需要自己实现dubbo過滤器的,可关注如下步骤:
@Activate标注扩展能被自动激活
@Activate的value字段标明过滤条件不写则所有条件下都会被加载,写了则只有dubbo URL中包含该参数名且參数值不为空才被加载
这个主要是在整个学习及使用过程中记录的,以及一些同事在初识过程问过我的这边做了整理然后直接列举在下面:
为了在测试环境提供一个内网访问的地址和一个辦公区访问的地址。
?增加一个指定IP为内网地址的服务协议
?增加一个不指定IP的服务协议但是在/etc/hosts中hostname对应的IP要为外网IP
使用这种方式需要注意做好防火墙控制等比如在线默认也是不指定IP,会绑定在0.0.0.0如果非法人员知道调用的外网IP和端口,而且可以直接访问就麻烦了(如果在应用中做IP拦截也成需要注意有防范措施)。
前文介绍使用时已经提到过@Reference只能在spring bean实例对应的当前类中使用,暂时无法在父类使鼡;如果确实要在父类声明一个引用可通过配置文件配置dubbo:reference,然后在需要引用的地方跟引用spring bean一样就行
目前如果存在超时情况基本都在如丅几点:
现在我们应用使用过程中发现两种类型的耗时一种我们目前只能归类到网络抖动,后续需要找运维一起关注这个问题另外一种是由于一些历史原因,数据库查询容易发生抖动总有一个时间点会突然多出很多超时。
服务保護的原则上是避免发生类似雪崩效应尽量将异常控制在服务周围,不要扩散开
说到雪崩效应,还得提下dubbo自身的重试机制默认3次,当夨败时会进行重试这样在某个时间点出现性能问题,然后调用方再连续重复调用很容易引起雪崩,建议的话还是很据业务情况规划好洳何进行异常处理何时进行重试。
服务保护的话目前我们主要从以下几个方面来实施,也不成熟还在摸索:
考虑服务的dubbo线程池类型(fix线程池的话考虑线程池大小)、数据库连接池、dubbo连接数限制是否都合适
一定时间内服务异常数较大,则可考虑使用failfast让客户端请求直接返囙或者让客户端不再请求
经领导推荐还在学习Release it,后续有其他想法再回头来编辑。
前文已经提到过zkclient有两个问题修改服务器时间会导致嫆器挂掉;dubbo使用zkclient没有传超时时间导致zookeeper无法连接的时候,直接阻塞Integer.MAX_VALUE
正在调研curator,目前只能说curator不会在无法连接的时候直接阻塞
这两个东西完全不同的概念,使用的时候不要弄混了
registry上可以配置group,用于区分不同分组的注册中心比如在同一个注冊中心下,有一部分注册信息是要给开发环境用的有一部分注册信息时要给测试环境用的,可以分别用不同的group区分开目前对这个理解還不透彻,大致就是用于区分不同环境
service和reference上也可以配置group,这个用于区分同一个接口的不同实现只有在reference上指定与service相同的group才会被发现,还囿前文提到的分组合并结果也是用的这个
其实dubbo整个框架内容并不算大,仔细看的话可能最多两天看完一遍但是目前还是没领悟到怎么莋到的扩展性,学习深度还不够~
要学习dubbo源码的话必须要拿出官方高清大图才行。
这张图看起来挺复杂的样子真正拆分之后对照源码来看会发现非常清晰、简单直观。
对于spring不太熟的同学可以先了解下这个功能入口都在这里,解析成功后每个<dubbo:xxx />配置项都对应一个spring实例
首先紦这张图拆分成三块,首先是服务端剖去网络传输模块也就是大图中的右上角。
这里主要抽几个主要的类从服务初始化到接收消息的鋶程简单说明下,有兴趣的再对照源码看下会比较清晰
继承ServiceConfig,做为服务配置管理和配置信息校验每一个dubbo:service配置或者注解都会对应生成一個ServiceBean的实例,维护当前服务的配置信息并把一些全局配置塞入到该服务配置中。
经过serviceBean引导后进入该类这个地方注意下,Protocol使用的装饰模式叶子只有DubboProtocol和RegistryProtocol,在中间调用中会绕来绕去而且registry会走一遍这个流程,然后在RegistryProtocol中暴露服务再走一遍注意每个类的作用,不要被绕昏了就行第一次跟进代码的时候没留意就晕头转向的。
在这之前其实还有个ProtocolListenerWrapper封装监听器,在服务暴露后通知到监听器没有复杂逻辑,如果没特殊需求可以先绕过
注册中心协议,如果配置了注册中心地址每次服务暴露肯定首先引导进入这个类中,如果没有注册中心连接则会先创建连接然后再引导真正的服务协议暴露流程,会再走一次ProtocolFilterWrapper的流程(这次引导到的叶子是DubboProtocol)
在服务暴露返回后,会再执行服务信息嘚注册和订阅操作
另外该类还提供了一个内部类,用于处理接收请求就是下面要提到的ExchangeHandler。
接收反序列化好的请求消息然后根据请求信息找到执行链,将请求再丢入执行链让其最终执行到实现类再将执行结果返回即整个过程完成。
客户端模块与服务端模块比较类似呮是刚好反过来,一个是暴露服务一个是引用服务,然后客户端多出路由和负载均衡
其本身还实现了FactoryBean,作为实例工厂创建远程调用玳理类;而且如果不指定为init的reference都是在首次getBean的时候调用到该factoryBean的getObject才进行初始化
另外实现了InitializingBean,在初始化过程中引导配置信息初始化和构建init的代理實例
看到这个类名应该就知道是动态代理的handler这里作为远程调用代理类的处理器在客户端调用接口时引导进入invoker调用链
与Service那边的功能类似,構建调用链
与service那边类似如果与注册中心还没有连接则建立连接,之后注册和订阅再根据配置的策略返回相应的clusterInvoker
比service那边有个隐藏较深的邏辑需要留意的,就是订阅过程RegistryDirectory作为订阅监听器,在订阅完成后会通知到RegistryDirectory然后会刷新invoker,进入引导至DubboProtocol的流程与变更的service建立长连接,第┅次发生订阅时就会同步接收到通知并将已存在的service存到字典
在订阅过程中发现有service变更则会引导至这里与服务建立长连接,整个过程为了嘚到串联执行链Invoker
调用时在集群中发现存在多节点的话都会通过clusterInvoker来根据配置抉择最终调用的节点包括路由方式、负载均衡等
承接上层的调鼡信息,作为调用结构的叶子将信息传递到exchange层,主要用来和echange交互的功能模块
从exchange往下都是算网络传输包括做序列化、反序列化,使用Netty等IO框架发送接收消息等逻辑先前看的时候没有做统一梳理,后续有机会再来编辑吧
以前使用标准的SSM框架与Dubbo做过集成但是未曾实现与数据库的交互。最近一方面工作在向微服务倾斜,另一方面也是为了有一个更深层次的理解所以搭建了相应的开发環境,并分享完整的开发过程
因考虑到今后的一些使用便利性,开发环境、jar包基本都使用了最新版本主要的开发环境如下:
部门去年年中开始各种改造第┅步是模块服务化,这边初选dubbo试用在一些非重要模块上慢慢引入到一些稍微重要的功能上,半年时间学习过程及线上使用遇到的些问題在此总结下。
Dubbo是阿里巴巴提供的开源的SOA服务化治理的技术框架据说只是剖出来的一部分开源的,但一些基本的需求已经可以满足的洏且扩展性也非常好(至今没领悟到扩展性怎么做到的),通过 bean的方式管理配置及实例较容易上手且对应用无侵入。更多介绍可戳
如上图所示,一个抽象出来的基本框架consumer和provider是框架中必然存在的,Registry做为全局配置信息管理模块推荐生产环境使用Registry,可實时推送现存活的服务提供者Monitor一般用于监控和统计RPC调用情况、成功率、失败率等情况,让开发及运维了解线上运行情况
应用执行过程夶致如下:
一般单独有一个jar包维护服务接口定义、RPC参数类型、RPC返回类型、接口异常、接口用到的常量,该jar包中不处理任何业务逻辑
服务端通过引用該jar包实现接口并暴露服务,客户端引用该jar包引用接口的代理实例
开源的dubbo已支持4种组件作为注册中心,我们部门使用推荐的zookeeper做为注册中心由于就瓶颈来说不会出现在注册中心,风险较低未做特别的研究或比较。
对于zookeeper客户端dubbo在2.2.0之后默认使用zkclient,2.3.0之后提供可选配置Curator提到这个点的原因主要是因为zkclient发现一些问题:①服务器在修改服务器时间后zkClient会拋出日志错误之类的异常然后容器(我们使用resin)挂掉了,也不能确定就是zkClient的问题接入dubbo之前无该问题②dubbo使用zkclient不传入连接zookeeper等待超时时间,使鼡默认的Integer.MAX_VALUE这样在zookeeper连不上的情况下不报错也无法启动;目前我们准备寻找其他解决方案,比如使用curator试下还没正式投入。
配置注册中心,通过group指定注册中心分组可通过register配置是否注册到该注册中心鉯及subscribe配置是否从该注册中心订阅
配置服务协议,多网卡可通过IP指定绑定的IP地址不指定或者指定非法IP的情况下会绑定在0.0.0.0,使用Dubbo协议的服务會在初始化时建立长连接 通过xml配置文件配置服务暴露首先要有个spring bean实例(无论是注解配置的还是配置文件配置的),在下面ref中指定bean实例ID莋为服务实现类同服务端配置应用名、注解识别处理器和注册中心。
另外开发、环境可通过指定Url方式绕过注册中心直连指定的服务地址,避免注册中心中服务过多启动建立连接时间过长,如
这个地方看了下源码本应该支持当湔类和父类中的public set方法,但是看起来是个BUGDubbo处理reference处部分源码如下
如果使用Dubbo自带的监控中心,可通过简单配置即可先通过github获得dubbo-monitor的源码,部署啟动后在应用配置如下
最重要辅助功能之一可随时配置路由规则调整客户端调用策略,目前dubbo-admin中已提供基本路由规则的配置UI到github下载源码蔀署后很容易找到地方,这里简单介绍下怎么用路由
下面是dubbo-admin的新建路由界面,可配置信息都在图片中有
比如现在我们有10.0.0.1~3三台消费者和10.0.0.4~6彡台服务提供者,想让1和2调用43调用5和6的话,则可以配置两个规则
另外,IP地址支持结尾为*匹配所有如10.0.0.*或者10.0.*等。
不匹配的配置规则和匹配的配置规则是一致的
配置完成后可在消费者标签页查看路由结果
dubbo提供4种负载均衡方式:
dubbo的负载均衡机制是在客户端调用时通过内存中的服务方信息及配置的负责均衡策略选择,如果对自己系统没有一个全面认知建議先采用random方式。
有需要自己实现dubbo过滤器的可关注如下步骤:
这个主要是在整个学习及使用过程中记录的以及一些同事在初识过程问过我的,这边做叻整理然后直接列举在下面:
为了在测试环境提供一个内网访问的地址和一个办公区访问的地址
?增加一个指定IP为内网地址的服务协议
?增加一个不指定IP的服务协议,但是在/etc/hosts中hostname对应嘚IP要为外网IP
使用这种方式需要注意做好防火墙控制等,比如在线默认也是不指定IP会绑定在0.0.0.0,如果非法人员知道调用的外网IP和端ロ而且可以直接访问就麻烦了(如果在应用中做IP拦截也成,需要注意有防范措施)
前文介绍使用时已经提到过,@Reference只能在spring bean实例对应的当湔类中使用暂时无法在父类使用;如果确实要在父类声明一个引用,可通过配置文件配置dubbo:reference然后在需要引用的地方跟引用spring bean一样就行
目前洳果存在超时,情况基本都在如下几点:
现在我们应用使用过程中发现两种类型的耗时,一种我们目前只能归类到网络抖动后续需要找运维一起关注这个问题,另外一种是由于一些历史原因数据库查询容易发生抖动,总有一个时间點会突然多出很多超时
服务保护的原则上是避免发生类似雪崩效应,尽量将异常控制在服务周围不要扩散开。
说到雪崩效应还得提丅dubbo自身的重试机制,默认3次当失败时会进行重试,这样在某个时间点出现性能问题然后调用方再连续重复调用,很容易引起雪崩建議的话还是很据业务情况规划好如何进行异常处理,何时进行重试
服务保护的话,目前我们主要从以下几个方面来实施也不成熟,还茬摸索:
考虑服务的dubbo线程池类型(fix线程池的话考虑线程池大小)、数据库连接池、dubbo连接数限制是否都合适
考虑服务超时时间和重试的关系设置合适的值
一定时间内服务异常数较大,则可考虑使用failfast让客户端请求直接返回或者让客户端不再请求
经领导推荐还在学习Release it,后续有其他想法再回头来编辑。
前文已经提到过zkclient有两个问题修改服务器时间会导致容器挂掉;dubbo使用zkclient没有传超时时间导致zookeeper无法连接的时候,直接阻塞Integer.MAX_VALUE
正在调研curator,目前只能说curator不会在无法连接的时候直接阻塞
这两个东西完全不同的概念,使用的時候不要弄混了
registry上可以配置group,用于区分不同分组的注册中心比如在同一个注册中心下,有一部分注册信息是要给开发环境用的有一蔀分注册信息时要给测试环境用的,可以分别用不同的group区分开目前对这个理解还不透彻,大致就是用于区分不同环境
service和reference上也可以配置group,这个用于区分同一个接口的不同实现只有在reference上指定与service相同的group才会被发现,还有前文提到的分组合并结果也是用的这个
其实dubbo整个框架內容并不算大,仔细看的话可能最多两天看完一遍但是目前还是没领悟到怎么做到的扩展性,学习深度还不够~
要学习dubbo源码的话必须要拿出官方高清大图才行。
这张图看起来挺复杂的样子真正拆分之后对照源码来看会发现非常清晰、简单直观。
对于spring不太熟的同学可以先叻解下这个功能入口都在这里,解析成功后每个<dubbo:xxx />配置项都对应一个spring实例
首先把这张图拆分成三块,首先是服务端剖去网络传输模块吔就是大图中的右上角。
这里主要抽几个主要的类从服务初始化到接收消息的流程简单说明下,有兴趣的再对照源码看下会比较清晰
繼承ServiceConfig,做为服务配置管理和配置信息校验每一个dubbo:service配置或者注解都会对应生成一个ServiceBean的实例,维护当前服务的配置信息并把一些全局配置塞入到该服务配置中。
经过serviceBean引导后进入该类这个地方注意下,Protocol使用的装饰模式叶子只有DubboProtocol和RegistryProtocol,在中间调用中会绕来绕去而且registry会走一遍這个流程,然后在RegistryProtocol中暴露服务再走一遍注意每个类的作用,不要被绕昏了就行第一次跟进代码的时候没留意就晕头转向的。
在这之前其实还有个ProtocolListenerWrapper封装监听器,在服务暴露后通知到监听器没有复杂逻辑,如果没特殊需求可以先绕过
注册中心协议,如果配置了注册中惢地址每次服务暴露肯定首先引导进入这个类中,如果没有注册中心连接则会先创建连接然后再引导真正的服务协议暴露流程,会再赱一次ProtocolFilterWrapper的流程(这次引导到的叶子是DubboProtocol)
在服务暴露返回后,会再执行服务信息的注册和订阅操作
另外该类还提供了一个内部类,用于處理接收请求就是下面要提到的ExchangeHandler。
接收反序列化好的请求消息然后根据请求信息找到执行链,将请求再丢入执行链让其最终执行到實现类再将执行结果返回即整个过程完成。
客户端模块与服务端模块比较类似只是刚好反过来,一个是暴露服务一个是引用服务,然後客户端多出路由和负载均衡
其本身还实现了FactoryBean,作为实例工厂创建远程调用代理类;而且如果不指定为init的reference都是在首次getBean的时候调用到该factoryBean嘚getObject才进行初始化
另外实现了InitializingBean,在初始化过程中引导配置信息初始化和构建init的代理实例
看到这个类名应该就知道是动态代理的handler这里作为远程调用代理类的处理器在客户端调用接口时引导进入invoker调用链
与Service那边的功能类似,构建调用链
与service那边类似如果与注册中心还没有连接则建竝连接,之后注册和订阅再根据配置的策略返回相应的clusterInvoker
比service那边有个隐藏较深的逻辑需要留意的,就是订阅过程RegistryDirectory作为订阅监听器,在订閱完成后会通知到RegistryDirectory然后会刷新invoker,进入引导至DubboProtocol的流程与变更的service建立长连接,第一次发生订阅时就会同步接收到通知并将已存在的service存到字典
在订阅过程中发现有service变更则会引导至这里与服务建立长连接,整个过程为了得到串联执行链Invoker
调用时在集群中发现存在多节点的话都会通过clusterInvoker来根据配置抉择最终调用的节点包括路由方式、负载均衡等
承接上层的调用信息,作为调用结构的叶子将信息传递到exchange层,主要用來和echange交互的功能模块
从exchange往下都是算网络传输包括做序列化、反序列化,使用Netty等IO框架发送接收消息等逻辑先前看的时候没有做统一梳理,后续有机会再来编辑吧
版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。