ljzsdut
GitHubToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeBack to homepage

00 Ceph概念与原理

ceph工作原理

一、rados逻辑架构

image-20210912202607061

RADOS集群组件:

  • OSD:object storage daemon(ceph-osd),对象存储设备,一般是一个磁盘。
    • 存储数据
    • 处理数据replication(复制)、recovery(恢复)、rebalancing(重新平衡)
    • 检查其他osd的心跳并向mon、mgr提供监控信息
  • Mon:维护集群元数据,而非文件元数据。基于帕克索斯协议(Paxos)实现数据强一致性。
    • ceph monitor守护进程(ceph-mon)用于维护集群状态运行图(cluster map),包含monitor map、osd map、mds map、pg map、crush map,分别对应ceph mon|osd|fs|pg| dumpceph osd crush dumpceph osd getcrushmap命令用于导出相关的map。
    • 管理daemon和client之间、daemon之间的认证。
  • Mgr:manager,主要用于响应监控数据查询操作,无状态服务。
    • manager守护进程(ceph-mgr)主要负责跟踪运行时metrics、ceph集群当前状态(比如存储性能、当前性能metrics、system load)
    • 具有web-based manager dashboard、REST api
  • Mds:metadata server,为Ceph文件系统存储元数据。可选,只有当使用cephfs时需要部署。

逻辑对象:

  • Pool:存储池,作用类似于名称空间。其大小取决于底层的存储空间。相关属性:副本数、配额
  • PG:放置组,是一个虚拟概念。为了避免直接对对象进行管理过于精细,代价过高。于是引进了PG的逻辑对象,用于管理一组对象。一个对象一定会落到某个pool上的某个pg上。而且pg会根据其所在pool配置的副本数n选择n个osd进行存储。

什么是Cluster Map?

Ceph最为核心的部分是RADOS,理解RADOS是理解Ceph工作原理的基础。RADOS主要由Ceph OSD进程(Object Storage Daemon)和 Ceph Monitor构成。Ceph存储集群通常包含众多分布式的OSD进程,OSD进程主要运行在OSD节点上,并负责完成数据的存储和维护功能。而Ceph Monitor则负责完成集群系统的状态检测和维护功能。在实际运行中,Ceph OSD和Monitor之间相互共享节点状态信息,并通过这些信息计算出集群系统当前运行的整体状态,从而得到一个记录集群全局性系统状态的数据结构,即前面提到的Cluster Map。对于 Ceph存储系统而言,Cluster Map记录了Ceph数据对象操作全部所需的关键信息,RADOS所采用的 CRUSH算法便是基于Cluster Map记录的集群信息进行计算。

Client如何获取到存储数据的OSD?

当客户端通过Ceph提供的各类API接口访问RADOS时,高并发的客户端程序通过与运行中的Monitor进程交互以获取Ceph集群的Cluster Map信息,然后直接在本地客户端进行计算以获取需要读取或存入数据对象的存储位置(即哪个OSD)。获取对象存取位置后客户端便直接与对应的OSD节点交互从而完成对数据对象的读写操作。

什么情况会导致Cluster Map发生变化?

从客户端与RADOS的交互中可以看出,若Ceph集群的Cluster Map信息保持稳定不变,则客户端对于对象数据的读写访问无须通过元数据服务器进行查询即可实现,客户端获取Cluster Map信息之后只需进行简单的计算即可获取数据对象存储位置并完成数据访问操作。对于运行中的RADOS而言,通常只有在集群OSD出现意外故障或者人为有计划地增删扩容OSD节点导致在线OSD数目变化时,Ceph集群的Cluster Map信息才会出现变化。而对于一个正常运行的生产系统,出现这两种场景的频率显然要远低于客户端数据的读写频率,这也是Ceph存储集群可以提供高并发和高性能客户端数据访问的主要原因。

二、File、Object、PG、Pool、OSD关系

JbrvaB-1608615394356

数据存储过程由上到下所涉及的Ceph术语包括了File、Object、PG、OSD。

1、File

File是最高层次的数据对象,即终端用户所能看到和操作的数据对象,也是用户需要存储或者访问的数据文件。对于那些基于 Ceph对象存储而开发的应用程序而言,这里的File就是应用程序所要存储访问的“对象”,或者说就是用户希望存取访问的“对象”。

2、Object

Object是从Ceph角度所看到的对象,或者说是 RADOS的操作对象单位,Ceph对象存储中的“对象”通常便是指 Object。Object与 File的区别在于,Object由File 拆分映射而来,通常RADOS限定了Object大小或尺寸(Pool中的参数指定),如RADOS规定每个Object 的大小为4MB或8MB,以便Ceph可以实现对底层存储的组织和管理。所以,如果Ceph客户端向RADOS写人较大Size的File,则对应着会产生很多相同大小的Object (最后一个Object 的 Size可能会小于 RADOS 规定的最大值),而这些Object最终将会被映射到不同的PG中。

3、PG

PG,即Placement Group(归置组),是逻辑上的Object组织单位或者容器,其主要作用就是对Object的存储进行组织和位置映射。实际应用中,每个PG负责组织若干个Object,而PG与Object之间的映射关系为一对多,即每个Object 只能映射到一个PG中,而一个PG可以容纳多个Object。由于PG是逻辑上的存储单位,因此PG最终还需映射到 OSD上,而PG与OSD之间为多对多的关系,即一个PG可以映射到多个OSD,而一个OSD也可以存储多个PG。在实际应用中,通常每个PG会对应着有一个Primary OSD 和多个SecondaryOSD,生产环境中建议至少为3个。

3.1、概述

