这篇文章给大家聊聊关于空包网站源码分享,以及对应的知识点,希望对各位有所帮助,不要忘了收藏本站哦。
重启的服务因为是主动关闭Spring容器,所以有时间也有主动权去告知注册中心“我要下线了”。但是,对于暴力停机,比如kill-9或者机器宕机,Dubbo服务又是如何通知到注册中心的呢?
目录
一、zookeeper配置参数
二、zookeeper的数据存储结构
三、zookeeper与dubbo的心跳感应
1.client定时发送ping
2.server定时检测client
四、zkserver摘除宕机client节点
五、dubbo消费者摘除宕机client节点
六、结语
一、zookeeper配置参数
我们先来看一看zookeeper的配置参数。还记得如何安装zookeeper么?这里有一份攻略(都大同小异):
zookeeper的安装文件目录结构也比较简单,如下图:
bin目录:zookeeper支持的运行命令集合
这些命令集合分为windows系统命令和linux系统命令。
以.cmd结尾的命令,即是在windows环境上运行使用的命令,以.sh结尾的命令,即是在linux环境上运行使用的命令。
conf目录:存放配置文件,包括日志配置、zookeeper启动配置等
在运行zk之前,必须配置.cfg。注意,默认是没有zoo.cfg文件的,但是有zoo_sample.cfg文件,需要重命名为zoo.cfg。
zoo.cfg文件比较重要,zookeeper的心跳间隔参数就在此中,下面是此文件中一些主要参数说明:
?
1.tickTime:client和server间通信心跳时间,单位是毫秒
zookeeper客户端与服务器之间建立长连接,并通过心跳机制保持通信,每个tickTime时间间隔就会发送一个心跳。tickTime以毫秒为单位,默认是2000毫秒。
tickTime=2000
2.initLimit:LF初始通信时限
这是一个zookeeper集群参数,表示集群中的follower服务器(F)与leader服务器(L)之间初始连接时能容忍的最多心跳数(tickTime的数量)。
initLimit=5
3.syncLimit:LF同步通信时限
这是一个zookeeper集群参数,表示集群中的follower服务器与leader服务器之间请求和应答之间能容忍的最多心跳数(tickTime的数量)。
syncLimit=2
4.dataDir:zookeeper用于保存内存数据库的快照的目录
zookeeper保存数据的目录,默认情况下,zookeeper将写数据的事务日志文件也保存在这个目录里。
dataDir=/tmp/zookeeper
5.clientPort:客户端连接的socket端口
客户端连接server的端口,即对外服务端口,一般设置为2181。
clientPort=2181
?
docs目录:帮助文档
包括一些官方说明文档,比如zookeeperStarted.html文件,打开可以看到zookeeper的安装启动向导:
lib目录:zookeeper需要依赖的jar包
因为zookeeper是用Java开发的,zookeeper依赖的jar包都会放在这个目录中。
二、zookeeper的数据存储结构
zookeeper存储数据的核心数据结构是一个DataTree,源码是采用一个Map<String,DataNode>数据结构,其中key是path,DataNode是真正保存数据的核心数据结构。
类似文件系统的目录结构进行存储,目录树中的每个节点被称为Znode,Znode既可以存储数据,也可以拥有自己的子节点。
比如保存dubbo服务信息的结构如下:
总共分为四层,从上到下,分别为group分组、服务全限定名接口、分类、服务节点地址。
上图右侧即是节点Znode的关系依赖,在最底层的是服务节点url地址,格式形如dubbo://com.xx.xx:xxxx?xx=xx。
比如我本地起的服务,最终保存到zookeeper的服务提供者节点信息如下:
?
dubbo://192.168.31.19:30058/com.tin.example.dubbo.demo.facade.GiftFacade?anyhost=true&application=demo-provider&class=com.tin.example.dubbo.demo.impl.GiftFacadeImpl&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=com.tin.example.dubbo.demo.facade.GiftFacade&mapping-type=metadata&mapping.type=metadata&metadata-type=remote&methods=give&pid=25334&release=2.7.15&serialization=jackson&service.name=ServiceBean:/com.tin.example.dubbo.demo.facade.GiftFacade&side=provider&telnet=ls,ps,cd,pwd,trace,count,invoke,select,status,log,help,clear,exit,shutdown&timeout=500×tamp=1650163947650
?
当然zookeeper保存的url是进行encode编码后的url(以上是我decode后的结果),如下:
三、zookeeper与dubbo的心跳感应
前面配置说明有说到zookeeper的心跳参数tickTime,不错,它是zookeeper在server端检测client存活的时间间隔。
我们把zookeeper源码下载下来一看究竟。因为我的dubbo版本是2.7.15,依赖的zookeeper版本是3.4.13。
所以我下载zookeeper3.4.13版本。
zookeeper源码地址,有需自取:https://github.com/apache/zookeeper/tree/branch-3.4.13
在zookeeper的client端(比如集成到dubbo内的zookeeper-client),则定时向zookeeper的server发送ping包,上报自身的健康状态。
注意,这里的client端的ping包发送和server端间隔tickTime进行存活检测不一样。
client端的ping包发送是轮询隔一段时间后向server端发送ping请求,其意义是告诉server端,我还活着。
而server端的tickTime间隔时间进行存活检测意义是检测client连接对象是否已经无效,如果已经无效则将连接对象进行清除关闭。
1.client定时发送ping
重点逻辑在org.apache.zookeeper.ClientCnxn.SendThreadinitializeAndRun方法,
initializeAndRun()方法内又分为集群模式和单机模式启动,分别对应①和②处,因为我们本节只为讨论server是如何和client保持连接的,所以我们看②处代码,当然①处代码也是一样的。
ZookeeperServerMain最终会实例化一个ZookeeperServer,最后也即是一个zk服务器进程对应一个ZookeeperServer,如下图:
new出来的ZookeeperServer由zk的一个启动工厂类负责启动:
工厂类统一调用ZookeeperServer的startup方法:
org.apache.zookeeper.server.ZooKeeperServerprocessTxn(org.apache.zookeeper.txn.TxnHeader,org.apache.jute.Record,boolean)
?在killSession内最终会调用DataTree.deleteNode方法,删除node节点。
到此zkserver完成了临时节点的删除。
五、dubbo消费者摘除宕机client节点
dubbo服务提供者在zk上注册了临时节点,消费者监听该临时节点。一旦临时节点有修改,zk就会通知消费者,消费者进行处理。
对于服务提供者宕机的情况,上文已说明zkserver自动删除临时节点的逻辑,接下来我们看看消费者又是如何做到摘除client节点的。
分两部分,第一部分是client启动时向对应的临时节点注册监听器;第二部分是zk节点有变更时,client接收对应的event并做出相应的处理动作。
dubbo启动时,会初始化一个zk注册器ZookeeperRegistry(dubbo源码),用于服务提供者服务注册和服务消费者服务订阅。
下面着重讲服务订阅部分,对应doSubscribe方法源码。
publicvoiddoSubscribe(finalURLurl,finalNotifyListenerlistener){\nif(Constants.ANY_VALUE.equals(url.getServiceInterface())){\n//①全量service订阅逻辑\n}else{\n//②部分类别订阅逻辑\n}\n}
以上①处是服务治理(dubbo-admin)需要用到,订阅所有的service,因为我们是消费者,那么只需要进入②,如下图:
②处代码作用是为当前分类节点添加“子节点列表变更的”watcher监听,zkListener是RegistryChildListenerImpl,通过debug也证明了这点:
RegistryChildListenerImpl的listener属性最终值类型是RegistryDirectory。
所以,当zk节点有变更时,最终会回调到RegistryDirectorynotify源码如下:
以上④即实现consumer本地摘除提供者节点!同理,摘除宕机client节点也就在这里啦!
我们做一个测试,比如我本地启动一个provider,同时启动一个consumer。
那么,在我的zk服务器上是可以查得到这两个节点的:
同样,在本地通过jps命令也可以看到:
接下来,我通过执行kill-9,把ProviderApplication这个进程删除:
然后,本地consumer在RegistryDirectorydestroyAllInvokers方法,其内部实现destroyinvoker,最终实现摘除provider节点,如下:
好啦,现在consumer也走完摘除client节点逻辑啦~
六、结语
感谢大家阅读,本人见识有限,有不对的地方还望各位大佬指点,在此表示感激不尽。文章持续更新中…….
原文出处:https://heapdump.cn/article/3789086
关于空包网站源码分享的内容到此结束,希望对大家有所帮助。