-
Leader
首先将事务请求持久化到事务日志文件中。 -
Leader
生成事务提议,将其广播给所有Follower
。 -
Follower
收到事务提议,也将事务持久化到事务日志文件,并给Leader
回应一个ACK
消息,表示已做完事务持久化工作。
(2)第二阶段执行事务提交
第二阶段,Leader
收到半数以上的ACK
后,认为半数以上的服务都完成了事务日志持久化操作,可以继续将事务请求同步到内存数据库中,此为事务提交阶段。具体流程如下:
-
Leader
收到一半以上的ACK
信息后,进入事务commit
阶段,Leader
先将事务请求同步到内存数据库。 -
如果是
Leader
自己收到的事务请求,此时就可以响应客户端了。 -
Leader 向所有
Follower
广播 COMMIT 消息。 -
Follower
收到 COMMIT 后,将事务请求同步到内存数据库。 -
如果是
Follower
收到的事务请求又转发给Leader,此时Follower
就可以响应客户端了。
如下图分别为 Leader
接收到事务请求和 Follower
接收事务请求的处理过程:
需要注意,假设集群有3个服务节点,Leader
先将事务写入日志文件,相当于已经有一个服务节点完成了第一阶段(就是 Leader
自己),然后广播事务提议给 Follower
,只要有一个 Follower
响应了ACK
,Leader
就可以进入第二阶段 COMMIT
,此时Leader
将事务同步到内存数据库,就可以响应客户端了。
其实在集群中可能还会存在一种运行模式,即Observer
,和 Follower
一样统称为Learner
,也可以参与到数据同步的两阶段过程中,但是没有任何投票权利,Observer
无需回应ACK
给Leader
,Observer
不计入集群过半机制。
3、ZXID
从两阶段流程可以看出,ZooKeeper
保证的是最终一致性,即 Leader
向客户端返回写入成功后,可能有部分 Follower
还没有写入最新的数据。
ZooKeeper
的最终一致性是严格的顺序一致性,所有事务请求统一由Leader
发起提议,严格按ZXID
顺序执行,当前事务请求没有处理完,再来新的事务请求就会阻塞。
ZXID
是由 Leader
生成的事务ID,是一个16进制的递增数字,共64位(二进制),由两部分组成:高32位代表当前Leader
任期编号,递增;低32位是事务计数器,递增,整体上是递增的。
ZooKeeper
适合读多写少的场景,读操作几乎是内存级别的,这得益于ZooKeeper
将数据保存在内存中。数据在内存中,就有一个问题,ZooKeeper
重启了数据还会在吗?
当然在了,ZooKeeper
将数据以事务日志形式持久化到文件中。每个更新请求,必须先将事务日志写到文件中,然后才把数据同步到内存数据库。
1、事务日志存放目录
事务日志文件默认存储在dataDir
目录下,因为每次事务请求都是一次磁盘IO操作,事务日志的写入性能直接影响了ZooKeeper
对事务请求的吞吐,为了更高的吞吐和低延迟,建议单独为事务日志配置一个目录dataLogDir
,以免受其他操作影响。
dataLogDir
下会先生成一个子目录version2
,2表示ZooKeeper
日志格式的版本号,同一版本的日志可以互相迁移恢复数据。version2
下才是事务日志文件。
2、文件大小和后缀名
事务日志的文件有两个特点:
-
文件大小出奇一致:都是
67108880KB
,即64MB
。 -
文件名后缀是一串看似有些规律的数字,而且随着修改时间推移呈递增状态。
(1)磁盘空间预分配
文件大小都是64MB
,是因为日志文件的磁盘空间预分配。
事务日志不断追加写入文件的操作会触发底层磁盘IO为文件开辟新的磁盘块,即磁盘Seek,为了避免频繁的文件大小增长带来的磁盘Seek开销,ZooKeeper
在创建事务日志文件时就向操作系统预分配了一块比较大的磁盘块,保证了单一事务日志文件所占用的磁盘块是连续的,以此提升事务的写入性能。默认是64MB
,空闲部分用空字符(\0
)填充。
如果后续检测到文件空间不足4KB
,将扩容再次预分配64MB
,直到创建新的事务日志文件。
(2)ZXID作为后缀名
文件名后面的一串数字是事务ID:ZXID
,并且是写入事务日志文件的第一条事务ZXID
。前面讲了,ZXID
高32位是当前Leader
任期编号,低32位是事务计数器,比如 log.1400000001
、log.1400000003
,都是Leader
任期编号为20时产生的事务日志文件。
3、事务日志可视化
事务日志文件中存放的是二进制格式的数据,不能用vim、cat等工具直接打开,需要用apache-zookeeper-3.7.0
提供的脚本bin/zkTxnLogToolkit.sh
打开:
bin/zkTxnLogToolkit.sh logs/zoo-1/version-2/log.1400000003
一行就是一个事务记录,每行从左到右依次是操作时间、客户端session
ID、CXID
(客户端操作序列号)、ZXID
、操作类型(做了什么),如果操作类型是 createSession
,后面的30000就是session
的超时时间。
4、相关配置项
跟事务日志有关的配置除了dataLogDir
外,还有 preAllocSize
。
(1)dataLogDir
zoo.cfg
中默认没有显式配置dataLogDir
,事务日志和快照日志共享dataDir
。但是强烈建议,单独为事务日志指定dataLogDir
。
事务日志记录对磁盘性能要求极高,为了保证数据一致性,ZooKeeper
在返回客户端请求响应前,必须将本次请求对应的事务日志写入到磁盘中。因此,事务日志写入性能直接决定了ZooKeeper
在处理事务请求时的吞吐。
针对同一块磁盘的其他并发读写操作(如ZooKeeper
运行时日志输出和操作系统自身的读写等),尤其是数据快照操作,会极大影响事务日志的写性能。因此尽量给事务日志的输出配置一个单独的磁盘或是挂载点,极大提高ZooKeeper
整体性能。
(2)preAllocSize
java 系统属性: ZooKeeper.preAllocSize
,从字面意思就可以看出,preAllocSize
是用来配置事务日志文件预先分配文件大小的参数。默认65536
,单位KB
,即64MB
。
5、什么时候创建新日志文件
在进行事务日志写入前,ZooKeeper
会判断是否正在关联一个可写的事务日志文件,如果有则继续追加到该文件中,如果没有就需要创建新的日志文件并关联上。
什么时候ZooKeeper
没有关联上一个可写的事务日志文件呢?有两种情况:
-
ZooKeeper
停止会导致之前关联的事务日志文件断开,重启后第一次事务日志写入,需要创建新的日志文件。 -
上一个事务日志文件写满了(达到阈值,触发了快照之后),需要创建新的日志文件。
需要注意ZooKeeper
服务不要频繁重启,否则会产生很多日志文件,并且有些文件还没有写满,非常浪费磁盘空间。
快照日志是将ZooKeeper
服务器上某个时刻的全量内存数据,写入到指定磁盘文件中。可以这样理解,快照日志文件是存量数据,事务日志文件是增量数据,二者加起来就是最大限度的全量数据。
1、文件存储
和事务日志类似,快照日志存放在dataDir
子目录version2
中,文件名为snapshot.ZXID
,不需要像事务日志文件一样预分配空间。
需要强调快照文件名后缀 ZXID
是触发快照的瞬间,提交的最后一个事务ID。如果是事务ZXID5
触发快照,那么快照文件名就是snapshot.ZXID5
,快照之后的下一个事务的ID是ZXID6
,新的事务日志名就是log.ZXID6
。
在数据恢复阶段,ZooKeeper
可以根据快照文件名后缀ZXID
,确定增量事务日志的起点文件。
2、快照日志可视化
快照日志内容同样也是二进制格式的,需要用 apache-zookeeper-3.7.0
提供的脚本bin/zkSnapShotToolkit.sh
打开:
bin/zkSnapShotToolkit.sh data/zoo-1/version-2/snapshot.1300000000 |less
快照日志记录每个节点的元信息,每个节点从上到下依次为:
-
cZxid
,创建这个节点时的事务ID。 -
ctime
,创建节点时间。 -
mZxid,
最后修改节点的事务ID。 -
mtime,
最后修改节点时间。 -
pZxid,
,该节点最后更新子节点列表的事务ID。 -
cversion
,该节点子节点列表更新版本号,即子节点列表修改次数(不是子节点的值修改)。 -
dataVersion
,节点数据版本号。 -
aclVersion
,节点访问控制列表版本号。 -
ephemeralOwner
,如果为临时节点,则为节点拥有者的sessionID
,如果不是临时节点则为0。 -
dataLength,
,节点数据长度。
3、相关配置
快照日志相关的配置,除了dataLog
,还有snapCount
、autopurge.snapRetainCount
和autopurge.purgeInterval
。
(1)snapCount
java 系统属性: ZooKeeper.snapCount
,默认100,000,表示每写100,000次事务日志,触发一次快照,并滚动事务日志,即切换新的事务日志文件。
但是,实际情况,快照是一个比较好性能的操作。为了防止集群中的所有机器同时触发快照操作,当事务日志中的事务数量达到运行时[ snapCount/2 + 1,snapCount ]
范围内生成的随机值时,该ZooKeeper
服务器就触发一次快照。
(2)日志清理
每一个快照日志文件都是zk集群某个时刻的全量数据快照,理论上只需要最新的一个快照日志文件及其后面的事务日志即可,所以定时清理一些不需要的日志文件以节省磁盘内存资源。
日志的清理跟autopurge.snapRetainCount
和autopurge.purgeInterval
有关。
-
autoburge.snapretaincount
表示保留多少个快照日志文件,如果启动日志清理功能,zk会保留autoburge.snapretaincount
个最近的快照日志文件和dataDir
和dataLogDir
中相应的事务日志文件,并删除其余的。autopurge.snapRetainCount
默认为3,最小也是3。 -
autopurge.purgeInterval
,清理任务触发的小时数时间间隔。设置为正整数(1及以上) ,以启用自动清洗。默认为0不启动。
4、什么时候触发数据快照
触发快照即生成新的快照日志文件有两种情况,事务日志写入数量达到阈值snapCount
和新Leader
同步数据。
(1)事务日志写入数量达到阈值snapCount
每进行一次事务日志记录之后,ZooKeeper
都会判断当前是否需要进行数据快照。前面也说过,理论上进行snapCount
次事务操作后就会触发一次数据快照,但是考虑到数据快照对zk集群的整体性能影响,需要尽量避免所有机器同时进行数据快照。
所以采用过半随机策略,某个ZooKeeper
服务器的事务次数在[ snapCount/2 + 1,snapCount ]
范围内生成的随机值时,触发数据快照。
满足快照条件后,ZooKeeper
先进行事务日志文件的切换,即创建新的事务日志文件,然后再异步进行数据快照操作,尽量不影响正常流程。
(2)新Leader同步数据
运行中的ZooKeeper
集群,如果发生Leader重新选举,新Leader所在机器会检查最近一次快照之后是否有事务日志产生,有就对最近的一次事务之前的全量数据做一次数据快照。
ZooKeeper
服务器启动期间,需要进行数据初始化工作,就是将磁盘中的日志文件加载到ZooKeeper
服务器内存中,主要包括两个过程:从快照日志文件中加载快照数据和根据事务日志进行数据修正。
1、加载并解析快照日志文件
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Linux运维工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Linux运维全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Linux运维知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加VX:vip1024b (备注Linux运维获取)
为了做好运维面试路上的助攻手,特整理了上百道 【运维技术栈面试题集锦】 ,让你面试不慌心不跳,高薪offer怀里抱!
这次整理的面试题,小到shell、MySQL,大到K8s等云原生技术栈,不仅适合运维新人入行面试需要,还适用于想提升进阶跳槽加薪的运维朋友。
本份面试集锦涵盖了
- 174 道运维工程师面试题
- 128道k8s面试题
- 108道shell脚本面试题
- 200道Linux面试题
- 51道docker面试题
- 35道Jenkis面试题
- 78道MongoDB面试题
- 17道ansible面试题
- 60道dubbo面试题
- 53道kafka面试
- 18道mysql面试题
- 40道nginx面试题
- 77道redis面试题
- 28道zookeeper
总计 1000+ 道面试题, 内容 又全含金量又高
- 174道运维工程师面试题
1、什么是运维?
2、在工作中,运维人员经常需要跟运营人员打交道,请问运营人员是做什么工作的?
3、现在给你三百台服务器,你怎么对他们进行管理?
4、简述raid0 raid1raid5二种工作模式的工作原理及特点
5、LVS、Nginx、HAproxy有什么区别?工作中你怎么选择?
6、Squid、Varinsh和Nginx有什么区别,工作中你怎么选择?
7、Tomcat和Resin有什么区别,工作中你怎么选择?
8、什么是中间件?什么是jdk?
9、讲述一下Tomcat8005、8009、8080三个端口的含义?
10、什么叫CDN?
11、什么叫网站灰度发布?
12、简述DNS进行域名解析的过程?
13、RabbitMQ是什么东西?
14、讲一下Keepalived的工作原理?
15、讲述一下LVS三种模式的工作过程?
16、mysql的innodb如何定位锁问题,mysql如何减少主从复制延迟?
17、如何重置mysql root密码?
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
怎么选择?
7、Tomcat和Resin有什么区别,工作中你怎么选择?
8、什么是中间件?什么是jdk?
9、讲述一下Tomcat8005、8009、8080三个端口的含义?
10、什么叫CDN?
11、什么叫网站灰度发布?
12、简述DNS进行域名解析的过程?
13、RabbitMQ是什么东西?
14、讲一下Keepalived的工作原理?
15、讲述一下LVS三种模式的工作过程?
16、mysql的innodb如何定位锁问题,mysql如何减少主从复制延迟?
17、如何重置mysql root密码?
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-3bm7J5on-1712564978487)]