归置组(Placement Group)是用于跨OSD将数据存储在某个存储池中的内部数据结构:

  • 相对于存储池来说,PG是一个虚拟组件,它是对象映射到存储池时使用的虚拟层;

  • 出于规模伸缩及性能方面的考虑,Ceph将存储池细分为归置组,把每个单独的对象映射到归置组,并将归置组分配给一个主OSD;

  • 存储池由一系列的归置组组成,而CRUSH算法则根据集群运行图和集群状态,将所有PG均匀伪随机地分布到集群中的OSD之上;(伪随机:对于同一个pg,每次crush计算得到的osd集合是固定的;而对于多个pg进行crush计算,pg的分布式随机的。)

  • 若某OSD失败或需要对集群进行重新平衡,Ceph则移动或复制整个归置组而无需单独寻址每个对象。即PG是移动和复制的基本单元

  • CRUSH动态地映射PG到OSDs;

  • 当Client存储对象时,CRUSH将映射每一个对象到一个PG;

归置组在OSD守护进程和Ceph客户端之间生成了一个中间层,CRUSH算法(一致性hash+crush)负责将每个对象动态映射到一个归置组,然后再将每个归置组动态映射到一个或多个OSD 守护进程,从而能够支持在新的OSD设备上线时动态进行数据重新平衡。

image-20211007125501705

3.2、归置组计数

使用以下方法创建新池时:

ceph osd pool create {pool-name} pg_num

必须选择的值pg_num,因为它不能自动计算。以下是一些常用的值:

  • 少于5个OSD设置pg_num为128
  • 5至10个OSD设置pg_num为512
  • 10至50个OSD设置pg_num为1024
  • 如果您有超过50个OSD,则需要了解折衷方法以及如何自己计算pg_num值,要自行计算pg_num值,请使用pgcalc工具

随着OSD数量的增加,为pg_num选择正确的值变得更加重要,因为它对群集的行为以及发生错误时的数据持久性具有重大影响(即,灾难性事件导致数据丢失)。

归置组的数量由管理员在创建存储池时指定,而后由CRUSH负责创建和使用。

  • 通常,PG的数量应该是数据的合理粒度的子集。例如,一个包含256个PG的存储池意味着每个PG包含大约1/256的存储池数据

  • PG的数量会对Ceph性能产生影响

    • PG数量过少,每个PG中包含的数据量较大,当需要将PG从一个OSD移动到另一个OSD时,Ceph将不得不同时移动相当大数量的数据,其产生的网络负载将对集群的正常性能输出产生负面影响

    • 而在过多的PG数量场景中在移动极少量的数据时,Ceph将会占用过多的CPU和RAM对PG进行追踪,从而对集群的计算资源产生负面影响。

  • PG数量在群集分发数据和重新平衡时扮演着重要作用

    • 在所有OSD之间进行数据持久存储及完成数据分布会需要较多的归置组,但是它们的数量应该减少到达到最大性能所需的最小数量值(保证性能的前提下使用最少的数量),以节省CPU和内存资源;
    • 一般说来,对于有着超过50个OSD的RADOS集群,建议每个OSD大约有50-100个PG以平衡资源使用,取得更好的数据持久性和数据分布,更大规模的集群中,每个OSD大约可持有100-200个PG;
    • 至于应该使用多少个PG,可通过下面的公式计算后,将其值以类似于四舍五入到最近的2的N次幂:(Total OSDs * PGPerOSD)/Replication factor => Total PGs。例如8个osd的集群中,如果每个osd上建议的pg数为100,则有100*8=800个pg,对于3副本的pool,则pg数量为800/3=266,取小于266的最大的2的N次方数字,则为256。所以该集群中所有pool可以使用的pg总数为256个。
    • PG计算器:https://ceph.com/pgcalc/
    • 一个RADOS集群上可能会存在多个存储池,因此管理员还需要考虑所有存储池上的PG分布后每个OSD需要映射的PG数量,一般按照Pool存储数据量大小的比例分配PG的数量。

3.3、归置组状态

依据PG当前的工作特性或工作进程所处的阶段,它总是处于某个或某些个”状态“中,最为常见的状态应该为”active+clean“(active + clean是PG的健康状态)。

