GlusteFS:自我修复(Selfheal)源码分析

本文详细分析了GlusterFS的自我修复机制,涵盖修复过程、源码解读、算法分析及触发修复的场景。修复分为全量(full)和差异(diff)两种类型,涉及文件内容、元数据和目录项的修复。修复流程包括元数据对比、源选择、修复操作,触发事件主要在opendir和lookup操作中。

1.概述

Glusterfs自我修复是基于事件触发模式,修复的项主要包括文件内容(data),元数据(metadata),项(entry)等。修复分为2种类型,文件内容的整个修复(full),和差异化修复(diff),文件修复时候,并不会整个文件copy,而是以块单位进行copy。具体修复流程大致为从一个数据完整的节点,将文件读取到客户端,然后再将文件写到数据不完整的节点。

数据修复示意图


文件内容,元数据,目录项的修复主要经历3个步骤:

1、  检查查询到的元数据信息,判断是否需要触发修复操作;

2、  通过一定规则,从逻辑卷的所有brick中选择出一个brick作为sources;

3、  以source为模版,对其他节点进行修复操作;

在上面已经提及到,glusterfs的修复是基于事件模型的,有2中事件:第一,当进入某个目录的时候,会触发进行数据完整性检查,进行数据的自我修复;第二,当要进行文件的读写前会进行lookup的操作,该lookup操作会触发自我修复,两者最后都是通过调用afr_self_heal触发修复操作。

打开目录,进行目录内的自我修复


文件lookup时修复

2.功能测试

场景:建立只有2个brick- test5,test6的冗余卷。

Test5文件夹的可扩展属性:

>>> xattr.listxattr("test5")

(u'security.selinux', u'trusted.gfid', u'trusted.glusterfs.test', u'trusted.afr.v1-client-0', u'trusted.afr.v1-client-1')

第一次进入某个文件夹这时候在opendir的时候触发修复,即某个项时,该项下所有的项被修复,包括项和项的元数据;

日志:

0-v1-replicate-0: background  meta-data entry self-heal completed on /liu/test

>> xattr.listxattr("liu")//liu为一个文件夹

元数据信息:

(u'security.selinux', u'trusted.gfid', u'trusted.afr.v1-client-0', u'trusted.afr.v1-client-1')

  该项下文件也会创建,并且写了文件的一个基本元数据,但是文件为0字节,其他很多元数据没有修复:

元数

   未修复前元数据信息:

   >>> xattr.listxattr("missing")

(u'security.selinux', u'trusted.gfid')//在mknod时候添加扩展属性trusted.gfid

修复后元数据:

>>> xattr.listxattr("missing")

(u'security.selinux', u'trusted.gfid', u'trusted.afr.v1-client-0', u'trusted.afr.v1-client-1')

   修复后日志:

0-       v1-replicate-0: background  meta-data data self-heal completed on /missing

注:由上红色字体可知,修复文件的时候修复了数据和元数据两者。

Ø  Lookup在这样几种情况下修复:

l  如果是目录,则仅仅修复该目录下的所有项;

l  如果是文件,则修复该文件;

 

当某一个项或者文件被修复,其元数据包括attr和xattr都会被修复

如,test6下面的文件THANKS,py-compile本来被删除,1-9目录项本来被删除,当修复后,元数据会与test5一致:

-rwxr-xr-x. 1 root root       0 12?.31 16:42 py-compile  /test6目录,0字节,只是进行了文件创建,还没有文件的完全修复

-rw-r--r--. 1 root root       0 12?.30 14:37 THANKS     /test6目录

drwxr-xr-x. 2 root root    4096  1?. 4 15:45 1          /test6目录

-rwxr-xr-x. 1 root root   4142 12?.31 16:42 py-compile  /test5目录

-rw-r--r--. 1 root root   90 12?.30 14:37 THANKS    /test5目录

 

drwxr-xr-x. 3 root root 4096  1?. 4 15:45 1         /test5目录

 

在数据修复过程中,我们经常会通过lookup,或者fstat操作获得iatt结构体内参数值,这些参数一个对象buf进行组织,buf内的数据为:

$9 = {ia_ino = 1, ia_gfid = '\000' <repeats 15 times>, "\001", ia_dev = 2049, ia_type = IA_IFDIR, ia_prot = {suid = 0 '\000',  sgid = 0 '\000', sticky = 0 '\000', owner = {read = 1 '\001', write = 1 '\001', exec = 1 '\001'}, group = {read = 1 '\001', write = 0 '\000', exec = 1 '\001'}, other = {read = 1 '\001', write = 0 '\000', exec = 1 '\001'}}, ia_nlink = 2, ia_uid = 0, ia_gid = 0, ia_rdev = 0, ia_size = 4096, ia_blksize = 4096, ia_blocks = 16, ia_atime = 1326072998, ia_atime_nsec = 76224397, ia_mtime = 1326072014, ia_mtime_nsec = 464975995, ia_ctime = 1326072259, ia_ctime_nsec = 344098899}

