1 说明
软件版本:GlusterFS6.10
操作系统:CentOS Linux release 7.8.2003 (Core)
本文以2副本+1仲裁卷进行解释说明,卷参数配置如下:
Volume Name: vol1
Type: Replicate
Volume ID: dba77e5d-3e70-4ff5-98d9-de2583a05f62
Status: Started
Snapshot Count: 0
Number of Bricks: 1 x (2 + 1) = 3
Transport-type: tcp
Bricks:
Brick1: 10.10.176.232:/c001_vol1
Brick2: 10.10.176.221:/c001_vol1
Brick3: 10.10.176.188:/c001_vol1_arbiter (arbiter)
Options Reconfigured:
performance.client-io-threads: off
nfs.disable: on
transport.address-family: inet
2 数据不一致的产生
2.1 数据写入
gluster副本卷会同时写入多个副本,每个基于写入的 FOP 都采用由 5 个阶段组成的写入事务模型:
- Lock 阶段 锁定正在修改文件,以便其他客户端的 AFR 在尝试同时修改同一文件时被阻止;
- Pre-op 阶段 在所有参与的 brick 上将 xattr (trusted.afr.dirty) 增加 1,作为即将发生 FOP 的指示;
- FOP 阶段 在所有 brick 上执行实际的 FOP(比如 setfattr)
- Post-op 阶段 在 FOP 成功的 brick 上将脏 xattr (trusted.afr.dirty) 减 1。此外,还要增加成功 brick 上的“待处理”xattr (trusted.afr.$VOLNAME-client-x) xattr,以识别 FOP 失败的 brick;
- Unlock 阶段 释放在阶段 1 中获得的锁。任何竞争客户端现在都可以继续自己的写入事务。
2.2 扩展属性说明
2.2.1 trusted.afr.dirty
trusted.afr.dirty 的前8个数字表示数据(data)的变化,接下来的8个数字表示元数据(metadata)的变化 最后8个数字表示目录项目(entry)的变化
不同的文件操作会导致扩展属性值变化:
FOP | Value after pre-op phase | Value after post-op phase |
---|---|---|
afr_writev | trusted.afr.dirty=0x00000001 00000000 00000000 | trusted.afr.dirty=0x00000000 00000000 00000000 |
afr_setattr | trusted.afr.dirty=0x00000000 00000001 00000000 | trusted.afr.dirty=0x00000000 00000000 00000000 |
afr_create | trusted.afr.dirty=0x00000000 00000000 00000001 | trusted.afr.dirty=0x00000000 00000000 00000000 |
因此,根据FOP的类型(即数据/元数据/目录项事务),dirty xattr的不同字节集会递增/递减,只有在某些brick上的FOP失败时,它才会在操作后增加。
2.2.2 trusted.afr.volname-client-subvolume-index
trusted.afr.volname-client-subvolume-index用来维护文件的changelog。该值是由glusterfs客户端(fuse或nfs服务器)进程计算的。
当glusterfs客户端修改文件或目录时,客户端会联系每个brick,并根据brick的响应更新扩展属性。
subvolume-index是在gluster volume info<volname>输出中的(brick number - 1),以我们的测试卷为例,对应的3个brick对应的扩展属性分别为
trusted.afr.vol1-client-0、trusted.afr.vol1-client-1、rusted.afr.vol1-client-2
trusted.afr.volname-client-subvolume-index的前8个数字表示数据(data)的changelog,接下来的8个数字表示元数据(metadata)的changelog 最后8个数字表示目录项(entry)的changelog
0x 000003d7 00000001 00000000
| | |
| | \_ changelog of directory entries
| \_ changelog of metadata
\ _ changelog of data
对于目录,元数据和目录项changelog是有效的,对于文件,数据和元数据的changelog是有效的,对于一些如设备文件之类的特殊文件,元数据changelog是有效的。
2.3 副本状态
根据副本的changeLog数值可以确定副本的几种状态
WISE:即该副本的ChangeLog中对方对应的数值大于0而且自身对应的数值等于0.
INNOCENT:即该副本上的ChangeLog即不指责对方也不指责自己,ChangeLog全为0.
FOOL:即该副本上的ChangeLog是指责自己的。
IGNORANT:即该副本的ChangeLog丢失。
2.4 数据不一致
1、当两节点都是WISE状态时,这就出现了声名狼藉的脑裂状态。通常3副本或者2副本+仲裁不会出现脑裂。
2、脑裂的处理:https://docs.gluster.org/en/main/Troubleshooting/resolving-splitbrain/
脑裂示例(同时发生数据和元数据脑裂):
副本1:
#file: gfs/brick-a/a
trusted.afr.vol-client-0=0x000000000000000000000000
trusted.afr.vol-client-1=0x000003d70000000100000000
trusted.gfid=0x80acdbd886524f6fbefa21fc356fed57
副本2:
#file: gfs/brick-b/a
trusted.afr.vol-client-0=0x000003b00000000100000000
trusted.afr.vol-client-1=0x000000000000000000000000
trusted.gfid=0x80acdbd886524f6fbefa21fc356fed57
3、除脑裂外的数据不一致可自动修复,具体方法见下一章。
3 数据不一致的修复
3.1 补充说明
在文件写入事务的五个阶段,还有一个细节:
在 pre-op 阶段,除了标记 trusted.afr.dirty 之外,每个 brick 还将文件的 gfid 字符串存储在其 .glusterfs/indices/dirty 目录中。
在 post-op 阶段,brick会从其 .glusterfs/indices/dirty 中删除 gfid 字符串。如果在某些 brick 上写入失败,则成功的 brick 会将 gfid 字符串存储在 .glusterfs/indices/xattrop 目录
中。因此,当文件上没有发生 I/O 并且在 .glusterfs/indices/dirty 中存在 brick 的 gfid 时,这意味着 brick 在 post-op 操作阶段之前发生了故障。 如果在 .glusterfs/indices/xattrop 中找到 gfid,则意味着在其他 brick 上发生了写入失败。
glustershd 读取 .glusterfs/indices/* 中的条目列表并在它们上触发修复, 这称为索引修复。
3.2 修复触发
如下情况时会触发修复:
- Self-heal进程周期扫描 bricks/.glusterfs/indices/xattrop/目录 (进程默认每 10 分钟一次;可通过 heal-timeout 选项调整)
- 客户端访问目标文件
- 执行命令 gluster volume heal
3.3 修复分类
数据(data)修复:仅对文件发生。 文件的内容从 source 复制到 sink。
元数据(metadata)修复:文件和目录都会发生。 文件所有权、文件权限和扩展属性从 source 复制到 sink。
目录项(entry)修复:仅对目录发生。 如果 source 中不存在给定目录下的条目(即文件和子目录),则它们将从 sink 中删除。 同样,如果条目不存在于 source 中,则会在 sink 上创建条目。
对于给定的文件,一组 brick 可能是数据修复的 source,而另一组 brick 可能是元数据修复的 source。这完全取决于哪些 FOP 在哪些 brick 上失败。
如果 self-heal 观察到具有非零 xattrs 的文件,它会执行以下步骤:
- 获取 afr xattrs,检查哪一组 8 个字节是非零的,并确定文件所需的相应修复 - 即数据修复/元数据修复/目录项修复。
- 通过 xattr 值来判断哪些 brick 是好的(sources)和哪些是坏的(sinks)。
- 选择 source brick,并以它来修复 sink brick。
- 如果修复成功,则将 afr xattrs 重置为零。
4 操作示例
4.1 正常写入文件
副本节点1
root@sims-node1[/c001_vol1]# getfattr -d -m . -e hex file1
# file: file1
trusted.afr.dirty=0x000000000000000000000000
trusted.gfid=0x16fe42dc8223445fab9ccc9521d03163
trusted.gfid2path.d16e15bafe6e4256=0x30303030303030302d303030302d303030302d303030302d3030303030303030303030312f66696c6531
trusted.glusterfs.mdata=0x01000000000000000000000000665fc4cc0000000017a08ddb00000000665fc4cc0000000017a08ddb00000000665fbfb4000000000f5cda87
副本节点2
root@sims-node2[/c001_vol1]# getfattr -d -m . -e hex file1
# file: file1
trusted.afr.dirty=0x000000000000000000000000
trusted.gfid=0x16fe42dc8223445fab9ccc9521d03163
trusted.gfid2path.d16e15bafe6e4256=0x30303030303030302d303030302d303030302d303030302d3030303030303030303030312f66696c6531
trusted.glusterfs.mdata=0x01000000000000000000000000665fc4cc0000000017a08ddb00000000665fc4cc0000000017a08ddb00000000665fbfb4000000000f5cda87
仲裁节点
root@sims-node3[/c001_vol1_arbiter]# getfattr -d -m . -e hex file1
# file: file1
trusted.afr.dirty=0x000000000000000000000000
trusted.gfid=0x16fe42dc8223445fab9ccc9521d03163
trusted.gfid2path.d16e15bafe6e4256=0x30303030303030302d303030302d303030302d303030302d3030303030303030303030312f66696c6531
trusted.glusterfs.mdata=0x01000000000000000000000000665fbfb4000000000f5cda8700000000665fbfb4000000000f5cda8700000000665fbfb4000000000f5cda87
4.2 写入过程brick进程异常
副本节点1写入成功,trusted.afr.dirty正常,存在属性值trusted.afr.vol1-client-1,自己正常,指责brick2异常
root@sims-node1[/c001_vol1]# getfattr -d -m . -e hex file5
# file: file5
trusted.afr.dirty=0x000000000000000000000000
trusted.afr.vol1-client-1=0x000000020000000000000000
trusted.gfid=0xaac4ba54db614de18360046ae1230262
trusted.gfid2path.1517de5c13a1c906=0x30303030303030302d303030302d303030302d303030302d3030303030303030303030312f66696c6535
trusted.glusterfs.mdata=0x01000000000000000000000000665fd409000000001fe6a9f200000000665fd409000000001fe6a9f200000000665fd402000000000f2fb3c4
此时,副本节点1 .glusterfs/indices/xattrop目录下存在aac4ba54-db61-4de1-8360-046ae1230262
索引
root@sims-node1[/c001_vol1/.glusterfs/indices/xattrop]# ls -al
total 0
drw------- 2 root root 102 Jun 5 10:57 .
drw------- 5 root root 55 Apr 29 10:23 ..
---------- 2 root root 0 Jun 4 09:46 aac4ba54-db61-4de1-8360-046ae1230262
---------- 2 root root 0 Jun 4 09:46 xattrop-883ac3e0-3426-4efb-9342-7495fdd0627f
写入过程中kill了副本节点2的brick进程,因此trusted.afr.dirty的数据内容为1(因为没有成功,所以没有减1)
root@sims-node2[/c001_vol1]# getfattr -d -m . -e hex file5
# file: file5
trusted.afr.dirty=0x000000010000000000000000
trusted.gfid=0xaac4ba54db614de18360046ae1230262
trusted.gfid2path.1517de5c13a1c906=0x30303030303030302d303030302d303030302d303030302d3030303030303030303030312f66696c6535
trusted.glusterfs.mdata=0x01000000000000000000000000665fd406000000001b2741e900000000665fd406000000001b2741e900000000665fd402000000000f2fb3c4
仲裁节点,trusted.afr.dirty正常,存在属性值trusted.afr.vol1-client-1,自己正常,指责brick2异常
root@sims-node3[/c001_vol1_arbiter]# getfattr -d -m . -e hex file5
# file: file5
trusted.afr.dirty=0x000000000000000000000000
trusted.afr.vol1-client-1=0x000000020000000000000000
trusted.gfid=0xaac4ba54db614de18360046ae1230262
trusted.gfid2path.1517de5c13a1c906=0x30303030303030302d303030302d303030302d303030302d3030303030303030303030312f66696c6535
trusted.glusterfs.mdata=0x01000000000000000000000000665fd402000000000f2fb3c400000000665fd402000000000f2fb3c400000000665fd402000000000f2fb3c4
此时,仲裁节点 .glusterfs/indices/xattrop目录下存在aac4ba54-db61-4de1-8360-046ae1230262
索引
root@sims-node1[/c001_vol1/.glusterfs/indices/xattrop]# ls -al
total 0
drw------- 2 root root 102 Jun 5 10:57 .
drw------- 5 root root 55 Apr 29 10:23 ..
---------- 2 root root 0 Jun 4 09:46 aac4ba54-db61-4de1-8360-046ae1230262
---------- 2 root root 0 Jun 4 09:46 xattrop-883ac3e0-3426-4efb-9342-7495fdd0627f
恢复brick进程后,自动修复