PG的常见状态:

  • Active:主OSD和各辅助OSD均处于就绪状态,可正常服务于客户端的IO请求。一般,Peering操作过程完成后即会转入Active状态,这个状态意味着主从OSD的该PG都可以提供读写了。

  • Clean:主OSD和各辅助OSD均处于就绪状态,所有对象的副本数量均符合期望,并且PG的活动集和上行集是为同一组OSD。这个状态的意思就是主从OSD已经成功peer并且没有滞后的副本。PG的正常副本数满足集群副本数。

    • 活动集(Acting Set):由PG当前的主OSD和所有的处于活动状态的辅助OSD组成,这组OSD负责执行此PG上数据对象的存取操作I/O

    • 上行集(Up Set):根据CRUSH的工作方式,集群拓扑架构的变动将可能导致PG相应的OSD变动或扩展至其它的OSD之上,这个新的OSD集也称为PG的”上行集(Up Set)“,其映射到的新OSD集可能部分地与原有OSD集重合,也可能会完全不相干; 上行集OSD需要从当前的活动集OSD上复制数据对象,在所有对象同 步完成后,上行集便成为新的活动集,而PG也将转为“活动(active)”状态

      • up ([1,0,2], p1) up set ,按顺序表示副本存在于哪个osd上,osd1(primary)osd0(secondary)和osd2(tertiary)
      • acting ([1,0,2], p1) acting set 通常情况下和up set相同,不同的情况需要理解pg_temp,即如果pg的acting set 为[0,1,2], 此时如果osd.0出现故障,导致CRUSH算法重新分配该pg的acting set 为[3,1,2]. 此时osd.3为该pg的主osd,但是osd.3并不能负担该pg的读操作,因为其上现在还没有数据。所以向monitor申请一个临时的pg,osd.1为临时主osd,这时acting set依然为[0,1,2],up set 变为[1,3,2],此时就出来acting set 和up set的不同。当osd.3 backfill完成之后,该pg的up set恢复为acting set, 也就是acting set 和 up set都为[3,1,2]
  • Peering:对等操作,一个PG中的所有OSD必须就它们持有的数据对象状态达成一致,而”对等(Peering)“即是让其OSD从不一致转为一致的过程。peering过程实际上就是让3个保存同一个PG副本的OSD对保存在各自OSD上的对象状态元数据(版本,主从关系等)进行协商的过程,但是呢,peering完成并不意味着每个副本都保存着最新的数据。(在Peering的过程中,PG会根据PGLog检查PG的多个副本的一致性,并尝试计算PG的不同副本的数据缺失,最后得到一份完整的对象缺失列表,用作后续进行Recovery操作时的依据。对于无法根据PGLog计算丢失数据的PG,需要通过Backfill操作拷贝整个PG的数据来恢复。需要注意的是,在这Peering过程完成前,PG的数据都是不可靠的,因此在Peering过程中PG会暂停所有客户端的IO请求。)简述:Peering操作作用:确定受影响的数据,得到一份完整的对象缺失列表。

  • Peered:如果pg的当前副本数<min_size,此时保持对等状态的副本数不满足条件,pg就会进入peered状态,表示等待其他兄弟姐妹上线。此时,处于peered状态的PG不能响应外部的读写操作。

  • Degraded:降级,在某OSD标记为”down“时,所有映射到此OSD的PG即转入“降级(degraded)”状态,此时这些PG的副本数小于设定的副本数。

    • 如果此OSD重新启动并完成Peering操作后,PG将重新转回clean
    • 一旦OSD标记为down的时间超过5分钟,它将被标记出集群,而后Ceph将对降级状态的PG启动恢复操作,直到所有因此而降级的PG重回clean状态
    • 在其内部OSD上某对象不可用或悄然崩溃时,PG也会被标记为降级状态,直至对象从某个权威副本上正确恢复
  • Stale:过期,每个OSD都要周期性地向RADOS集群中的监视器报告以其作为主OSD所持有的所有PG的最新统计数据,因任何原因导致某个主OSD无法正常向监视器发送此类报告,或者由其它OSD报告某个OSD已经down掉,则所有以此OSD为主OSD的PG将立即被标记为stale状态。(从而会重新选举新的主OSD)

  • Undersized:低于指定副本数量:PG中的副本数少于其存储池定义的个数时即转入undersized状态,恢复和回填操作在随后会启动以修复其副本数为期望值

  • Remapped:ceph强大的自我恢复能力,是我们选择它的一个重要原因,例如对于一个3副本的pool,我们关闭了两个OSD,但是至少还有一个PG 0.44存活在osd.0上,如果那两个盘真的坏了,ceph还是可以将这份仅存的数据恢复到别的OSD上的。

    在OSD挂掉5min(default 300s)之后,这个OSD会被标记为out状态,可以理解为ceph认为这个OSD已经不属于集群了,然后就会把PG 0.44 map到别的OSD上去,这个map也是按照一定的规则的,重映射之后呢,就会在另外两个OSD上找到0.44这个PG,而这只是创建了这个目录而已,丢失的数据是要从仅存的OSD上回填到新的OSD上的,处于回填状态的PG就会被标记为backfilling

    所以当一个PG处于remapped+backfilling状态时,可以认为其处于自我克隆复制的自愈过程。

  • Scrubbing:

    • 各OSD还需要周期性地检查其所持有的数据对象的完整性,以确保所有对等OSD上的数据一致; 处于此类检查过程中的PG便会被标记为scrubbing状态,这种通过校验码检查的方式,也通常被称作light scrubs、shallow scrubs或者simply scrubs;
    • 另外,PG还偶尔需要进行deep scrubs检查以确保同一对象在相关的各OSD上能按位匹配,此时 PG将处于scrubbing+deep状态;
  • Recovering:添加一个新的OSD至存储集群中或某OSD宕掉时,PG则有可能会被CRUSH重新映射进而将持有与此不同的OSD集,而这些处于内部数据同步过程中的PG则被标记为recovering状态; Ceph设计之初就考虑到了容错性,比如软硬件的错误。当一个OSD挂了,它所包含的副本内容将会落后于其他副本,当这个OSD起来之后(即pg中osd在down之后重新up,未发生重新映射), 这个OSD的数据将会更新到当前最新的状态。这段时间,这个OSD上的PG就会被标记为recover

  • Backfilling:新OSD加入存储集群后,CRUSH会重新规划PG将其他OSD上的部分PG迁移到这个新增的PG上(remapped状态:PG被CRUSH重新映射进不同的新OSD集),Ceph则会进入数据重新均衡的状态,即一些数据以PG为恢复力度单位在进程后台从现有OSD移到新的OSD之上,此操作过程即为backfill; 所以当一个PG处于remapped+backfilling状态时,可以认为其处于自我克隆复制的自愈过程。

Recovering与Backfilling的区别:

Recovering:PG进行Recovering时,是以对象为粒度进行数据恢复。

Backfilling:PG进行Backfilling时,是以PG为粒度进行进行数据的全量拷贝。

具体的数据恢复流程,请参考:https://www.kancloud.cn/willseecloud/ceph/2360768

调整recovery、backfill的速率
#调节mon
ceph tell mon.* injectargs --osd_recovery_max_active   10
ceph tell mon.* injectargs --osd_recovery_op_priority  30
ceph tell mon.* injectargs --osd_max_backfills  30
#调节osd
ceph tell osd.* injectargs --osd_recovery_max_active   10
ceph tell osd.* injectargs --osd_recovery_op_priority  30 
ceph tell osd.* injectargs --osd_max_backfills  30

还原配置:
ceph tell mon.* injectargs --osd_recovery_max_active   3
ceph tell mon.* injectargs --osd_recovery_op_priority  3
ceph tell mon.* injectargs --osd_max_backfills  1

ceph tell osd.* injectargs --osd_recovery_max_active   3
ceph tell osd.* injectargs --osd_recovery_op_priority  3 
ceph tell osd.* injectargs --osd_max_backfills  1

其他解释:

