Java 底层架构之RPC 框架Dubbo 核⼼原理之源码分析Dubbo是Alibaba开源的分布式服务框架,它最⼤的特点是按照分层的⽅式来架构,使⽤这种⽅式可以使各个层之间解耦合(或者最⼤限度地松耦合)。从服务模型的⾓度来看,Dubbo采⽤的是⼀种⾮常简单的模型,要么是提供⽅提供服务,要么是消费⽅消费服务,所以基于这⼀点可以抽象出服务提供⽅(Provider)和服务消费⽅(Consumer)两个⾓⾊。 Dubbo是什
简单说呢,Dubbo⽤起来就和EJB、WebService差不多,调⽤⼀个远程的服务(或者JavaBean)的时候在本地有⼀个接⼝,就像调⽤本地的⽅法⼀样去调⽤,它底层帮你实现好你的⽅法参数传输和远程服务运⾏结果传回之后的返回,就是RPC的⼀种封装啦~ 当然,这个只是Dubbo的最基本的功能,它的特点是: 1.它主要是使⽤⾼效的⽹络框架和序列化框架,让分布式服务之间调⽤效率更⾼。
2.采
注册中⼼
管理众多的服务接⼝地址,当你想调⽤服务的时候只需要跟注册中⼼询问即可,不⽤像使⽤WebService
⼀样每个服务都得记录好接⼝调⽤⽅式。
3
.
监控中⼼
:实现对服务⽅和调⽤⽅之间运⾏状态的监控,还能控制服务的优先级、权限、权重、上下线等,让整个庞⼤的分布式服务系统的维护和治理⽐较⽅便。
4.⾼可⽤:有个服务宕机了?注册中⼼就会从服务列表去掉该节点。还是调⽤到了?客户端会向注册中⼼请求另⼀台可⽤的服务节点重新调⽤。注册中⼼宕机?注册中⼼也能实现⾼可⽤(ZooKeeper)。
5.负载均衡:采⽤软负载均衡算法实现对多个相同服务的节点的请求负载均衡。
Dubbo注册中
上⾯已经安装完成了zookeeper的注册中⼼了,这个注册中⼼主要就是负责dubbo的所有服务地址列表
维护,并且可以通过在ZooKeeper 节点中设置相应的值来实现对这个服务的权重、优先级、是否可⽤、路由、权限等的控制。
你可以先记住,之后在Dubbo的管理控制台对服务的⼀堆治理策略设置和调整,实际上就是修改了注册中⼼中的服务对应的配置数据(即修改了zookeeper中服务对应的节点的配置数据)。
之后
Consumer  从注册中⼼请求到服务的数据时就能根据这些配置数据进⾏相应的治理配置参数的代码执⾏⽣效。
Dubbo样例服务开
发 这⾥我⽤maven构建项⽬,在Spring环境中配置Provider和Consumer。
先说明使⽤的依赖:
org.springframework
spring-core
4.2.3.RELEASE
org.springframework  spring-beans
4.2.3.RELEASE
org.springframework  spring-context
4.2.3.RELEASE
org.springframework  spring-test
4.2.3.RELEASE
org.springframework  spring-tx
4.2.3.RELEASE
org.springframework  spring-web
4.2.3.RELEASE
org.springframework  spring-webmvc
4.2.3.RELEASE
com.alibaba
dubbo
2.8.4
javassist
javassist
3.12.0.GA
org.jbossty
netty
LATEST
com.101tec
zkclient
0.10
org.slf4j
slf4j-log4j12
1.7.12
Provider
声明服务的接⼝:
public interface IMyDemo { String sayHello(String name);
}
对接⼝进⾏实现(这⾥是Provider,需要真的实现,之后在Consumer端调⽤接⼝之后实际就是在这⾥的实现代码执⾏所需逻辑的):
public class MyDemo implements IMyDemo { @Override
public String sayHello(String name) {
String hello = "hello " + name;
System.out.println(hello); return hello;
}
}
本地测试⼀下这个服务是否可⽤,这⾥还没⽤到Dubbo,只是先测试⼀下Spring容器是否有问题:
@org.junit.Testpublic void testDubbo() throws InterruptedException {
ApplicationContext providerContext = new ClassPathXmlApplicationContext("l");
IMyDemo demo = Bean(IMyDemo.class);
System.out.println(demo.sayHello("world"));
Thread.sleep(6000
0);
}
RPC之 Dubbo 实现
主要为三点,动态代理、反射、socket⽹络编程
看过很多讲dubbo原理的⽂章,总感觉太抽象,偶然间看到⼀个直播课堂讲dubbo原理。结合了⼀个订单的例⼦现场画笔⼯具画图,直观很多。截屏记录下来。(提供技术直播的为⽼马的北京尚学堂,感谢)
客户端使⽤动态代理的⽅式,“假装”实现了createOrder⽅法。
⽅法相关的数据通过序列化,进⼊到socket服务器。dubbo的socket实现为Netty。
服务端从socket服务器取出数据,通过反射的⽅式到“真实”的服务实现。
服务端的⽅法在服务启动时已注⼊。
IMG_4519.PNG
服务发现层,可⽤zookeeper。zookeeper保证了CP(⼀致性,分区容错性)。缺点:master节点挂掉时,需要时间重新选择master,这段时间内注册中⼼将不可⽤。
注意:服务端可消费端注册成功后,通讯只⾛socket服务器,不会经过注册中⼼。
Dubb
o
⼀、dubbo核⼼技术简介
远程服务的调⽤流程,dubbo本质上就是解决了此问题。validation框架
远程服务器调⽤流程
1.客户端发起接⼝调⽤
2.服务中间件进⾏路由选址:到具体接⼝实现的服务地址
3.客户端将请求信息进⾏编码(序列化: ⽅法名,接⼝名,参数,版本号等)
4.建⽴与服务端的通讯(不是调度中⼼,⽽是客户端与服务端直连)
5.服务端将接收到的信息进⾏反编码(反序列化)
6.根据信息到服务端的接⼝实现
7.将执⾏结果反馈给客户端
针对上⾯的调⽤流程,结合dubbo的服务架构,是不是对dubbo的了解⼜深⼊了⼀些?同学们有空也可以根据上述的流程⾃⼰实现⼀遍简单的远程调⽤,下⾯为dubbo核⼼模块⽤到的⼀些技术,可以提前做⼀些知识储备。
核⼼技术
1.java多线程
2.JVM
3.⽹络通讯(NIO)
4.动态代理
5.反射
6.序列化
7.路由节点管理(zookeeper)
⼆、dubbo实际中常⽤配置
常见的⼀些业务场景和dubbo配置。
分包
建议将服务接⼝,服务模型,服务异常等均放在API包中,因为服务模型及异常也是API的⼀部分,同时,这样做也符合分包原则:重⽤发布等价原则(REP),共同重⽤原则(CRP)
如果需要,也可以考虑在API包中放置⼀份spring的引⽤配置,这样使⽤⽅,只需在Spring加载过程中引⽤此配置即可,配置建议放在模块的包⽬录下,以免冲突,如:com/alibaba/china/l
粒度
服务接⼝尽可能⼤粒度,每个服务⽅法应代表⼀个功能,⽽不是某功能的⼀个步骤,否则将⾯临分布式事务问题,Dubbo暂未提供分布式事务⽀持。
服务接⼝建议以业务场景为单位划分,并对相近业务做抽象,防⽌接⼝数量爆炸
不建议使⽤过于抽象的通⽤接⼝,如:Map query(Map),这样的接⼝没有明确语义,会给后期维护带来不便。
版本
每个接⼝都应定义版本号,为后续不兼容升级提供可能,如:
建议使⽤两位版本号,因为第三位版本号通常表⽰兼容升级,只有不兼容时才需要变更服务版本。
当不兼容时,先升级⼀半提供者为新版本,再将消费者全部升为新版本,然后将剩下的⼀半提供者升为新版本。
兼容性
服务接⼝增加⽅法,或服务模型增加字段,可向后兼容,删除⽅法或删除字段,将不兼容,枚举类型新增字段也不兼容,需通过变更版本号升级。
各协议的兼容性不同,参见: 服务协
枚举值
如果是完备集,可以⽤Enum,⽐如:ENABLE, DISABLE。
如果是业务种类,以后明显会有类型增加,不建议⽤Enum,可以⽤String代替。
如果是在返回值中⽤了Enum,并新增了Enum值,建议先升级服务消费⽅,这样服务提供⽅不会返回新值。
如果是在传⼊参数中⽤了Enum,并新增了Enum值,建议先升级服务提供⽅,这样服务消费⽅不会传⼊新值。
序列化
服务参数及返回值建议使⽤POJO对象,即通过set,get⽅法表⽰属性的对象。
服务参数及返回值不建议使⽤接⼝,因为数据模型抽象的意义不⼤,并且序列化需要接⼝实现类的元信息,并不能起到隐藏实现的意图。
服务参数及返回值都必需是byValue的,⽽不能是byRef的,消费⽅和提供⽅的参数或返回值引⽤并不是同⼀个,只是值相同,Dubbo不⽀持引⽤远程对象。
异常
建议使⽤异常汇报错误,⽽不是返回错误码,异常信息能携带更多信息,以及语义更友好,
如果担⼼性能问题,在必要时,可以通过override掉异常类的fillInStackTrace()⽅法为空⽅法,使其不拷贝栈信息,
查询⽅法不建议抛出checked异常,否则调⽤⽅在查询时将过多的atch,并且不能进⾏有效处理,
服务提供⽅不应将DAO或SQL等异常抛给消费⽅,应在服务实现中对消费⽅不关⼼的异常进⾏包装,否则可能出现消费⽅⽆法反序列化相应异常。
调⽤
不要只是因为是Dubbo调⽤,⽽把调⽤Try-Catch起来。Try-Catch应该加上合适的回滚边界上。
对于输⼊参数的校验逻辑在Provider端要有。如有性能上的考虑,服务实现者可以考虑在API包上加上服务Stub类来完成检验。
版本控制
在dubbo最佳实践中有提到,所有接⼝都应定义版本,在这⾥有⼏点需要注意下,接⼝服务如果更新频繁,并且兼容⽼版本的,不建议更改版本号,因为dubbo这边对除 * 以外的版本号,都是采⽤完全匹配的⽅式进⾏匹配。即服务端的版本号如果从1.0升级为1.1,并且未保留原有的1.0的服务,那么客户端必须同时也将服务版本号升级为1.1,否则将⽆法匹配到远处服务。
博主在⾃⼰项⽬中的版本使⽤规则如下,仅供参考:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。