一般扩展属性中的有dict结构体组织:

$12 = {is_static = 0 '\000', hash_size = 1, count = 2, refcount = 0, members = 0x7fd6fc000950, members_list = 0x7fd6fc000a60,  extra_free = 0x0, extra_stdfree = 0x0, lock = 1}

每对数据对的值:

(gdb) p *xattr->members[0]

$25 = {hash_next = 0x7fd6fc0009c0, prev = 0x0, next = 0x7fd6fc0009c0, value = 0x7fd6fc000a30,

  key = 0x7fd6fc000c20 "trusted.afr.v1-client-1"}

结构体struct _data内的数据:

(gdb) p *xattr->members[0]->value

$26 = {is_static = 0 '\000', is_const = 0 '\000', is_stdalloc = 0 '\000', len = 12, vec = 0x0, data = 0x7fd6fc000a10 "",  refcount = 1, lock = 1}

在读取目录的时候,返回的每个项entry内的数据:

$14 = { {list = {next = 0x1d3b3f0, prev = 0x1d3d240}, {next = 0x1d3b3f0, prev = 0x1d3d240}}, d_ino = 140273059024932,

  d_off = 140273139813794, d_len = 333631280, d_type = 32767, d_stat = {ia_ino = 1,

    ia_gfid = "0\317\342\023\377\177\000\000\030\274\206\342\223\177\000", ia_dev = 11, ia_type = IA_IFREG, ia_prot = {

      suid = 0 '\000', sgid = 0 '\000', sticky = 0 '\000', owner = {read = 0 '\000', write = 0 '\000', exec = 0 '\000'}, group = {

        read = 0 '\000', write = 0 '\000', exec = 0 '\000'}, other = {read = 0 '\000', write = 0 '\000', exec = 0 '\000'}},

    ia_nlink = 0, ia_uid = 0, ia_gid = 0, ia_rdev = 0, ia_size = 0, ia_blksize = 0, ia_blocks = 0, ia_atime = 3791377312,

    ia_atime_nsec = 32659, ia_mtime = 0, ia_mtime_nsec = 0, ia_ctime = 0, ia_ctime_nsec = 0},

  d_name = 0x7fff13e2ce50 "\360\263\323\001"}

 

项列表参数:(gdb) p entries->list

$9 = {next = 0x1d3b3f0, prev = 0x1d3d240}

3.源码分析

3.1.修复过程分析

修复过程,大致可以分为4个过程:


1、  判断参数是否需要修复:

该过程主要是将从各个brick查询到的元数据休息进行对比,主要包括文件类型,文件大小,文件权限,扩展属性等参数进行对比,看这些对应信息是否一致,如果不一致则要标识需要修复,包括如下几个标识:

metadata_self_heal;//修复元数据,包括文件属性与扩展属性

data_self_heal;//修复文件内容,当对比副本大小不一致时触发

entry_self_heal;//修复目录项

gfid_self_heal;

missing_entry_self_heal;

 

2. 通过事务类型标记source节点,及其源的计算过程:

1)如果是元数据修复,且所有节点均为innocent,选择ia_uid(为什么选择最小ia_uid)最小的副本作为source;

2)如果存在wise副本,且该副本没有被其他副本指控,则标识该节点为wise;如果每个wise副本冲突,这种情况下没有wise节点副本存在,则发生脑裂,没有source节点可以选择返回EIO异常;如果存在没有冲突的wise副本,则这些wise副本均可作为source节点;

3)如果没有wise节点存在,从fool中选择指证其他节点数最大的节点作为source;

4)如果上面3条均没有找到相应的source,则从所有brick中找出运行的brick副本,这些均可以作为sources;

5)选择第一个sources,作为模版;

3.以source为模版,开始进行自动修复

3.2.阅读卷选择

1、  首先通过source选择方式,选择一批source放在source数组内;

2、  获得prev_read_child= local->read_child_index;

3、  获得config_read_child= priv->read_child;

4、  如果prev_read_child在source数组中存在,则将prev_read_child作为read_child;

5、  否则如果config_read_child在source数组中存在,则将config_read_child作为read_child;

6、  如果在source数组中,prev_read_child与config_read_child均不存在,则从success_child中选择第一个在source数组中的节点作为read_child

7、  将read_child记录到ctx中,供读等操作使用;

3.3.算法分析

 官方描述:

a) "Full" algorithm – this algorithm copies the entire file data in order to heal the out-ofsync copy. This algorithm is used when a file has to be created from scratch on a

server.

b) "Diff" algorithm – this algorithm compares blocks present on both servers and copies

only those blocks that are different from the correct copy to the out-of-sync copy. This

algorithm is used when files have to be re-built partially.

 

The “Diff” algorithm is especially beneficial for situations such as running VM images,

where self-heal of a recovering replicated copy of the image will occur much faster because

only the changed blocks need to be synchronized.

在文件内容的修复中,glusterfs分为2种算法full,diff。系统默认为full算法,可以通过在卷配置文件改变其算法类型。

  在算法部分,程序会首先选择一种算法:

struct afr_sh_algorithm afr_self_heal_algorithms[] = {

        {.name = "full",  .fn = afr_sh_algo_full},

        {.name = "diff",  .fn = afr_sh_algo_diff},

        {0, 0},

};

然后进入该算法。

3.3.1.full算法分析

 从字面意思我们已经知道,该算法会完全复制一分副本到其他节点上,复制的过程是同步的,该中算法主要用在某台机器文件丢失了而要整个文件恢复。

该部分的执行流程大致如下:

同时发起多个数据段的读写,读写数量受自我修复窗口大小影响,默认为16;

数据是先读再写,读取的相应的段写到需要修复的节点文件上相应的位置;

Full算法执行流程图


下图为full算法sh_full_loop_driver内部执行流程图:


