目录
高性能RPC通信框架
1.为了解决单机应用的问题以及性能,并发等问题,面向服务架构SOA出现了.SOA单一进程的应用做了拆分,形成对外提供服务的组件,每个组件通过网络协议对外提供服务.协议可以是TCP也可以是HTTP.SOA具有以下特点:
①明确的协议:通过协议通信
②明确的接口:对外提供接口,服务复用
③合作方式的改变:可以更细化的分工与合作
④通信方式:JSON通信
2.早期的SOA
常见的SOA实现方式有两种:WebService和ESB,WebService使用Http或https
EJB适合老企业的内部不同语言,没有统一交换协议,通过总线负责服务之间的消息解析转换路由等
3.dubbo的架构
服务提供者向注册中心注册,消费者订阅服务,当注册中心发生数据变更会推送给订阅者,消费者通过RPC调用服务提供者,在RPC调用前后消费者会向监控中心上报统计信息(如并发数,调用的接口)
4.dubbo 解决如下问题
①高性能,透明RPC调用,
②服务注册与发现,自动负载与容错.动态容量调度权重,路由规则.依赖分析与调用分析
5.dubbo总体分层:
dubbo总体分为BIz业务层,RPC层,Remote层
细分可以分为10层.除了最上面的两层,service,和config可以认为是API层,给 使用者调用,其余层都称为SPI层,主要是给扩展者使用,做二次开发
5.dubbo服务总体调用过程
服务器端(服务提供者端)在框架启动时,会初始化服务实例,通过proxy组件调用具体协议,把服务端要暴露的接口封装成invoke,然后转换成成exporter,这个时候框架会打开服务端接口等并记录服务实例到内存中,最后通过register把服务注册到注册中心.
开发第一款dubbo应用程序
1.dubbo的实现可以通过xml 配置,注解方式,和API的形式实现
基于API的应用场景:比如网关类的应用,需要动态消费不同版本的服务,通过APi方式,可以根据前端请求参数动态构造不同版本的服务实例等
2.注意:当服务提供者退出并正常停机(排除强制杀掉进程),dubbo框架会进行优雅停机处理,在规定超时时间内,服务端会等待线程池队列执行完成并断开远程客户端连接
ServerConfig server = new ServerConfig()
server.setInterfacexxx.class) 指定服务暴露的接口
server.setRef(xxxImpl.class) 指定真实服务对象
3.采用java APi方式是最灵活的方式,可以第三方框架集成,特备适合于动态消费的场景
最典型的场景是泛化调用,可以指定一个本地不存在的接口发起RPC调用
dubbo注册中心
1.dubbo注册中心是其核心组件之一,dubbo通过注册中心实现了分布式环境中各服务之间的注册与发现,其主要作用如下:
①动态加入:服务提供者通过注册中心可以动态的暴露自己,无须消费者逐个去更新配置文件
②动态发现:消费者可以动态敢追新的配置路由规则,无须重启
③动态调整:
④统一配置
2.dubbo-register模块中主要包含四种注册中心的实现,分别是zookeeper,redis,simple(基于内存的默认实现,不支持集群,可能出现单点故障),multicast(multicast模式,广播,订阅的方式,不建议生产使用,无需注册中心),其中zookeeper是官方推荐的注册中心
3.dubbo 注册中心工作流程
①服务提供者启动,注册,并写入自己的元数据,并定于配置元数据
②消费者启动,订阅,并写入自己的元数据
③服务治理中心,dubbo-admin启动,同时订阅服务提供者和消费者,及路由信息
④当有提供者离开或加入,注册中心提供者陌路会发生变化,变化信息会通知消费者,和服务治理中心
⑤当服务消费方发起服务调用,会异步将调用统计信息等上报给监控中心,monitor
4.zookeeper原理概述
zookeeper是树形结构的注册中心,每个节点类型分为持久,持久顺序,临时,临时顺序
dubbo使用zookeeper作为注册中心,只会使用持久节点会临时节点两种,对创建顺序没有要求
dubbo注册的树形结构:
结构关系如下:
根节点:/dubbo
服务接口--server
四种服务目录①provider
具体URL
②consumer
具体URL
③routers
具体URL
④configurators
具体URL
5.redis原理概述
redis也是如上的一个四层结构,只不过是使用了key/map结构实现了这个需求
root.,server,type组成了redis的key,value是一个Map结构,URL作为Map的key,超时时间作为Map的value
在数据结构在组装逻辑在org.apache.dubbo.registry.redis.RediRegistry#doRegister()方法中
6.订阅与发布(注册中心自动的完成配置的更新,通知)
1.zookeeper的实现
①发布的实现:服务提供者和消费者都要注册自己到注册中心,,zookeeper发布代码非常简单,只是调用了zookeeper1的客户端库在注册中心上创建一个目录.
取消发布,只是把zook对应的路径删除
②订阅的实现
订阅有两种:一种是客户端主动拉取,另外一种是注册中心推送给客户端.dubbo采用的是第一次拉取,后续接受到事件重新拉取
7.dubbo中zookeeper的客户端实现有两种:Curator,zkCLient,默认第一种
zookeeper采用的是事件通知+客户端拉取
第一次连接全量拉取,并在订阅节点上注册一个watcher,客户端与注册中心保持长连接,,后续每个节点有任何数据变化时,注册中心根据watch的回调主动通知客户端,客户端接到通知再全量拉取
,局限是当节点比较多事拉取会对网络造成压力
zookeeper的每个节点都有一个版本号,当某一个接地那发生变化,该版本号就会发生变化,触发watcher事件,推送数据给订阅放
什么操作是被认为事务操作?
客户端任何的新增删除修改会话创建,失效操作都是事务操作,由zookeeper的leader执行,即使在非leader节点,请求也会转与leader操作
8.redis的实现
redis订阅发布使用的是过期机制publish/subscribe,提供者发布服务,首先在redis中创建key,然后发布register事件消息,发布者启用一个线程周期性的刷新key过期时间,如果宕机,key因过期失效而被删除,认为是下线
订阅方首次连接获取全量数据,后续通过该广播接收事件消息,如果redis的key因为宕机下线是不会有消息的,不可靠的,需要依赖服务治理中心,由治理中心定时调度遍历,对超时的key发起事件通知来保持数据最终一致
9.缓存机制
缓存的存在就是用空间换取时间.这样可以减少流量压力,提高性能
消费者和治理中心获取注册信息后会做本地缓存,内存中一份,磁盘中也会持久化一份
如果应用在启动过程中注册中心无法连接或宕机,则dubbo框架会自动通过本地缓存加载
10.设计模式
①模板模式:整个注册中心的逻辑部分使用了模板模式
②工厂模式:所有的注册中心实现,都是通过对应的工厂创建的,
dubbo扩展点加载机制
1.dubbo良好的扩展性因为2个方面:针对不同场景使用了各种设计模式;加载机制
2.java SPI
SPI全称service provider Interface
java SPI使用了策略模式,一种接口多种实现,我们只声明接口,具体的实现在配置掌握,来装配
3.扩展点加载机制的改进,
dubbo SPI自己实现了IOC和AOP机制
JDK SPI会一次性加载所有扩展点实现,浪费时间,浪费资源
xxxx = com.xxx.xxximpl 配置文件
@SPI("xxxx")
public interface service{
void print();
}
4.扩展地配置规范
dubbo启动时会默认扫描 META-INF/service,META-INF/dubbo/,META-INF/dubbo/internal
内容key =value.,多个用换行分隔符
配置文件名称:全路径名
5.扩展类的特性:
自动包装:如果发现这个扩展类包含其他扩展点作为构造函数的参数,则这个扩展类就会被认为是Wrapper类,这是一种装饰器模式,把通用的抽象逻辑进行封装或对子类进行增强,让子类更加专注具体发的实现
自动加载:如果某个扩展类是另外一个扩展点类的成员属性,并且拥有setter方法,那么框架也会自动注入对应的扩展点实例。但是如果扩展类的属性是一个接口,那么他有多个实现,应该注入那个实现呢?这就需要自适应
自适应:
自动激活
自适应:使用@Adaptive注解,动态的将url的参数来确定要是要哪个具体实现类
自动激活,使用@Activate
6.扩展点注解
@SPI,可以用在类,接口,枚举上,用于标记这个接口是一个SPI,即一个扩展点,可以由多个不同的实现,运行时需要通过配置找到具体的实现类
@Adaptive自适应注解,可以标记在类,接口,方法,枚举上,
@activate自动激活注解,可以标记在类,接口,枚举,方法上,主要用在有多个扩展点实现没需要根据不同条件被激活的场景,
7.extensionLoader的工作原理
extensionLoader是整个扩展机制的主要逻辑类,在这个类里面实现了配置的加载,扩展类的缓存,自适应对象生成等所有工作,
工作流程:
extensionLoader的逻辑入口可以分为:getExtension,getAdaptiveExtension,getActivateExtension三个,分别是获取普通扩展类,获取自适应,获取自激活扩展类
此章节介绍了getExtension,getAdaptiveExtension,getActivateExtension,ExtensionFactory的实现原理及部分代码,内容较多,比较抽象。
扩展点动态编译器的实现:
总体上游三种代码编译器:JDK,JAVASsist,AdaptiveCompiler
dubbo启停原理解析
配置解析
目前dubbo提供了三种配置方式:xml.注解,属性文件ymal,常用的是xml和注解的方式
基于schema设计解析
dubbo配置文件在dubbo-config/.../.../dubbo.xsd中
dubbo.xsd文件中比如有xml配置时的标签和属性,<dubbo:service><dubbo:referencr>等。spring在解析到自定义的namespace标签时会查找对应的springschema,springhandler来处理
基于xml配置原理解析
主要的解析逻辑入口是在dubbonamespaceHandler,此类继承了namespaceHandlerSupport类,主要把不同标签关联到解析器实现类上
基于注解配置原理解析
核心主键是@EnableDubbo
注解解析逻辑主要包含3部分:①如果是用户使用了配置文件,则框架需要生产对应的bean,②将所有使用dubbo的注解@server的class提升为bean,③要为使用@reference的注解字段或方法注入代理对象
@EnableDubbo注解
①dubbo框架首先会提取用户配置的扫描包名称,调用spring占位符进一步解码
②开始真正的注解扫描,委托spring对所有符合包名的。class文件做字节码分析,
③通过@service作为过滤条件
④将@service标注的服务提升为bean
⑤普通的bean生成为servicebean的占位符
⑥提取普通bean的service会注解成新的rootBeanDefinition,用于spring你 启动后的服务暴露
服务暴露的实现原理
配置承载初始化
不管是服务暴露还是服务消费场景下,dubbo框架都会依据优先级对配置做信息聚合处理,目前默认的策略主要遵循以下几点原则
①-D传递给JVM的优先级最高,如 -Dubbo。protocol。port=20880
②代码或xml配合优先级次高。,如在xml中制定<dubbo:protocol:port="20880">
③配置优先级最低,如dubbo。properties中的dubbo:protocol:port=20880,一般推荐使用properties作为默认值,如果xml没有配置就可以使用properties,通常用于共享公共配置,如应用名称
优雅停机原理解析
①接受jvm退出事件(收到kill 9 进程退出信号)
②反注册服务元数据到register
③推送地址列表给consumer
④provider发送readonly报文给consumer
⑤provider等待线程池任务完成&拒绝新任务处理
⑥tcp连接断开
dubbo协议发送readonly时间报文时,consumer端会响应provider为不可用状态,下次负载均衡时就不会调用下线的机器
dubbo远程调用
整个章节写的什么鬼,看不懂,大量的贴代码
dubbo集群容错
容错机制的特性
failover,当出现失败时会重试其他服务器
failfast:快速失败,当请求失败快速返回异常不做任何重试
failSafe:如果出现异常直接忽略
failBack:如果出现失败,则会定期重试
available:不做负载均衡,遍历找到第一个可用的服务调用,没有就抛异常
broadcast:广播给所有节点,任意节点报错就返回异常
forKing:同时并行请求多个服务,只有一个返回则直接返回
章章看不懂
dubbo扩展点
dubbo核心扩展点概述
dubbo按使用者和开发者分,可以分为spi层和api层,api只关注业务,SPI层自定义不同的实现类来实现整个框架的功能
按逻辑分为业务层,RPC,Remote领域,由于业务层不属于SPI扩展内容.可扩展的RPC和remote还可以细分成7层
RPC层:config,proxy,register,cluster,
Remote层:protocol,exchange,transport,serialize
proxy扩展点
我们发起远程调用就像调用本地调用一样,主要是在proxy层的proxyfactory帮我们生成的代理类,当我们远程调用时,其实是在使用代理类,
proxyfactorym默认2种实现,javassist和jdk,默认javassist,可以自行扩展其实现.
@SPI()
public interface ProxyFactory{
...接口中有三个方法要实现
}
Register层扩展点
其扩展点RegisterFactory,这个框架的注册与发现都是由这个扩展点负责的,
可以自定义注册实现类,如redis,dubbo,zookeeper,multicast
@SPI()
punbic interface RegisterFactory{
@Adaptive({redis})
ddd();
}
cluster层扩展点
此层设计dubbo框架的集群容错,涉及的扩展点较多,如容错cluster,路由router,负载均衡loadBalance,配置工作configuratorFactory,和合并器merger
cluster扩展点:主要负责容错机制,如failsave,failfast等.默认使用failOver
@SPI()
public interFace cluster {
@adaptive
join();
},
其容错机制
failover,当出现失败时会重试其他服务器
failfast:快速失败,当请求失败快速返回异常不做任何重试
failSafe:如果出现异常直接忽略
failBack:如果出现失败,则会定期重试
available:不做负载均衡,遍历找到第一个可用的服务调用,没有就抛异常
broadcast:广播给所有节点,任意节点报错就返回异常
forKing:同时并行请求多个服务,只有一个返回则直接返回
routerFactory扩展点
是一个工厂类,用于创建不同的router.如一个接口有多个提供者提供服务,由配置的路由规则制定提供者
@SPI()
public interface RouterFactory{
@Adaptive(xx)
Router getRouter(xx)
}
已有的RouterFactory实现由file,script,condition,service,app ,tag,mock
LoadBlance扩展点
负载均衡扩展点,内置随机,轮询,最小连接数,一致性这几种方式,默认使用随机方式
ConfiguratorFactory扩展点
merger扩展点:是合并器,可以对调用的结果集合并,如并行调用A,B两个服务都会返回一个list,merger可以合并成一个返回给应用,默认支持11种类型的返回值
Protocol扩展点
其包含4大扩展点:protocol,filter,exporterListener和InvokerListener,其中:protocol,filter使用最多.
protocol扩展点:是dubboRPC的核心调用层,具体的RPC协议都可以由他扩展,如果想要增加一种新的RPC协议,则只需扩展一个新的扩展点即可,
filter扩展点:是dubbo过滤器扩展点,可以自定义过滤器,在Invoker前后执行自定义逻辑,
Transport扩展点
屏蔽不同通信框架的异同,封装了统一的对外接口.
dubbo高级特性
服务分组和版本
dubbo中提供的服务分组和版本是强隔离的,如果服务指定了服务分组和版本,则消费调用者也必须传递相同的分组名称和版本名称
比如一个接口在1.0和2.0 有不同的实现类,我们可以指定版本version
参数回调
dubbo支持异步参数回调,当消费方调用服务方方法时,允许服务端在某个时间点回调客户端的方法,
异步调用
客户端消费接口是,配置异步标识,在调用时从上下文获取future对象,在期望结果返回时再调用阻塞方法Future.get()即可
泛化调用:
不依赖接口API发起远程调用,适合于框架集成和网关类应用开发.
结果缓存:用于加速热门数据的访问速度,cache,声明式缓存,需要在消费放配置,
dubbo过滤器
dubbo过滤器提供在服务调用前后插入自定义逻辑的途径.提供了服务站和消费者调用过程的拦截,但由于每次调用都会执行,因此它对性能是有影响的
过滤器的使用
注意:过滤器顺序,自定义过滤器默认会在内置过滤器之后,也可以修改配置改变顺序
剔除过滤 ,可以使用 -xxfilter,使此过滤器不生效,
过滤器的叠加:如果消费者和服务站都配置了过滤器,那么他们会叠加都会生效
过滤器的总体结构
分为消费者和服务者过滤器,有18种之多,详见过滤器列表,
这么多的过滤器都会在扩展初始化的时候进行加载排序,
AccessLogFilter,日志过滤器,
ExecuteLimitFilter用于限制每个服务中每个方法的最大并发数,有接口级别和方法级别的配置方式,如不设置,不做限制,
classLoadfilter:切当前的工作线程的类加载器到接口的类加载器以便和接口的类加载器的上下文一起工作,
目的是为了违反类似java加载机制的双亲委派模型,
contextFilter:记录每个请求的调用上下文,通常记录在ThreadLocal中,作为一个全局参数
ExceptionFilter:用于同一异常处理,防止序列化失败,
TimeoutFilter:用于日志类型的过滤器,记录调用时间如果超时则会打印一条警告日志
TokenFilter:某些服务提供者不想让消费者绕过注册中心直连自己,则可以使用令牌验证,服务提供在发布时生成令牌,与服务一起注册到注册中心,消费者必须通过注册中心才能获取到令牌,TokenFilter就是做令牌校验,\
TpsLimitFilter:服务端限流
以上都是服务端过滤器
以下都是消费端过滤器
ActiveLimitFilter同ExecuteLimitFilter,限制并发数,
consumerContextFilter:和contextFilter一起配合使用,
futureFilter:主要实现框架在调用前后出现异常时,触发调用用户配置的回调方法