http://xuxiaopang.com/2016/11/11/doc-ceph-table/ (推荐整理)

https://blog.csdn.net/wuxianweizai/article/details/78925479

https://www.iteye.com/blog/wx1568152809-2448090

https://www.icode9.com/content-4-802928.html

4、OSD

OSD 即是对象存储设备(Object Storage Device),是Ceph存储集群中的最终物理存储设备,其主要作用就是存储逻辑上的PG,并且通过运行在OSD上的OSD进程实现不同OSD之间的通信以及与 Ceph Monitor的通信。由于OSD是 Ceph存储集群最终的物理存储设备,Ceph集群中 OSD数目的设置很大程度上直接影响到Ceph存储集群的配置和性能。理论上,Ceph集群中的OSD数目越多,则越有利于充分发挥 Ceph存储系统的高可用、高可靠和高性能等特性。

OSD状态说明

[root@stor01 ~]# ceph osd stat
8 osds: 8 up (since 24h), 8 in (since 2d); epoch: e119
  • 集群内(in)
  • 集群外(out):可以理解为ceph认为这个OSD已经不属于集群了
  • 活着且在运行(up)
  • 挂了且不再运行(down):比如手动执行systemctl stop ceph-osd停掉ceph-osd服务,该osd就会进入down状态

正常情况下OSD的状态是up+in状态,如果down掉OSD,它的状态会变为down+in,过了300秒(mon_osd_down_out_interval)后,MON会自动将down掉的OSD标记为out,一旦out数据就会开始迁移其归置组迁移到其他OSD, CRUSH就不会再分配归置组给它。

5、Pool

5.1、概述

RADOS存储集群提供的基础存储服务需要由“存储池(pool)”分割为逻辑存储区域(Pool实际上是对若干PG进行组织管理的逻辑划分),此类的逻辑区域亦是对象数据的名称空间。

  • 实践中,管理员可以为特定应用程序存储不同类型数据的需求分别创建专用的存储池, 例如rbd存储池、rgw存储池等,也可以为某个项目或某个用户创建专有的存储池
  • 存储池还可以再进一步细分为一至多个名称空间(namespace)
  • 客户端(包括rbd和rgw等)存取数据时,需要事先指定存储池名称、用户名和密钥等信息完成认证,而后将一直维持与其指定的存储池的连接,于是也可以把存储池看作是客户端的IO接口

创建Pool至少需要设定以下参数:

  • PG数目。
  • 该pool使用的crush规则。(有默认值)
  • 对象副本的数目。(有默认值)
  • 对象的所有权/访问权。

5.2、存储池类型

  • 副本池(replicated):把每个对象在集群中存储为多个副本,其中存储于主OSD的为主副本,副本数量在创建存储池时由管理员指定,默认为3;此类型为默认的存储池类型;
  • 纠删码池(erasure code):把各对象存储为N=K+M个块,其中,K为数据块数量,M为编码块数量,因此存储池的尺寸为 K+M ;此时冗余的块数量为M,磁盘空间利用率为K/N。RGW可以使用纠删码存储池,但RBD不支持。相对于副本池,节省磁盘空间,但是会消耗更多的CPU资源。

5.2.1、副本池IO

  • 将一个数据对象存储为多副本
  • 写入操作时,Ceph客户端使用CRUSH算法来计算对象的PG ID和Primary OSD
  • 主OSD根据设定的副本数、对象的名称、存储池名称和集群运行图(Cluster Map )计算出PG的各辅助OSD,而后由主OSD将数据同步给这些辅助OSD

image-20211007123403267

5.2.2、纠删码池IO

纠删码是一种前向纠错(FEC)代码

  • 通过将K块的数据转换为N块,假设N=K+M,则其中的M代表纠删码算法添加的额外或冗余的块数量以提供冗余机制(即编码块),而N则表示在纠删码编码之后要创建的块的总数,其可以故障的总块数为M(即N-K)个
  • 类似于RAID 5

纠删码池减少了确保数据持久性所需的磁盘空间量,但计算量上却比副本存储池要更贵一些(耗费更多的CPU资源)。

RGW可以使用纠删码存储池,但RBD不支持。

  • 例如,把包含数据“ABCDEFGHI”的对象NYAN保存到存储池中时,假设纠删码算法会将内容分割为三个数据块:第一个包含“ABC",第二个为”DEF“,最后一个为”GHI“,并为这三个数据块额外创建两个编码块:第四个”YXY“和第五个”GQC“
  • 在有着两个编码块配置的存储池中,它容许至多两个OSD不可用而不影响数据的可用性。假设,在某个时刻OSD1和OSD3因故无法正常响应客户端请求,这意味着客户端仅能读取到 ”ABC“、”DEF“和”QGC“,此时纠删编码算法会通过计算得出”GHI“和”YXY“

image-20211007123541664

image-20201221111625391

三、Ceph数据存储过程

在 Ceph存储集群中,数据存取的核心基础是RADOS,上层应用(如RBD、RGW 和 CephFS)对于数据对象存储的理论核心均是基于RADOS实现的。

1、概述

把对象直接映射到OSD之上会导致二者之间的紧密耦合关系,在OSD设备变动时不可避免地对整个集群产生扰动(防止某个OSD上存放是紧密地联系在一起的一组连续数据,而不是随机分配的一组数据),于是,Ceph将一个对象映射进RADOS集群的过程分为两步:

  • 首先是以一致性哈希算法将对象名称映射到PG
  • 而后是将PG ID基于CRUSH算法映射到OSD

此两个过程都以“实时计算”的方式完成,而非传统的查表方式,从而有效规避了任何组件被“中心化”的可能性,使得集群规模扩展不再受限,这个实时计算操作到的算法就是CRUSH(Controlled Replication Under Scalable Hashing)。它是一种数据分布式算法,类似于一致性哈希算法,用于为RADOS存储集群控制数据分布。

image-20211007140937004

