Dubbo学习总结(2)——Dubbo架构详解
一、前言
部门去年年中开始各种改造,第一步是模块服务化,这边初选dubbo试用在一些非重要模块上,慢慢引入到一些稍微重要的功能上,半年时间,学习过程及线上使用遇到的些问题在此总结下。
整理这篇文章差不多花了两天半时间,请尊重劳动成果,如转载请注明出处http://blog.csdn.net/u012562943/article/details/49025303
二、什么是dubbo
Dubbo是阿里巴巴提供的开源的SOA服务化治理的技术框架,据说只是剖出来的一部分开源的,但一些基本的需求已经可以满足的,而且扩展性也非常好(至今没领悟到扩展性怎么做到的),通过spring bean的方式管理配置及实例,较容易上手且对应用无侵入。更多介绍可戳http://alibaba.github.io/dubbo-doc-static/Home-zh.htm。
三、如何使用dubbo
1.服务化应用基本框架
如上图所示,一个抽象出来的基本框架,consumer和provider是框架中必然存在的,Registry做为全局配置信息管理模块,推荐生产环境使用Registry,可实时推送现存活的服务提供者,Monitor一般用于监控和统计RPC调用情况、成功率、失败率等情况,让开发及运维了解线上运行情况。
应用执行过程大致如下:
- 服务提供者启动,根据协议信息绑定到配置的IP和端口上,如果已有服务绑定过相同IP和端口的则跳过
- 注册服务信息至注册中心
- 客户端启动,根据接口和协议信息订阅注册中心中注册的服务,注册中心将存活的服务地址通知到客户端,当有服务信息变更时客户端可以通过定时通知得到变更信息
- 在客户端需要调用服务时,从内存中拿到上次通知的所有存活服务地址,根据路由信息和负载均衡机制选择最终调用的服务地址,发起调用
- 通过filter分别在客户端发送请求前和服务端接收请求后,通过异步记录一些需要的信息传递到monitor做监控或者统计
2.服务接口定义
一般单独有一个jar包,维护服务接口定义、RPC参数类型、RPC返回类型、接口异常、接口用到的常量,该jar包中不处理任何业务逻辑。
比如命名api-0.1.jar,在api-0.1.jar中定义接口
- public interface UserService
- {
- public RpcResponseDto isValidUser(RpcAccountRequestDto requestDto) throws new RpcBusinessException, RpcSystemException;
- }
并在api-0.1.jar中定义RpcResponseDto,RpcAccountRequestDto,RpcBusinessException,RpcSystemException。
服务端通过引用该jar包实现接口并暴露服务,客户端引用该jar包引用接口的代理实例。
3.注册中心
开源的dubbo已支持4种组件作为注册中心,我们部门使用推荐的zookeeper做为注册中心,由于就瓶颈来说不会出现在注册中心,风险较低,未做特别的研究或比较。
- zookeeper,推荐集群中部署奇数个节点,由于zookeeper挂掉一半的机器集群就不可用,所以部署4台和3台的集群都是在挂掉2台后集群不可用
- redis
- multicast,广播受到网络结构的影响,一般本地不想搭注册中心的话使用这种调用
- dubbo简易注册中心
对于zookeeper客户端,dubbo在2.2.0之后默认使用zkclient,2.3.0之后提供可选配置Curator,提到这个点的原因主要是因为zkclient发现一些问题:①服务器在修改服务器时间后zkClient会抛出日志错误之类的异常然后容器(我们使用resin)挂掉了,也不能确定就是zkClient的问题,接入dubbo之前无该问题②dubbo使用zkclient不传入连接zookeeper等待超时时间,使用默认的Integer.MAX_VALUE,这样在zookeeper连不上的情况下不报错也无法启动;目前我们准备寻找其他解决方案,比如使用curator试下,还没正式投入。
4.服务端
配置应用名
- <dubbo:application name="test"/>
配置dubbo注解识别处理器,不指定包名的话会在spring bean中查找对应实例的类配置了dubbo注解的
- <dubbo:annotation/>
配置注册中心,通过group指定注册中心分组,可通过register配置是否注册到该注册中心以及subscribe配置是否从该注册中心订阅
- <dubbo:registry address="zookeeper://127.0.0.1:2181/" group="test"/>
配置服务协议,多网卡可通过IP指定绑定的IP地址,不指定或者指定非法IP的情况下会绑定在0.0.0.0,使用Dubbo协议的服务会在初始化时建立长连接
- <dubbo:protocol name="dubbo" port="20880" accesslog="d:/access.log"></dubbo:protocol>
通过xml配置文件配置服务暴露,首先要有个spring bean实例(无论是注解配置的还是配置文件配置的),在下面ref中指定bean实例ID,作为服务实现类
- <dubbo:service interface="com.web.foo.service.FirstDubboService" ref="firstDubboServiceImpl" version="1.0"></dubbo:service>
通过注解方式配置服务暴露,Component是Spring bean注解,Service是dubbo的注解(不要和spring bean的service注解弄混),如前文所述,dubbo注解只会在spring bean中被识别
- @Component
- @Service(version="1.0")
- public class FirstDubboServiceImpl implements FirstDubboService
- {
- @Override
- public void sayHello(TestDto test)
- {
- System.out.println("Hello World!");
- }
- }
5.客户端
配置客户端reference bean。客户端跟服务端不同的是客户端这边没有实际的实现类的,所以配置的dubbo:reference实际会生成一个spring bean实例,作为代理处理Dubbo请求,然后其他要调用处直接使用spring bean的方式使用这个实例即可。
xml配置文件配置方式,id即为spring bean的id,之后无论是在spring配置中使用ref="firstDubboService"还是通过@Autowired注解都OK
- <dubbo:reference interface="com.web.foo.service.FirstDubboService"
- version="1.0" id="firstDubboService" ></dubbo:reference>
另外开发、测试环境可通过指定Url方式绕过注册中心直连指定的服务地址,避免注册中心中服务过多,启动建立连接时间过长,如
- <dubbo:reference interface="com.web.foo.service.FirstDubboService"
- version="1.0" id="firstDubboService" url="dubbo://127.0.0.1:20880/"></dubbo:reference>
注解配置方式引用,
- @Component
- public class Consumer
- {
- @Reference(version="1.0")
- private FirstDubboService service;
- public void test()
- {
- TestDto test = new TestDto();
- test.setList(Arrays.asList(new String[]{"a", "b"}));
- test.setTest("t");
- service.sayHello(test);
- }
- }
Reference被识别的条件是spring bean实例对应的当前类中的field,如上是直接修饰spring bean当前类中的属性
这个地方看了下源码,本应该支持当前类和父类中的public set方法,但是看起来是个BUG,Dubbo处理reference处部分源码如下
- Method[] methods = bean.getClass().getMethods();
- for (Method method : methods) {
- String name = method.getName();
- if (name.length() > 3 && name.startsWith("set")
- && method.getParameterTypes().length == 1
- && Modifier.isPublic(method.getModifiers())
- && ! Modifier.isStatic(method.getModifiers())) {
- try {
- Reference reference = method.getAnnotation(Reference.class);
- if (reference != null) {
- Object value = refer(reference, method.getParameterTypes()[0]);
- if (value != null) {
- method.invoke(bean, new Object[] { });//??这里不是应该把value作为参数调用么,而且为什么上面if条件判断参数为1这里不传参数
- }
- }
- } catch (Throwable e) {
- logger.error("Failed to init remote service reference at method " + name + " in class " + bean.getClass().getName() + ", cause: " + e.getMessage(), e);
- }
- }
- }
6.监控中心
- <dubbo:monitor protocol="registry" /> <!--通过注册中心获取monitor地址后建立连接-->
- <dubbo:monitor address="dubbo://127.0.0.1:7070/com.alibaba.dubbo.monitor.MonitorService" /> <!--绕过注册中心直连monitor,同consumer直连-->
7.服务路由
8.负载均衡
- Random,随机,按权重配置随机概率,调用量越大分布越均匀,默认是这种方式
- RoundRobin,轮询,按权重设置轮询比例,如果存在比较慢的机器容易在这台机器的请求阻塞较多
- LeastActive,最少活跃调用数,不支持权重,只能根据自动识别的活跃数分配,不能灵活调配
- ConsistentHash,一致性hash,对相同参数的请求路由到一个服务提供者上,如果有类似灰度发布需求可采用
9.dubbo过滤器
- dubbo初始化过程加载META-INF/dubbo/internal/,META-INF/dubbo/,META-INF/services/三个路径(classloaderresource)下面的com.alibaba.dubbo.rpc.Filter文件
- 文件配置每行Name=FullClassName,必须是实现Filter接口
- @Activate标注扩展能被自动激活
- @Activate如果group(provider|consumer)匹配才被加载
- @Activate的value字段标明过滤条件,不写则所有条件下都会被加载,写了则只有dubbo URL中包含该参数名且参数值不为空才被加载
- @Activate(group = Constants.PROVIDER, value = Constants.ACCESS_LOG_KEY)
- public class AccessLogFilter implements Filter {
- }
10.其他特性
http://alibaba.github.io/dubbo-doc-static/User+Guide-zh.htm#UserGuide-zh-%3Cdubbo%3Amonitor%2F%3E
可关注以上链接内容,dubbo提供较多的辅助功能特性,大多目前我们暂时未使用到,后续我们这边关注到的两个特性可能会再引进来使用:
- 结果缓存,省得自己再去写一个缓存,对缓存没有特殊要求的话直接使用dubbo的好了
- 分组合并,对RPC接口不同的实现方式分别调用然后合并结果的一种调用模式,比如我们要查用户是否合法,一种我们要查是否在黑名单,同时我们还要关注登录信息是否异常,然后合并结果
四、前车之鉴
1.服务版本号
- 引用只会找相应版本的服务
- <dubbo:serviceinterface=“com.xxx.XxxService” ref=“xxxService” version=“1.0” />
- <dubbo:referenceid=“xxxService” interface=“com.xxx.XxxService” version=“1.0”/>
- 为了今后更换接口定义发布在线时,可不停机发布,使用版本号
2.暴露一个内网一个外网IP问题
为了在测试环境提供一个内网访问的地址和一个办公区访问的地址。
上面这种方案是一开始使用的方案,后面发现dubbo在启动过程无论是否配路由还是会一个个去连接,虽然不影响启动,但是由于存在超时所以会影响启动时间,而且每台机器还得特别配置指定IP,后面使用另外一套方案:
- 服务不配置ip,绑定到0.0.0.0,自动获取保证获取到是内网IP注册到注册中心即可,如果不是想要的IP,可以在/etc/hosts中通过绑定Hostname指定IP
- 内网访问方式通过注册中心或者直连指定内网IP和端口
- 外网访问方式通过直连指定外网IP和端口
3.dubbo reference注解问题
4.服务超时问题
- 客户端耗时大,也就是超时异常时的client elapsed xxx,这个是从创建Future对象开始到使用channel发出请求的这段时间,中间没有复杂操作,只要CPU没问题基本不会出现大耗时,顶多1ms属于正常
- IOThread繁忙,默认情况下,dubbo协议一个客户端与一个服务提供者会建立一个共享长连接,如果某个客户端处于特别繁忙而且一直往一个服务提供者塞请求,可能造成IOThread阻塞,一般非常特殊的情况才会出现
- 服务端工作线程池中线程全部繁忙,接收消息后塞入队列等待,如果等待时间比预想长会引起超时
- 网络抖动,如果上述情况都排除了,还出现在请求发出后,服务接收请求前超过预想时间,只能归类到网络抖动了,需要SA一起查看问题
- 服务自身耗时大,这个需要应用自身做好耗时统计,当出现这种情况的时候需要用数据来说明问题及规划优化方案,建议采用缓存埋点的方式统计服务中各个执行阶段的耗时情况,最终如果超过预想时间则把缓存统计的耗时情况打日志,减少日志量,且能够得到更明确的信息
5.服务保护
- 考虑服务的dubbo线程池类型(fix线程池的话考虑线程池大小)、数据库连接池、dubbo连接数限制是否都合适
- 考虑服务超时时间和重试的关系,设置合适的值
- 一定时间内服务异常数较大,则可考虑使用failfast让客户端请求直接返回或者让客户端不再请求
6.zkclient的问题
7.注册中心的分组group和服务的不同实现group
五、dubbo如何工作的
1.如何跟进源码
2.服务提供者
- ServiceBean
- ProtocolFilterWrapper
- RegistryProtocol
- DubboProtocol
- DubboProtocol$ExchangeHandler
3.客户端
- ReferenceBean
- InvokerInvocationHandler
- ProtocolFIlterWrapper
- RegistryProtocol
- DubboProtocol
- ClusterInvoker
- DubboInvoker
4.网络传输层
Dubbo学习总结(2)——Dubbo架构详解的更多相关文章
- 第15.22节 PyQt(Python+Qt)入门学习:Model/View架构详解
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 一.简介 在PyQt和Qt中,Model/View架构是图形界面开发时用于管理数据和界面展现方式的关 ...
- Nop--NopCommerce源码架构详解专题目录
最近在研究外国优秀的ASP.NET mvc电子商务网站系统NopCommerce源码架构.这个系统无论是代码组织结构.思想及分层都值得我们学习.对于没有一定开发经验的人要完全搞懂这个源码还是有一定的难 ...
- 学习《深度学习与计算机视觉算法原理框架应用》《大数据架构详解从数据获取到深度学习》PDF代码
<深度学习与计算机视觉 算法原理.框架应用>全书共13章,分为2篇,第1篇基础知识,第2篇实例精讲.用通俗易懂的文字表达公式背后的原理,实例部分提供了一些工具,很实用. <大数据架构 ...
- NopCommerce源码架构详解--初识高性能的开源商城系统cms
很多人都说通过阅读.学习大神们高质量的代码是提高自己技术能力最快的方式之一.我觉得通过阅读NopCommerce的源码,可以从中学习很多企业系统.软件开发的规范和一些新的技术.技巧,可以快速地提高我们 ...
- NopCommerce源码架构详解
NopCommerce源码架构详解--初识高性能的开源商城系统cms 很多人都说通过阅读.学习大神们高质量的代码是提高自己技术能力最快的方式之一.我觉得通过阅读NopCommerce的源码,可以从 ...
- Zookeeper系列二:分布式架构详解、分布式技术详解、分布式事务
一.分布式架构详解 1.分布式发展历程 1.1 单点集中式 特点:App.DB.FileServer都部署在一台机器上.并且访问请求量较少 1.2 应用服务和数据服务拆分 特点:App.DB.Fi ...
- Hyperledger Fabric架构详解
区块链开源实现HYPERLEDGER FABRIC架构详解 区块链开源实现HYPERLEDGER FABRIC架构详解 2018年5月26日 陶辉 Comments 10 Comments hyper ...
- B/S架构详解
学习笔记: * B/S架构详解 * 资源分类: 1. 静态资源: * 使用静态网页开发技术发布的资源. * 特点: ...
- Java学习-007-Log4J 日志记录配置文件详解及实例源代码
此文主要讲述在初学 Java 时,常用的 Log4J 日志记录配置文件详解及实例源代码整理.希望能对初学 Java 编程的亲们有所帮助.若有不足之处,敬请大神指正,不胜感激!源代码测试通过日期为:20 ...
- 领域驱动设计(Domain Driven Design)参考架构详解
摘要 本文将介绍领域驱动设计(Domain Driven Design)的官方参考架构,该架构分成了Interfaces.Applications和Domain三层以及包含各类基础设施的Infrast ...
随机推荐
- RxJava使用介绍
主讲人:阳石柏 RxJava基本概念 背压概念介绍 RxJava 2.0版本介绍及更新 一.RxJava基本概念 RxJava 在 GitHub 主页上的自我介绍是 “a library for co ...
- Bing Maps进阶系列七:Bing Maps功能导航菜单华丽的变身
Bing Maps进阶系列七:Bing Maps功能导航菜单华丽的变身 Bing Maps Silverlight Control所提供的功能导航是非常强大的,在设计上对扩展的支持非常好,提供了许多用 ...
- imagebutton 设置了src属性的图片更换
<ImageButton android:id="@+id/mediacontroller_play_pause" android:layout_width="wr ...
- 70.资金管理-福利表管理 Extjs 页面
1. <%@ page language="java" import="java.util.*" pageEncoding="UTF-8&quo ...
- Android.mk添加第三方jar包(转载)
转自:www.cnblogs.com/hopetribe/archive/2012/04/23/2467060.html LOCAL_PATH:= $(call my-dir)include $(CL ...
- PCB WebAPI 接口测试工具与接口文档生成
我们自己写WebAPI或调用对方系统提供的WebAPI时,测试WebAPI接口工具用哪些工具呢. 这里将3种WebAPI常用到的工具使用说明.主要是讲对第3种WebApiTestClientWebAp ...
- canvas做的一个写字板
<!DOCTYPE html><html><head><title>画板实验</title> <meta charset=" ...
- Singleton.java.ft not found 相关错误的解决办法
Entry fileTemplates//Singleton.java.ft not found in C:/Users/admin/Desktop/android-studio/lib/resour ...
- 联想 K5 Note(L38012)免解锁BL 免rec 保留数据 ROOT Magisk Xposed 救砖 ZUI3.9.218
>>>重点介绍<<< 第一:本刷机包可卡刷可线刷,刷机包比较大的原因是采用同时兼容卡刷和线刷的格式,所以比较大第二:[卡刷方法]卡刷不要解压刷机包,直接传入手机后用 ...
- mongoDB 删除集合后,空间不释放的解决方法
mongoDB 删除集合后,空间不释放,添加新集合,没有重新利用之前删除集合所空出来的空间,也就是数据库大小只增不减. 方法有: 1.导出导入 dump & restore 2.修复数据库 r ...