Ceph:一个 Linux PB 级分布式文件系统
Ceph最初是一项关于存储系统的 PhD研究项目,由 Sage Weil在 University of California, Santa Cruz(UCSC)实施。但是到了 2010年 3月底,您可以在主线 Linux内核(从 2.6.34版开始)中找到 Ceph的身影。虽然 Ceph可能还不适用于生产环境,但它对测试目的还是非常有用的。本文探讨了 Ceph文件系统及其独有的功能,这些功能让它成为可扩展分布式存储的最有吸引力的备选。
“Ceph”对一个文件系统来说是个奇怪的名字,它打破了大多数人遵循的典型缩写趋势。这个名字和 UCSC(Ceph的诞生地)的吉祥物有关,这个吉祥物是“Sammy”,一个香蕉色的蛞蝓,就是头足类中无壳的软体动物。这些有多触角的头足类动物,提供了一个分布式文件系统的最形象比喻。
开发一个分布式文件系统需要多方努力,但是如果能准确地解决问题,它就是无价的。Ceph的目标简单地定义为:
不幸的是,这些目标之间会互相竞争(可扩展性会降低或者抑制性能或者影响可靠性)。Ceph开发了一些非常有趣的概念(动态元数据分区,数据分布和复制),这些概念在本文中只进行简短地探讨。Ceph的设计还包括保护单一点故障的容错功能,它假设大规模(PB级存储)存储故障是常见现象而不是例外情况。它的设计并没有假设某种特殊工作负载,但是包括适应变化的工作负载,提供最佳性能的能力。它利用 POSIX的兼容性完成所有这些任务,允许它对当前依赖 POSIX语义(通过以 Ceph为目标的改进)的应用进行透明的部署。Ceph是开源分布式存储,也是主线 Linux内核(2.6.34)的一部分。
让我们探讨一下 Ceph的架构以及高端的核心要素。然后我会拓展到另一层次,说明 Ceph中一些关键的方面,提供更详细的探讨。
Ceph生态系统可以大致划分为四部分(见图 1):客户端(数据用户),元数据服务器(缓存和同步分布式元数据),一个对象存储集群(将数据和元数据作为对象存储,执行其他关键职能),以及最后的集群监视器(执行监视功能)。
如图 1所示,客户使用元数据服务器,执行元数据操作(来确定数据位置)。元数据服务器管理数据位置,以及在何处存储新数据。元数据存储在一个存储集群(标为“元数据 I/O”)。实际的文件 I/O发生在客户和对象存储集群之间。更高层次的 POSIX功能(打开、关闭、重命名)就由元数据服务器管理,不过 POSIX功能(例如读和写)则直接由对象存储集群管理。
另一个架构视图由图 2提供。一系列服务器通过一个客户界面访问 Ceph生态系统,这就明白了元数据服务器和对象级存储器之间的关系。分布式存储系统可以在一些层中查看,包括一个存储设备的格式(Extent and B-tree-based Object File System [EBOFS]或者一个备选),还有一个设计用于管理数据复制,故障检测,恢复,以及随后的数据迁移的覆盖管理层,叫做 Reliable Autonomic Distributed Object Storage(RADOS)。监视器用于识别组件故障,包括随后的通知。
了解了 Ceph的概念架构之后,您可以挖掘到另一个层次,了解在 Ceph中实现的主要组件。Ceph和传统的文件系统之间的重要差异之一就是,它将智能都用在了生态环境而不是文件系统本身。
图 3显示了一个简单的 Ceph生态系统。Ceph Client是 Ceph文件系统的用户。Ceph Metadata Daemon提供了元数据服务器,而 Ceph Object Storage Daemon提供了实际存储(对数据和元数据两者)。Ceph Monitor提供了集群管理。要注意的是,Ceph客户,对象存储端点,元数据服务器(根据文件系统的容量)可以有许多,而且至少有一对冗余的监视器。这个文件系统是如何分布的呢?
早期版本的 Ceph利用在 User SpacE(FUSE)的 Filesystems,它把文件系统推入到用户空间,还可以很大程度上简化其开发。但是Ceph已经被集成到主线内核,使其更快速,因为用户空间上下文交换机对文件系统 I/O已经不再需要。
因为 Linux显示文件系统的一个公共界面(通过虚拟文件系统交换机 [VFS]),Ceph的用户透视图就是透明的。管理员的透视图肯定是不同的,考虑到很多服务器会包含存储系统这一潜在因素(要查看更多创建 Ceph集群的信息,见参考资料部分)。从用户的角度看,他们访问大容量的存储系统,却不知道下面聚合成一个大容量的存储池的元数据服务器,监视器,还有独立的对象存储设备。用户只是简单地看到一个安装点,在这点上可以执行标准文件 I/O。
Ceph文件系统—或者至少是客户端接口—在 Linux内核中实现。在大多数文件系统中,所有的控制和智能在内核的文件系统源本身中执行。在 Ceph中,文件系统的智能分布在节点上,这简化了客户端接口,并为 Ceph提供了大规模(甚至动态)扩展能力。
Ceph使用一个有趣的备选,而不是依赖分配列表(将磁盘上的块映射到指定文件的元数据)。Linux透视图中的一个文件会分配到一个来自元数据服务器的 inode number(INO),对于文件这是一个唯一的标识符。然后文件被推入一些对象中(根据文件的大小)。使用 INO和 object number(ONO),每个对象都分配到一个对象 ID(OID)。在 OID上使用一个简单的哈希,每个对象都被分配到一个放置组。放置组(标识为 PGID)是一个对象的概念容器。放置组到对象存储设备的映射是一个伪随机映射,使用一个叫做 Controlled Replication Under Scalable Hashing(CRUSH)的算法。放置组(以及副本)到存储设备的映射就不用依赖任何元数据,而是依赖一个伪随机的映射函数。这种操作是理想的,因为它把存储的开销最小化,简化了分配和数据查询。
分配的最后组件是集群映射。集群映射是设备的有效表示,显示了存储集群。有了 PGID和集群映射,您就可以定位任何对象。
元数据服务器(cmds)的工作就是管理文件系统的名称空间。虽然元数据和数据两者都存储在对象存储集群,但两者分别管理,支持可扩展性。元数据在一个元数据服务器集群上被进一步拆分,元数据服务器能够自适应地复制和分配名称空间,避免出现热点。如图 4所示,元数据服务器管理名称空间部分,可以(为冗余和性能)进行重叠。元数据服务器到名称空间的映射在 Ceph中使用动态子树逻辑分区执行,它允许 Ceph对变化的工作负载进行调整(在元数据服务器之间迁移名称空间)同时保留性能的位置。
但是因为每个元数据服务器只是简单地管理客户端人口的名称空间,它的主要应用就是一个智能元数据缓存(因为实际的元数据最终存储在对象存储集群中)。进行写操作的元数据被缓存在一个短期的日志中,它最终还是被推入物理存储器中。这个动作允许元数据服务器将最近的元数据回馈给客户(这在元数据操作中很常见)。这个日志对故障恢复也很有用:如果元数据服务器发生故障,它的日志就会被重放,保证元数据安全存储在磁盘上。
元数据服务器管理 inode空间,将文件名转变为元数据。元数据服务器将文件名转变为索引节点,文件大小,和 Ceph客户端用于文件 I/O的分段数据(布局)。
Ceph包含实施集群映射管理的监视器,但是故障管理的一些要素是在对象存储本身中执行的。当对象存储设备发生故障或者新设备添加时,监视器就检测和维护一个有效的集群映射。这个功能按一种分布的方式执行,这种方式中映射升级可以和当前的流量通信。Ceph使用 Paxos,它是一系列分布式共识算法。
和传统的对象存储类似,Ceph存储节点不仅包括存储,还包括智能。传统的驱动是只响应来自启动者的命令的简单目标。但是对象存储设备是智能设备,它能作为目标和启动者,支持与其他对象存储设备的通信和合作。
从存储角度来看,Ceph对象存储设备执行从对象到块的映射(在客户端的文件系统层中常常执行的任务)。这个动作允许本地实体以最佳方式决定怎样存储一个对象。Ceph的早期版本在一个名为 EBOFS的本地存储器上实现一个自定义低级文件系统。这个系统实现一个到底层存储的非标准接口,这个底层存储已针对对象语义和其他特性(例如对磁盘提交的异步通知)调优。B-tree文件系统(BTRFS)可以被用于存储节点,它已经实现了部分必要功能(例如嵌入式完整性)。
因为 Ceph客户实现 CRUSH,而且对磁盘上的文件映射块一无所知,下面的存储设备就能安全地管理对象到块的映射。这允许存储节点复制数据(当发现一个设备出现故障时)。分配故障恢复也允许存储系统扩展,因为故障检测和恢复跨生态系统分配。Ceph称其为 RADOS(见图 3)。
如果文件系统的动态和自适应特性不够,Ceph还执行一些用户可视的有趣功能。用户可以创建快照,在 Ceph的任何子目录上(包括所有内容)。文件和容量计算可以在子目录级别上执行,它报告一个给定子目录(以及其包含的内容)的存储大小和文件数量。
虽然 Ceph现在被集成在主线 Linux内核中,但只是标识为实验性的。在这种状态下的文件系统对测试是有用的,但是对生产环境没有做好准备。但是考虑到 Ceph加入到 Linux内核的行列,还有其创建人想继续研发的动机,不久之后它应该就能用于解决您的海量存储需要了。
Ceph在分布式文件系统空间中并不是唯一的,但它在管理大容量存储生态环境的方法上是独一无二的。分布式文件系统的其他例子包括 Google File System(GFS),General Parallel File System(GPFS),还有 Lustre,这只提到了一部分。Ceph背后的想法为分布式文件系统提供了一个有趣的因为海量级别存储导致了海量存储问题的唯一挑战。
ceph pg inconsistent不一致(主副本是好的),ceph pg repair无效
ceph pg repair这一操作会先进行pg scrub,得到该PG中不一致的对象,然后再进行recovery。
pg scrub时主副本和从副本均会进行资源预约,只有当scrubs_pending+ scrubs_active< _conf->osd_max_scrubs时scrub才能继续进行,也即repair才能进行,否则,repair会失效。
scrubs_pending:该osd已经预约成功,即将进行scrub的pg。
scrubs_active:该osd正在进行scrub的对象。
osd_max_scrubs:一个osd同一时刻默认只能有一个pg做scrub。
资源预约失败日志如下图:
解决办法:
把三副本的osd的osd_max_scrubs都先调大,等到修复好后再调回为1。
备注:
1、只有主副本是好的,从副本有问题时,才能直接使用ceph pg repair。主副本损坏导致的不一致,需要使用其他方法修复。
2、主副本和从副本均有可能因为资源预约失败。
3、初始调大为2,依然无效,调大为5,成功。
ceph分布式存储-常见 PG 故障处理
创建一个新集群后,PG的状态一直处于 active, active+ remapped或 active+ degraded状态,而无法达到 active+ clean状态,那很可能是你的配置有问题。
你可能需要检查下集群中有关 Pool、 PG和 CRUSH的配置项,做以适当的调整。
你的集群中需要多于 1个 OSD,并且存储池的 size要大于 1副本。
有时候,我们需要搭建一个单节点的 Ceph实验环境。此时,在开始创建 monitor和 OSD之前,你需要把 Ceph配置文件中的 osd crush chooseleaf type选项从默认值 1(表示 host或 node)修改为 0(表示 osd)。这样做是告诉 Ceph允许把数据的不同副本分布到同一 host的 OSDs上。
如果你已经启动了 2个 OSD,它们都处于 up和 in的状态,但 PG仍未达到 active+ clean状态,那可能是给 osd pool default size设置了一个大于 2的值。
如果你想要在 active+ degraded状态( 2副本)操作你的集群,可以设置 osd pool default min size为 2,这样你就可以对处于 active+ degraded的对象写入数据。然后你还可以把 osd pool default size的值改为 2,这样集群就可以达到 active+ clean状态了。
修改参数 osd pool default size/min_size后,只会对后面新建的 pool起作用。如果想修改已存在的 pool的 size/min_size,可用下面的命令:
注意:你可以在运行时修改参数值。如果是在 Ceph配置文件中进行的修改,你可能需要重启集群。
如果你设置了 osd pool default size的值为 1,那你就仅有对象的单份拷贝。OSD依赖于其他 OSD告诉自己应该保存哪些对象。如果第一个 OSD持有对象的拷贝,并且没有第二份拷贝,那么也就没有第二个 OSD去告诉第一个 OSD它应该保管那份拷贝。对于每一个映射到第一个 OSD上的 PG(参考 ceph pg dump的输出),你可以强制第一个 OSD关注它应该保存的 PGs:
PG达不到 clean状态的另一个可能的原因就是集群的 CRUSH Map有错误,导致 PG不能映射到正确的地方。
有失败发生后,PG会进入“degraded”(降级)或“peering”(连接建立中)状态,这种情况时有发生。通常这些状态意味着正常的失败恢复正在进行。如果一个 PG长时间处于这些状态中的某个,就意味着有更大的问题。因此 monitor在 PG卡( stuck)在非最优状态时会告警。我们具体检查:
你可以用下列命令显式地列出卡住的 PGs:
卡在 stale状态的 PG通过重启 ceph-osd进程通常可以修复;卡在 inactive状态的 PG通常是互联问题(参见 PG挂了——互联失败);卡在 unclean状态的 PG通常是由于某些原因阻止了恢复的完成,像未找到的对象(参见未找到的对象)。
在某些情况下, ceph-osd互联进程会遇到问题,阻值 PG达到活跃、可用的状态。 ceph health也许显示:
可以查询到 PG为何被标记为 down:
recovery_state段告诉我们互联过程因 ceph-osd进程挂了而被阻塞,本例是 osd.1挂了,启动这个进程应该就可以恢复。
或者,如果 osd.1发生了灾难性的失败(如硬盘损坏),我们可以告诉集群它丢失( lost)了,让集群尽力完成副本拷贝。
重要:集群不能保证其它数据副本是一致且最新的,就会很危险!
让 Ceph无论如何都继续:
恢复将继续进行。
某几种失败相组合,可能导致 Ceph抱怨有找不到( unfound)的对象:
这意味着存储集群知道一些对象(或者存在对象的较新副本)存在,却没有找到它们的副本。下例展示了这种情况是如何发生的,一个 PG的数据存储在 ceph-osd 1和 2上:
1知道这些对象存在,但是活着的 ceph-osd都没有这些副本。这种情况下,读写这些对象的 IO就会被阻塞,集群只能指望 down掉的节点尽早恢复。这样处理是假设比直接给用户返回一个 IO错误要好一些。
你应该确认哪些对象找不到了:
如果在一次查询里列出的对象太多, more这个字段将为 true,你就可以查询更多。
你可以找出哪些 OSD上探测到、或可能包含数据:
本例中,集群知道 osd.1可能有数据,但它挂了( down)。所有可能的状态有:
有时候集群要花一些时间来查询可能的位置。
还有一种可能性,对象存在于其它位置却未被列出。集群里的一个 ceph-osd停止且被剔出集群,然后集群完全恢复了;后来一系列的失败导致了未找到的对象,它也不会觉得早已死亡的 ceph-osd上仍可能包含这些对象。(这种情况几乎不太可能发生)。
如果所有可能的位置都查询过了但仍有对象丢失,那就得放弃丢失的对象了。这仍可能是罕见的失败组合导致的,集群在写操作恢复后,未能得知写入是否已执行。以下命令把未找到的( unfound)对象标记为丢失( lost)。
上述最后一个参数告诉集群应如何处理丢失的对象。
拥有 PG拷贝的 OSD可能会全部失败,这种情况下,那一部分的对象存储不可用, monitor也就不会收到那些 PG的状态更新了。为检测这种情况,monitor会把任何主 OSD失败的 PG标记为 stale(不新鲜),例如:
可以找出哪些 PG是 stale状态,和存储这些归置组的最新 OSD,命令如下:
如果想使 PG 2.5重新上线,上面的输出告诉我们它最后由 osd.0和 osd.2管理,重启这些 ceph-osd将恢复之(可以假定还有其它的很多 PG也会进行恢复)。
如果你的集群有很多节点,但只有其中几个接收数据,检查下存储池里的 PG数量。因为 PG是映射到多个 OSD的,较少的 PG将不能均衡地分布于整个集群。试着创建个新存储池,设置 PG数量是 OSD数量的若干倍。更详细的信息可以参考 Ceph官方文档—— Placement Groups。
如果你的集群已启动,但一些 OSD没起来,导致不能写入数据,确认下运行的 OSD数量满足 PG要求的最低 OSD数。如果不能满足, Ceph就不会允许你写入数据,因为 Ceph不能保证复制能如愿进行。这个最低 OSD个数是由参数 osd pool default min size限定的。
如果收到 active+ clean+ inconsistent这样的状态,很可能是由于在对 PG做擦洗( scrubbing)时发生了错误。如果是由于磁盘错误导致的不一致,请检查磁盘,如果磁盘有损坏,可能需要将这个磁盘对应的 OSD踢出集群,然后进行更换。生产环境中遇到过不一致的问题,就是由于磁盘坏道导致的。
当集群中出现 PG不一致的问题时,执行 ceph-s命令会出现下面的信息:
1、查找处于 inconsistent状态的问题 PG:
这个有问题的 PG分布在 osd.1、 osd.2和 osd.0上,其中 osd.1是主 OSD。
2、去主 OSD( osd.1)的日志中查找不一致的具体对象。
从日志中可以知道,是 rbd_data.1349f035c101d9.0000000000000001这个对象的属性 _丢失了,所以在 scrub的过程中产生了 error。
3、执行 ceph pg repair命令修复问题 PG。
4、检查 Ceph集群是否恢复到 HEALTH_OK状态。
osd.1的日志里也提示修复成功:
如果经过前面的步骤,Ceph仍没有达到 HEALTH_OK状态,可以尝试用下面这种方式进行修复。
1、停掉不一致的 object所属的 osd。
2、刷新该 osd的日志。
3、将不一致的 object移除。
4、重新启动该 osd。
5、重新执行修复命令。
6、检查 Ceph集群是否恢复到 HEALTH_OK状态。
有时候,我们在 ceph-s的输出中可以看到如下的告警信息:
这是因为集群 OSD数量较少,测试过程中建立了多个存储池,每个存储池都要建立一些 PGs。而目前 Ceph配置的默认值是每 OSD上最多有 300个 PGs。在测试环境中,为了快速解决这个问题,可以调大集群的关于此选项的告警阀值。方法如下:
在 monitor节点的 ceph.conf配置文件中添加:
然后重启 monitor进程。
或者直接用 tell命令在运行时更改参数的值而不用重启服务:
而另一种情况, too few PGs per OSD(16< min 20)这样的告警信息则往往出现在集群刚刚建立起来,除了默认的 rbd存储池,还没建立自己的存储池,再加上 OSD个数较多,就会出现这个提示信息。这通常不是什么问题,也无需修改配置项,在建立了自己的存储池后,这个告警信息就会消失。