存取对象时,客户端从Ceph mon请求获取集群运行图,绑定到指定的存储池,并对存储池上PG内的对象执行IO操作:

  • 存储池的CRUSH规则集和PG的数量是决定Ceph如何放置数据的关键性因素;
  • 基于最新版本的集群运行图,客户端能够了解到集群中的所有监视器mon和OSD以及它们各自的当前状态。不过,客户端对目标对象的位置却一无所知;

执行对象的存取操作时,客户端需要输入的是对象标识存储池名称:客户端需要在存储池中存储命名对象时,它将对象名称、对象名称的哈希码、存储池中的PG数量和存储池名称作为输入,而后由CRUSH计算出PG的ID(pg_id)及此PG的主OSD。

  • 通过将对象标识进行一致性哈希运算得到的哈希值与PG位图掩码进行”与“运算得到目标PG,从而得出目标PG的ID(pg_id),完成由Object至PG的映射
  • 而后,CRUSH算法便将以此pg_id、CRUSH运行图和归置规则(Placement Rules)为输 入参数再次进行计算,并输出一个确定且有序的目标存储向量列表(OSD列表),从而完 成从PG至OSD的映射

示例:

Ceph客户端使用以下步骤来计算PG ID:

  • 客户端输入存储池名称及对象名称,例如,pool = pool1以及object-id = obj1

  • 获取对象名称并通过一致性哈希算法对其进行哈希运算,即hash(o),其中o为对象名称

  • 将计算出的对象标识哈希码与PG位图掩码进行“与”运算获得目标PG的标识符,即PG ID,例如1701

    • 计算公式为pgid=func(hash(o)&m,r),其中,变量o是对象标识符,变量m是当前存储池中PG的位图掩码,变量r是指复制因子,用于确定目标PG中OSD数量
  • CRUSH根据集群运行图计算出与目标PG对应的有序的OSD集合,并确定出其主OSD

  • 客户端获取到存储池名称对应的数字标识,例如,存储池“pool1”的数字标识11

  • 客户端将存储池的ID添加到PG ID,例如,11.1701

  • 客户端通过直接与PG映射到的主OSD通信来执行诸如写入、读取或删除之类的对象操作

image-20201221093753982

1)取得Object的name进行Hash运算。取得的Hash值与PG数取余,得到的结果与Pool ID结成PG的编号(如图10-5中的4.32)。

2)通过CRUSH算法,把PG映射到具体的主OSD和辅助OSD。

在Ceph里,PG是数据存储的管理单元,如果把PG当作一致性Hash里的存储节点,那么它就是最简单的数据分布(即取余算法)方式。不同的是,PG是抽象的存储节点,它不会随着物理节点的加入或者离开而增加或减少(一个pool中的pg数量不会因为osd的数目变化而发生变化),因此object到PG的映射是稳定的。

2、流程详解

image-20210912202928996

整个数据存储过程中,共分为三个层次的映射,在每一个层次的映射中, Ceph均采用不同的映射方式:

  • 第一次映射为File –> Object,
  • 第二次映射为 Object –> PG,
  • 第三次映射为PG –> OSD。

整体而言,Ceph存储系统中的数据存储过程大致如下:

  • 首先File被条带化为数据块,每个数据块均被转换为Object,在这个过程中,Ceph根据每个数据块所对应File的Inode Number(INO)和Object Number (ONO)赋予每个Object一个Object ID (OID);
  • 之后Ceph利用Object的OID进行Hash计算,并将每个Object分配到不同的PG中,PG是逻辑上的Object容器,每个PG中均可存放多个Object,此外每个PG均有对应的PGID;
  • 最后Ceph利用每个PG的PGID执行CRUSH算法以将每个PG均映射到物理对象存储设备上,即OSD中。这样,逻辑上的数据文件被拆分后以分布式的存储方式存储到Ceph集群不同的OSD中。

2.1、File至Object的映射

File –> Object的映射是 Ceph存储系统中数据存储的第一次映射,也是最简单的映射。这个映射过程可以看成是对 File进行条带化(类似磁盘阵列RAID上的条带化技术),条带化后的数据块便是 Object,而Object的大小由RADOS规定,如2MB或者4MB。File –> Object映射所带来的好处之一就是,将用户提交的Size 大小不一的File拆分为Size一致、并可被RADOS 高效管理的多个Object。另外一个优势就是将传统对File的单机串行处理变为集群多节点下的并行处理。因此对于相同大小的File,在 Ceph存储系统中的存取速率要远高于传统文件系统中的存取速率。File被切分后产生的每个Object都将获得唯一的OID。OID的生成也非常简单,即简单地对 File的INO 和Object的ONO 进行线性组合即是Object的OID。例如,某个名称为 warrior.txt的 File,其大小为10MB, INO为10。假设RADOS规定每个Object最大 Size为2MB,则warrior.txt将被拆分为大小为2MB的5个Object,每个Object的OID分别为101、102、103、104和105。

2.2、Object到PG的映射(一致性Hash)

Object –> PG的映射是Ceph存储系统中数据存储的第二次映射,这里的映射采用的是Hash算法。Hash算法的输入参数为Object的OID。图10-23中所示的计算公式为hash(oid) & mask --> pgid,即首先使用静态哈希函数计算Object的OID哈希值,这样会将OID映射成近似均匀分布的伪随机值,再将这个伪随机值与给定的MASK按位进行“与”(and或&)操作(可以简单理解为取余操作),从而找到PGID,并最终确定该Object应该映射到哪个PG。

当在Ceph里创建存储池(在创建Pool时需要指定PG数量,对于这个Pool来说,PG数量是固定的,OSD数量变化时,只会影响整个集群的PG数量,但不会影响该Pool中的PG数量),这个Pool中的PG组成的整个Hash环就固定了,如图10-6所示,对象到PG的映射就唯一确认,即Object具体存储到哪个PG是确定的,不会随着下层OSD的增删而改变,这充分体现了Ceph在数据可靠性的特征之一。