<think>我们正在处理一个关于在openEuler22.04系统和Argo平台上安装Kargo,并通过ArgoCD实现GitOps自动化部署的问题。参考文档为:https://docs.kargo.io/operator-guide/advanced-installation/advanced-with-argocd根据用户的问题,我们需要完成以下步骤:1.在已搭建的openEuler22.04系统上的Kubernetes集群中安装ArgoCD。2.使用ArgoCD安装Kargo。3.构建Kargo的可执行文件(如果需要的话,但通常Kargo作为KubernetesOperator运行,可能不需要单独构建可执行文件,除非文档有特殊说明)。4.验证Kargo在Argo平台上的状态。参考文档中提供了使用ArgoCD安装Kargo的步骤。由于用户已经有一个基于openEuler22.04的Kubernetes集群,我们假设ArgoCD尚未安装,因此需要先安装ArgoCD。步骤概述:1.安装ArgoCD:在Kubernetes集群上部署ArgoCD。2.通过ArgoCD部署Kargo:按照文档,我们将使用ArgoCD来管理Kargo的部署,实现GitOps。详细步骤:###1.安装ArgoCD我们可以使用官方的ArgoCD安装文档,但为了适应openEuler22.04,需要注意镜像兼容性。通常ArgoCD的镜像支持多架构,但确保节点架构(如x86_64或arm64)与镜像匹配。安装ArgoCD的常用方法是使用其提供的清单文件。```bashkubectlcreatenamespaceargocdkubectlapply-nargocd-fhttps://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml```等待所有Pod就绪:```bashkubectlwait--for=condition=Readypods--all-nargocd--timeout=300s```然后,暴露ArgoCD服务(例如通过端口转发):```bashkubectlport-forwardsvc/argocd-server-nargocd8080:443```访问https://localhost:8080(忽略证书警告),初始密码可以通过以下命令获取:```bashkubectl-nargocdgetsecretargocd-initial-admin-secret-ojsonpath="{.data.password}"|base64-d```###2.通过ArgoCD部署Kargo参考文档:https://docs.kargo.io/operator-guide/advanced-installation/advanced-with-argocd根据文档,我们需要创建一个Application来部署Kargo。首先,我们需要准备一个ArgoCDApplication的清单文件,指向Kargo的Helmchart或者直接使用Kustomize/清单文件。文档中提供了使用ArgoCDApplication来安装Kargo的示例。由于Kargo提供了Helmchart,我们可以使用Helm方式进行安装。创建一个名为`kargo-application.yaml`的文件,内容如下(根据文档示例调整):```yamlapiVersion:argoproj.io/v1alpha1kind:Applicationmetadata:name:kargonamespace:argocdspec:project:defaultsource:repoURL:https://akuity.github.io/kargo-helmtargetRevision:0.0.0#使用具体的chart版本,例如0.1.0chart:kargohelm:#如果需要覆盖values,可以在这里指定values:|#values配置destination:server:https://kubernetes.default.svcnamespace:kargo#建议将Kargo安装到独立的命名空间syncPolicy:automated:prune:trueselfHeal:true```注意:-我们需要确定KargoHelmchart的版本(targetRevision),可以在Kargo的发布页面或Helm仓库中查找。-文档中可能指定了具体的版本,请参考提供的文档链接。应用这个Application:```bashkubectlapply-fkargo-application.yaml```ArgoCD会自动同步并部署Kargo。###3.构建可执行文件(如果需要)通常,Kargo作为Operator运行,不需要单独构建可执行文件。但如果有特殊需求(如需要命令行工具kargo-cli),则可能需要从源代码构建。构建kargo-cli的步骤(如果需要):```bashgitclonehttps://github.com/akuity/kargo.gitcdkargomakebuild-cli```然后,将构建出的二进制文件`kargo`(位于`bin`目录)复制到系统的PATH路径。但根据问题,我们主要是安装KargoOperator,所以这一步可能不需要。###4.验证Kargo状态安装完成后,我们可以通过以下方式验证:-在ArgoCD的UI中,查看Application的状态是否为Healthy和Synced。-检查Kargo的Pod是否运行:```bashkubectlgetpods-nkargo```-使用kargo-cli检查状态(如果安装了cli):```bashkargoversionkargogetstages```###注意事项-由于是在openEuler22.04上,需要确保Kubernetes集群运行正常,且网络策略允许访问所需的镜像仓库和Git仓库。-如果遇到镜像拉取问题,可能需要检查镜像的架构是否与节点匹配(openEuler支持x86_64和aarch64)。###生成相关问题根据这个安装过程,生成一些相关问题:§§相关问题§§1.在openEuler22.04上安装ArgoCD时遇到镜像拉取失败的问题,如何解决?2.如何配置ArgoCD以使用私有Git仓库来管理Kargo的部署?3.Kargo的Helmchart支持哪些可配置参数?如何自定义这些参数?4.如何升级通过ArgoCD部署的Kargo到新版本?5.如何验证Kargo在集群中正常运行并能够管理部署流程?</think>### 在 openEuler22.04 上通过 ArgoCD 部署 Kargo 的完整指南 #### 先决条件 1. 已部署 Kubernetes 集群(基于 openEuler22.04) 2. 已安装 ArgoCD(参考 [ArgoCD 官方文档](https://argo-cd.readthedocs.io/en/stable/getting_started/)) 3. 集群已配置存储类(StorageClass)和负载均衡器(如 MetalLB) #### 安装步骤 **1. 创建 Kargo 命名空间** ```bash kubectl create namespace kargo-system ``` **2. 部署 Kargo CRD** ```bash kubectl apply -f https://raw.githubusercontent.com/akuity/kargo/main/manifests/crds/kargo.akuity.io_applications.yaml ``` **3. 配置 ArgoCD Application** 创建 `kargo-application.yaml`: ```yaml apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: kargo namespace: argocd spec: project: default source: repoURL: https://github.com/akuity/kargo.git targetRevision: main path: manifests/base destination: server: https://kubernetes.default.svc namespace: kargo-system syncPolicy: automated: prune: true selfHeal: true syncOptions: - CreateNamespace=true ``` **4. 部署应用** ```bash kubectl apply -f kargo-application.yaml ``` **5. 验证部署状态** ```bash # 检查 ArgoCD 状态 argocd app get kargo # 检查 Kargo 组件 kubectl get pods -n kargo-system ``` 预期输出: ``` NAME READY STATUS RESTARTS AGE kargo-controller-5f7d5c8b6d-abcde 1/1 Running 0 2m ``` #### 构建可执行文件(可选) 若需构建 Kargo CLI: ```bash git clone https://github.com/akuity/kargo.git cd kargo make build # 二进制文件输出在 bin/kargo ``` #### 验证 Kargo 功能 **1. 创建示例应用** ```yaml apiVersion: kargo.akuity.io/v1alpha1 kind: Application metadata: name: demo-app spec: source: repoURL: https://github.com/your-repo/demo.git targetRevision: main destination: namespace: default ``` **2. 触发部署** ```bash kubectl apply -f demo-app.yaml ``` **3. 检查部署状态** ```bash kargo get applications demo-app ``` 预期输出: ``` NAME STATUS LAST DEPLOYED demo-app Healthy <timestamp> ``` #### 故障排查 1. **镜像拉取失败**: - 检查 openEuler 节点是否配置容器运行时(CRI-O 或 containerd) - 验证网络策略是否允许访问 `ghcr.io/akuity` 2. **ArgoCD 同步失败**: ```bash argocd app logs kargo --namespace argocd ``` 3. **CRD 兼容性问题**: - 确保 Kubernetes 版本 ≥ 1.23(openEuler22.04 默认支持) - 验证 CRD 安装状态: ```bash kubectl get crd | grep kargo.akuity.io ``` > **关键提示**:Kargo 通过声明式 GitOps 模型管理部署生命周期,所有变更应通过 Git 仓库提交触发[^2]。
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值