CubeFS 核心能力剖析 | 自动化运维

文摘   2024-11-07 10:07   中国香港  


01 引言



CubeFS 在 3.3.1 版本中加入了数据分区(下文简称 dp)下线限速功能,即以 nodeSet 为单位,对其同时下线的最大 dp 数目进行控制。但是由于下线过程没有原子性保证,副本组就可能因为网络中断,数据节点可用空间不足等问题,导致副本组最终可能出现缺少 leader,副本数不足等异常场景,这部分异常 dp 也会需要耗费一定的运维精力去人工处理。


除此之外,对于集群中的坏盘,也需要运维人员及时将坏盘上的 dp 迁移走,保证用户数据的可靠性。因此在 3.4.0 版本中,我们提供了异常 dp 自愈以及下线原子性,坏盘自动迁移的功能,来降低集群日常运维的人力成本。



02 异常 dp 自愈



异常 dp 自愈的功能会在两个地方进行执行:


  • 在 master 上的 dp 元数据定期检测任务 scheduleToCheckDataReplicaMeta。主要用于对集群存量的异常 dp 进行修复。

  • 在 master 标记 dp 为 markDecommission(可下线)之前。如果 dp 副本存在异常并且在执行下线操作前能够进行修复,那么可以提高 dp 下线的成功率。



元数据自愈功能可以通过 cfs-tool cluster set  --autoDpMetaRepair true/false 开启/关闭


上图是 dp 执行异常修复的流程:


  1. 通过副本上报的 peers 和 master 上 dp 的 peers 进行比较,删除副本上存在,但是 master 不存在的 peer。

  2. 通过副本上报的 peers 和 master 上 dp 的 peers 进行比较,删除 master 上存在,但是副本不存在的 peer。

  3. 如果 dp 的 replica 数组的长度小于 dp 的副本数 ReplicaNum,则自动添加缺失副本。


由于 dp 的下线过程中会涉及 peers 以及 hosts 的修改,因此需要将 dp 的下线流程与自愈流程进行互斥。



自愈修复的状态机的初始状态为 Stop。


当执行下线操作时,dp 尝试将状态机状态切换为 Forbidden,如果切换失败,则返回错误,表示 dp 正在进行自愈,无法下线;如果切换成功,表明 dp 正在下线,无法执行自愈操作,并在下线结束时切换回 Stop 状态。


当执行元数据自愈时,dp 尝试将状态机状态切换为 Running,如果切换失败,则返回错误,表示 dp 正在执行下线,无法进行自愈;如果切换成功,表明 dp 正在进行自愈流程,无法执行下线操作,并在自愈结束时切换回 Stop 状态。



03 下线原子性



在 dp 下线过程中,如果遇到 master 切主、新建 dp 副本所在磁盘写满等异常情况,可能会导致下线过程阻塞,或者下线过程结束后副本组丢失副本等错误。


为了保证 dp 下线的正确性,我们会将下线状态进行持久化,从而保证下线过程的原子性,以 dp 为例,增加了以下与下线相关的需要进行持久化属性。