image-20201221094140651

根据RADOS的设计原理,假设Ceph集群中某个Pool的PG的总数为N(N通常为2的m次方,m为整数),则MASK的值取为N-1。因此,图10-23 中所示的PGID 计算公式其实是从所有N个PG中近似均匀地随机选取一个PG来存放Object,这里之所以强调“近似”,是因为根据概率统计的理论,只有PG数目足够多才能足够接近随机性。根据这一原理,只有在存在大量Object和PG的情况下, Ceph集群才能够将Object 近似随机地分布到PG中,最终也才能保证存储集群中每个PG所组织管理的Object数量均衡,而这一点对于Ceph存储集群的正常运行和性能提升有很大影响,因为只有数据均匀分布,才不至于某些节点过于负载,某些节点却“无所事事”。

为保证Objects近似均匀地分布到PGs中,一方面需要合理设置Object的Size以保证File被拆分为尽量多的Object,同时Ceph集群中的PG数目在OSD数目一定的情况下不宜太少,通常PG数目需要设置为OSD数目的数百倍。至于Object的Size和PG的数目如何精确设置,目前并没有特别严谨的计算公式,更多的需要根据用户的实际使用测试结果来评估。

2.3、PG到OSD的映射(CRUSH)

CRUSH函数简述:CRUSH(pgid,cluster map,placement rule)-->[l,m,n]

输入:

  • pgid:是根据一致性Hash得出的,可以认为是一个随机数。

  • cluster map:是Ceph集群拓扑结构的逻辑描述形式。实际应用中Ceph集群通常具有形如“数据中心→机架→主机→磁盘”这样的树状层级关系,所以cluster map可以使用树这种数据结构来实现:

    • 每个叶子节点都是真实的最小物理存储设备(例如磁盘),称为 device;
    • 所有中间节点统称为bucket,每个 bucket可以是一些 device的集合,也可以是低一级的 buckets集合;
    • 根节点称为root,是整个集群的入口。
  • Placement Rule:数据分布策略。Ceph将集群的cluster map和所有的placement rule合并成一张CRUSH map,因此基于CRUSH map可以独立实施数据备份及分布策略。使用cluster map建立对应集群的拓扑结构描述之后,可以定义placement rule来完成数据映射。

输出:

针对指定输入pgid, CRUSH将输出一个包含n(n为副本数)个不同目标存储对象(osd)的集合。

结论:

CRUSH的计算过程中仅仅使用pgid,cluster map和placement rule作为哈希函数的输入。一般而言placement rule不会轻易变化,因此,如果cluster map不发生变化,那么对于同一个pgid来说,结果就是确定的;同时因为使用的哈希函数得到的pgid是伪随机的,所以CRUSH选择每个目标存储对象OSD概率相对独立(然而我们在后面将会看到一受控的副本策略改变了这种独立性),从而可以保证数据在整个集群之间均匀分布。

PG –> OSD的映射是 Ceph存储系统中数据存储的第三次映射,也是逻辑到物理存储的映射。如图10-23所示,RADOS采用CRUSH算法进行PG到OSD的映射,而CRUSH算法的输入参数为PGID, CRUSH算法计算的结果将是一组m个OSD,m通常也代表了数据对象的副本数,生产系统中建议设置为3,这样每个PG将会映射到3个不同的OSD中,其中包括1个Primary OSD 和2个Secondary OSD。PG到OSD的映射如图10-24所示。

image-20210912203805727

PG与OSD之间的映射采用的是CRUSH算法,而CRUSH算法依赖Ceph集群中的Cluster Map和集群数据存储策略(Policy),通常集群策略在配置完成之后就不会发生改变,因此影响CRUSH的因素主要是Cluster Map,而Cluster Map会根据集群OSD数目的变化(如OSD意外故障而离线或者人为增删 OSD数目等)而变化,因此PG与OSD之间的映射并非固定不变,即特定的PG并不会永远固定地映射到特定的某个OSD。正是因为CRUSH算法在实际应用中不会经常改变计算结果,因此PG与OSD的映射关系也不会经常变化,但是正因为CRUSH算法的动态性,Ceph集群才具有了在OSD等故障情况下的自我愈合能力。例如OSD的故障或者增加必然导致Cluster Map变化,Cluster Map的改变必然导致CRUSH算法得到的PG与OSD之间的映射与故障发生之前的映射不一致,这意味着Ceph集群会自动将故障OSD上的PG迁移到正常运行的OSD中,通常将这个过程称为数据再平衡(Re-balancing)。OSD数目增加时,PG在OSD中Re-balancing的过程如图10-25所示,图中,PG最初全部分布在OSD1和 OSD2上,由于新增OSD3导致Cluster Map变化,因此PG的映射关系也跟着改变,Re-balancing过程使得原有的PG重新分布到OSD1、OSD2和OSD3上,而根据RADOS的设计,最终的PG应该近似均匀地分布到OSD集群中。

image-20210912203835669

通常,对于OSD故障情况,数据自动Re-balancing是用户所希望的,但是如果是用户人为扩展OSD数目,则数据Re-balancing 会消耗大量节点资源,因此用户并不希望这种场景下出现数据的Re-balancing,这也正是使用CRUSH算法的主要原因,即在大规模的OSD 集群中,如果OSD数目继续增大,Ceph集群中大多数的PG与OSD之间的映射关系不会受到影响,仅有小部分PG的映射关系会发生变化从而引起数据Re-balancing。因此,总结起来,使用CRUSH算法可以使得PG与OSD之间的映射具有独特的动态性和稳定性,所以,除了数据访问无须查表的优势之外,CRUSH算法的设计也是Ceph的核心灵魂。

到此,文件数据在Ceph存储系统中的存储映射过程已经完成,高层次的文件数据File经过Ceph内部的三次映射之后,已经成功分布存储到物理存储设备OSD中。从整个存储过程来看,数据的存取没有经历任何查表操作,并且第三次映射所采用的CRUSH算法为Ceph集群的自我愈合和数据稳定性提供了强大支撑。

