dubbo源码,dubbo系列之-qos运维-2021-01-17
dubbo源码,dubbo系列之-qos运维-2021-01-17详细介绍
本文目录一览: Dubbo启动源码解析一
这次讲 dubbo-spring-boot-starter 启动方式,所以入口就是Spring的SPI机制;
首先在META-INF/spring.factories配置下,配置了org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration类,在启动时,则会把DubboAutoConfiguration类注册到spring容器中;
我们来看下DubboAutoConfiguration
先看启动流程
我们先看下生产者端的启动流程,首先是在Spring中注册ServiceAnnotationBeanPostProcessor类
该类实现了BeanDefinitionRegistryPostProcessor接口,则在Spring容器初始化时,会调用postProcessBeanDefinitionRegistry方法
我们会看到,这个时候会去注册DubboBootstrapApplicationListener类,这个类我们等流程到了在分析,我们先按启动流程看过去;resolvePackagesToScan方法先获取到需要扫描的包 ,然后再调用registerServiceBeans去注册相关实例,我们重点来看下registerServiceBeans方法
接下来,我们主要去看下registerServiceBean方法
接下来,我们来看下buildServiceBeanDefinition方法
到这,ServiceBean注册成功,ServiceBean类很重要,每个Dubbo service实例都对应一个ServiceBean,相关配置都在ServiceBean中;我们再回到开始注册的DubboBootstrapApplicationListener类
DubboBootstrapApplicationListener类继承了OneTimeExecutionApplicationContextEventListener,OneTimeExecutionApplicationContextEventListener实现了ApplicationListener,主要监听了Spring容器生命周期,我们看下onApplicationContextEvent方法
我们可以看到,当Spring容器启动成功时,会调用dubboBootstrap.start();
接下来,主要逻辑在ServiceBean中,这个export方法在其父类ServiceConfig中,我们下一篇主要讲ServiceConfig逻辑;
源码修炼笔记之Dubbo线程池策略
FixedThreadPool
FixThreadPool内部是通过ThreadPoolExecutor来创建线程,核心线程数和最大线程数都是上下文中指定的线程数量threads,因为不存在空闲线程所以keepAliveTime为0, 当queues=0,创建SynchronousQueue阻塞队列; 当queues<0,创建无界的阻塞队列LinkedBlockingQueue; 当queues>0,创建有界的阻塞队列LinkedBlockingQueue。 采用dubbo自己实现的线程工厂NamedInternalThreadFactory,将线程置为守护线程(Demon) 拒绝策略为AbortPolicyWithReport,策略为将调用时的堆栈信息保存到本地文件中,并抛出异常RejectedExecutionException
CachedThreadPool
CachedThreadPool与FixedThreadPool的区别是核心线程数和最大线程数不相等,通过alive来控制空闲线程的释放
LimitedThreadPool
LimitedThreadPool与CachedThreadPool的区别是空闲线程的超时时间为Long.MAX_VALUE,相当于线程数量不会动态变化了,创建的线程不会被释放。
EagerThreadPool
与上述三种线程池不同,EagerThreadPool并非通过JUC中的ThreadPoolExecutor来创建线程池,而是通过EagerThreadPoolExecutor来创建线程池,EagerThreadPoolExecutor继承自ThreadPoolExecutor,实现自定义的execute方法,采用的阻塞队列是TaskQueue,TaskQueue继承自LinkedBlockingQueue。
execute方法首先调用ThreadPoolExecutor的execute方法,如果执行失败会重新放入TaskQueue进行重试。
实现自定义的ThreadPool
ThreadPool被定义为一个扩展点,如下所示,
其默认实现是FixedThreadPool,可以通过实现该扩展来实现自定义的线程池策略。
Dubbo之SPI实现原理详解
?SPI全称为Service Provider Interface,是一种服务提供机制,比如在现实中我们经常会有这种场景,就是对于一个规范定义方而言(可以理解为一个或多个接口),具体的服务实现方是不可知的(可以理解为对这些接口的实现类),那么在定义这些规范的时候,就需要规范定义方能够通过一定的方式来获取到这些服务提供方具体提供的是哪些服务,而SPI就是进行这种定义的。
说明:
Dubbo 的扩展点加载是基于JDK 标准的 SPI 扩展点发现机制增强而来的,Dubbo 改进了 JDK 标准的 SPI 的以下问题:
dubbo对于SPI的实现主要是在ExtensionLoader这个类中,这个类主要有三个方法:
如下是getExtension()方法的源码:
createExtension()方法的源码:
在createExtension()方法中,其主要做了三件事:
关于wrapper对象,这里需要说明的是,其主要作用是为目标对象实现AOP。wrapper对象有两个特点:
getExtensionClasses()方法的源码
loadDirectory()方法的源码:
loadClass()方法的源码
loadClass()方法主要作用是对子类进行划分,这里主要划分成了三部分:
总结而言,getExtension()方法主要是获取指定名称对应的子类。在获取过程中,首先会从缓存中获取是否已经加载过该子类,如果没加载过则通过定义文件加载,并且使用获取到的wrapper对象封装目标对象返回。
getAdaptiveExtension()方法源码
分布式天花板?阿里百万架构师的ZK+Dubbo笔记,颠覆认知
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式锁服务、集群管理、生成分布式唯一ID等。
Apache Dubbo 是一款高性能、轻量级的开源Java RPC框架,提供面向接口代理的高性能RPC调用、智能负载均衡、服务自动注册和发现、运行期流量调度、可视化服务治理和运维等功能。
作为架构师必须掌握的分布式架构技术, 你的我(雷锋)在这个星期费心费力给大家着重收集并整理了这份关于ZooKeeper+Dubbo技术栈的源码+笔记+项目实战的资料。
以上就是资料包含的内容,下面我会展示目录和详细内容截图,有需要完整版源码+笔记的朋友,只有点赞+关注,然后在我的主页私信【分布式】即可免费领取!!
一:Zookeeper篇
1.分布式概述
2.ZK概述
3.分布式CAP
4.一致性实现
5.ZK单机&集群搭建
6.ZK快速入门
7.ZK源码解析
8.ZK应用场景
9.分布式锁和队列
二:Dubbo篇
1.RPC核心
2.手写RPC
3.Dubbo高可用
4.Dubbo IO模型
5.Dubbo 架构
6.源码解析
第一部分Nginx能帮我们做什么
第二部分如何编写HTTP模块
第三部分深入Nginx
有需要完整版源码+笔记的朋友:
dubbo之Cluster(容错)
在介绍dubbo的cluster之前,先来看一下cluster在dubbo整体设计中的位置。按照官网的说法,Cluster作为路由层, 封装多个提供者的路由及负载均衡,并桥接注册中心,以 Invoker 为中心,核心扩展接口为 Cluster , Directory , Router , LoadBalance ,接口间的依赖关系如下:
虚拟Invoker暴露流程程: Cluster => (Directory => Router) => LoadBalance => Invoker ,依照这个顺序,我们先来看Cluster。Cluster不属于核心层,目的是将多个 Invoker 伪装成一个 Invoker,这样其它人只要关注 Protocol 层 Invoker 即可,加上 Cluster 或者去掉 Cluster 对其它层都不会造成影响,因为只有一个提供者时,是不需要 Cluster 的。本文主要关注Cluster层的容错及其核心接口(LoadBalance在之前的文章已经做过介绍)。
先来看Cluster层中的Cluster接口,支持SPI扩展、自适应扩展,默认SPI实现是FailOverCluster,核心只有一个join接口
比较好理解,把Directory中的所有原始Invoker合并成一个虚拟Invoker,虚拟Invoker是一系列通过合并原始Invoker,并在此基础上扩展带有容错机制的Invoker。以FailOverCluster为例,join返回FailoverClusterInvoker,具体的invoke逻辑由虚拟Invoker( FailoverClusterInboker )实现,构造方法( 这里以FailoverClsterInvoker为例,其他虚拟Invoker的构造方法大同小异 )通过继承父类AbstractClusterInvoker实现,只有一个Directory参数:
当前dubbo版本提供的虚拟Invoker主要有下面几种,下面来分别介绍:
所有8种cluster中,除去AvailableCluster、MergeableCluster、BroadcastCluster,其他都需要根据LoadBalance选取可用Invoker,具体逻辑在AbstractClusterInvoker.select。先来看AbstractClusterInvoker的构造方法:
两个核心参数,Directory和URL,Directory本节先不做介绍,这里的URL是被调用服务的URL;availableCheck为了与服务的availableCheck做区分,这里的参数名是 cluster.availablecheck ;核心关注上面提到的select方法,先来看逻辑:
整体select方法都是为了尽可能保证每次选出的Invoker不重复,也就是说最大限度的保证负载均衡;doSelect方法在处理的时候,通过loadBalance选出的Invoker,还会对其进一步判断是否已被选中过,步骤如下:
doSelect方法中的loadbalance.select已经在LoadBalance部分做了分析,这里不再冗述,重点关注reSelect方法;先把备选Invoker中,未被选中过的Invoker过滤出来,优先从中选取可用Invoker,步骤如下:
Cluster层的容错主要通过几种常用的容错机制配合负载均衡,保证最终通过Cluster暴露可用的Invoker;而且,dubbo在保证Invoker可用性前提下,要求尽可能均衡负载,过程会多次执行负载均衡策略。
注:dubbo源码版本2.7.1,欢迎指正。
dubbo privider与consumer同时配置retry以哪个为主
dubbo配置优先级:
方法级>接口级>全局级
消费方配置优先于提供方配置
所以,retry如果都配了,以消费方为主。
DUBBO的介绍部分我这里就不介绍了,大家可参考官方文档。
DUBBO的注册中心安装
DUBBO的注册中心支持好几种,公司用到zookeeper注册中心,所以我这边只说明zookeeper注册中心如何安装。
安装zookeeper注册中心首先得下载zookeeper。大家可到zookeeper的官网http://zookeeper.apache.org/releases.html上去下载。
我下载了zookeeper-3.4.5.tar.gz版本的包。接下来把zookeeper-3.4.5.tar.gz解压到文件夹D:\zookeeper-3.4.5\中,
然后将zoo_sample.cfg改名为zoo.cfg。然后将配置文件zoo.cfg改成如下:
[html] view plain copy
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=D:\\zookeeper-3.4.5\\data
dataLogDir=D:\\zookeeper-3.4.5\\log
# the port at which the clients will connect
clientPort=2181
然后就可以启动了。
DUBBO的管理平台DUBBO-ADMIN的部署
dubbo-admin.war可在网上百度去下载,但是我下载了好几个war包,发布上去服务启动都报错,这个时候大概是我们系统的JDK和编译
dubbo-admin.war的JDK版本不同导致的了。所以我之后直接下载了dubbo-master的源代码,然后自己编译了一个war包,这样就不会存
在启动报错的问题了。
以上就是我下载下来的导入eclipse的源码。
dubbo的所有源码可在https://github.com/alibaba/dubbo上下载。用MAVEN在最外层目录编译即可将所有项目全部编译。
下载编译的时候会出现问题,首先是找不到opensesame的情况,这个好解决。去这个地址https://github.com/alibaba/opensesame
将pom文件下载下来,然后用MAVEN命令下载依赖包到本地仓库就好了。然后就可以顺利编译DUBBO MASTER项目了。
编译好之后在dubbo-admin项目中会出现dubbo-admin.war包
将dubbo-admin.war导入到TOMCAT中,然后启动TOMCAT,然后输入localhost:8080然后输入账号密码(默认都是root)
就可以访问到dubbo控制中心了。注意得将WEB-INF中的dubbo.properties中的配置项改成这样
(配置的地址端口必须和zookeeper的服务的地址端口一致)
[html] view plain copy
dubbo.registry.address=zookeeper://127.0.0.1:2181
DUBBO的管理平台DUBBO
MONITOR的部署
dubbo
monitor部署非常简单,之前把dubbo-master全编译了,所以在编译好的dubbo-monitor-simple项目中就
能拿到dubbo-monitor-simple-2.5.4-SNAPSHOT-assembly.tar.gz包
然后解压到文件夹中,打开配置文件,将配置文件中的端口修改为未占用的端口
[html] view plain copy
dubbo.protocol.port=6066
dubbo.jetty.port=6060
我随便改成了6066和6060,这个随自己改,只要其它服务没占用就行,然后双击start.bat启动服务,
浏览器输入localhost:6060就能访问了,访问到的内容如下:
DUBBO的provider和consumer
provider和consumer的案例网上应该有很多了,如果在工作中,项目中有DUBBO肯定也会知道provider和consumer如何布置,
我这里就不多说了。我这边主要是讲我们在项目中不会碰到的一些东西,比如zookeeper,dubbo-admin,dubbo-monitor如何布置,
因为我们开发者往往接触不到如何布置。
Dubbo——服务调用、服务暴露、服务引用过程
1、InvokerInvocationHandler jdk动态代理
5、RegistryDirector返回Invokers Router分为:Script 脚本路由、Condition 条件路由
6、通过MockInvokersSelector的route方法(getNormalInvokers)拿到能正常执行的invokers
8、当回到AbstractClusterInvoker后,执行(默认FailoverClusterInvoker,根据配置的是,Failfast Cluster(快速失败) , Failsafe Cluster(失败安全) , Failback Cluster(失败自动恢复) , Forking Cluster(并行调用多个服务器,只要一个成功即返回) , Broadcast Cluster(广播调用所有提供者,逐个调用,任意一台报错则报错))doInvoker方法
9、FailoverClusterInvoker调用AbstractClusterInvoker的select方法
10、执行doSelect方法
11、调用AbstractLoadbalance的select方法
12、根据配置的负载均衡策略调用对应的(如RoundRobinLoadBalance)类的doSelect方法
13、返回invokers.get()方法
14、调用FailoverClusterInvoker的invoke方法
均继承自抽象类AbstractDirectory
Directory 获取 invoker 是从 methodInvokerMap 中获取的,主要都是读操作,那它的写操作是在什么时候写的呢?就是在回调方法 notify 的时候操作的,也就是注册中心有变化,则更新 methodInvokerMap 和 urlInvokerMap 的值
根据dubbo-admin配置的路由规则来过滤相关的invoker,当我们对路由规则点击启用,就会触发 RegistryDirectory 类的 notify 方法。
notify方法调用refreshInvoker方法。
route方法的实现类为ConditionRoute 根据条件进行过滤
1、调用mathThen方法
2、调用matchCondition方法
3、调用isMatch判断
4、调用isMatchGlobPattern方法
? 集群模块是服务提供者和服务消费者的中间层,为服务消费者屏蔽了服务提供者的情况,这样服务消费者就可以专心处理远程调用相关事宜。比如发请求,接受服务提供者返回的数据等。这就是Dubbo Cluster集群的作用。
通过cluster来指定集群容错方式
其实就是应对出错情况采取的策略
用于有状态服务,尽可能让客户端总是向同一提供者发起调用,除非提供者挂了,再连另一台,自动开启延迟链接,以减少长接数
? 启动时服务提供者将当前进程启动时间注册到ZK;服务消费者发现该节点后计算服务启动时间(相对当前时间),在默认预热时间的前20%时间内,该节点权重始终固定为2,这样客户端的负载均衡器只会分发极少的请求至节点。
? 在预热时间之后的80%时间内,该节点权重将随着时间的推移而线性增长;待预热时间到期后,权重自动恢复为默认值100;负载均衡器的内核是一个标准的WLC算法模块,即加权最少连接算法;
? 如果某个节点Hang住或宕机,其权重会迅速自动调节降低,避免持续性影响;当节点下线时,服务端提前触发权重调节,重载默认权重至1并发布到注册中心,服务消费者将迅速感知到该事件; 服务提供者优雅下线步骤(注意这套逻辑仅在服务端执行)在ok.htm?down=true对应的controller中加入下列逻辑,注意要判断down是否为true,因为正常来说false表示启动验证而不是关机
服务者消费者配置
dubbo服务支持参数动态调整,例如动态调整权重,但dubbo实现方式较为特殊,并不是常规思路。
? ServiceConfig类拿到对外提供服务的实际类ref,然后通过ProxyFactory类的getInvoker方法使用ref生成一个AbstractProxyInvoker实例,到这一步就完成具体服务到Invoker的转换(javassistProxyFacory、JdkProxyFactory),接着要做Invoker转换到Export的过程
? 服务发布:本地暴露、远程暴露
? 为什么会有 本地暴露 和 远程暴露 呢?不从场景考虑讨论技术的没有意义是.在dubbo中我们一个服务可能既是 Provider ,又是 Consumer ,因此就存在他自己调用自己服务的情况,如果再通过网络去访问,那自然是舍近求远,因此他是有 本地暴露 服务的这个设计.从这里我们就知道这个两者的区别
1、spring启动,解析配置文件
2、创建dubbo标签解析器
3、解析dubbo标签
4、ServiceBean解析
5、容器创建完成,触发ContextRefrestEvent
6、export暴露服务
7、duExportUrls
8、doExportUrlsFor1Protocol
9、getInvoker
10、protocol.export
11、开启服务器 openServer()如nettyServer
12、注册服务到注册中心 registerProvider
Filter 在服务暴露前,做拦截器初始化,在加载所有拦截器时会过滤支队provider生效的数据。
可以。zookeeper的信息会缓存到本地作为一个缓存文件,并且转换成 properties 对象方便使用。建立线程池,定时检测并连接注册中心,失败了就重连。
注册服务到zk其实就是在zk上创建临时节点,当节点下线或者down掉时,即会删除临时节点,从而使服务从可用列表中剔除。
持久节点
临时节点
1、export的时候进行zk订阅
2、设置监听回调的地址,回调给FailbackRegistry的notify
3、创建持久节点
4、设置对该节点的监听
5、更新新的服务信息,服务启动和节点更新回调,都会调用到这里
6、更新缓存文件
7、对比新旧信息是否有变化,有则重新暴露服务
高并发大业务量情况下,暂时屏蔽边缘业务
MockClusterInvoker
? SPI 全称为 Service Provider Interface,是一种服务发现机制。SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。正因此特性,我们可以很容易的通过 SPI 机制为我们的程序提供拓展功能。SPI 机制在第三方框架中也有所应用,比如 Dubbo 就是通过 SPI 机制加载所有的组件。不过,Dubbo 并未使用 Java 原生的 SPI 机制,而是对其进行了增强,使其能够更好的满足需求。在 Dubbo 中,SPI 是一个非常重要的模块。基于 SPI,我们可以很容易的对 Dubbo 进行拓展。如果大家想要学习 Dubbo 的源码,SPI 机制务必弄懂。接下来,我们先来了解一下 Java SPI 与 Dubbo SPI 的用法,然后再来分析 Dubbo SPI 的源码。
说一下Dubbo的工作原理?注册中心挂了可以继续通信吗?
答案是肯定可以的,我将从下面几点进行说明:
1.dubbo 的调用流程
2.Dubbo整体设计
3.从源码上说明注册中心挂了还是可以继续通信的
Dubbo 调用流程
架构图
流程说明:
1.Provider(提供者)绑定指定端口并启动服务
2.提供者连接注册中心,并发本机IP、端口、应用信息和提供服务信息发送至注册中心存储
3.Consumer(消费者),连接注册中心 ,并发送应用信息、所求服务信息至注册中心
4.注册中心根据 消费 者所求服务信息匹配对应的提供者列表发送至Consumer 应用缓存。
5.Consumer 在发起远程调用时基于缓存的消费者列表择其一发起调用。
6.Provider 状态变更会实时通知注册中心、在由注册中心实时推送至Consumer
这么设计的意义:
Dubbo 整体设计 其协作流程如下:
从源码上说明注册中心挂了还是可以继续通信的
首先要把消费者注册到Zookeeper注册中心
然后使用RegistryDirectory 监听一下几个目录(会自动触发一次去获取这些目录上的当前数据)
当前所引入的服务的动态配置目录:/dubbo/config/dubbo/org.apache.dubbo.demo.DemoService:1.1.1:g1.configurators
比如监控providers 目录:
当有服务提供者注册,zookeeper会自动推动给订阅的消费者,然后转换为invoker存储到缓存中
我们在看调用时的代码:
我们看到 FailoverClusterInvoker 的doInvoke方法
Invoker invoker = select(loadbalance, invocation, copyInvokers, invoked);
此方法根据负载均衡器去缓存中获取一个invoker,
上面的 copyInvokers 就是上面我们缓存进去的 List
invokers = routerChain.route(getConsumerUrl(), invocation);
总结 在我们系统启动时,已经缓存了注册中心上的所有服务,后续的注册中心挂了只会影响到后续则注册,不会影响调用!
Dubbo分布式的RPC,微服务框架,
包括三个关键功能:基于接口的远程调用,容错与负载均衡,服务自动注册与发现。
Dubbo使得调用远程服务就像调用本地java服务一样简单。
参考Dubbo官方文档:包括实现细节,远程调用细节,服务提供者暴露服务。
主要流程。
1、provider向注册中心去注册
2、consumer从注册中心订阅服务,注册中心会通知consumer注册好的服务
3、consumer调用provider
4、consumer和provider都异步的通知监控中心
基于zk作为注册中心:
【提供者】在【启动】时,向注册中心zk 【注册】自己提供的服务。
【消费者】在【启动】时,向注册中心zk 【订阅】自己所需的服务。
所以是可以的,消费者在启动时,消费者会从zk拉取注册的生产者的地址接口等数据,缓存在本地。每次调用时,按照本地存储的地址进行调用,消费者本地有一个生产者的列表,他会按照列表继续工作,倒是无法从注册中心去同步最新的服务列表,短期的注册中心挂掉是不要紧的,但一定要尽快修复,挂掉是不要紧的,但前提是你没有增加新的服务,如果你要调用新的服务,则是不能办到的
dubbo 2.8.3 支持jdk1.7么
据我所知,暂不支持,jdk1.7暂无方法ConcurrentHashMap.KeySetView,而这个已经被dubbo收录使用了,详见
http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.KeySetView.html
及dubbo源码的
com.alibaba.dubbo.common.utils.ConcurrentHashSet
本人用jdk8+
dubbo系列之-qos运维-2021-01-17
dubbo自带的运维工具dubbo-admin,主要面向开发人员去管理服务,携带很多管理、控制等功能,然后在dubbo新版本又推出了qos(Quality of Service),主要面向运维管理。我在之前公司有用到次功能,在和k8s结合时,通过http发送主动下线功能(下线注册,但不下线服务),等到流量完全停止,在下线pod,实现平滑发布。
怎么样去管理?
dubbo通过 QosProtocolWrapper 这个包装器实现qos发布,QosProtocolWrapper 是Protocol 三大包装器(filter,listener,qos)其中之一,默认会开启qos功能,可以配置关闭
qos 主要提供了ls,online,offline,help 功能,具体说,只有三种,上下线服务和查看服务
我们跟读一下源码,看看qos 服务的启动,请求处理,上下线等。
在dubbo 生产者服务暴露和消费者消费引用的过程中都会启动qos,并且qos 通过cas来保证一个jvm只启动一次。
同样qos 功能也是通过netty启动server,处理类指定为 QosProcessHandler,这个handler实现了netty的 ByteToMessageDecoder 可以将网络流中的字节解码为对象
channelActive() 方法含有为连接建立的时候回调,这里有个定时任务500ms,会刷一个美体的dubbo给客户端,我们验证下。
我们看看 QosProcessHandler#decode 是怎么处理请求的。
上面方法讲究,先读取第一个字节判断请求是http 还是 tcp,为什么用第一个字节呢,我们知道http信息头开始为 GET /xx 或者 POST /xx,第一个字符要么G要么P,判断为http 则用http编解码,如果为tcp 则用 LineBasedFrameDecoder 编解码,这是一个换行分割读取的解码方式遇到(\n,\r)[就是telnet时候的回车]时,就截断,如果为tcp 还会添加一个 IdleStateHandler 作为心跳检测,最后处理指令的handler 为 TelnetProcessHandler。
先演示下效果
为了便于观察我们这里看http的处理指令的方式 HttpProcessHandler。
HttpCommandDecoder. decode (msg)会将get或者post请求携带的路径等返回给 commandContext , BaseCommand.class 为指令扩展点会根据uri 传入的指令,来指定要处理的类,优点类似策略模式。我们看看offline 是怎么处理的
可以传入服务,默认所有服务,18行中从注册工厂中获取服务对应的注册中心,然后调用注册中心的unregister() 最后层层调用到zk客户端的delete()方法来,删除zk临时节点。
qos 的功能和简单,之所以单独拿出来讲是因为这里涵盖了我们web开发中常提到的“http服务器”概念,通过netty 启动服务,然后处理请求。