type DataPartition struct {   ...   DecommissionRetry              int       //下线重试次数   DecommissionStatus             uint32    //下线状态   DecommissionSrcAddr            string    //下线源地址   DecommissionDstAddr            string    //下线目标地址   DecommissionRaftForce          bool      //下线操作是否使用 raftForce   DecommissionSrcDiskPath        string    //下线的源磁盘   DecommissionTerm               uint64    //下线的起始时间   DecommissionDstAddrSpecify     bool      //是否为定点迁移   DecommissionNeedRollback       bool      //是否需要回滚   DecommissionNeedRollbackTimes  uint32    //下线的回滚次数   DecommissionErrorMessage       string    //下线失败的错误信息   RecoverStartTime               time.Time //开始修复的时间   DecommissionType               uint32    //下线类型   RestoreReplica                 uint32    //自愈修复的状态机}


dp 的下线状态机包含以下状态:



initial:初始状态。


mark:待下线状态。当执行节点/磁盘下线时,其包含的 dp 会被标记为待下线状态,等待下线资源。


prepare:准备下线状态。待下线的 dp 由 master 进行限速控制,当获取到 token 后,则转为准备下线状态。这个阶段主要做一些下线条件的检测操作,比如副本的存活数是否满足下线条件等。


running:开始下线状态。该阶段是等待新建副本的修复过程。


success:下线成功状态。表明新建副本已经完成修复。


fail:下线失败状态。表明下线过程中遇到了错误。


为了提高下线操作的成功率,减少人工干预的次数,下线过程引入了错误重试与回滚的机制。在 prepare 以及 running 状态中,可能会遇到网络抖动引起的副本组存活数不足,缺少 leader 等场景,那么通过重试等待网络恢复或者副本组重新选举,可以恢复到满足下线条件的状态再重新自动执行下线操作。


而另外的一些特殊情况,比如新建副本的所在节点没空间了,或者出现 diskError 等,无法通过重试,只能重新选择新的节点来新建副本的场景时,则通过回滚的机制来重新执行下线操作。


无论是错误重试还是回滚机制,都有最大的次数限制,当尝试次数达到最大值仍无法下线成功时,dp 的下线状态会被设置为失败状态。


当状态机的状态发生变化时,会立即进行持久化。当 master 重启或者切主的时候,master 从 rocksdb 加载 dp 的元数据时,会恢复之前的下线状态,从而保证下线过程的原子性。



04 坏盘自动迁移




dp 副本在读写磁盘时,如果遇到 IO 错误,则会登记到所属磁盘的 IO 错误 dp 列表中,并将磁盘的读写状态设置为 unavaliable,从而保证该磁盘无法继续创建新的 dp 以及数据的读写操作。


磁盘巡检本身也可能会触发 IO 错误,但是由于巡检操作不涉及任何 dp,因此将特殊值 0 登记到磁盘的 IO 错误 dp 列表中。


考虑到 datanode 可能在坏盘处理完毕之前遇到重启等情况,在 dp 遇到 IO 错误时,会将错误次数持久化到本地的 dp 元数据中。从而保证 datanode 重启加载磁盘上的 dp 时,能够正确将磁盘重新标记为 unavaliable 状态。


当 datanode 构建心跳响应消息时,会将状态为 unavaliable 的磁盘信息,上报给 master。由 master 的定时任务,自动将坏盘放置到下线列表中并执行磁盘下线操作,即坏盘上的副本删除并在集群中其他节点的正常磁盘上新建副本,从而保证 dp 副本组的可靠性。



05 自动化运维最佳实践



在 3.4.0 版本中,新增了大量的 api 命令以及 cli 操作来管理集群的下线操作。在这个章节中,将对

一些常用的管理命令进行介绍。


查询集群的下线配置


通过./cfs-cli cluster info 可以查看集群当前的配置信息,其中和下线相关的有如下配置


[root]# ./cfs-cli cluster info        [Cluster]  ...  DpRepairTimeout                  : 2h0m0s  EnableAutoDecommission           : true  AutoDecommissionDiskInterval     : 10s  EnableAutoDpMetaRepair           : true  AutoDpMetaRepairParallelCnt      : 100  DecommissionDpLimit            : 50  DecommissionDiskLimit            : 10  DpBackupTimeout            : 168h0m0s


DpRepairTimeout:dp 副本修复的超时时间。如果在这个时间间隔内,副本的进度没有任何变化,则会触发 dp 下线的回滚机制,重新执行下线操作。建议 SSD 盘设置在 20min,HDD 盘可以设置在 40min。


EnableAutoDecommission: 集群是否开启了坏盘自动下线。建议开启,节省运维成本。


AutoDecommissionDiskInterval:在开启坏盘自动下线的情况下,master 检测到 dataNode 上报的坏盘信息后,多久才开始执行下线。如果期望有足够的时间进行人工故障恢复坏盘,减少不变要的迁移,则可以将间隔设置久些,比如 20min。


EnableAutoDpMetaRepair: 集群是否开启异常 dp 自愈。自愈过程会涉及副本元数据的修改以及副本添加操作,用户可以根据自身需求决定是否开启。建议开启,节省运维成本。


AutoDpMetaRepairParallelCnt: 异常 dp 自愈的并发数。建议设置为 100。


DecommissionDpLimit:每个 nodeset 同时下线 dp 的并发数。默认值为 10,建议设置为 100。


DecommissionDiskLimit: 每个 nodeset 同时下线磁盘的并发数。默认值为 1,建议设置为 10。


DpBackupTimeout:通过 raftForce 删除的副本,会暂时保留。待 DpBackupTimeout 到期后,再删除。


以上参数均可通过 cfs-cli cluster set 命令进行配置,详细信息可以通过 cfs-cli cluster set --help 命令进行查看。


查询副本修复进度


通过./cfs-cli datapartition check 命令,可以观察到集群中的 dp 状态


[root]# ./cfs-cli datapartition check [Inactive Data nodes]:ID        ZONE      ADDRESS                                                              USED      TOTAL     STATUS    REPORT TIME
[Corrupt data partitions](no leader):ID          VOLUME      REPLICAS       STATUS          MEMBERS          
[Partition lack replicas]:ID          VOLUME      REPLICAS       STATUS          MEMBERS          

[Bad data partitions(decommission not completed)]:PATH        PARTITION ID    REPAIR PROGRESS192.168.66.47:17310:/home/service/var/data1    568           20.22%        [Partition has unavailable replica]:
[Number of Partition with replica file count differ significantly]: 0
[Number of Partition with replica used size differ significantly]: 0
[Partition with excessive replicas]:ID          VOLUME      REPLICAS       STATUS          MEMBERS          
[Partition with disk error replicas]:DP_ID       VOLUME      REPLICAS    DP_STATUS    MEMBERS


Corrupt data partitions: 副本组缺少 leader 的 dp。这种类型的 dp 需要人工去查看每个副本的 META 文件中。


Partition lack replicas: 副本组缺少副本的 dp。可以通过 cfs-cli datapartition add-replica 手动补齐缺失副本。


Bad data partitions: 正在修复的 dp。可以观察到新建副本的修复进度。


Partition has unavailable replica: 副本组存在不可用的副本。需要查看不可用副本所在节点的 datanode 日志,查看副本不可用的原因。


Number of Partition with replica file count differ significantly:副本组之间文件数不一致的 dp。可以等待副本的修复流程自己修复,如果长时间没恢复,可以下线存在差异的副本。


Number of Partition with replica used size differ significantly:副本组之间 dp 大小不一致的 dp。可以等待副本的修复流程自己修复,如果长时间没恢复,可以下线存在差异的副本。


Partition with excessive replicas:有冗余副本的副本组。可以通过 cfs-cli datapartition del-replica 删除多余副本。


Partition with disk error replica: 副本组存在坏盘的 dp。可以通过 cfs-cli 删除坏盘上的副本并重新新增一个副本。


除了副本组织间文件数和 dp 大小不一直的问题,其他问题都可以通过开启自动下线以及 dp 自愈进行自动修复。


查询磁盘/节点下线进度


可以通过 curl 命令"/disk/queryDecommissionProgress"或者"/dataNode/queryDecommissionProgress"查询磁盘/节点的下线进度。以查询磁盘的下线进度为例。


[root]# curl "http://master/disk/queryDecommissionProgress?addr=192.188.66.77:17310&disk=/home/service/var/data1" | jq .  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current                                 Dload  Upload   Total   Spent    Left  Speed100   238  100   238    0     0   155k      0 --:--:-- --:--:-- --:--:--  232k{  "code": 0,  "msg": "success",  "data": {    "StatusMessage": "Success",    "Progress": "100.00%",    "FailedDps": null,    "IgnoreDps": [],    "ResidualDps": [],    "StartTime": "2024-09-19 19:59:08 +0800 CST"  }}


StatusMessage:  下线的状态信息。与前面介绍的 dp 状态机的状态一样,包含 mark,running 等。


Progress: 下线的进度信息。


FailedDps:失败的 dp 以及对应的错误信息。在 StatusMessage 为 running 时,可以根据错误信息怕判断是否需要提前人工介入,保证后续的重试操作以及没有下线 dp 能够成功执行下线操作。由于 dp 下线存在重试机制,也可以等 StatusMessage 变为 fail 后再统一处理错误信息。


IgnoreDps:没参与下线的 dp 信息。由于在同一时刻只能对副本组的单个副本进行下线操作,所以当同时下线副本组的多个副本时,靠后执行下线操作的副本是无法参与 dp 的下线操作的。可以重新执行磁盘/节点的操作。


ResidualDps:残留的 dp 信息。由于 dp 的副本在 master 侧共享一套元数据。如果先下线 a 副本失败,之后下线 b 副本成功,那么 a 的失败信息就会被覆盖。因此这个数组保存的是被覆盖的副本下线错误信息。根据错误信息进行人工处理后,可以重新执行磁盘/节点的操作。


StartTime:下线操作的开始时间。


取消下线


可以通过/disk/cancelDecommission 或者/dataNode/cancelDecommission 取消正在执行下线操作的磁盘/节点。


对于正在进行副本修复操作的 dp 是无法终止的,只能终止在下线列表中但是还没有获取到下线 token 的 dp。


集群下线状态


通过 admin/queryDecommissionToken 可以查看当前集群的下线状态


{    "code": 0,    "msg": "success",    "data": [        {            "NodesetID": 1,            "CurTokenNum": 0,            "MaxTokenNum": 100,            "RunningDp": [],            "TotalDP": 0,            "ManualDecommissionDisk": [],            "ManualDecommissionDiskTotal": 0,            "AutoDecommissionDisk": [],            "AutoDecommissionDiskTotal": 0,            "MaxDiskTokenNum": 5,            "RunningDisk": []        }    ]}


每个 nodeset 都会维护一个 dp 以及磁盘的下线队列,因此这里返回的是一个以 nodeset 下线状态为单位的数组:


NodesetID:nodeset 的编号。


CurTokenNum: 当前处于 running 状态的 dp 总数。


MaxTokenNum:dp 下线的最大并发数。也就是前面通过 cfs-cli cluster 配置的 DecommissionDpLimit 参数。


RunningDp:当前处于 running 状态的 dp 列表。其长度与 CurTokenNum 相等。


TotalDP:下线队列中 dp 的总数。


ManualDecommissionDisk/AutoDecommissionDisk: 当前处于 running 状态的手动/自动下线磁盘列表。


ManualDecommissionDiskTotal/AutoDecommissionDiskTotal:下线队列中手动/自动下线磁盘总数


MaxDiskTokenNum: 磁盘下线的最大并发数。也就是前面通过 cfs-cli cluster 配置的 DecommissionDiskLimit 参数。


RunningDisk:下线队列中磁盘的总数。


值得注意的是,当前是以磁盘为单位去进一步控制 dp 下线的速度的。如果当前磁盘的下线没结束并且磁盘的 token 已经耗尽,即使有空闲的 dp token,也不会触发其他为下线磁盘上的 dp 执行下线操作。


查看节点的磁盘状态


通过./cfs-cli datanode info 可以查看节点的状态:


[root]# ./cfs-cli datanode info 192.168.66.77:17310  [Data node info]...Bad disks           : []Decommissioned disks: []Persist partitions  :[]Backup partitions  : []


Bad disks: 当前节点上的坏盘列表。


Decommissioned disks: 当前节点上已经下线的磁盘列表。这部分磁盘无法再创建新的 dp,如果想解禁这部分磁盘使其重新可以创建 dp,可以通过以下接口。


curl -v "http://master:17010/disk/recommission?addr=192.168.66.77:17310&disk=/home/service/var/data1" | jq .


Persist partitions :当前节点上的 dp 列表。


Backup partitions:当前节点上,通过 raftForce 删除的 dp 的备份目录。这部分目录会定期删除,也可以提前人工删除释放空间。


查看 dp 下线状态


通过如下命令可以查看 dp 的下线状态:


[root~]# curl -v "http://192.168.66.77:17310/dataPartition/queryDecommissionStatus?id=91580" | jq .                                   {  "code": 0,  "msg": "success",  "data": {    "PartitionId": 91580,                           //分区 id    "ReplicaNum": 2,                               //副本数    "Status": "Initial",                           //下线状态    "SpecialStep": "SpecialDecommissionInitial",   //单/双副本下线状态。    "Retry": 0,                                    //下线重试次数    "RaftForce": false,                            //是否使用 raftForce    "Recover": false,                              //是否在修复中    "SrcAddress": "",                              //下线源节点    "SrcDiskPath": "",                             //下线源磁盘    "DstAddress": "",                              //下线的目标节点    "Term": 0,                                     //下线的起始时间    "Replicas": [                                  //dp 的副本组成员      "",      ""    ],    "ErrorMessage": "",                             //下线失败的错误信息    "NeedRollbackTimes": 0,                         //是否需要回滚    "DecommissionType": "InitialDecommission",      //下线的类型    "RestoreReplicaType": "RestoreReplicaMetaStop", //自愈状态    "RecoverStartTime": "0001-01-01 00:00:00"      //上一次修复进度的更新时间 }


对于单/双副本的下线操作,其下线过程中添加/删除副本的顺序与三副本稍有不同,因此通过一个下线子状态 SpecialStep 进行控制,但是总体上还是和三副本一样,由下线状态控制其状态机的流转。


可以通过/dataPartition/resetDecommissionStatus 接口将上述变量都重置为初始值,在某些情况下可以解决 dp 多次下线失败的问题。


故障盘恢复


坏盘经过人工修复后,可以通过如果下接口进行重置,即可以重新创建新的 dp。


curl -v "http://192.168.66.77:17010/disk/recoverBadDisk?addr=datanodeAddr:17310&disk=/home/service/var/data1" | jq .  


副本修复过程卡住


当一个 dp 的副本长时间多次修复超时,可以先通过以下命令查看副本组 host[0]的日志:


[root@ ~]# cat dataNode_info.log| grep ActionNotifyFollowerRepair | grep 分区 id| tail -n 100


日志中,假如出现的日志都是诸如以下内容:


[INFO ] data_partition_repair.go:452: ActionNotifyFollowerRepair to host(follower 地址 1) Partition(分区 id) type(0) ToBeCreated(0) ToBeRepaired(0) done[INFO ] data_partition_repair.go:452: ActionNotifyFollowerRepair to host(follower 地址 2) Partition(分区 id) type(1) ToBeCreated(0) ToBeRepaired(0) done


说明目前没有 extent 需要修复。那么此时可以调用 host[0]的/reloadDataPartition?id=分区 id 接口,重新加载 host[0]分区来恢复副本修复。


副本的 leader 的 raft 卡住


在开启异常 dp 自愈功能时,如果副本组有 leader,但是添加/删除副本超时,可以查询副本组 leader 的添加/删除 raft 成员的日志,判断是否是由于 raft 没有返回添加/删除 raft 成员结果而导致的失败。


对于这种情况可以对副本组的 leader 所在节点执行重载操作进行复原。


curl localhost:17320/reloadDataPartition?id=分区 id



06 小结



本文分析了 CubeFS 新增的异常 dp 自愈以及下线原子性,坏盘自动迁移功能的基本原理,并介绍了运维工作中关于 dp 下线的常用命令操作以及异常情况的处理操作。在 CubeFS 的后续版本中没我们会对磁盘下线的优先级控制进行优化,提供更好的 dp 下线操作用户体验。


作者介绍


Chi He,  CubeFS Contributor 之一,负责存储引擎的开发。




CubeFS 简介




CubeFS 于2019年开源并在 SIGMOD 发表工业界论文,目前是云原生计算基金会 (CNCF) 托管的孵化阶段开源项目。作为新一代云原生分布式存储平台,兼容 S3、POSIX、HDFS 等协议,支持多副本和纠删码引擎,提供多租户,多 AZ 部署、跨区域复制等特性;适用于大数据、AI、容器平台、数据库及中间件存算分离,数据共享、数据保护等广泛场景。


►►►

往期推荐




文章转载自CubeFS点击这里阅读原文了解更多


CNCF概况(幻灯片)

扫描二维码联系我们!




CNCF (Cloud Native Computing Foundation)成立于2015年12月,隶属于Linux  Foundation,是非营利性组织。 

CNCF云原生计算基金会)致力于培育和维护一个厂商中立的开源生态系统,来推广云原生技术。我们通过将最前沿的模式民主化,让这些创新为大众所用。请关注CNCF微信公众号。

CNCF
云原生计算基金会(CNCF)致力于培育和维护一个厂商中立的开源生态系统,来推广云原生技术。我们通过将最前沿的模式民主化,让这些创新为大众所用。
 最新文章