四、Ceph数据访问流程

这里主要从抽象性的角度来分析客户端访问Ceph存储集群的步骤和流程。

Ceph客户端在向 Ceph存储集群写人数据时,首选需要从Ceph Monitor中提取Cluster Map,并根据 Cluster Map信息在客户端本地计算出数据的存储位置信息,然后再将数据写人Ceph的Pools 中。这里Pool是 PG的集合,Ceph中的PG对 Objects进行组织管理,而Pool又对PG 进行组织管理(PG 和 Pool都是逻辑概念),如对客户端的授权访问等操作便是通过 Pool来实现的。Ceph客户端向 Ceph存储集群写人数据的抽象过程如图10-26所示。

image-20210912203951611

现假设客户端需要将较小的数据文件Filel存人 Ceph存储集群中,且Filel1仅被映射为一个Object。 Object被映射到某个PG中,而根据用户设置最终的PG需要映射到3个OSD中(即数据副本为3份),则File1写人Ceph存储集群中的具体流程如图10-27所示。

image-20210912204009466

根据前文的分析,Filel被映射为 Object, Object被映射到PG, PG再通过CRUSH 算法映射到一组OSD中,这里一组OSD包含三个OSD,通常这组OSD中的三个OSD拥有不同的OSD序号,而较为靠前的OSD通常被称为Primary OSD,后面两个则分别是Secondary OSD 和 Tertiary OSD。当客户端经过三个映射步骤找到File1文件的最终存储位置后,便会向Primary OSD 发起写操作,如图10-27中的步骤1所示。当Primary OSD接收到客户端的写请求后,便会向Secondary OSD和Tertiary OSD 发起写操作,如图10-27中的步骤2和3所示。Secondary OSD 和 Tertiary OSD写操作完成后,便会分别向 Primary OSD返回写成功应答信号,如图10-27中步骤4和5所示。Primary OSD接收到Secondary OSD 和Tertiary OSD的写完成信号,并确认自己的写操作也完成后,便向Ceph客户端返回本次写操作执行成功的应答信号,如图10-27中的步骤6所示。在图10-24所示的数据写人流程中,客户端只需向Primary OSD 发出写请求,而不用同时向 Secondary OSD 和 TertiaryOSD 发出写请求,这样的设计缓减了客户端发送多次重复请求所造成的网络带宽压力,在高并发大量客户端同时访问的场景中,这对存储系统的性能提升起到了非常关键的作用。另外,由于客户端需要等待3个OSD均返回数据写人磁盘成功的信号后才能执行后续的操作,这对于客户端而言将是难以忍受的等待。鉴于此,Ceph提供了二次应答机制,即一旦全部 OSD将数据写人缓存,即返回写人成功的信号给客户端,此时客户端可以进行后续操作,而当数据全部写入磁盘后,OSD再次返回最终的确认信号给客户端,此时客户端便可对之前的数据进行删除操作。

从图10-26 和图10-27中可以看到,Ceph客户端对Ceph存储集群的访问完全无须查表寻址这一过程,而且各个客户端获取 Cluster Map信息后在自己本地进行数据存储位置的简单计算,而不是依赖中心化的元数据服务器进行地址查询,当客户端计算出数据存储位置后直接对Primary OSD 发起访问请求。因此,大量高并发的客户端可以同时对 Ceph存储集群发起访问,各个客户端独立进行地址计算并且与不同的OSD进行交互,彼此之间不影响,所以 Ceph存储集群在宏观上是一种可以提供高并发访问的存储集群。此外,如果客户端的File被切分为多个Object,则客户端可以并行与多个OSD交互从而一次性并发获取多个Object,因此从微观数据访问来看,Ceph存储集群也具备并发性。最后,从微观到宏观的并发性真正实现了Ceph存储集群的高性能。

五、Ceph数据恢复流程

参考:https://cloud.tencent.com/developer/article/1592159

Ceph使用多副本机制来保证数据的高可靠性,给定一份数据,Ceph在后台自动存储多份副本(一般使用3个副本),从而使得在硬盘损毁、服务器故障、机柜停电等故障情况下,不会出现数据丢失,甚至数据仍能保持在线。不过在故障发生后,Ceph需要及时做故障恢复,将丢失的数据副本补全,以维系持续的数据高可靠性。

因此多副本机制是分布式存储系统的核心机制之一,它带来了数据高可靠性,也提高了数据可用性。然而事情是没有十全十美的,多副本机制同时带来了分布式系统的最大问题之一:数据一致性。

除此之外,Ceph数据恢复(或者说分布式存储数据恢复)还有其他几个难点:

  • 感知故障,并自动触发数据恢复。做到这点,能减轻运维压力,也使发现和处理故障更为及时。
  • 尽量降低数据恢复过程中对集群资源的消耗。比如最为明显的,如何减少网络带宽的占用。Ceph恢复数据时,是拷贝整个4M对象,还是只恢复有差异的数据,这两种方式直接影响网络间传输的数据量。
  • 数据恢复是否影响用户的线上业务,Ceph是如何控制和降低这个影响的?

带着这几个问题,下面和大家一起来探讨Ceph数据恢复的流程和关键细节。

Ceph故障处理的流程

我们先来看一下Ceph故障处理的主要流程,主要分为三大步骤:

  1. 感知集群状态:首先Ceph要能通过某种方法,及时感知集群故障,确定集群中节点的状态,判定哪些节点离开了集群,为确定哪些数据的副本受到故障影响提供权威依据。
  2. 确定受故障影响的数据:Ceph根据新的集群状态计算和判定副本缺失的数据。
  3. 恢复受影响的数据。

1、感知集群状态

Ceph集群分为MON集群和OSD集群两大部分。其中MON集群由奇数个Monitor节点组成,这些Monitor节点通过Paxos算法组成一个决策者集群,共同作出关键集群事件的决策和广播。“OSD节点离开”和“OSD节点加入”就是其中两个关键的集群事件。

