一、Dubbo 创造者对于Dubbo的价值与意义作出过精辟的见解
1、单一应用架构
网站流量很小,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本此时,用于简化增删改查工作量的 数据访问框架(ORM) 是关键。
2、垂直应用架构 访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆成互不相干的几个应用,以提升效率,此时,用于加速前端页面开发的 Web框架(MVC) 是关键。
3、分布式服务架构 垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求,此时,用于提高业务复用及整合的 分布式服务框架(RPC) 是关键。
4、流动计算架构 服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率,此时,用于提高机器利用率的 资源调度和治理中心(SOA) 是关键。
关键在于第3向第4的转变,原因在大规模服务化之前,应用可能只是通过RMI或Hessian等工具,简单的暴露和引用远程服务,通过配置服务的URL地址进行调用,通过F5等硬件进行负载均衡。
(1) 当服务越来越多时,服务URL配置管理变得非常困难,F5硬件负载均衡器的单点压力也越来越大。
此时需要一个服务注册中心,动态的注册和发现服务,使服务的位置透明。
并通过在消费方获取服务提供方地址列表,实现软负载均衡和Failover,降低对F5硬件负载均衡器的依赖,也能减少部分成本。
(2) 当进一步发展,服务间依赖关系变得错踪复杂,甚至分不清哪个应用要在哪个应用之前启动,架构师都不能完整的描述应用的架构关系。
这时,需要自动画出应用间的依赖关系图,以帮助架构师理清理关系。
(3) 接着,服务的调用量越来越大,服务的容量问题就暴露出来,这个服务需要多少机器支撑?什么时候该加机器?
为了解决这些问题,第一步,要将服务现在每天的调用量,响应时间,都统计出来,作为容量规划的参考指标。
其次,要可以动态调整权重,在线上,将某台机器的权重一直加大,并在加大的过程中记录响应时间的变化,直到响应时间到达阀值,记录此时的访问量,再以此访问量乘以机器数反推总容量。
二、低侵入式集成
1、独立服务接口层
单独打包,服务提供方和消费方都需依赖此包
如:com.alibaba.dubbo.demo.DemoService
2、服务提供方
<!-- 声明需要暴露的服务接口 -->
<
dubbo:service
interface
=
"com.alibaba.dubbo.demo.DemoService"
ref
=
"demoService"
/>
<!-- 和本地bean一样实现服务 -->
<
bean
id
=
"demoService"
class
=
"com.alibaba.dubbo.demo.provider.DemoServiceImpl"
/>
3、服务消费方
<!-- 生成远程服务代理-->
<
dubbo:reference
id
=
"demoService"
interface
=
"com.alibaba.dubbo.demo.DemoService"
/>
<!-- 和本地服务一样使用远程服务 -->
<
bean
id=“xxxAction” class=“com.xxx.XxxAction”>
<
property
name=“demoService” ref=“demoService” />
</
bean
>
三、服务信息注册
1、配置中心ConfigServer
每个Server/Client之间会作一个实时的心跳检测(因为它们都是建立的Socket长连接),比如几秒钟检测一次。收集每个Server提供的服务的信息,每个Client的信息,整理出一个服务列表,如:
serviceName | serverAddressList | clientAddressList |
UserService | 192.168.0.1,192.168.0.2,192.168.0.3,192.168.0.4 | 172.16.0.1,172.16.0.2 |
ProductService | 192.168.0.3,192.168.0.4,192.168.0.5,192.168.0.6 | 172.16.0.2,172.16.0.3 |
OrderService | 192.168.0.10,192.168.0.12,192.168.0.5,192.168.0.6 | 172.16.0.3,172.16.0.4 |
2、提供方与消费方都需要的
<dubbo:application name="hello-world-app-xxx" /> //提供方与消费方不要重名就可以了,没有格式要求,只用于计算依赖关系
<dubbo:registry address="multicast://224.5.6.7:1234" />//使用广播的方式暴露(提供方)和通知发现(消费方)服务地址
3、提供方专有
<dubbo:protocol name="dubbo" port="20880" />//标明使用哪种协议和端口提供服务
四、多样化支持
1、多个注册中心
支持同时有多个服务注册中心,一个服务也可以注册到多个注册中心。
<!-- 多注册中心配置 -->
<dubbo:registry id="chinaRegistry" address="10.20.141.150:9090" /><dubbo:registry id="intlRegistry" address="10.20.141.151:9010" default="false" /><!-- 向多个注册中心注册 --><dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" registry="chinaRegistry,intlRegistry" /><!-- 向中文站注册中心注册 -->
<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" registry="chinaRegistry" /><!-- 向国际站注册中心注册 --><dubbo:service interface="com.alibaba.hello.api.DemoService" version="1.0.0" ref="demoService" registry="intlRegistry" />2、多种服务协议
支持同时使用多个服务协议,一个服务可以用多个协议暴露
如:
<!-- 多协议配置 -->
<dubbo:protocol name="dubbo" port="20880" /> <dubbo:protocol name="rmi" port="1099" /> <!-- 使用dubbo协议暴露服务 --> <dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" protocol="dubbo" /> <!-- 使用rmi协议暴露服务 --> <dubbo:service interface="com.alibaba.hello.api.DemoService" version="1.0.0" ref="demoService" protocol="rmi" /><!-- 使用多个协议暴露服务 -->
<dubbo:service id="helloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" protocol="dubbo,hessian" />五、多版本
当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。
1、提供方提供多个版本
<dubbo:service interface="com.foo.BarService" version="1.0.0" />
<dubbo:service interface="com.foo.BarService" version="2.0.0" />2、消费方可以忽略版本
<dubbo:reference id="barService" interface="com.foo.BarService" version="*" />六、结果缓存
结果缓存,用于加速热门数据的访问速度,Dubbo提供声明式缓存,以减少用户加缓存的工作量。
1、lru 基于最近最少使用原则删除多余缓存,保持最热的数据被缓存。
2、threadlocal 当前线程缓存,比如一个页面渲染,用到很多portal,每个portal都要去查用户信息,通过线程缓存,可以减少这种多余访问。
3、jcache 与集成,可以桥接各种缓存实现。
如:
<
dubbo:reference
interface
=
"com.foo.BarService"
cache
=
"lru"
/>
<
dubbo:reference
interface
=
"com.foo.BarService"
>
<
dubbo:method
name
=
"findBar"
cache
=
"lru"
/>
</
dubbo:reference
>
七、上下文信息
上下文RpcContext中存放的是当前调用过程中所需的环境信息,RpcContext是一个ThreadLocal的临时状态记录器,当接收到RPC请求,或发起RPC请求时,RpcContext的状态都会变化。
比如:A调B,B再调C,则B机器上,在B调C之前,RpcContext记录的是A调B的信息,在B调C之后,RpcContext记录的是B调C的信息。八、参数回调
参数回调方式与调用本地callback或listener相同,只需要在Spring的配置文件中声明哪个参数是callback类型即可,Dubbo将基于长连接生成反向代理,这样就可以从服务器端调用客户端逻辑。
九、事件通知
在调用之前,调用之后,出现异常时,会触发oninvoke, onreturn, onthrow三个事件,可以配置当事件发生时,通知哪个类的哪个方法。
十、连接控制
1、限制服务器端接受的连接不能超过10个:(以连接在Server上,所以配置在Provider上)
<
dubbo:provider
protocol
=
"dubbo"
accepts
=
"10"
/>
<
dubbo:protocol
name
=
"dubbo"
accepts
=
"10"
/>
2、限制客户端服务使用连接连接数:(如果是长连接,比如Dubbo协议,connections表示该服务对每个提供者建立的长连接数)
<
dubbo:reference
interface
=
"com.foo.BarService"
connections
=
"10"
/>
十一、令牌验证
防止消费者绕过注册中心访问提供者,在注册中心控制权限,以决定要不要下发令牌给消费者,注册中心可灵活改变授权方式,而不需修改或升级提供者
<!--随机token令牌,使用UUID生成-->
<
dubbo:provider
interface
=
"com.foo.BarService"
token
=
"true"
/>
<!--固定token令牌,相当于密码-->
<
dubbo:provider
interface
=
"com.foo.BarService"
token
=
"123456"
/>
也可在服务和协议级别上设置