1 什么是dubbo
Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和Spring框架无缝集成。
从上述描述中我们可以看到对dubbo的一个简单的介绍,阐述出来两个问题
1.1 什么是rpc
名称为Remote Procedure Call Protocol (远程调用协议)的首字母缩写,远程调用协议,通过网络从远程服务器上请求服务。在java中简单的理解即远程服务接口本地化,让开发人员使用接口的方式于本地使用没有太大的区别。
一个java实现的简单的Rpc示例
简单定义 host 10.10.1.1 port 1234
client
refer:T.class <--- new socket ---> export:return obj
proxy:10.10.1.1 service:10.10.1.1
refer的伪代码
client端页面 T表示接口名
refer(<T>interfaceClass,host,port)
proxy.newProxyInstance(<T>.classloader,interfaceClass,invocationHandler(){
public object invoke(proxy,method,arguments){
socket =new socket(host,port);
objectOutputStream = new ObjectOutputStream(socket.getOutPutStream);
objectOutputStream.write(method.getName);
objectOutputStream.writeObject(method.getParameterTypes);
objectOutputStream.writeObject(arguments);
objectInputStream = new ObjectInputStream(socket.getInputStream);
result = input.readObject;
input output close;
socket close}});
在客户端用到了 socket ,java的反射和序列化
export的伪代码
export(inerfaceImplObj,port){
serverSocket = new ServerSocket(port);
while(true){
socket = serverSocket.accpet();
new Thread(new Runnable(){
void run(){
objectInputStream = new ObjectInputStream(socket.getInputStream);
objectOutputStream = new ObjectOutputStream(socket.getOutputStream);
methodName = objectInputStream.read;
parameterTypes,arguments = objectInputStream.readObject();
method = inerfaceImplObj.getCalss.getMethod(methodName,parametertTypes);
result = method.invoke(inerfaceImplObj,method);
objectOutputStream.write();
}
});
}
}
这个分别是客户端和服务端的两端伪代码,完成一次远程调用。rpc的基础性的功能就这些
以上有这几个功能点:动态代理、java序列化、网络io
1.2 dubbo的rpc方案
我们来看下dubbo的体系图
根据上图我们看到了体系中多了3个模块registry、container、monitor
具体还有更多的技术方案我们在下面去解决。
1.3 为什么能和spring无缝集成
首先我们可以看到dubbo的缺省依赖包含:spring-context.jar
[INFO] +- com.alibaba:dubbo:jar:2.5.9-SNAPSHOT:compile
[INFO] | +- org.springframework:spring-context:jar:4.3.10.RELEASE:compile
[INFO] | +- org.javassist:javassist:jar:3.21.0-GA:compile
[INFO] | \- org.jboss.netty:netty:jar:3.2.5.Final:compile
由此我们推论dubbo采用的spring的容器。既然采用了spring容器于其的兼容肯定会很easy,spring-context的采用主要解决了对dubbo的bean管理。
我们采用的xml配置信息就是用的spring的配置,这点可以根据配置信息
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd" default-autowire="byName">
--spring对bean的管理方式我们先不深究。?
2 为什么用dubbo
2.1 dubbo的背景于需求
网络大时代的到来: 海量用户和高复杂业务导致服务越来越多不便于管理和扩展。更甚特殊业务比如跟金融或者银行业务服务的稳定性和严谨性的要求,需要一款框架来解决这些问题。
2.2 dubbo的特性
根据它的体系图来注册中心模块,容器模块,监控模块(比较隐性)成就了dubbo优势。
2.2.1扩展性
这里说的是dubbo的开发扩展性+容器模块的概念,这个性能可称之为dubbo的核心性能。dubbo本身包含第三方的插件不足以满足业务需求时,可以随时根据业务的瓶颈替换三方插件去解决问题(dubbo默认本身的策略都挺优的)。
2.2.2 伸缩性
因为注册中心模块的引入,dubbo集群新增或者减少服务的发现性相当的灵活,几乎不需要再让开发去做什么事情。也介绍了运维很大一部分的工作量。
2.2.3 健壮性
这里的健壮性只得就是各种机器或者服务因为不同原因宕机(非业务问题,一旦业务代码或者关键性代码写的有问题多少台机器都会挂掉)将不会影响提供者和消费者两大模块的使用。
3 dubbo有哪些技术依赖
dubbo的依赖可以看看它从哪方面去考虑的,我们回头来看看java的简单rpc示例的问题:
3.1 java序列化问题
java本身序列化消耗cpu性能问题一直被人诟病,现在有很多jar都单独对这块做了优化,看看dubbo的依赖jar hessian/fastjson/kryo...
3.2 bio问题
rpc示例就是一个简单的通信,尤其是在如今现在的互联网产业中瓶颈之大惨不忍睹。nio无疑可以解决这个,所以dubbo就采用nio框架netty和mina还有grizzly等等
3.3 其他的问题的依赖
dubbo的几大特性的满足需要注册中心就包含了zookeeper/jedis等,还有关于一些日志jar或者其他的jar都是为了完善整体项目。
从以上几点可以看出dubbo的包主要是从解决技术或业务壁垒、调优参数的获取已经一些比较常见的功能jar
4 dubbo在项目中是如何使用的,可以解决哪些场景问题和调优问题
目前使用dubbo自己完成了一套基于spring的配置模式,上手更简单,维护也更清晰:接下来我们说的就是以这中模板为基础。
4.1 根据dubbo的体系图角度我们可以来看看如何使用的。
4.1.1 consumer 模块的配置
xml配置如下
<dubbo:application name="dubbo-consumer"/>
<dubbo:consumer retries="${consumer.retries}" check="${consumer.check}" timeout="${consumer.timeout}"/>
<dubbo:annotation package="${consumer.package}"/>
<!--这段xml信息是对consumer模块比较简单的配置,相对来说大大的减少了维护性,为什么说大大减少了维护呢,再看xml配置-->
<dubbo:application name="dubbo-consumer"/>
<dubbo:consumer id="${service.name1}" interface="${service.interface1}" check="${consumer.check}" retries="${consumer.retries}" timeout="${consumer.timeout}"/>
<dubbo:consumer id="${service.name2}" interface="${service.interface2}" check="${consumer.check}" retries="${consumer.retries}" timeout="${consumer.timeout}"/>
...
下面的dubbo配置相对来说力度就有所不同,每个consumer都可以很好的控制,这里的dubbo:consumer也可以替换成dubbo:reference,现在来看看dubbo:ref是如何应用
dubbo:reference 这块属性与consumer兼容
服务消费者引用服务配置。 包含的属性在应用场景中可以提供比较好的解决。对应的配置类: com.alibaba.dubbo.config.ReferenceConfig几大属性作用
必填属性 id、interface 这个是基本规则不多说
服务发现 version、group这个在项目中用到的比例应该是比较高的,它很好的解决了服务器多版本维护的问题,同时也给服务灰度提供了一个良好的解决方案。
性能方案
- timeout比较常见没什么可说的。
- retries这个一定要注意幂等的方式配置才不为0.如果说非幂等或者有业务增量一旦服务异常或者超时等则会引起严重的bug。
- connections 表示的服务连接性,这个一般配置在provider,可能看到的人比较少,但是在大型数据或者高密集访问的时候这个对服务稳定性有很大的帮助。这个阈值可以跟测试一起协商设置。
- loadbalance 负载均衡策略,可选值:random,roundrobin,leastactive。字面理解即可。
- 其他的相关的属性可以参照下dubbo的用户使用文档
4.1.3 provider 模块的配置
关于生产者模块的配置于消费模块一样也可以配置的很简单
<dubbo:application name="bbtree-provider" />
<dubbo:provider timeout="${provider.timeout}" retries="${provider.retries}" threads="${provider.threads}" accepts="${provider.accepts}"/>
<dubbo:annotation package="${provider.package}" />
<!-- 与comuser的简单配置一样低维护的方式 -->
<dubbo:application name="bbtree-provider" />
<dubbo:provider interface="${service.interface1}" ref="${serviceName1}" timeout="${provider.timeout}" registry="register"/>
provider和service配置同consumer和ref一样可以可以从属性特性来说有一些名称是公共的就不再强调了。
必填属性 interface接口名称 ref引用名称,这个命名消费者使用不能乱起哦。
服务发现 消费者根据需求配置。服务端同一个service命名和版本。新老版本升级的过度有较为友好的方式。
性能方案 模块特有 connections 也是根据项目的瓶颈去设定阈值。
其他部分属性或于consumer一致,或用于特殊场景,就不一一列举了
这里可以小结一下:对于dubbo基础模块的属性,是服务的根本。有的同学就说了这个服务端与客户端好多共有属性,这个不会有歧义么。dubbo出了一台解决方案,从优原则的优先方案。
如果在同一个服务链中相同属性,的从优原则都是以上游为准。
4.1.4 registry 模块的配置
注册模块的配置针对于生产或者消费模块整体容器的一个统一标准的地方。
<dubbo:registry protocol="${registry.protocol}" address="${registry.address}"/>
address属性是必填项 注册机的配置地址,比如zk或者redis地址,可以写成多重模式表达。这一点完全没有必要。dubbo在各个方面都体现了这一点,太多模式导致本身的代码成本和开发理解成本都很高..其实有个标准性质的方式会更容易读懂和接受。
其他属性类似于对容器整体的一个配置
http://dubbo.apache.org/books...
4.2 dubbo的解决方案中如何理解开发中的难点和思路
容错处理: 在调试和生产环境当中竟让会遇到关于invoke问题
com.alibaba.dubbo.rpc.RpcException: Rpc cluster invoker for...
com.alibaba.dubbo.rpc.RpcException: Failed to invoke the method...
等异常。
dubbo的invoke的机制都是可以配置的,我们来看看示意图
集群模式通过invoker通过list列表、路由规则或者负载模式最终定位。可以说保证集群处理中应对各种各样的业务场景问题
failover是默认的模式,出现失败了会抛出异常,通过重试参数retries可以重新调用。这种切记不能对写操作的业务设置重试。
failfast更常见于我们的开发场景,目前由于互联网业务的复杂往往一个service中都是非幂等或者单纯的已读
failsafe用的比较少见,忽略异常的场景,官方说明常用于审计。failback失败自动恢复,后台记录失败请求,定时重发。以上两种模式本人不太理解业务请求,请原谅我的无知。
forking和broadcast用户两种对立的场景,都是多次调用服务。前者可控个数并且并行访问,任意一个成功即返回,后者则是所有的provider都运行一次,任意一台报错则报错。场景的话forking应用于对业务高需求并是读操作的方式,很吃性能,如果跨机房的服务可采用这种--前提条件比较多。后者做服务安全性的操作会比较多,尤其是有的业务按照服务来隔离数据的情况。
大概的cluster机制,如何去选择provider我们都清楚了,再看看图片的右侧是服务端提供的List的方式。比如已注册的、黑白名单、负载算法退出的生产者。
我们通过这种机制可以如何看待
dubbo通过调用者和提供者都给出一套策略,已确保服务可实施性,也能确保互联网中各种各样的业务场景。解决业务场景是一切架构的基本构造,如果架构解决一些空想型的业务场景是完全没有必要的。
5 dubbo的重新维护
dubbo于2017年9月开始更新,首先支持到了jdk1.8。
解决各种各样的bug
比如关闭服务的优雅、对注解形式各种不支持(@Service Bean 不支持 Spring AOP等等)...
互联网时代来说,对于一些公司是美好的辅音,同时也希望dubbo越来越简约和易用。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。