caBvAj-1643285516686

MON集群管理着整个Ceph集群的成员状态,将OSD节点的状态信息存放在OSDMap中,OSD节点定期向MON和对等OSD(Peer OSD)发送心跳包,声明自己处于在线状态。MON接收来自OSD的心跳消息确认OSD在线;同时,MON也接收来自OSD对于Peer OSD的故障检测。MON根据心跳间隔等信息判定OSD是否在线,同时更新OSDMap并向各个节点通告最新集群状态。比如某台服务器宕机,其上OSD节点和MON集群的心跳超时或是这些OSD的对等OSD发送的失败通告超过阈值后,这些OSD将被MON集群判定为离线。

Fw56yp-1643285537485

判定OSD节点离线后,Ceph将最新的OSDMap通过消息机制随机分发给一个OSD,客户端(对等OSD)处理IO请求的时候发现自身的OSDMap版本过低,会向MON请求最新的OSDMap。每个OSD中PG的另外两个副本可能在集群任意OSD中,借此经过一段时间的传播,最终整个集群的OSD都会接收到OSDMap的更新。

9JMJgc-1643285551408

2、确定受影响的数据

Ceph中对象数据的维护由PG(Placement Group)负责,PG作为Ceph中最小的数据管理单元,直接管理对象数据,每个OSD都会管理一定数量的PG。客户端对于对象数据的IO请求,会根据对象ID的Hash值均衡分布在各个PG中。PG中维护了一份PGLog,用来记录该PG的数据变化,这些记录会被持久化记录到后端存储中。

PGLog中记录了每次操作的数据和PG的版本,每次数据变更操作都会使PG的版本自增,PGLog中默认保存3000条记录,PG会定期触发Trim操作清理多余的PGLog。通常情况下,在同一个PG的不同副本中的PGLog应该是一致的,故障发生后,不同副本的PGLog可能会处于不一致的状态。

OSD在收到OSDMap更新消息后,会扫描该OSD下所有的PG,清理已经不存在的PG(已经被删除等情况),对PG进行初始化,如果该OSD上的PG是Primary PG的话,PG将进行Peering操作。在Peering的过程中,PG会根据PGLog检查多个副本的一致性,并尝试计算PG的不同副本的数据缺失,最后得到一份完整的对象缺失列表,用作后续进行Recovery操作时的依据。对于无法根据PGLog计算丢失数据的PG,需要通过Backfill操作拷贝整个PG的数据来恢复。需要注意的是,在这Peering过程完成前,PG的数据都是不可靠的,因此在Peering过程中PG会暂停所有客户端的IO请求。

3、数据恢复

Peering完成后,PG进入Active状态,并根据PG的副本状态将自己标记为Degraded/Undersized状态,在Degraded状态下,PGLog存储的日志数量默认会扩展到10000条记录,提供更多的数据记录便于副本节点上线后的数据恢复。进入Active状态后,PG可用并开始接受数据IO的请求,并根据Peering的信息决定是否进行Recovery和Backfill操作。

Primary PG将根据对象的缺失列表进行具体对象的数据拷贝,对于Replica PG缺失的数据Primary 会通过Push操作推送缺失数据,对于Primary PG缺失的数据会通过Pull操作从副本获取缺失数据。在恢复操作过程中,PG会传输完整4M大小的对象。对于无法依靠PGLog进行Recovery的,PG将进行Backfill操作,进行数据的全量拷贝。待各个副本的数据完全同步后,PG被标记为Clean状态,副本数据保持一致,数据恢复完成。

4、控制恢复影响

通过Ceph处理故障的流程,我们可以看到Ceph如何应对集群故障常见的问题。首先是减少对资源的消耗:在断电重启这类故障中,Ceph可以只恢复有变化的数据,从而减少数据恢复量;另一方面,MON不会主动向所有OSD推送集群状态,而是采用OSD主动获取最新OSDMap的方式防止大规模集群发生故障场景下产生突发流量。

另外,由于Ceph的IO流程必须要通过Primary PG进行,一旦Primary PG所在的OSD宕机,IO将无法正常进行。为了保证恢复过程中不会中断正常的业务IO,MON会分配PG Temp临时处理IO请求,在数据恢复完成后再移除PG Temp。

同时在整个恢复过程中,Ceph也允许用户通过配置文件调整恢复线程数,同时进行的恢复操作数,恢复数据网络传输优先级等相关参数来限制恢复的速度,从而降低对正常业务的影响。

5、数据恢复优化

Ceph在数据恢复方面,设计和细节做的都相当不错。但是,目前Ceph恢复的颗粒度仍然比较大,需要更多的IO消耗;并且,被动的OSDMap更新可能会导致PG不会及时恢复故障数据,在一段时间内数据可靠性会降低。

同时,提醒我们在Ceph日常处理故障时需要注意的细节:

  • PGLog是Ceph进行数据恢复的重要依据,但是记录的日志数量有限,所以在发生故障后,尽快让故障节点重新上线,尽量避免产生Backfill操作,能极大的缩短恢复时间。
  • PG在Peering阶段会阻塞客户端IO,所以要保证PG能快速进行Peering。
  • 如果在故障过程中PGLog丢失,导致无法完成Peering,PG会进入Incomplete状态,这种情况下需要让故障节点上线帮助完成数据修复。

虽然Ceph的Recovery操作能够避免很多不必要的对象数据恢复,但是使用的还是完全对象拷贝,进一步的优化,可以考虑在PGLog中记录操作对象的具体数据位置、或是利用类似rsync的机制,只恢复对象副本间的差异数据。

参考资料

推荐笔记:

https://www.bookstack.cn/read/ceph-handbook/Operation-monitor_cluster.md

https://www.kancloud.cn/willseecloud/ceph/2360768

推荐:《OpenStack高可用集群(上册)》(山金孝) 10.3.3 ceph工作原理