一、Ceph概述

1、存储发展史

企业中使用存储按照其功能,使用场景,一直在持续发展和迭代,大体上可以分为四个阶段:

  • DAS:Direct Attached Storage,即直连存储,第一代存储系统,通过SCSI总线扩展至一个外部的存储,磁带整列,作为服务器扩展的一部分;
  • NAS:Network Attached Storage,即网络附加存储,通过网络协议如NFS远程获取后端文件服务器共享的存储空间,将文件存储单独分离出来;
  • SAN:Storage Area Network,即存储区域网络,分为IP-SAN和FC-SAN,即通过TCP/IP协议和FC(Fiber Channel)光纤协议连接到存储服务器;
  • Object Storage:即对象存储,随着大数据的发展,越来越多的图片,视频,音频静态文件存储需求,动仄PB以上的存储空间,需无限扩展。

存储的发展,根据不同的阶段诞生了不同的存储解决方案,每一种存储都有它当时的历史诞生的环境以及应用场景,解决的问题和优缺点。

区别如下:

DAS 直连存储服务器使用 SCSI 或 FC 协议连接到存储阵列、通过 SCSI 总线和 FC 光纤协议类型进行数据传输;例如一块有空间大小的裸磁盘:/dev/sdb。DAS存储虽然组网简单、成本低廉但是可扩展性有限、无法多主机实现共享、目前已经很少使用了。

NAS网络存储服务器使用TCP网络协议连接至文件共享存储、常见的有NFS、CIFS协议等;通过网络的方式映射存储中的一个目录到目标主机,如/data。NAS网络存储使用简单,通过IP协议实现互相访问,多台主机可以同时共享同一个存储。但是NAS网络存储的性能有限,可靠性不是很高。

SAN存储区域网络服务器使用一个存储区域网络IP或FC连接到存储阵列、常见的SAN协议类型有IP-SAN和FC-SAN。SAN存储区域网络的性能非常好、可扩展性强;但是成本特别高、尤其是FC存储网络:因为需要用到HBA卡、FC交换机和支持FC接口的存储。

Object Storage对象存储通过网络使用API访问一个无限扩展的分布式存储系统、兼容于S3风格、原生PUT/GET等协议类型。表现形式就是可以无限使用存储空间,通过PUT/GET无限上传和下载。可扩展性极强、使用简单,但是只使用于静态不可编辑文件,无法为服务器提供块级别存储。

综上、企业中不同场景使用的存储,使用表现形式无非是这三种:磁盘(块存储设备),挂载至目录像本地文件一样使用(文件共享存储),通过API向存储系统中上传PUT和下载GET文件(对象存储)。

2、Ceph简介

什么是分布式存储? 打个比方, 我在一个环境当中,有很多很多的服务器,服务器上也有它自己很多的硬盘,我通过软件的形式把若干服务器都收集起来,部署成一个软件,在这个逻辑的软件里可以同时看到我若干服务器的磁盘的空间,这个逻辑的软件对外就像是一个整体一样,这个整体叫storage spool,用户呢有一天想用这个空间了,用户直接去对应这个存储池提供的接口,这用的话,用户保存一个文件,实际上保存在若干个服务器里,文件会随机存到第一个服务器的第一块硬盘里,下一次就可能存到第二个服务器的第三块硬盘里。它会把文件进行打散,分成不同的小块,每块存放的位置可能是不同的服务器上的不同硬盘里。

通俗的说:分布式文件系统管理的物理存储资源不一定直接连接在本机节点上,而是通过计算机网络与节点相连(把分散在局域网内各个计算机上)共享文件夹,集合到一个文件夹内(虚拟共享文件夹)

分布式存储还可以对文件进行安全备份,我这个文件存在后端的服务器里,可以保存多份,多份叫副本也可以叫镜像。就是说对我打散的每块文件做一个镜像在保存在不同服务器上的不同硬盘里,这样,如果后端有服务器宕掉了,我的文件还是完整的。ceph就可以做到这么一种功能。

Ceph是一种为优秀的性能、可靠性和可扩展性而设计的统一的、分布式文件系统,主要由Ceph存储系统的核心RADOS以及块存储接口、对象存储接口和文件系统存储接口组成。Ceph 的统一体现在可以提供文件系统、块存储和对象存储,分布式体现在可以动态扩展,在国内一些公司的云环境中,通常会采用 ceph 作为openstack 的唯一后端存储来提高数据转发效率。

Ceph项目最早起源于Sage就读博士期间的工作(最早的成果于2004年发表),并随后贡献给开源社区。在经过了数年的发展之后,目前已得到众多云计算厂商的支持并被广泛应用。RedHat及OpenStack都可与Ceph整合以支持虚拟机镜像的后端存储。但是在2014年OpenStack火爆的时候、Ceph并不被很多人所接受。当时Ceph并不稳定(Ceph发布的第四个版本 Dumpling v0.67),而且架构新颖,复杂,当时人们对Ceph在生产落地如何保障数据的安全,数据的一致性存在怀疑。

云计算三驾马车为计算、网络和存储, Ceph最初仅支持文件系统存储方式,后来发展到支持块存储和对象存储接口。

随着OpenStack的快速发展,给Ceph的发展注入了强心剂,越来越多的人使用Ceph作为OpenStack的底层共享存储,Ceph在中国的社区也蓬勃发展起来。近两年OpenStack火爆度不及当年,借助于云原生尤其是Kubernetes技术的发展,作为底层存储的基石,Ceph再次发力,为Kubernets有状态化业务提供了存储机制的实现。

Ceph官网:Ceph.io — Home

Ceph中文开源社区:Ceph中国社区 – The Future of Storage™

3、Ceph特点

高性能:

1. 摒弃了传统的集中式存储元数据寻址的方案,采用CRUSH算法,数据分布均衡,并行度高。

2. 考虑了容灾域的隔离,能够实现各类负载的副本放置规则,例如跨机房、机架、感知等。

3. 能够支持上千个存储节点的规模,支持TB到PB级的数据。

4.  并且客户端与存储数据的OSD设备直接进行数据交互,大大提高了数据的存取性能。

高可用性:

1. 副本数可以灵活控制。(就是说让副本保存份数可以多份,在正常的生产环境是保存3副本)

2. 支持故障域分隔,数据强一致性。

3. 多种故障场景自动进行修复自愈。

4.没有单点故障,自动管理。(假如说我这个文件设置的是3副本,如果后端服务器坏掉,副本数不够3,它会自动补充至3副本)

5. Ceph的核心RADOS通常是由少量的负责集群管理的Monitor进程和大量的负责数据存储的OSD进程构成,采用无中心节点的分布式架构,对数据进行分块多份存储,具有良好的高可用性。

高可扩展性:

1. 去中心化。

2. 扩展灵活。

3. 随着节点增加而线性增长。

丰富的特性

1. Ceph分布式文件系统提供了多种客户端,包括块存储(我得到的是硬盘)、文件存储(目录)、对象存储(有可能给你对接的是一个挂载的目录,但是后端怎么去存的,它会把数据打散,采用键值对形式存储),具有广泛的适用性。

2. 支持自定义接口,支持多种语言驱动,如S3.compatible、Swift.compatible。

3. Ceph作为分布式文件系统,其能够在维护 POSIX 兼容性的同时加入了复制和容错功能。从2010 年 3 月底,以及可以在Linux 内核(从2.6.34版开始)中找到 Ceph 的身影,作为Linux的文件系统备选之一,Ceph.io已经集成入Linux内核之中。Ceph 不仅仅是一个文件系统,还是一个有企业级功能的对象存储生态环境。

CRUSH算法:

能实现各类负载的副本放置规则,具有相当强大的拓展性,支持数千个存储节点。

4、Ceph应用场景

Ceph是一种开源、高可扩展、部署在通用架构服务器的软件定义存储产品。其设计思路是将通用
的服务器和硬盘设备通过网络协议进行集群组建,构建成一套存储集群,对外提供多种访问接口,实现满足多种使用场景的分布式存储。

设计原理决定其对网络和硬件设备的依赖较为明显,因此投产Ceph的环境必须使用万兆网络,同
时配置SSD硬盘设备对集群进行写加速。另外,Ceph存储数据是按照2MB为基本单位进行读写的,即便是小文件也要按照此种方式进行操作。写入时要组成2MB的块一次性写入,读取时一次性读取2MB的块。如果用户数据为字节级别,频繁读写将对Ceph的性能产生冲击。

因此,在设计原理的限制下,你在投产Ceph时必须要考虑清楚其使用场景。如果不满足Ceph的使
用场景,此类数据建议不要放入Ceph中。

目前,推荐使用Ceph的应用场景,主要分为5大类:数据分析、云计算平台、富媒体和
归档、企业文件同步和共享、服务器和应用程序。这5类场景特点主要体现在数据海量,对数据读写性能要求不苛刻,而对计算水平要求较高。

1. Ceph可以提供对象存储、块设备存储和文件系统服务,其对象存储可以对接网盘(owncloud)应用业务等。

2. 由于大数据分析中捕获的数据量巨大,并且需要在数据专家和数据分析师团队之间共享有限的资
源,因此传统的数据分析基础架构承受着巨大的压力。各方呼吁推出一种全新的架构和存储形态。一些数据平台团队正在将Apache Hadoop和Spark大数据分析平台作为其数据分析的主要工具,后端采用Hadoop分布式文件系统(HDFS)集群。不幸的是,由于HDFS通常不会在不同集群之间共享数据,因此在大型计算集群中的每个集群间复制数据会付出很高的代价。

一些团队希望其集群的分析工具尽量稳定,因此不愿意更新版本,而其数据分析的业务单元需要加载最新的分析工具版本。最终,这些团队都构建了自己单独的、量身定制的分析集群,以免与其他
团队竞争资源。使用传统的Hadoop时,每个单独的分析集群通常都有自己专用的HDFS数据包。
为了在不同的Hadoop / HDFS集群中能访问相同的数据,平台团队必须在集群之间复制非常大的数据集,以保持数据的一致性和时效性。因此,公司维护了许多单独的固定分析集群(其中一家公司
中有50多个集群)。每个集群在HDFS中都有自己的冗余数据副本。就资本支出(Capex)和运营支出(Opex)而言,在各个集群上维护5PB、10PB或20PB副本数据的成本都非常高。

Ceph和IaaS云、PaaS云的结合为解决上述一系列问题提供了新的方案。Ceph在底层多集群间可以实现数据自动同步,这大大降低了集群数据复制的开销和运营成本,为Hadoop或Spark的大数据分析工具提供了另一种分布式存储选择。

3. 其块设备存储可以对接(IaaS),当前主流的IaaS运平台软件,如:OpenStack、CloudStack、Zstack、Eucalyptus等以及kvm等。

4. 中国银监会、证监会、保监会发出行业规范,要求逐步实施金融类产品在销售过程中录音和录像
(简称“双录”)同步,加强金融类产品的全过程风险管理。因此,录音和录像等大文件的存储发生了新的变化。此部分数据的使用率较低,但是需要在线查看,因此容量大、低成本、安全、可靠成为存储的新要求。

传统制造业面临同样的需求。公司内部的研发数据、扫描单据、文档等都需要归档备份。不论哪
个场景,此类数据的共同特点是要求存储容量大、安全、可靠。

很多企业在考虑使用基于网络的备份解决方案(NBU),支持所有完善的操作系统(例如Linux、UNIX、Windows、macOS X)可以备份到磁盘、磁带驱动器以及磁带库。除了完整、增量和
差异备份等常见备份策略外,企业还要求解决方案有迁移、副本、去重等功能。而基于网络的备份解决方案提供的备份机制和策略很难完全满足要求,因此数据需要存放在更加灵活、安全、可靠的分布式存储系统中。

Ceph成为这类网络备份的首选后端存储方案。较为典型的开源备份软件有Bareos、Bacula、Amanda等。Ceph提供了与这类备份软件的集成方案,可以将备份直接写入后端,传输过程中对数据进行加密,因此很安全。企业通过这类开源备份软件自我备份,可以在发生灾难时迅速恢复数据运行。

Ceph集成Bareos/Bacula/Amanda备份软件,可以实现应用数据文件的备份。数据中心现有的应用程序或客户端产生的数据不论存放在Ceph集群还是传统存储中,你都可以搭建开源备份软件对数
据进行备份和归档。而如果采用Ceph,你就采用了分布式技术,也就意味着数据存放在更加安全的存储资源池中,使未来存储扩容更加便捷。同时,Ceph底层技术提供数据容灾,从某种意义上讲对备份方案是一种补充,提高了备份归档方案的灵活性。

5. 在使用服务器时,你经常遇到磁盘空间不足,需要扩容或者添加新磁盘的情况。如果是在服务器
(裸机或VM)上的Linux系统中添加磁盘,需要通过网络将磁盘映射到本地,以便新设备对其进行分区格式化处理。Ceph提供的RBD块存储映射到服务器后,在服务器后端即可看到/dev/目录下生成了新的RBD设备。对这个设备的所有操作都将写入Ceph集群。

另一种场景是Linux服务器上的某个目录空间不足,不需要新增磁盘,只需要将CephFS文件系统
挂载到该目录下,将原有数据重新映射进来,即可使用CephFS提供的存储空间。此目录下所有的数据都将落入服务器外部的Ceph集群。这样,服务器目录的扩展问题通过Ceph提供的存储空间得到了有效解决。服务器以添加Ceph RBD的方式增加服务器系统上的块设备。

对于企业应用产生的数据,你可以直接在应用程序中将数据或者日志写入后端存储。实现方法是
调用Ceph的对象存储S3兼容接口,将应用数据直接写入Ceph的S3 URL地址,这样数据可通过Ceph对象网关写入Ceph集群,实现数据共享。

5、生产环境推荐

1. 存储集群采用全万兆网络;

2. 集群网络(不对外)与公共网络分离(使用不同网卡);

3. mon、mds与osd分离部署在不同机器上;

4. journal推荐使用SSD,一般企业级IOPS可达40万以上;

5. OSD使用SATA亦可;

6. 根据容量规划集群;

7. 至强E5 2620 V3或以上cpu,64GB或更高内存;

8. 最后,集群主机分散部署,避免机柜故障(电源、网络);

6、其他存储方案

1. GPFS/通用并行文件系统

GPFS(General Parallel File System,通用并行文件系统)是一个分布式文件系统,由IBM开发及拥有。这是一个专有、闭源的存储系统,这使得它缺少吸引力并且难以适应。存储硬件加上授权以及支持成本使得它非常昂贵。另外,它提供的存储访问接口非常有限;它既不能提供块存储,也不能提供RESTful接口来访问存储系统,因此这是一个限制非常严格的系统。甚至最大的数据副本数都限制只有3个,这在多个组件同时故障的情形下降低了系统的可靠性。

2. iRDOS

iRDOS是面向规则的数据系统的代表,它是依据第三条款(3-clause)BSD协议发布的开源数据管理软件。iRDOS不是一个高度可靠的存储系统,因为它的iCAT元数据服务器是单点(single point of failure,SPOF),并且它不提供真正的HA。另外,它提供的存储访问接口很有限;既不能提供块存储,也不能提供RESTful接口来访问存储系统,因此这是一个限制非常严格的系统。它更适合于存储少量大文件,而不是同时存储小文件和大文件。iRdos采用传统的工作方式,维护一个关于物理位置(与文件名相关联)的索引。由于多个客户端都需要从元数据服务器请求文件位置,使得元数据服务器需要承受更多的计算负载,从而导致单点故障以及性能瓶颈。

3. HDFS

HDFS是一个用Java写的并且为Hadoop框架而生的分布式可扩展文件系统。HDFS不是一个完全兼容POSIX的文件系统,并且不支持块存储,这使得它的适用范围不如Ceph。HDFS的可靠性不需要讨论,因为它不是一个高度可用的文件系统。HDFS中的单点故障以及性能瓶颈主要源于它单一的NameNode节点。它更适合于存储少量大文件,而不是同时存储小文件和大文件。

4. Lustre

Lustre是一个由开源社区推动的并行分布式文件系统,依据GNU(General Public License,通用公共许可证)发布。在Lustre中,由单独一个服务器负责存储和管理元数据。因此,从客户端来的所有I/O请求都完全依赖于这个服务器的计算能力,但对企业级计算来说通常这个服务器的计算能力都比较低。与iRDOS和HDFS类似,Lustre适合于存储少量大文件,而不是同时存储小文件和大文件。与iRDOS类似,Lustre管理一个用于映射物理位置和文件名的索引文件,这就决定了它是一个传统的架构,而且容易出现性能瓶颈。Lustre不具备任何节点故障检测和纠正机制。在节点出现故障时,客户端只能自行连接其他节点。

5. Gluster

GlusterFS最初由Gluster公司开发,该公司2011年被Red Hat收购。GlusterFS是一个横向扩展的网络附加(network-attached)文件系统。在Gluster中,管理员必须明确使用哪种安置策略来将数据副本存储到不同地域的机架上。Gluster本身不内置块访问、文件系统和远程副本,而是以扩展(add-ons)的方式支持。

二、Ceph存储架构

1、Ceph三大存储接口

Ceph能够提供企业中三种常见的存储需求:块存储、文件存储和对象存储。正如Ceph官方所定义的一样“Ceph uniquely delivers object, block, and file storage in one unified system.”,Ceph在一个统一的存储系统中同时提供了对象存储、块存储和文件存储,即Ceph是一个统一存储,能够将企业企业中的三种存储需求统一汇总到一个存储系统中,并提供分布式、横向扩展,高度可靠性的存储系统。

Ceph提供了三种存储接口:块存储RBD、对象存储RGW、文件存储CephFS,每种存储都有其相应的功能和特性:

官方文档:http://docs.ceph.org.cn/

1. CEPH OBJECT STORE对象存储,包含功能,特性如下:

  • RESTful Interface RESTful风格接口;
  • S3- and Swift-compliant APIs 提供兼容于S3和Swfit风格API;
  • S3-style subdomains S3风格的目录风格;
  • Unified S3/Swift namespace 统一扁平的S3/Swift命名空间,即所有的对象存放在同一个平面上;
  • User management 提供用户管理认证接入;
  • Usage tracking 使用情况追踪;
  • Striped objects 对象切割,将一个大文件切割为多个小文件(objects);
  • Cloud solution integration 云计算解决方案即成,可以与Swfit对象存储即成;
  • Multi-site deployment 多站点部署,保障可靠性;
  • Multi-site replication 多站点复制,提供容灾方案。

2. CEPH BLOCK DEVICE块存储,包含功能,特性如下:

  • Thin-provisioned 瘦分配,即先分配特定存储大小,随着使用实际使用空间的增长而占用存储空间,避免空间占用;
  • Images up to 16 exabytes 耽搁景象最大能支持16EB;
  • Configurable striping 可配置的切片,默认是4M;
  • In-memory caching 内存缓存;
  • Snapshots 支持快照,将当时某个状态记录下载;
  • Copy-on-write cloning Copy-on-write克隆复制功能,即制作某个镜像实现快速克隆,子镜像依赖于母镜像;
  • Kernel driver support 内核驱动支持,即rbd内核模块;
  • KVM/libvirt support 支持KVM/libvirt,实现与云平台如openstack,cloudstack集成的基础;
  • Back-end for cloud solutions 云计算多后端解决方案,即为openstack,kubernetes提供后端存储;
  • Incremental backup 增量备份;
  • Disaster recovery (multisite asynchronous replication) 灾难恢复,通过多站点异步复制,实现数据镜像拷贝。

3. CEPH FILE SYSTEM文件存储,包含功能,特性如下:

  • POSIX-compliant semantics POSIX风格接口;
  • Separates metadata from data 元数据metadata和数据data分开存储;
  • Dynamic rebalancing 动态数据均衡;
  • Subdirectory snapshots 子目录快照;
  • Configurable striping 可配置切割大小;
  • Kernel driver support 内核驱动支持,即CephFS;
  • FUSE support 支持FUSE风格;
  • NFS/CIFS deployable 支持NFS/CIFS形式部署;
  • Use with Hadoop (replace HDFS) 可支持与Hadoop继承,替换HDFS存储。

简而言之:

  • 块存储:采用SAN架构组网时,光纤交换机,造价成本高。 主机之间无法共享数据。
  • 文件系统:读写速率低。 传输速率慢。
  • 对象存储:具备块存储的读写高速。 具备文件存储的共享等特性。

Ceph的块设备存储具有优异的存储性能但不具有共享性,而Ceph的文件系统具有共享性,然而性能较块设备存储差,对象存储具有共享性而存储性能好于文件系统存储的存储,对象存储就这样出现了文件系统存储具有复杂的数据组织结构,能够提供给用户更加丰富的数据操作接口,而对象存储精简了数据组织结构,提供给用户有限的数据操作接口,以换取更好的存储性能。对象接口提供了REST API,非常适用于作为web应用的存储。

2、Ceph支持的接口

1. S3.compatible:

S3兼容的接口,提供与Amazon S3大部分RESTfuI API接口兼容的API接口。

2. Swift.compatible:

提供与OpenStack Swift大部分接口兼容的API接口。

3、Ceph核心组件

Ceph独一无二地用统一的系统提供了对象、块、和文件存储功能,它可靠性高、管理简便、并且是自由软件。 Ceph 的强大足以改变贵公司的 IT 基础架构、和管理海量数据的能力。

Ceph可提供极大的伸缩性,供成千用户访问 PB 乃至 EB 级的数据,Ceph 节点以普通硬件和智能守护进程作为支撑点, Ceph 存储集群组织起了大量节点,它们之间靠相互通讯来复制数据、并动态地重分布数据。

我们先来看一下Ceph的存储架构,了解Ceph的分布式架构,功能组件和涉及相关概念。

RADOS:Ceph分布式集群是建立在RADOS算法之上的,Ceph所有的存储功能都是基于RADOS实现。RADOS是一个高可扩展性,高可靠、高性能能、高自动化的存储服务算法,是Ceph的实现的基础。

LIBRADOS库:基于RADOS层的上一层,为应用程度提供访问接口。同时也为块存储、对象存储、文件系统提供原生的接口。允许应用程序通过访问该库来与RADOS系统进行交互,支持多种编程语言。

RADOSGW:对象存储接口,提供对象存储服务。它使用librados向客户端提供RESTful接口的对象存储接口,来实现允许应用程序与Ceph对象存储建立连接,兼容S3 和 Swift 兼容的RESTful API接口。注:S3提供与Amazon S3大部分RESTfuI API接口兼容的API接口, Swift 提供与OpenStack Swift大部分接口兼容的API接口。

RBD:块设备存储接口,是Ceph对外提供的块设备服务,它能够自动精简配置并可调整大小,而且将数据分散存储在多个OSD上。一个数据块是一个字节序列(例如,一个512字节的数据块),基于数据块存储接口最常见的介质,如硬盘,光盘,软盘,甚至是传统的9磁道的磁带的方式来存储数据。块设备接口的普及使得虚拟块设备成为构建像Ceph海量数据存储系统理想选择, 在一个Ceph的集群中, Ceph的块设备支持自动精简配置,调整大小和存储数据。Ceph的块设备可以充分利用 RADOS功能,实现如快照,复制和数据一致性。Ceph的RADOS块设备(即RBD)通过RADOS协议与内核模块或librbd的库进行交互。

CEPH FS:是Ceph对外提供的文件系统服务的接口,与POSIX兼容的文件系统,基于librados封装原生接口,使用Ceph的存储集群来存储其数据。

RADOS所有其他客户端接口使用和部署的基础。主要由两部分组成,分别是OSD和Monitor:Ceph Monitors(Ceph监视器)和Ceph OSDs(Ceph OSD 守护进程)

典型的RADOS部署架构由少量的Monitor监控器以及大量的OSD存储设备组成,它能够在动态变化的基于异质结构的存储设备集群之上提供一种稳定的、可扩展的、高性能的单一逻辑对象存储接口。

Ceph客户端接口(Clients) :Ceph架构中除了底层基础RADOS之上的LIBRADOS、RADOSGW、RBD以及Ceph FS统一称为Ceph客户端接口。简而言之就是RADOSGW、RBD以及Ceph FS根据LIBRADOS提供的多编程语言接口开发,所以他们之间是一个阶梯级过渡的关系。

功能组件整体架构:

详细的功能组件整体架构:

根据Ceph提供的不同功能,其他组件包括:

  • Ceph Monitors(ceph-mon);
  • Ceph OSDs(ceph-osd);
  • Ceph MDS(ceph-mds),用于提供CephFS文件存储,提供文件存储所需元数据管理;
  • Ceph RGW(ceph-rgw),用于提供Ceph对象存储网关,提供存储网关接入;
  • Ceph Manager(ceph-mgr),提供集群状态监控和性能监控。

OSD(Object Storage Device):用于集群中所有数据与对象的存储,主要功能包括存储数据、处理集群数据的复制、恢复、回补、平衡数据分布,并将一些相关数据提供给ceph monitor,例如ceph OSD心跳等。一块硬盘对应一个OSD,由OSD来对硬盘存储进行管理,至少需要2个OSD守护进程,集群才能达到active+clean状健康状态和有效的保存数据的双副本(默认情况下是双副本,可以调整)。

注:active表示磁盘处于活动状态,clean表示主osd和副本osd成功同步。每一个disk、分区都可以成为一个OSD。

完成存储数据的工作绝大多数是由 OSD daemon 进程实现。在构建 Ceph OSD的时候,建议采用SSD 磁盘以及xfs文件系统来格式化分区,此外OSD还对其它OSD进行心跳检测,检测结果汇报给Monitor

Monitor:Ceph的监控器,负责监视Ceph集群。主要功能是维护整个集群健康状态,各种Map图(包括建施图、OSD图、归置图(PG)图、CRUSH图),还维护了monitor、OSD和PG的状态改变历史信息、提供一致性的决策。

MDS(Metadata Server)文件系统元数据服务节点:主要保存的是Ceph文件系统的元数据。注意:Ceph的块存储和Ceph对象存储都不需要MDS服务。MDS为基于POSIX文件系统的用户提供了一些基础命令,也支持多台机器分布 式的部署,以实现系统的高可用性。

MGR:分担和脱渣monitor的部分功能,减轻monitor的负担,更好的管理Ceph存储系统。

其中:

一般写数据到ceph集群时,都是先将数据写入到journal盘中,然后每隔一段时间再将journal盘中的数据刷到文件系统中,为了使读写时延更小,都采用SSD,一般分配再10G以上。Ceph中引入journal盘的概念是因为运行journal盘:eph OSD随机小块的写操作首先写入journal,然后合并成顺序IO刷到文件系统。

Ceph Monitor作为集群中的控制中心,拥有整个集群的状态信息,各个组件如OSDs将自己的状态信息报告给Ceph Monitor这个总司令,由此可以可知,Ceph Monitor这个总司令肩负起整个集群协调工作。

同时Ceph Monitor还负责将集群的指挥工作,将集群的状态同步给客户端,客户端根据Ceph Monitor发送的集群状态信息可以获取到集群的状态,当集群状态有变化如OSD增加或故障时,Ceph Monitor会负责更新集群状态并下发给客户端。

Ceph Monitor的重要不言而喻,为了保障集群的可用性,需要部署高可用,一般需要部署2n+1个节点,如3个或5个Ceph Monitor节点。

集群状态如何维护呢?

Ceph Monitor中保存的集群状态根据其功能角色的不同,分为以下几个map状态表:

  • Monitor Maps,集群Ceph Monitor集群的节点状态,通过ceph mon dump可以获取;
  • OSD Maps,集群数据存储节点的状态表,记录集群中OSD状态变化,通过ceph osd dump可以获取;
  • PGs Maps,PGs即placement group,表示在OSD中的分布式方式,通过ceph pg dump可以获取;
  • Crush Maps,Crush包含资源池pool在存储中的映射路径方式,即数据是如何分布的;
  • MDS Maps,CephFS依赖的MDS管理组件,可通过ceph mds dump获取,用于追踪MDS状态。

除了Ceph Monitor之外,还有一个重要的组件是OSD,集群中通常有多个OSD组成,OSD即Object Storage Daemon,负责Ceph集群中真正数据存储的功能,也就是我们的数据最终都会写入到OSD中。

注:Ceph Monitor监视器维护着集群运行图的主副本。一个监视器集群确保了当某个监视器失效时的高可用性。存储集群客户端向 Ceph Monitor 监视器索取集群运行图的最新副本。

而Ceph OSD 守护进程检查自身状态、以及其它 OSD 的状态,并报告给监视器们。存储集群的客户端和各个 Ceph OSD 守护进程使用 CRUSH 算法高效地计算数据位置,而不是依赖于一个中心化的查询表。它的高级功能包括:基于 librados的原生存储接口、和多种基于 librados 的服务接口。

4、Ceph架构

RADOS是Ceph存储功能的核心组件,且可扩展为数千个OSD。Ceph 通过librados 一分为二,上面是Ceph客户端,下面是Ceph服务端。

1)基础存储系统:RADOS(Reliable Autonomic Distributed Object Store)

RADOS是Ceph存储集群的基础。在Ceph中,所有数据都以对象的形式存储,并且无论什么数据类型,RADOS对象存储都将负责保存这些对象,保证一切都以对象形式存储,RADOS层可以确保数据始终保持一致。

RADOS 分布式存储相较于传统分布式存储的优势在于:

1. 将文件映射到object后,利用Cluster Map 通过CRUSH 计算而不是查找表方式定位文件数据存储到存储设备的具体位置。优化了传统文件到块的映射和Block MAp的管理。

2. RADOS充分利用OSD的智能特点,将部分任务授权给OSD,最大程度地实现可扩展。

2) 基础库:LIBRADOS

LIBADOS:功能是对RADOS进行抽象和封装,并向上层提供API,以便直接基于RADOS进行应用开发。

3)RADOSGW

RADOSGW功能特性基于LIBRADOS之上,提供当前流行的RESTful协议的网关,并兼容S3和Swift接口,提供对象存储服务。它使用librgw和librados来实现允许应用程序与Ceph对象存储建立连接。并且提供S3 和 Swift 兼容的RESTful API接口,可以对接网盘类应用以及HLS流媒体应用等。

4)RBD

RBD(Rados Block Device) 功能特性也是基于LIBRADOS之上,通过LIBRBD创建一个块设备,通过QEMU/KVM附加到VM上,做为传统的块设备来用。目前OpenStack、CloudStack都是采用这种方式为VM提供块设备,同时也支持快照、COW等功能。

5) Ceph FS

Ceph FS功能特性是基于RADOS来实现分布式的文件系统,引如了MDS,主要为兼容POSIX文件系统提供元数据,一般都是当作文件系统来挂载。

Ceph架构总结:

1. Ceph支持文件系统存储、块存储、对象存储;
2. 中间层 librados 是提供上层接口访问底层 RADOS 集群存储系统的各种库函数;
3. RAODS 提供了一个完整的存储系统,包含:Monitors、OSDs、MDS
    a. Monitor:用来监视Ceph集群的健康状态,并保存各种map信息;
    b. OSDs:主要用来存储数据的守护进程,以PG位单位进行数据的存储、迁移和恢复;
    c. MDS:文件系统的元数据管理服务流程,主要针对CephFS中的元数据信息进行管理。
4. 在 librados 的基础上又抽象出了块设备库(librbd)、对象存储的库(libgw)和文件系统库(libcephfs)

5、Ceph数据的存储原理

了解完Ceph的架构后,我们先来了解一下Ceph的读写流程,期间会涉及到CRUSH,PGs等这些概念。

当用户将数据存储到Ceph集群时,存储数据都会被分隔成多个object,每个object都有一个object id,每个object的大小都是可以设置的,默认4MB ,object时Ceph存储的最小存储单元。

由于object的数量很多,对象的size很小,在一个大规模的集群中可能由几百到上千万个对象,这么多对象光是遍历寻址,速度都是很缓慢的,为了解决这些问题,Ceph引入了归置组(Placcment Group即PG)的概念用于管理object,每个object最后都会通过CRUSH算法计算映射到某个pg中,一个pg可以包含多个object。

pg也需要通过CRUSH计算映射到osd中去存储,如果是二副本的,则每个pg都会映射到二个osd,比如[osd.1,osd.2],那么osd.1是存放该pg的主副本,osd.2是存放该pg的从副本,保证了数据的冗余。

pg是用来存放object的,pgp相当于是pg存放osd的一种排列组合。比如有3个osd,osd.1、osd.2和osd.3,副本数是2,如果pgp的数目为1,那么pg存放的osd组合就只有一种,可能是[osd.1,osd.2],那么所有的pg主从副本分别存放到osd.1和osd.2,如果pgp设为2,那么其osd组合可以两种,可能是[osd.1,osd.2]和[osd.1,osd.3]。

不管是RBD块存储接口,RGW对象存储接口还是文件存储CephFS接口,其存储如到Ceph中的数据均可以看作是一个对象,Ceph中一切皆对象,一个文件需要切割为多个对象(object),然后将object存储到OSD中。

如下图:

注:Ceph 存储集群从 Ceph 客户端接收数据——不管是来自 Ceph 块设备、 Ceph 对象存储、 Ceph 文件系统、还是基于librados的自定义实现——并存储为对象。每个对象是文件系统中的一个文件,它们存储在对象存储设备上。由 Ceph OSD 守护进程处理存储设备上的读/写操作。

那么,这些切割后的object怎么选择到对应的OSD存储节点呢,这需要依赖于Ceph的智能调度算法CRUSH,通过CRUSH算法将object调度到合适的OSD节点上,不管是客户端还是OSD,均使用CRUSH算法来计算object在集群中OSD的位置信息,同时保障object的副本能落到合适的OSD节点上。

CRUSH(Controlled Replication Under Scalable Hashing):它表示数据存储的分布式选择算法,Ceph 的高性能/高可用就是采用这种算法实现。CRUSH 算法取代了在元数据表中为每个客户端请求进行查找,它通过计算系统中数据应该被写入或读出的位置。CRUSH能够感知基础架构,能够理解基础设施各个部件之间的关系。并CRUSH保存数据的多个副本,这样即使一个故障域的几个组件都出现故障,数据依然可用。CRUSH 算是使得Ceph 实现了自我管理和自我修复。

详情可以参考:CRUSH:x Controlled, Scalable, Decentralized Placement of Replicated Data。

Ceph OSD 在扁平的命名空间内把所有数据存储为对象(也就是没有目录层次)。对象包含一个标识符、二进制数据、和由名字/值对组成的元数据,元数据语义完全取决于 Ceph 客户端。例如, CephFS 用元数据存储文件属性,如文件所有者、创建日期、最后修改日期等等。

object调度到OSD节点上,如果一个文件发生了变动或OSD出现了异常,以一个100G的文件为例,每个object默认为4M,将会切割为25600个object,如果Ceph集群需要正对每个object都进行调度的话,可想而知,在一个大规模集群中,crush的调度将会变得异常的繁重。因此,Ceph引入了另外一个概念PG,PG是Place Group即放置组,可以简单理解为一个装载object的容器,object将映射到PG中,PG最终会调度到某个具体的OSD上,因此CRUSH由object调度转为PG的调度,而PG的数量是相对固定的,因此集群分布时调度相对没有那么繁重,同时,当某个OSD异常时,CRUSH调度算法只需将其上的PG调度至其他OSD上(而不是将其上的object进行调度)。

Ceph整个数据调度写入流程如下图:

  • 一个文件将会切割为多个object(如1G文件每个object为4M将切割为256个),每个object会由一个由innode(ino)和object编号(ono)组成oid,即object id,oid是真个集群唯一,唯一标识object对象;
  • 针对object id做hash并做取模运算,从而获取到pgid,即place group id,通过hash+mask获取到PGs ID,PG是存储object的容器;
  • Ceph通过CRUSH算法,将pgid进行运算,找到当前集群最适合存储PG的OSD节点,如osd1和osd2(假设为2个副本);
  • PG的数据最终写入到OSD节点,完成数据的写入过程,当然这里会涉及到多副本,一份数据写多副本。

首先用户把一个文件放到Ceph集群后,先把文件进行分割,分割为等大小的小块,小块叫object,然后这些小块根据一定算法跟规律,算法是哈希算法,将这些对象进行分组,放置到PG组里,就是所谓的归置组,然后再根据一定的策略把归置组存储到集群的OSD节点中。

无论使用哪种存储方式(对象、块、文件系统),存储的数据都会被切分成Objects。Objects size大小可以由管理员调整,通常为2M或4M。每个对象都会有一个唯一的OID,由ino与ono生成,虽然这些名词看上去很复杂,其实相当简单。

•ino:即是文件的File ID,用于在全局唯一标识每一个文件•ono:则是分片的编号

比如:一个文件FileID为A,它被切成了两个对象,一个对象编号0,另一个编号1,那么这两个文件的oid则为A0与A1。

File —— 此处的file就是用户需要存储或者访问的文件。对于一个基于Ceph开发的对象存储应用而言,这个file也就对应于应用中的“对象”,也就是用户直接操作的“对象”。

Ojbect —— 此处的object是RADOS所看到的“对象”。Object与上面提到的file的区别是,object的最大size由RADOS限定(通常为2MB或4MB),以便实现底层存储的组织管理。因此,当上层应用向RADOS存入size很大的file时,需要将file切分成统一大小的一系列object(最后一个的大小可以不同)进行存储。为避免混淆,在本文中将尽量避免使用中文的“对象”这一名词,而直接使用file或object进行说明。

PG(Placement Group)—— 顾名思义,PG的用途是对object的存储进行组织和位置映射。具体而言,一个PG负责组织若干个object(可以为数千个甚至更多),但一个object只能被映射到一个PG中,即PG和object之间是“一对多”映射关系。同时,一个PG会被映射到n个OSD上,而每个OSD上都会承载大量的PG,即,PG和OSD之间是“多对多”映射关系。在实践当中,n至少为2,如果用于生产环境,则至少为3。一个OSD上的PG则可达到数百个。事实上,PG数量的设置牵扯到数据分布的均匀性问题。关于这一点,下文还将有所展开。

OSD —— 即object storage device,前文已经详细介绍,此处不再展开。唯一需要说明的是,OSD的数量事实上也关系到系统的数据分布均匀性,因此其数量不应太少。在实践当中,至少也应该是数十上百个的量级才有助于Ceph系统的设计发挥其应有的优势。

把一个对象存储到 OSD 中分几步走?

对象的分发需要经过两个阶段的计算,才能得到存储该对象的OSD,然后将对象存储到OSD中对应的位置:

(1) 对象到PG的映射。PG是对象的逻辑集合。PG是系统向OSD节点分发数据的基本单位,相同PG里的对象将被分发到相同的OSD节点中(一个主OSD节点多个备份OSD节点)。对象的PG是由对象ID号通过Hash算法,结合其他一些修正参数得到的。

(2) PG到相应的OSD的映射。RADOS系统利用相应的哈希算法根据系统当前的状态以及PG的ID号,将各个PG分发到OSD集群中。OSD集群是根据物理节点的容错区域(比如机架、机房等)来进行划分的。

Ceph中的寻址至少要经历以下三次映射:

(1)File -> object映射 (2)Object -> PG映射,hash(oid) & mask -> pgid (3)PG -> OSD映射,CRUSH算法

Ceph IO流程及数据分布

正常IO流程

1. client 创建cluster handler(集群处理信息)。

2. client 读取配置文件。

3. client 连接上monitor,获取集群map信息。

4. client 读写io 根据crush map 算法请求对应的主osd数据节点。

5. 主osd数据节点同时写入另外两个副本节点数据。

6. 等待主节点以及另外两个副本节点写完数据状态。

7. 主节点及副本节点写入状态都成功后,返回给client,io写入完成

新主IO流程

如果新加入的OSD1取代了原有的 OSD4成为 Primary OSD, 由于 OSD1 上未创建 PG , 不存在数据,那么 PG 上的 I/O 无法进行,怎样工作的呢?

新主IO流程步骤:

1. client连接monitor获取集群map信息。

2. 同时新主osd1由于没有pg数据会主动上报monitor告知让osd2临时接替为主。

3. 临时主osd2会把数据全量同步给新主osd1。

4. client IO读写直接连接临时主osd2进行读写。

5. osd2收到读写io,同时写入另外两副本节点。

6. 等待osd2以及另外两副本写入成功。

7. osd2三份数据都写入成功返回给client, 此时client io读写完毕。

8. 如果osd1数据同步完毕,临时主osd2会交出主角色。9.osd1成为主节点,osd2变成副本。

Ceph IO流程总结:

1. 客户端发起 IO 请求,其 IO 请求发送到服务端分为两种 IO 请求:(1)文件数据IO请求;(2)元数据IO请求;
2. 元数据请求对应的和元数据管理服务集群进行通信即可;
3. 客户端发起 IO 请求调用 libcephfs相关接口。此时,libcephpfs作为librados的客户端;
4. libcephfs 进行hash运算出此次的 IO 请求对应的PG,在根据 CRUSH 算法计算出 PG 对应的 OSD 组,并返回OSD 信息给客户端libcephfs
5. libcephfs将读写请求发送到刚才找到 OSD 组进行处理;
6. OSD集群中的每个OSD进程都运行在独立的存储驱动器上,OSD 接收到对应的IO请求后,根据对应的后端存储类型,执行对后端存储引擎的IO操作;
7. 如选择了文件系统作为后端存储引擎,则响应的需要将IO请求转为文件的读写;

Ceph逻辑层Pool

Ceph为了保存一个对象,对上构建了一个逻辑层,也就是池(Pool),这个不难理解,就像虚拟化中的存储池化,用来保存对象,如果把Pool比喻为一个中国象棋棋盘,那么保存一个对象的过程类似于把一粒芝麻放置到棋盘中。

Pool 再一次细分,即将一个 Pool 划分为若干的PG(归置组),这类似于棋盘上的方格,所有方格构成了整个棋盘,也就是说所有的PG构成了一个 Pool。

不论是视频,文本,照片等一切格式的数据,Ceph统一将其看作是对象,因为追其根源,所有的数据都是二进制数据保存于磁盘上,所以每一份二进制数据都看成一个对象,不以它们的格式来区分他们。

文件是一个个对象,对象则是存储在每个PG里的,而多个PG 构成了Pool。既然是对象,那对象就应该有对象名,而区分2个对象的就是通过对象名来区分的。

现在问题又来了,对象怎么知道要保存到哪个PG上呢?假定这里我们的 Pool 名叫 rbd,共有 256 个PG,给每个PG 编号分别叫做 0, 1,2, 3, 4。

要解决这个问题,首先看目前有什么?

  1. 不同的对象名
  2. 不同的PG编号

这里就引入了Ceph的第一个算法:HASH。

对于对象名分别为 bar 和 foo 两个对象,对他们的对象名进行计算即可:

  • HASH(‘bar’) = 0x3E0A4162
  • HASH(‘foo’) = 0x7FE391A0
  • HASH(‘bar’) = 0x3E0A4162

HASH算法应该是最常用的算法,对对象名进行HASH后,得到一串十六进制的输出值,也就是说通过HASH我们将一个对象名转化为一串数字,那么上面的第一行和第三行是一样的有什么意义?意义就是对于一个同样的对象名,计算出来的结果永远都是一样的,但是HASH算法的确将对象名计算得出了一个随机数。有了这个随机数,就对这个随机数除以PG总数,比如 256 ,得到的余数一定是落在 1-256 之间的,也就是这 256 个PG中的某一个。

公式:HASH('bar') % PG数:

  • 0x3E0A4162 % 0xFF ===> 0x62
  • 0x7FE391A0 % 0xFF ===> 0xA0

通过上面的计算,对象bar 保存到编号为 0x62 的PG中,对象 foo 保存在编号 0xA0 的PG中。对象 bar 永远都会保存在 PG 0x62中!对象 foo 永远都会保存到PG 0xA0中!

目前,可以总结一个对象是如何存入PG 中的:

对 对象名进行 HASH 取到一个随机数,然后在用这个随机数 对 PG 总数取余,得到的值一定落在 1- PG总数之间,改对象名的数据就会永远的存储在这个PG 中。

所以,自对象名确定了, 那么该对象保存数据的PG也就确定了。

由此衍生出来一个问题,对象名确定唯一性,难道就不管对象数据的大小了吗?

答案是肯定的,也就是Ceph不区分对象的真实大小内容以及任何形式的格式,只认对象名。

这里给出更Ceph一点的说明,实际上在Ceph中,存在着多个pool,每个pool里面存在着若干的PG,如果两个pool里面的PG编号相同,Ceph怎么区分呢? 于是乎,Ceph对每个pool进行了编号,比如刚刚的rbd池,给予编号0,再建一个pool就给予编号1,那么在Ceph里,PG的实际编号是由pool_id+.+PG_id组成的,也就是说,刚刚的bar对象会保存在0.62这个PG里,foo这个对象会保存在0.A0这个PG里。其他池里的PG名称可能为1.12f, 2.aa1,10.aa1等。

Ceph中的物理层

在逻辑层中,已经知道一个文件是如何存储在Ceph 中PG 里,简单来说就是通过对对象名进行hash 然后对PG总数取余,得到的余数就是对应的PG,然后将数据存储在这个PG归置组里。

接下来看看Ceph里的物理层。若干服务器,服务器上有若干磁盘,通常,Ceph 将一个磁盘看作一个OSD(实际上,OSD是管理磁盘的一个程序),于是物理层由若干OSD组成,我们最终目标是将对象保存到磁盘上,在逻辑层里,对象是保存到PG里的,那么现在的任务就是 打通PG和OSD之间的隧道。PG相当于一堆余数相同的对象的组合,PG把这一部分对象打了个包,现在我们需要把很多的包平均的安放在各个OSD上,这就是CRUSH 算法所有做的事:CRUSH计算 PG -> OSD的映射关系。

此时,加上刚刚逻辑层的对象到PG的算法,可以总结出两个公式:

  • 池ID+HASH('对象名') % PG_num --> PG_ID
  • CRUSH(PG_ID) --> OSD

在这里采用两种算法,HASH 和 CRUSH ,这两种算法有何差异呢?为什么不能直接用 HASH(PG_ID) 到对应的 OSD 上呢?

CURSH(PG_ID) ==> 改为 HASH(PG_ID) % OSD_num ==> OSD

  1. 如果挂掉一个OSD,OSD_num=1,于是所有的 PG % OSD_num 的余数都会变化,也就是说这个PG保存的磁盘发生了变化,这最简单的解释就是,这个PG 上的数据要从一个磁盘转移到另一个磁盘上去,一个优秀的存储架构应当在磁盘损坏时使得数据迁移量降到最低,CRUSH 可以做到;
  2. 如果保存多个副本,我们希望得到多个OSD 结果的输出,HASH只能获得一个,但是CRUSH 可以获得任意多个;
  3. 如果增加OSD 的数量,OSD_num 增大了,同样导致PG 在OSD之间的胡乱迁移,但是CRUSH 可以保证数据向新增机器均匀的扩散。

总结起来就是 HASH 算法只适合 1 对 1 的映射关系,并且计算的两个值还不能变,因此这里就不适合 PG -> OSD 的映射计算。因此,这里开始引入了 CRUSH 算法。

CRUSH算法

首先来看要做什么:

  • 把已有的PG_ID 映射到OSD上,有了映射关系就可以把一个PG保存到一块磁盘上;
  • 如果想要保存三个副本,可以把一个PG映射到三个不同的 OSD 上,这三个 OSD 上保存着一模一样的PG内容。

在来看看有什么:

  • 互不相同的PG_ID;
  • 如果给OSD也编个号,那么就有了互不相同的 OSD_ID;
  • 每个OSD最大的不同的就是它们的容量,即 4T还是800GB的容量,我们将每个OSD的容量又称为OSD的权重(weight),规定4T权重为4,800G为0.8,也就是以 T 位单位的值。

现在的问题转化为:如何将 PG_ID 映射到有各自权重的 OSD 上。这里直接使用 CRUSH 算法中的 straw 算法,翻译过来就是 抽签,说白了就是挑个最长的签,这里的签指的是 OSD 的权重。

那总不能每次都挑选容量最大的OSD吧,这不分分钟都把数据存满那个最大的OSD了吗? 所以在挑之前把这些OSD 搓一搓,这里直接介绍CRUSH 算法:

  • CRUSH_HASH( PG_ID, OSD_ID, r ) ===> draw
  • ( draw &0xffff ) * osd_weight ===> osd_straw
  • pick up high_osd_straw

第一行,我们姑且把r当做一个常数,第一行实际上就做了搓一搓的事情:将PG_ID, OSD_ID和r一起当做CRUSH_HASH的输入,求出一个十六进制输出,这和HASH(对象名)完全类似,只是多了两个输入。所以需要强调的是,对于相同的三个输入,计算得出的draw的值是一定相同的。

这个draw到底有啥用?其实,CRUSH希望得到一个随机数,也就是这里的draw,然后拿这个随机数去乘以OSD的权重,这样把随机数和OSD的权重搓在一起,就得到了每个OSD的实际签长,而且每个签都不一样长(极大概率),就很容易从中挑一个最长的。

说白了,CRUSH希望随机挑一个OSD出来,但是还要满足权重越大的OSD被挑中的概率越大,为了达到随机的目的,它在挑之前让每个OSD都拿着自己的权重乘以一个随机数,再取乘积最大的那个。那么这里我们再定个小目标:挑个一亿次!从宏观来看,同样是乘以一个随机数,在样本容量足够大之后,这个随机数对挑中的结果不再有影响,起决定性影响的是OSD的权重,也就是说,OSD的权重越大,宏观来看被挑中的概率越大。

上面的内容不理解也没关系,这里在简单梳理下PG选择一个OSD时做的事情:

  • 给出一个 PG_ID ,作为 CRUSH_HASH 的输入;
  • CRUSH_HASH(PG_ID, OSD_ID, r) 得出一个随机数(重点是随机数,不是HASH);
  • 对于所有的OSD用他们的权重乘以每个OSD_ID 对应的随机数,得到乘积;
  • 选出乘积最大的OSD;
  • 这个PG就会保存到这个OSD上;

通过上面的说明,已经可以解决一个PG映射到多个OSD的问题了, 而常量r,当 r+1,在求一遍随机数,再去乘以每个OSD的权重,再去选出乘积最大的OSD,如果和之前的OSD 编号不一样,那么就选中它,如果和之前的OSD 编号一样的话,那么再把 r+2,再选一次随机数,直到选出我们需要的三个不一样编号的OSD为止!

当然实际选择过程还要稍微复杂一点,我这里只是用最简单的方法来解释CRUSH在选择OSD的时候所做的事情。

到目前为止,我们已经知道了一份数据保存到一群Server的二步是如何完成的,再整体回顾下这个流程:

  • 每个文件都有一个唯一的对象名;
  • Pool_ID + HASH(对象名) % PG_NUM 得到PG_ID;
  • CRUSH(PG_ID) 得到该PG将要保存的OSD组合;
  • 这个对象就会保存到位于这些OSD上的PG上(PG就是磁盘上的目录)

所以,HASH算法负责计算对象名到PG的映射,CRUSH负责计算PG到OSD的映射。

总结:

Pool是Ceph存储数据时的逻辑分区,它起到namespace的作用。每个Pool包含一定数量(可配置) 的PG,PG里的对象被映射到不同的Object上。

Pool是分布到整个集群的,Pool可以做故障隔离域,根据不同的用户场景不统一进行隔离。Pool对Ceph集群进行逻辑划分,设置存储对象的权限、备份数目、PG数以及CRUSH规则等属性。

再来回归一下Ceph的整体架构,从上往下看:

1. Ceph 对外提供了 4 个接口:

  • 应用直接访问RADOS,这个需要通过自行开发调用接口,适合自主开发;
  • 对象存储接口,支持(Amazon)S3 和 Swift 的调用方式,适合存储对象存储,如图片、视频等;
  • 块存储接口(RBD),主要对外提供块存储,例如提供给虚拟机使用的块设备存储;
  • 文件存储(CephFS),类似于NFS 的挂载目录存储。

2. 应用直接访问、对象存储、块存储都是依赖于 LibRados库文件的

3. Ceph将底层是一个RADOS对象存储系统,通过RADOS对象存储系统对外提供服务

4. MDS 元数据节点、MON 管理控制节点、很多的 Pool存储池

5. 在Pool存储池中包含了很多PG归置组,然后通过 CRUSH 算法将PG中的数据存储到各个 OSD 组中。

在上面的步骤中,我们需要重点关注第 5 点,上文说过,在 Ceph中,一切皆对象。首先通过将对象名 通过 HASH 算法得到一个16进制的数,再对 Pool中的PG总数取余,得到的余数一定落在 PG总数中的一个节点上,Ceph就将这个对象名的数据存储在这个PG里,然后再通过 CRUSH_HASH(PG_ID, OSD_ID, r) 计算得到一个值,这样就可以将数据落到OSD上,而在Ceph中,OSD 就是磁盘的代名词。

通过图示来表示这一过程:

Ceph IO 流程总结:

1. 在Ceph中,文件被看作对象;

2. RADOS将对象保存到一个逻辑分区(Pool)中;

3. Pool 通过多副本和纠删码两种方式来实现数据冗余;

4. 在每个Pool中,对象被划分到不同的归置组(PG);

5. Ceph的数据冗余策略中,数据以PG为单位进行保存,PG是副本划分、数据迁移的最小单位;

6. PG通过一种伪随机算法(CRUSH)分配到不同的OSD 中;

7. PG和CRUSH算法构成了对象到OSD的转换层;

8. 当集群发生变化时,RADOS能够提供有效的数据迁移策略,确保高可用和负载均衡。

9. 在RADOS集群中,每块磁盘运行有独立的Ceph OSD 守护进程,每个OSD都会处理来自客户端的I/O请求,且能够相互合作,完成数据迁移、副本更新、错误恢复等;

10. ObjectStore封装了所有对底层存储的IO操作;

6、CRUSH算法的实际应用

理解了上面CRUSH选择OSD的过程,我们就很容易进一步将CRUSH算法结合实际结构:

最下面的蓝色长条可以看成一个个主机,里面的灰色圆柱形可以看成一个个OSD,紫色的cabinet可以也就是一个个机柜, 绿色的row可以看成一排机柜,顶端的root是我们的根节点,没有实际意义,你可以把它看成一个数据中心的意思,也可以看成一个机房的意思,不过只是起到了一个树状结构的根节点的作用。

基于这样的结构选择OSD,我们提出了新的要求:

  • 一共选出三个OSD;
  • 这三个OSD 需要都位于一个row下面;
  • 每个cabinet内至多有一个OSD。

这样的要求,如果用上一节的CRUSH 选 OSD 的方法,不能满足二三两个要求,因为 OSD 的分布是随机的。

那么要完成这样的要求,先看看有什么:

  • 每个OSD的weight;
  • 每个主机也可以有一个weight,这个weight由主机内的所有 OSD 的weight累加而得;
  • 每个cabinet的weight由所有主机的weight累加而得,其实就是这个cabinet下的所有OSD的权重值和;
  • 同理推得每个row的weight有cabinet累加而得;
  • root的weight其实就是所有的OSD的权重之和。

所以在这棵树状结构中,每个节点都有了自己的权重,每个节点的权重由下一层节点的权重累加而得,因此根节点root的权重就是这个集群所有的OSD的权重之和,那么有了这么多权重之后,我们怎么选出那三个OSD呢?

仿照CRUSH 选 OSD 的方法:

  • CRUSH从root下的所有的row中选出一个row;
  • 在刚刚的一个row下面的所有cabinet中,CRUSH选出三个cabinet;
  • 在刚刚的三个cabinet下面的所有OSD中,CRUSH分别选出一个OSD。

因为每个row都有自己的权重,所以CRUSH选row的方法和选OSD的方法完全一样,用row的权重乘以一个随机数,取最大。然后在这个row下面继续选出三个cabinet,再在每个cabinet下面选出一个OSD。

这样做的根本意义在于,将数据平均分布在了这个集群里面的所有OSD上,如果两台机器的权重是16:32,那么这两台机器上分布的数据量也是1:2。同时,这样选择做到了三个OSD分布在三个不同的cabinet上。

那么结合图例这里给出CRUSH算法的流程:

  • take(root) ============> [root]
  • choose(1, row) ========> [row2]
  • choose(3, cabinet) =====> [cab21, cab23, cab24] 在[row2]下
  • choose(1, osd) ========> [osd2107, osd2313, osd2437] 在三个cab下
  • emit ================> [osd2107, osd2313, osd2437]

这里给出CRUSH算法的两个重要概念:

  • BUCKET/OSD:OSD和我们的磁盘一一对应,bucket是除了OSD以外的所有非子节点,比如上面的 cabinet,row,root等都是;
  • RULE:CRUSH选择遵循一条条选择路径,一个选择路径就是一个rule。

RULE 一般分为三步走: take -> choose N -> emit.

Take这一步负责选择一个根节点,这个根节点不一定是root,也可以是任何一个Bucket。

choose N 做的就是按照每个 Bucket 的weight 以及每个 choose 语句选出符合条件的 Bucket,并且,下一个 choose 的选择对象为上一步得到的结果。

emit 就是输出最终结果相当于出栈。

再举个简单的例子,也就是我们最常见的三个主机每个主机三个OSD的结构:

我们要从三个host下面各选出一个OSD,使得三个副本各落在一个host上,这时候,就能保证挂掉两个host,还有一个副本在运行了,那么这样的RULE就形如:

  • take(root) ============> [default] 注意是根节点的名字
  • choose(3, host) ========> [ceph-1, ceph-2, ceph-3]
  • choose(1, osd) ========> [osd.3, osd.1, osd.8]
  • emit()

这里在简单总结下:

我们把一个生产环境的机房画成一个树状结构,最下面一层为OSD层,每个OSD有自己的权重。

OSD的上面由host/rack/row/room/root等等节点构成,每个节点的权重都是由下层的节点累加而成。

CRUSH选择每个节点的算法(straw)都是一样的,用它们的weight乘以一个随机数取其中最大,只是我们通过choose的语句来判断选择的节点类型和个数。

最后不要忘了选出来的结果是PG->OSD的映射,比如:pg 0.a2 ---> [osd.3, osd.1, osd.8]和pg 0.33 ---> [osd.0, osd.5, osd.7], 每个PG都有自己到OSD的映射关系,这个关系用公式总结就是: CRUSH(pg_id) ---> [osd.a, osd.b ...osd.n]。

三、Ceph存储引擎

1、Ceph存储引擎发展

Ceph提供存储功能的核心组件是RADOS集群,其本质是一个提供了大量接口的分布式对象存储集群,最终都是以对象存储的形式对外提供服务。但在底层的内部实现中,Ceph的后端存储引擎在近十年来经历了许多变化。现如今的Ceph系统中仍然提供的后端存储引擎有FileStore、NewStore和BlueStore。但该三种存储引擎都是近年来才提出并设计实现的。

Ceph存储引擎最初的实现为 EBOFS(Extent and B-Tree-based Object File System),其本质也为文件系统,只是在文件系统的基础上做了扩展,主要核心逻辑使用B-Tree来实现,但EBOFS缺少了很多生产环境中的必须的实用性功能,如事务和校验和等,2008年出现并引入了Btrfs之后就摒弃了EOBFS。

Btrfs作为Ceph的后端存储系统经历了长时间的开发,提供了EBOFS不能提供的事务、校验、数据去重等功能,但投入使用很长一段时间后发现Btrfs的碎片化现象比较严重,所以又开始了对新的文件系统存储后端的探索。

在FileStore的存储后端中,一个对象的集合对应一个目录,对象数据保存在文件中。一开始,对象的属性保存在POSIX的扩展文件属性中,但很快,由于文件存储的扩展属性数量和长度限制,Ceph将对象属性转移到LevelDB这类事务性数据库中。基于BtrFS的FileStore成为业界主流并持续了数年,暴露了一些问题。比如BtrFS仍然不稳定,数据和元数据碎片化严重。而与此同时,ObjectStore的接口也发生了很大变化,不能再使用过去的EBOFS实现。为了获得更好的扩容性和元数据处理性能,FileStore迁移到通用文件系统。

在2011年正式使用XFS作为Ceph存储后端之前,Ceph团队还尝试过使用其他文件系统如ext4、ZFS等作为存储后端,但最后选择了XFS,因为其具有更好的伸缩性,元数据的操作性能也较好。

XFS比起Btrfs在运行过程中更为稳定,性能波动较小,但仍让有元数据碎片的问题,无法充分利用硬件设备的性能。同时缺少事务的支持,使得需要实现额外的WAL机制来提供事务功能。Ceph于是提出了新的解决方案来处理元数据碎片化的问题。

Ceph于2015年开发了NewStore,一种键值存储引擎来管理元数据,从而避免元数据碎片带来的问题。通过建立在KV存储中建立和文件系统上的物理文件的索引来向外提供服务,该存储引擎未真正投入生产环境。但该存储引擎奠定了后来且流行至今的BlueStore的基础。

2017年开始在NewStore的基础上提出了BlueStore,使用了NewStore中对元数据的管理方式,但不再使用文件系统存储实际的数据,而直接使用了裸设备来直接存放,从而提升IO的性能。该引擎被无数次实践表明是目前性能最好的后端存储引擎,所以被广泛使用到生产环境中。

RADOS后端存储引擎:FileStore、NewStore、BlueStore;
在FileStore的存储后端中, 一个对象的集合对应一个目录,对象数据保存在文件中,为了获得更好的扩容性和元数据处理性能,FileStore迁移到通用文件系统;
FileStore 最好运行在 XFS文件系统之上,因为其有更好的伸缩性,元数据的操作性能更好;
NewStore提供了一种键值存储引擎来管理元数据,该存储引擎未真正投入生产环境;
BlueStore 使用键值存储来对元数据进行管理,不再使用文件系统存储实际数据,直接使用裸设备来直接存放,从而提升IO性能,该引擎是目前性能最好的后端存储引擎;

2、FileStore存储引擎

FileStore,也就是利用文件系统的POSIX接口实现ObjectStore API。每个Object在FileStore层会被看成是一个文件,Object的属性会利用文件的xattr属性存取,因为有些文件系统(如Ext4)对xattr的长度有限制,因此超出长度的元数据会被存储在DBObjectMap或omap中。通常DBObjectMap的存储引擎时LevelDB或RocksDB。

在 FileStore中,对象被看作文件,并借助文件系统的接口来进行存储。

体系架构

如图所示,开始时,所有写事务的数据和元数据都会先写入Journal文件,写入Journal成功以后立即返回。Journal类似于数据库的write-ahead-log。写入完成后,会使用O_DIRECT和O_DSYNC同步写入到Journal文件,随后该事务会被转移到FileStore的写入队列中,数据和元数据被异步写到指定区域。

write-ahead-log 和 append-only-file 的原理?

无论是RBDMS 还是 NOSQL ,如何最大程度上保证故障时的数据恢复,都涉及到数据持久化的技术。

write-ahead-log : WAL 日志,是数据库中一种高效的算法。从数据库原理而言,它实现的是redo日志模式。即修改数据库时,不直接修改数据库内容,而是将修改完的数据写入日志同步到磁盘上,这样对其他读进程没有影响。如果数据库崩溃,重启后扫描日志文件,然后更新到数据库中。为了提高效率,WAL日志模式提供了 checkpoint 操作,来定时进行数据更新操作。

append-only-file:AOF日志,以Redis为例。在Redis异常死掉时,最近的数据会丢失(丢失数据的多少视你save策略而定),当业务量很大时,可能丢失的数据会很多。Append-only方法可以做到全部数据不丢失,但Redis的性能就要差些。AOF就可以做到全程持久化,开启AOF之后,Redis每执行一个修改数据的命令,都会把它添加到aof文件中,当Redis重启时,将会读取AOF文件进行“Log-Rewriting 重放”以恢复到Redis关闭前的最后时刻。

简单的说,write-ahead-log(WAL)  为了保证数据的一致性,首先将数据写入到日志,然后在异步或者同步写入到数据文件,而checkpoint 的用途就是记录日志文件写入数据文件。

  • 首先,为了提高写事务的性能,FileStore增加了fileJournal功能,为了提高写事务的性能,所有的写事务在被FileJournal处理以后都会立即callback(上图中的第2步)。日志是按append only的方式处理的,每次都是被append到journal文件末尾,同时该事务会被塞到FileStore op queue;
  • 接着,FileStore采用多个thread的方式从op queue 这个 thread pool里获取op,然后真正apply事务数据到disk(文件系统pagecache)。当FileStore将事务落到disk上之后,后续的读请求才会继续(上图中的第5步)。
  • 当FileStore完成一个op后,对应的Journal才可以丢弃这部分Journal。对于每一个副本都有这两步操作,先写journal,再写到disk,如果是3副本,就涉及到6次写操作,因此性能上体现不是很好。

关键技术

Ceph曾持续很长一段时间,将FileStore作为产品线的存储后端。从当时的历史背景来看,是必然的。FileStore提供了很多优良的特性。

  • 利用了文件和对象天然的映射关系。
  • 利用页缓存机制和inode节点缓存机制作为数据、元数据的缓存。
  • 从软件层面保证磁盘的隔离性。

利用了文件和对象天然的映射关系

文件和对象存在天然的映射关系。文件名对应对象名,文件内容对应对象数据,文件的附加属性对应对象的元数据,文件的目录对应对象集合。通过简单的协议转化,FileStore可以利用现有的文件系统快速构建后端存储的基本功能。同时,POSIX接口是linux文件系统的标准,FileStore的转换层和文件系统耦合性很低,可以根据不同的要求,在不同文件系统上快速开发存储后端。

利用页缓存和inode缓存

Linux为文件系统提供了页缓存机制和inode缓存机制,能大幅度提升文件的访问速度。而FileStore基于文件系统构建,使用inode存储对象、对象集合的元数据,使用文件存储对象数据,能够直接利用页缓存和inode缓存,管理元数据,提升读写性能。

为了保证事务性,存储系统常常会采用WAL的方法。WAL机制需要先将数据同步到Journal文件,随后可以异步地写入磁盘,因而我们常常需要为Journal设定缓存,管理写入磁盘的数据队列。而使用文件系统避免了去实现另一套缓存方案。

从软件层面保证磁盘的隔离性

文件系统地一大优势在于,从软件的层次提供了隔离不同应用数据的方案。这让我们可以更高效的利用磁盘空间。我们可以同时在同一文件系统上运行操作系统,应用软件,以及Ceph的存储后端。这些进程的数据不会相互污染。

FileStore 完全基于文件系统建构的存储引擎,借助了诸多文件系统的功能。

存在的问题:

事务机制和性能难以均衡

应用需要存储系统提供事务性保证,但是在FileStore上,事务机制的实现却遇到了种种问题。现有的很多工作提出了文件系统的事务机制,但最终因为高性能开销,功能缺失,接口复杂,实现困难等原因,都不能适应生产环境。

例如,有三类实现事务的方法。

• 利用文件系统内部的事务机制;
    • 在用户空间实现WAL;
    • 使用WAL机制的数据库。这类实现就是上述提到的NewStore,在本节中不做过多阐述。

一、二两种方案都有各自的缺点。

第一类方法。利用文件系统内部的事务机制已经被证明是不合适的。一方面,我们需要进入内核态对文件系统内部进行修改,另一方面,文件系统的事务机制仅能保证文件系统中原子性操作的一致性,并不能保证整个存储后端的一致性。例如Btrfs,第一版的存储后端利用Btrfs的原子性操作接口来完成事务,但是常常如果事务中途发生故障,可能会出现事务部分提交的现象,产生不一致。

第二类方法,在用户空间实现WAL,这也是FileStore在生产环境中使用的方法。

这样的实现方式却面临三个问题。第一是读后写的问题。在进行小块数据写入时,因为块大小的限制,我们需要读取相邻数据进行修改。在连续的写入过程中,因为Journal的操作是严格串行化的,即只有当前一个事务提交成功后,才可以进行读取操作。事务的提交总共包含三个步骤:1)序列化事务并写入日志;2)调用fsync提交事务;3)等待事务操作在文件系统中生效。因为第二步的副作用,下一个事务可能会因为读后写机制阻塞。

第二个问题是操作的非幂等性。这里举一个例子,我们考虑这样一个事务:①克隆a->b,②更新a,③更新c。事务提交后,将日志异步写入后端存储的过程中,如果②③之间发生故障,系统会回滚重新执行操作①,但这个时候对象a已经被更新过了,这将导致不一致性。

第三个问题,重复写。在文件系统上添加WAL机制,直观来说会有两次重复写,一次写入Jounel,一次写入XFS文件系统。同时XFS本身也是一个日志文件系统,在其内部数据会写入两次。因而同一数据可能至少被写入三次。面对这种现象,开发者往往会进行妥协,仅日志化元数据而取消回滚的功能。即先将数据同步写入磁盘,然后将元数据写入日志,执行fsync完成事务提交。但这也会导致极大的同步开销。fsync会调用开销巨大的FLUSH CACHE指令,而如XFS的日志文件系统写入数据时,也会调用上述两次fsync操作,于是单次写入将调用四次fsync。

第三个重复写 WAL 机制 首先写入日志,然后在写入数据文件 一共两次,这里写入文件时,是在XFS文件系统上写入的,因此 XFS还会在记录一次,所以一共上三次,造成了多次重复的写入,带来了极大的性能开销。使用 FileStore作为后端存储引擎,写入一个文件时,系统会发生两次日志写入,一次数据文件写入,调用四次 fsync

低效的元数据管理

本地文件系统中低效的元数据管理始终是分布式系统的心腹大患。在FileStore中,这一问题主要表现为在庞大的目录项中枚举符合条件的目录的效率低下,并且返回的数据没有顺序难以处理。
RADOS中的对象通过hash函数映射到不同的PG中,并且按照hash值的排序进行遍历。在Ceph中,枚举操作是常常发生的,比如在数据去冗余、数据恢复、客户端提取对象列表等操作是,我们需要一一访问相应对象。

而很多时候由于上层负载的特性,RADOS中的对象拥有很长的对象名。FileStore因为文件名称长度限制,会将过长的对象名放在文件附加属性中,于是访问这些对象,常常需要调用额外的stat指令获取对象名。以上种种问题导致了元数据遍历十分低效,解决这一问题的一般方法是创建具有大扇区的目录层次结构,将对象分布在目录中,然后在读取后对所选目录的内容进行排序。

为了进行快速排序,减少额外的stat调用损耗,文件夹会保持较少的子文件数(一般是数百个)。当子文件夹数量增加时,会采取分割文件夹的放置维持数量。但这导致极大的并行性开销,首先,会占用大量目录项缓存,并产生大量磁盘小I/O;其次,XFS采用分配组的方式,让新的目录项与原有目录项相邻,导致分割文件夹使会浪费许多时间用于寻找对应空间。以上两个原因,影响了分割文件夹时的I/O性能。

总结:

FileStore 优势:

利用成熟的文件系统能够快速的实现存储引擎的构建。

FileStore劣势:

在写入数据前需要先写入Journal,然后在写入磁盘,带来了翻倍的性能消耗。

3、NewStore存储引擎

为了解决上述FileStore存在的问题,Ceph引入了新的存储引擎NewStore(又被称为Key-File Store)。通过将元数据从传统的文件系统上分离出来,使用专门的KV数据库如LevelDB或RocksDB来进行管理,而对应的对象数据依旧保存在文件系统中,从而避免文件系统作为后端存储引擎时的元数据碎片化问题,从而提升Ceph的整体性能。

NewStore相比FileStore来说,将元数据从传统的文件系统上分离出来利用专门的KV数据库进行管理。对于对象数据依旧保存在文件系统中,避免了FileStore文件系统元数据碎片化问题。

体系架构

NewStore的关键数据结构和KV数据分布如图所示。NewStore首先将Key的相关信息、对象的元数据信息以及对象的值的地址信息都统一进行了封装,以KV的形式存储在KV数据库中,而对象的值的信息则沿用文件系统的方式进行存储,相比于文件系统,添加了一些映射信息来将KV数据库中存取的元数据信息和存储在文件系统中的对象信息进行物理映射。下图中的保存在KV数据库中的ONode即为索引结构,建立Obejct和存储在文件系统中的物理文件之间的映射关系。

ONode又主要包含对象的扩展属性信息和存储了物理文件地址的分段信息。Object和Fragment的对应关系取决于对象的大小,所以很有可能一个Object对应多个Fragment,或者多个Object对应多个Fragment(当对象较大时,由于Fragment文件大小限制,所以需要你多个文件共同构成,当对象较小时,为了不浪费Fragment文件的空间,可以多个小对象对应一个Fragment文件)。为了较好地处理这两种情况,所以需要根据Fragment所在的物理地址(即偏移量)和Fragment的数据长度作为Fragment对象的属性,同时还包含FID对象,FID又主要包含了物理文件所在的目录信息即fset和文件编号fno,从而能够在文件系统中正确定位到真正的物理文件。

NewStore 将元数据和对象数据分离存放,元数据等信息则上通过键值对的形式存储在KV数据库的,而对象的值则还是和FileStore一样以文件的形式存储在文件系统中的。

关键技术

1. 解耦对象与本地物理文件间的一一对应关系,通过索引结构(上图中ONode)在对象和本地物理文件建立映射关系,并使用KV数据库存储索引数据信息,从而减小元数据碎片;
    2. 在保证事务特性的同时,对于对象的创建/追加写/覆盖写(与分段文件大小对齐)操作,无需Journal支持,减小了写放大;
    3. 对于非对齐的数据更新操作,先同步写入write-ahead-log文件中(简称为WAL,使用KV存储),再异步写入相应的分段(fragement)文件;
    4. 可以在KV数据库上层建立Onode数据缓存以加速索引数据信息的读取操作;
    5. 单个对象可以有多个分段(fragement)文件,多个对象也可共存于一个分段(fragement)文件,从而能够有效提升分段(fragement)文件的空间利用率,减小数据碎片的产生;
    6. 为了减小WAL的开销,在数据修改操作同步到分段(fragement)文件中后,立即将WAL日志从KV数据库中删除,同时增大KV数据的写缓冲区,尽量将WAL保存在缓冲区中,从而减少dump操作,在dump操作执行前,合并多个缓冲区的数据,减少dump的次数。

存在的问题

NewStore存在的问题和FileStore相似,因为NewStore沿用了FileStore存储对象数据的方式,只是将对象的元数据信息和对象数据进行了分离,引入KV数据库优化了元数据管理,但在文件系统层面仍然存在严峻的写放大问题。由于对象数据的最终形式都是以文件的形式存储在文件系统中,文件系统相关的保障机制不可避免地产生了写放大问题。

即便是存储在KV数据库中的元数据信息和对象扩展数据信息,由于KV数据库仍然运行在传统的文件系统上,最终的存储流程仍然不能绕过文件系统的层次,所以文件系统引入的高开销问题仍然不能被有效解决。但NewStore的提出和研究也为后来的BlueStore奠定了基础。

4、BlueStore存储引擎

首先,Ceph原本的FileStore需要兼容Linux下的各种文件系统,如EXT4、BtrFS、XFS。理论上每种文件系统都实现了POSIX协议,但事实上,每个文件系统都有一点“不那么标准”的地方。Ceph的实现非常注重可靠性,因而需要为每种文件系统引入不同的Walkaround或者Hack;例如Rename不幂等性,等等。这些工作为Ceph的不断开发带来了很大负担。

其次,FileStore构建与Linux文件系统之上。POSIX提供了非常强大的功能,但大部分并不是Ceph真正需要的;这些功能成了性能的累赘。另一方面,文件系统的某些功能实现对Ceph并不友好,例如对目录遍历顺序的要求,等等。

另一方面,是Ceph日志的双写问题。为了保证覆写中途断电能够恢复,以及为了实现单OSD内的事物支持,在FileStore的写路径中,Ceph首先把数据和元数据修改写入日志,日志完后后,再把数据写入实际落盘位置。这种日志方法(WAL)是数据库和文件系统标准的保证ACID的方法。但用在Ceph这里,带来了问题:

数据被写入两遍,即日志双写问题,这意味着Ceph牺牲了一半的磁盘吞吐量。

  1. Ceph的FileStore做了一遍日志,而Linux文件系统自身也有日志机制,实际上日志被多做了一遍。
  2. 对于新型的LSM-Tree类存储,如RocksDB、LevelDB,由于数据本身就按照日志形式组织,实际上没有再另加一个单独的WAL的必要。
  3. 更好地发挥SSD/NVM存储介质的性能。与磁盘不同,基于Flash的存储有更高的并行能力,需要加以利用。CPU处理速度逐渐更不上存储,因而需要更好地利用多核并行。存储中大量使用的队列等,容易引发并发竞争耗时,也需要优化。另一方面,RocksDB对SSD等有良好支持,它为BlueStore所采用。

另外,社区曾经为了FileStore的问题,提出用LevelDB作存储后端;对象存储转换为KeyValue存储,而不是转换问文件。后来,LevelDB存储没有被推广开,主流还是使用FileStore。但KeyValue的思路被沿用下来,BlueStore就是使用RocksDB来存储元数据的。

BlueStore 整体架构

bluestore 的诞生是为了解决 filestore 自身维护一套journal 并同时还需要基于文件系统的写放大问题,并且 filestore 本身没有对 SSD 进行优化,因此 bluestore 相比于 filestore 主要做了两方面的核心工作:

  1. 去掉 journal ,直接管理裸设备
  2. 针对 SSD 进行单独优化

bluestore 整体架构如下图:

通过Allocator(分配器)实现对裸设备的管理,直接将数据保存到设备上;同时针对 metadata 使用 RocksDB 进行保存,底层自行封装了一个BlueFS用来对接RocksDB 与裸设备。

核心模块

  • RocksDB: 存储预写式日志、数据对象元数据、Ceph的omap数据信息、以及分配器的元数据(分配器负责决定真正的数据应在什么地方存储)
  • BlueRocksEnv: 与RocksDB交互的接口
  • BlueFS: 小的文件系统,解决元数据、文件空间及磁盘空间的分配和管理,并实现了rocksdb::Env 接口(存储RocksDB日志和sst文件)。因为rocksdb常规来说是运行在文件系统的顶层,下面是BlueFS。 它是数据存储后端层,RocksDB的数据和BlueStore中的真正数据被存储在同一个块物理设备
  • BlockDevice(HDD/SSD): 物理块设备,存储实际的数据

rocksdb本身是基于文件系统的,不是直接操作裸设备。它将系统相关的处理抽象成Env,用户可用实现相应的接口。BlueRocksEnv是bluestore实现的一个类,继承自rocksdb::EnvWrapper,来为rocksdb提供底层系统的封装。

为了对接BlueRocksEnv,实现了一个小的文件系统BlueFS,只实现rocksdb Env需要的接口。所有的元数据的修改都记录在BlueFS的日志中,也就是对于BlueFS,元数据的持久化保存在日志中。在系统启动mount这个文件系统时,只需回放日志,就可将所有的元数据都加载到内存中。BluesFS的数据和日志文件都通过块设备保存到裸设备上(BlueFS和BlueStore可以共享裸设备,也可以分别指定不同的设备)。

bluestore不使用本地文件系统,直接接管裸设备,并且只使用一个原始分区,HDD/SSD所在的物理块设备实现在用户态下使用linux aio直接对裸设备进行I/O操作。由于操作系统支持的aio操作只支持directIO,所以对BlockDevice的写操作直接写入磁盘,并且需要按照page对齐。其内部有一个aio_thread 线程,用来检查aio是否完成。其完成后,通过回调函数aio_callback 通知调用方。

1) Allocator 模块

用来委派具体哪个实际存储块用来存储当前的object数据;同样采用bitmap的方式来实现allocator,同时采用层级索引来存储多种状态,这种方式对内存的消耗相对较小,平均1TB磁盘需要大概35M左右的ram空间。

2)BlueStore 模块

在之前的存储引擎filestore里,对象的表现形式是对应到文件系统里的文件,默认4MB大小的文件,但是在bluestore里,已经没有传统的文件系统,而是自己管理裸盘,因此需要有元数据来管理对象,对应的就是Onode,Onode是常驻内存的数据结构,持久化的时候会以kv的形式存到rocksdb里。

BlueStore 存储的最常用写路径应该尽量的短,尽量的简单,这样才能有最好的性能,尽快另外的异常处理路径可能是非常复杂的。BlueStore 的设计有如下特色:

  1. Ceph 并不需要POSIX 文件系统。抛弃它,实现一个尽量简单的文件系统,专门给 RocksDB 使用。这个文件系统叫做 BlueFS
  2. 元数据存储在RocksDB中,用KeyValue的方式正合适。而数据不需要文件系统,直接存储在裸块设备上即可。我们在块设备上需要的,其实是一个空间分配器(Allocator)。

还有一点,BlueStore 中不同组件可以使用不同的设备。例如给 RocksDB 的 WAL 文件配置 NVRAM,给SST文件配备 SSD,给数据文件配备HDD,方案是灵活的。

3)BlueStore 的元数据管理

在涉及写路径之前,先看看Ceph BlueStore 如何管理元数据。首先的问题是,对象如何映射成磁盘数据结构(Ceph 的底层是对象存储,向上封装出块存储、文件存储)?

Onode代表对象,名字大概是从Linux VFS的Inode沿袭过来的。Onode常驻内存,在RocksDB中以KeyValue形式持久化;

Onode包含多个lextent,即逻辑extent。Blob通过映射pextent、即物理extent,映射到磁盘上的物理区域。Blob通常包括来自同一个对象的多段数据,但是也可能被其它对象引用。Bnode是对象快照后,被用于多个对象共享数据的。

4)BlueStore 的写路径

写路径包含了对事务的处理,也回答了BlueStore如何解决日志双写问题。

首先,Ceph的事务只工作于单个OSD内,能够保证多个对象操作被ACID地执行,主要是用于实现自身的高级功能。每个PG(Placement Group,类似Dynamo的vnode,将hash映射到同一个组内的对象组到一起)内有一个OpSequencer,通过它保证PG内的操作按序执行。事务需要处理的写分三种:

(1)写到新分配的区域。考虑ACID,因为此写不覆盖已有数据,即使中途断电,因为RocksDB中的元数据没有更新,不用担心ACID语义被破坏。后文可见RocksDB的元数据更新是在数据写之后做的。因而,日志是不需要的。在数据写完之后,元数据更新写入RocksDB;RocksDB本身支持事务,元数据更新作为RocksDB的事务提交即可。

(2)写到Blob中的新位置。同理,日志是不需要的。

(3)Deferred Writes(延迟写),只用于覆写(Overwrite)情况。从上面也可以看到,只有覆写需要考虑日志问题。如果新写比块大小(min_alloc_size)更小,那么会将其数据与元数据合并写入到RocksDB中,之后异步地把数据搬到实际落盘位置;这就是日志了。如果新写比块大小更大,那么分割它,整块的部分写入新分配块中,即按(1)处理,;不足的部分按(3)中上种情况处理。

上述基本概述了BlueStore的写处理。可以看到其是如何解决FileStore的日志双写问题的。

首先,没有Linux文件系统了,也就没有了多余的Journaling of Journal问题。然后,大部分写是写到新位置的,而不是覆写,因此不需要对它们使用日志;写仍然发生了两次,第一次是数据落盘,然后是RocksDB事务提交,但不再需要在日志中包含数据了。最后,小的覆写合并到日志中提交,一次写完即可返回用户,之后异步地把数据搬到实际位置(小数据合并到日志是个常用技巧);大的覆写被分割,整块部分用Append-only方式处理,也绕开了日志的需要。至此,成为一个自然而正常的处理方式。

5)BlueFS 的架构

BlueFS以尽量简单为目的设计,专门用于支持RocksDB;RocksDB总之还是需要一个文件系统来工作的。BlueFS不支持POSIX接口。总的来说,它有这些特点:

(1)目录结构方面,BlueFS只有扁平的目录结构,没有树形层次关系;用于放置RocksDB的db.wal/,db/,db.slow/文件。这些文件可以被挂载到不同的硬盘上,例如db.wal/放在NVMRAM上;db/包含热SST数据,放在SSD上;db.slow/放在磁盘上。

(2)数据写入方面,BlueFS不支持覆写,只支持追加(Append-only)。块分配粒度较粗,约1MB。有垃圾回收机制定期处理被浪费掉的空间。

(3)对元数据的操作记录到日志,每次挂载时重放日志,来获得当前的元数据。元数据生存在内存中,并没有持久化在磁盘上,不需要存储诸如空闲块链表之类的。当日志过大时,会进行重写Compact。

如果问为什么BlueStore相比FileStore能够提高越一倍的吞吐量,可能在于其更加简单、更加短的写路径;解决了双写问题,大部分数据不再需要在日志中多写一遍;借用RocksDB处理元数据,后者实现成熟,对SSD优化良好。

存在的问题

BlueStore在自己实现读裸设备管理的核心思想下,就不得不面对很多机制都需要自己来实现优化的场景,面临的问题主要表现在以下三个方面:

1. 缓存大小的调整和写回策略的实现:由于BlueStore抛弃了文件系统作为实际的存储形式,所以不可避免地就需要自己是现在在文件系统中表现优异的各类缓存机制和策略。文件系统继承了操作系统页缓存的优势,会根据应用程序的使用情况动态调整缓存的大小;而对于类似于 BlueStore 穿过内核的存储后端需要自己实现类似的机制。BlueStore 中需要自己手动设置缓存大小相关的参数,如何在用户态构建一个如操作系统页缓存动态调整大小的机制时很多存储系统都面临的问题,如 PostgreSQl,RocksDB。同时面对已经出现的 NVMe SSD,缓存需要更加高效,才能减小 SSD 的写负载,同时也是当前页缓存面临的问题。

2. KV 存储的效率问题::Ceph 的经验表明把所有元数据给移植到有序的 KV 存储(如 RocksDB)上能够显著提高元数据操作的性能,然而同时也发现嵌入 RocksDB 带来的一些问题:Ceph 的经验表明把所有元数据给移植到有序的 KV 存储(如 RocksDB)上能够显著提高元数据操作的性能,然而同时也发现嵌入 RocksDB 带来的一些问题:

在 OSD 节点上使用 NVMe SSD 时,RocksDB 的压缩机制和严峻的写放大问题已经成为了主要的性能限制。

由于RockDB被视为一个黑盒,因此数据被序列化,并在其中来回复制,消耗数据 CPU 时间;

RocksDB 有自己的线程模型,这限制了自定义分片的能力。

3. CPU和内存的效率问题:Ceph 中复杂的数据结构,且生命周期较长,采用默认的布局一定程度上会造成内存的浪费。因为现代编译器在内存中对齐和填充基本数据类型,这样CPU就可以方便地获取数据,从而提高了性能。然而跨越了内核的存储后端控制几乎机器的所有的内存,内存的优化和隔离机制需要自己动手实现;如上提到的 KV 存储的问题,在使用 NVMe SSD 时,其工作负载会被 CPU 限制,涉及到大量的序列化和反序列化操作。故 Ceph 开发团队试图减小 CPU 的消耗,通过减小序列化和反序列化数据的大小,尝试使用 SeaStar 框架的共享模型来避免由于锁导致的上下文切换。

总结:

BlueStore 最大的特点是 OSD 可以直接管理裸磁盘设备,并且将对象数据存储在该设备中。另外对象有很多KV属性信息,这些信息之前是存储在文件的扩展属性或者LevelDB当中的。而在BlueStore中,这些信息存储在RocksDB当中。RocksDB本身是需要运行在文件系统之上的,因此为了使用RocksDB存储这些元数据,需要开发一个简单的文件系统(BlueFS)。

从BlueStore 的设计和实现上看,可以将其理解为用户态下的一个文件系统,同时使用RocksDB来实现BlueStore所有元数据的管理,简化实现。

​对于整块数据的写入,数据直接以aio的方式写入磁盘,再更新RocksDB中数据对象的元数据,避免了filestore的先写日志,后apply到实际磁盘的两次写盘。同时避免了日志元数据的冗余存储占用,因为传统文件系统有他们自己内部的日志和元数据管理机制。

BlueStore 其实是实现了用户态的一个文件系统。为了实现简单,又使用了RocksDB来实现了BlueStore的所有元数据的管理,简化了实现。

优点在于:

对于整块数据的写入,数据直接 AIO 的方式写入磁盘,避免了 filestore的先写日志,后 apply到实际磁盘的两次写盘。
对于随机IO,直接 WAL 的形式,直接写入 RocksDB 高性能的 KV 存储中。

展望

通过Ceph后端引擎的发展历程,我们不难发现,传统的文件系统存储后端在不断完善相关功能如事务、克隆和快照等操作的同时,也在进行转型。通过融合其他存储引擎的优势共同组成一个存储系统来对外提供服务,诸如元数据管理更多的是交给KV存储来进行处理,充分利用其他存储引擎所长,并将各自进行组件化,模块化,以模块的形式和其他存储模块进行融合,共同构成高效的存储系统。

后来产生的BlueStore正是存储引擎模块化组件化的成果,通过充分发挥各类存储引擎的优势,将KV存储引擎用于元数据的管理,将文件系统进行定制,根据实际的场景减小文件系统的功能复杂程度,定制了BlueFS,同时也有开天辟地的新型存储引擎的设计与实现,如基于裸设备的存储,通过将各类存储引擎组件化,可以根据实际的需求将组件进行整合,从而构成一个与需求紧密结合的存储系统。

未来存储系统的组件化将应用更加广泛,尤其是针对现如今不断发展的存储器件技术,传统的基于块设备的存储引擎势必需要对新型存储器件进行适配,组件化存储引擎之后可以充分减小适配的工作量,同时对于未来可能出现的新技术也能较好地进行吸收和整合。BlueStore的出现开启了一段存储系统变革的新纪元,未来面向实际应用场景的定制化存储系统可能才能真正充分发挥存储系统的性能。

四、Ceph安装部署与使用

1、硬件要求

Ceph 被设计成在普通硬件上运行,这使得建立和维护PB级别的数据集群在经济上可行的。在规划硬件集群时,需要平衡许多考虑事项,包括故障域和潜在的性能问题。硬件规划应该包括在许多主机上分发Ceph守护进程和其他使用Ceph的进程。

通常,建议在为该类型守护进程配置的主机上运行特定类型的Ceph守护进程。建议使用其他主机来处理利用你的数据集群的进程。

1)CPU

Ceph 元数据服务器对 CPU 敏感,它会动态地重分布它们的负载,所以你的元数据服务器应该有足够的处理能力(如 4 核或更强悍的 CPU )。Ceph 的 monitor 守护进程维护了 clustermap,它不给客户端提供任何数据,因此它是轻量级的,并没有严格的处理器要求。在大多数场景下,一个普通的单核服务器处理器就可以运行 Ceph monitor 服务。Ceph 的 OSD 运行着 RADOS 服务、用 CRUSH 计算数据存放位置、复制数据、维护它自己的集群运行图副本,因此 OSD 需要一定的处理能力(如双核 CPU )。监视器只简单地维护着集群运行图的副本,因此对 CPU 不敏感;但必须考虑机器以后是否还会运行 Ceph 监视器以外的 CPU 密集型任务。例如,如果服务器以后要运行用于计算的虚拟机(如 OpenStack Nova ),你就要确保给 Ceph 进程保留了足够的处理能力,所以我们推荐在其他机器上运行 CPU 密集型任务。

一个 Ceph OSD 守护进程需要相当数量的处理性能,因为它提供数据给客户端。要评估 Ceph OSD 的 CPU 需求,知道服务器上运行了多少 OSD 上非常重要的。通常建议每个 OSD 进程至少有一个核心。可以通过以下公式计算 OSD 的 CPU 需求:

((CPU sockets * CPU cores per socket * CPU clock speed in GHz )/ No.of OSD ) >= 1

比如:

Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz 6 core   --> 1 * 6 * 2.40 = 14.4 适合多达 14 个 OSD 的 Ceph 节点

Intel(R) Xeon(R) CPU E5-2680 v3 @ 2.50GHz 12 core   --> 1 * 12 * 2.50 = 30 适合多达 30 个 OSD 的 Ceph 节点

如果打算使用 Ceph 纠删码特性,最好能有一个更高性能的CPU ,因为运行纠删码需要更强的处理能力。

2)RAM 内存

元数据服务器和监视器必须可以尽快地提供它们的数据,所以他们应该有足够的内存,至少每进程 1GB 。 OSD 的日常运行不需要那么多内存(如每进程 500MB )差不多了;然而在恢复期间它们占用内存比较大(如每进程每 TB 数据需要约 1GB 内存)。通常内存越多越好。

3)网络

Ceph 是一个分布式存储系统,很大程度上依赖于底层的网络基础设施。要让Ceph集群变得可靠、高效,就得确保设计一个良好的网络。建议让所有的集群节点拥有两张冗余独立的网卡用于集群和客户端流量。

一个设计良好的Ceph集群使用两个物理隔离网络:一个是集群网络(内部网络),另一个是客户端网络(外部网络)。两个网络应该从服务器到网络交换机以及它们之间的一切环节都进行物理隔离,如下图:

4)数据存储

要谨慎地规划数据存储配置,因为其间涉及明显的成本和性能折衷。来自操作系统的并行操作和到单个硬盘的多个守护进程并发读、写请求操作会极大地降低性能。

重要提示:因为 Ceph 发送 ACK 前必须把所有数据写入日志(至少对 xfs 和 ext4 来说是),因此均衡日志和 OSD 性能相当重要。

5)硬盘驱动器

OSD 应该有足够的空间用于存储对象数据。考虑到大硬盘的每 GB 成本,我们建议用容量大于 1TB 的硬盘。建议用 GB 数除以硬盘价格来计算每 GB 成本,因为较大的硬盘通常会对每 GB 成本有较大影响,例如,单价为 $75 的 1TB 硬盘其每 GB 价格为 $0.07 ( $75/1024=0.0732 ),又如单价为 $150 的 3TB 硬盘其每 GB 价格为 $0.05 ( $150/3072=0.0488 ),这样使用 1TB 硬盘会增加 40% 的每 GB 价格,它将表现为较低的经济性。另外,单个驱动器容量越大,其对应的 OSD 所需内存就越大,特别是在重均衡、回填、恢复期间。根据经验, 1TB 的存储空间大约需要 1GB 内存。

提示:不顾分区而在当个硬盘上运行多个OSD 是不明智的!

提示:不顾分区而在运行了OSD的硬盘上同时运行监视器或元数据服务器也上不明智的!

存储驱动器受限于寻道时间、访问时间、读写时间、还有总吞吐量,这些物理局限性影响着整体系统性能,尤其在系统恢复期间。因此我们推荐独立的驱动器用于安装操作系统和软件,另外每个 OSD 守护进程占用一个驱动器。大多数 “slow OSD”问题的起因都是在相同的硬盘上运行了操作系统、多个 OSD 、和/或多个日志文件。鉴于解决性能问题的成本差不多会超过另外增加磁盘驱动器,你应该在设计时就避免增加 OSD 存储驱动器的负担来提升性能。

Ceph 允许你在每块硬盘驱动器上运行多个 OSD ,但这会导致资源竞争并降低总体吞吐量; Ceph 也允许把日志和对象数据存储在相同驱动器上,但这会增加记录写日志并回应客户端的延时,因为 Ceph 必须先写入日志才会回应确认了写动作。 btrfs 文件系统能同时写入日志数据和对象数据, xfs 和 ext4 却不能。

Ceph 最佳实践指示,你应该分别在单独的硬盘运行操作系统、 OSD 数据和 OSD 日志。

 6)固态硬盘

一种提升性能的方法是使用固态硬盘( SSD )来降低随机访问时间和读延时,同时增加吞吐量。 SSD 和硬盘相比每 GB 成本通常要高 10 倍以上,但访问时间至少比硬盘快 100 倍。

SSD 没有可移动机械部件,所以不存在和硬盘一样的局限性。但 SSD 也有局限性,评估SSD 时,顺序读写性能很重要,在为多个 OSD 存储日志时,有着 400MB/s 顺序读写吞吐量的 SSD 其性能远高于 120MB/s 的。

重要提示:建议发掘 SSD 的用法来提升性能。然而在大量投入 SSD 前,我们强烈建议核实 SSD 的性能指标,并在测试环境下衡量性能。

正因为 SSD 没有移动机械部件,所以它很适合 Ceph 里不需要太多存储空间的地方。相对廉价的 SSD 很诱人,慎用!可接受的 IOPS 指标对选择用于 Ceph 的 SSD 还不够,用于日志和 SSD 时还有几个重要考量:

  • 写密集语义: 记日志涉及写密集语义,所以你要确保选用的 SSD 写入性能和硬盘相当或好于硬盘。廉价 SSD 可能在加速访问的同时引入写延时,有时候高性能硬盘的写入速度可以和便宜 SSD 相媲美。
  • 顺序写入: 在一个 SSD 上为多个 OSD 存储多个日志时也必须考虑 SSD 的顺序写入极限,因为它们要同时处理多个 OSD 日志的写入请求。
  • 分区对齐: 采用了 SSD 的一个常见问题是人们喜欢分区,却常常忽略了分区对齐,这会导致 SSD 的数据传输速率慢很多,所以请确保分区对齐了。

SSD 用于对象存储太昂贵了,但是把 OSD 的日志存到 SSD 、把对象数据存储到独立的硬盘可以明显提升性能。 osd journal 选项的默认值是 /var/lib/ceph/osd/$cluster-$id/journal ,你可以把它挂载到一个 SSD 或 SSD 分区,这样它就不再是和对象数据一样存储在同一个硬盘上的文件了。

7)控制器

硬盘控制器对写吞吐量也有显著影响,要谨慎地选择,以免产生性能瓶颈。

8)其他注意事项

你可以在同一主机上运行多个 OSD ,但要确保 OSD 硬盘总吞吐量不超过为客户端提供读写服务所需的网络带宽;还要考虑集群在每台主机上所存储的数据占总体的百分比,如果一台主机所占百分比太大而它挂了,就可能导致诸如超过 full ratio 的问题,此问题会使 Ceph 中止运作以防数据丢失。

如果每台主机运行多个 OSD ,也得保证内核是最新的。

OSD 数量较多(如 20 个以上)的主机会派生出大量线程,尤其是在恢复和重均衡期间。很多 Linux 内核默认的最大线程数较小(如 32k 个),如果您遇到了这类问题,可以把 kernel.pid_max 值调高些。理论最大值是 4194303 。例如把下列这行加入 /etc/sysctl.conf文件:

kernel.pid_max = 4194303

Ceph OSD 节点的密度也是影响集群性能、可用容量和 TCO(Total Cost of Ownership ,即总拥有成本)的一个重要因素。通常,大量的小容量节点 比 少量的大容量节点要好,但这并不是定论,应该选择适当的 Ceph 节点密度,使得三个节点容量小于总容量的 10%。例如:在一个 1PB的ceph集群中,应该避免使用 4 个 250TB 的 OSD 节点,因为每个节点占用了 25% 的集群容量。相反,可以使用 13 个 80TB 的 OSD节点,每个节点容量小于集群容量的 10%。

2、自建ceph离线源

现在实验要求,离线安装 ceph-10.2.11版本的ceoh集群,怎样一次下载相关主包及其依赖?

国外开源软件,除了版本号数字,一般会将每个软件的版本设置一个代号,大家熟知的如Ubuntu系统,ceph也是如此。

ceph-10.2.11 的版本代号是 jewel。

操作系统:CentOS7.5。

1. 在下相关工具包

# yum  -y install epel-release
# yum -y install  yum-utils
# yum  -y install createrepo 

2. 添加ceph jewel 阿里云镜像仓库

# vim /etc/yum.repos.d/ceph.repo
#################################################
[ceph]
name=ceph
baseurl=http://mirrors.aliyun.com/ceph/rpm-jewel/el7/x86_64/
gpgcheck=0
[ceph-noarch]
name=cephnoarch
baseurl=http://mirrors.aliyun.com/ceph/rpm-jewel/el7/noarch/
gpgcheck=0
[ceph-source]
name=cephsource
baseurl=http://mirrors.aliyun.com/ceph/rpm-jewel/el7/x86_64/
gpgcheck=0
[ceph-radosgw]
name=cephradosgw
baseurl=http://mirrors.aliyun.com/ceph/rpm-jewel/el7/x86_64/
gpgcheck=0
######################################################
# yum clean all
# yum repolist # yum list ceph --showduplicates | sort -r
# yum list all | grep ceph-deploy

3. 一次性下载ceph-10.2.11相关主包及其依赖

# mkdir /root/ceph-jewel-10.2.11
# repotrack ceph-deploy-1.5.39 -p /root/ceph-jewel-10.2.11
# repotrack ceph-10.2.11 ceph-mgr-10.2.11 ceph-mon-10.2.11 ceph-mds-10.2.11 ceph-osd-10.2.11 ceph-fuse-10.2.11 ceph-radosgw-10.2.11  -p  /root/ceph-jewel-10.2.11
# ll /root/ceph-jewel-10.2.11/ | wc -l
# ll /root/ceph-jewel-10.2.11/ | grep ceph98

4. 生成用于离线安装的仓库元数据

# createrepo -v /root/ceph-jewel-10.2.11
# ll ceph-jewel-10.2.11

现在可以将  /root/ceph-jewel-10.2.11目录打包到目标机器用于搭建ceph安装的本地或者网络yum源了!

tar  -zcf  ceph-jewel-10.2.11.tar.gz  ceph-jewel-10.2.11

注意:如果使用自己搭建的局域网yum源,安装ceph集群时间,不要在deploy节点执行 :

ceph-deploy install node01 node02 node03

如果使用ceph-deploy install,会安装ceph-release这个包,在目标机器添加ceph的官方仓库,然后在内网环境,会因为找不到这个包或者仓库无法联网,导致安装失败!

改之,在node01 node02 node03 节点手动执行:

yum  -y install   ceph-10.2.11 ceph-mgr-10.2.11 ceph-mon-10.2.11 ceph-mds-10.2.11 ceph-osd-10.2.11 ceph-fuse-10.2.11 ceph-radosgw-10.2.11

3、RHEL/CentOS安装

① 环境准备

1. 准备6台虚拟机;

2. 物理主机上配置域名解析:

]#for i in {1..6}
>do
>echo -e “192.168.4.$i\tnode$i\tnode$i.tedu.cn” >> /etc/hosts
>done

3. 提前将服务器的密钥保存,不需要ssh时回答yes:

]# ssh-keyscan node{1..6} >> /root/.ssh/known_hosts

4. 实现免密登陆:

]# for i in {1..6}
> do
> ssh-copy-id node$i
> done

5. 配置yum源:

]# mkdir /var/ftp/ceph/
]# vim /etc/fstab
/ISO/rhcs2.0-rhosp9-20161113-x86_64.iso /var/ftp/ceph iso9660 defaults 0 0
]# mount -a
]# vim /tmp/server.repo[rhel7.4]
name=rhel7.4
baseurl=ftp://192.168.4.254/rhel7.4
enabled=1
gpgcheck=0
[mon]
name=mon
baseurl=ftp://192.168.4.254/ceph/rhceph-2.0-rhel-7-x86_64/MON
enabled=1
gpgcheck=0
[osd]
name=osd
baseurl=ftp://192.168.4.254/ceph/rhceph-2.0-rhel-7-x86_64/OSD
enabled=1
gpgcheck=0
[tools]
name=tools
baseurl=ftp://192.168.4.254/ceph/rhceph-2.0-rhel-7-x86_64/Tools
enabled=1
gpgcheck=0

批量执行:

#!/bin/bash
for vm in node{1…6}
do
scp /tmp/server.repo ${vm}:/etc/yum.repos.d/
done

② 配置node1节点为管理节点

1. 配置名称解析:

[root@node1 ~]# for i in {1..6}; do echo -e "192.168.4.$i\tnode$i.tedu.cn\tnode$i" >> /etc/hosts; done

2. 配置免密登陆:

[root@node1 ~]# ssh-keyscan node{1..6} >> /root/.ssh/known_hosts
[root@node1 ~]# ssh-keygen -f /root/.ssh/id_rsa -N ''
[root@node1 ~]# for i in {1..6}; do ssh-copy-id node$i; done
[root@node1 ~]# for vm in node{1..6}
> do
> scp /etc/hosts ${vm}:/etc/
> done

3. 配置node6为时间服务器

(1)配置

[root@node6 ~]# yum install -y chrony
[root@node6 ~]# vim /etc/chrony.conf
server 0.centos.pool.ntp.org iburst
#server 1.centos.pool.ntp.org iburst
#server 2.centos.pool.ntp.org iburst
#server 3.centos.pool.ntp.org iburst
allow 192.168.4.0/24
local stratum 10

启动服务:

[root@node6 ~]# systemctl enable chronyd
[root@node6 ~]# systemctl restart chronyd

4. 将node1-5配置为NTP的客户端

(1)配置

[root@node1 ~]# vim /etc/chrony.conf
#server 0.rhel.pool.ntp.org iburst
#server 1.rhel.pool.ntp.org iburst
#server 2.rhel.pool.ntp.org iburst
#server 3.rhel.pool.ntp.org iburst
server 192.168.4.6 iburst
[root@node1 ~]# systemctl restart chronyd

测试:

[root@node1 ~]# date -s "2018-7-13 12:00:00"
[root@node1 ~]# ntpdate 192.168.4.6
[root@node1 ~]# date

(2)同步其他主机:

[root@node1 ~]# for i in {2..5}
> do
> scp /etc/chrony.conf node$i:/etc/
> done
[root@node1 ~]# for vm in node{2..5}
> do
> ssh $vm systemctl restart chronyd
> done

5. 为node1-3各添加3块10GB的磁盘

可以在虚拟机不关机的情况下,直接添加硬盘,安装ceph:

1) 在node1上安装部署软件

[root@node1 ~]# yum install -y ceph-deploy

2) 创建ceph部署工具的工作目录

[root@node1 ~]# mkdir ceph-clu

3) 创建参与集群节点的配置文件

[root@node1 ceph-clu]# ceph-deploy new node{1..3}
[root@node1 ceph-clu]# ls

4) 在3个节点上安装软件包

[root@node1 ceph-clu]# ceph-deploy install node{1..3}

5) 初始化mon服务,获取密钥key,会在ceph-clu目录下生成几个key

[root@node1 ceph-clu]# ceph-deploy mon create-initial

如果出现以下错误:

[node1][ERROR ] admin_socket: exception getting command descriptions: [Errno 2] No such file or directory

解决方案:

[root@node1 ceph-clu]# vim ceph.conf 最下面加入行:
public_network = 192.168.0.0/24
再执行以下命令:
[root@host1 ceoh-clu]# ceph-deploy --overwrite-conf config push node1 node2 node3

6. 把node1-3的vdb作为日志盘。Ext/xfs都是日志文件系统,一个分区分成日志区和数据区。为了更好的性能,vdb专门作为vdc和vdd的日志盘:

[root@node1 ceph-clu]# for vm in node{1..3}
> do
> ssh $vm parted /dev/vdb mklabel gpt
> done
[root@node1 ceph-clu]# for vm in node{1..3}; do ssh $vm parted /dev/vdb mkpart primary 1M 50% ; done
[root@node1 ceph-clu]# for vm in node{1..3}; do ssh $vm parted /dev/vdb mkpart primary 50% 100% ; done
[root@node1 ceph-clu]# for vm in node{1..3}; do ssh ${vm} chown ceph.ceph /dev/vdb? ; done

创建OSD设备:

[root@node1 ceph-clu]# for i in {1..3}
> do
> ceph-deploy disk zap node$i:vdc node$i:vdd
> done
[root@node1 ceph-clu]# for i in {1..3}
> do
> ceph-deploy osd create node$i:vdc:/dev/vdb1 node$i:vdd:/dev/vdb2
> done

7. 验证

到第7步为止,ceph已经搭建完成,查看ceph状态:

[root@node1 ceph-clu]# ceph -s 如果出现health HEALTH_OK表示正常
[root@node1 ceph-clu]# ceph health

③ ceph常用命令

1. 服务相关:

systemctl status ceph*.service ceph*.target #查看所有服务
systemctl stop ceph*.service ceph*.target #关闭所有服务
systemctl start ceph.target #启动服务
systemctl stop ceph-osd*.service # 关闭所有osd服务
systemctl stop ceph-mon*.service #关闭所有mon服务
sudo systemctl start ceph-osd@{id} #启动单个osd服务
sudo systemctl start ceph-mon@{hostname} #启动单个mon服务
sudo systemctl start ceph-mds@{hostname} #启动单个mds服务

2. 查看:

ceph -help #查看命令帮助
ceph -s #查看状态
ceph osd pool set rbd pg_num 1024 # 修改pg_num数量
ceph osd pool set rbd pgp_num 1024 # 修改pgp_num数量
ceph osd tree #查看osd树列表
ceph osd pool ls #查看所有的osd池
ceph --admin-daemon /var/run/ceph/ceph-osd.0.asok config show # 查看指定的osd运行中的所有参数
rados df #查看储存池使用情况
rados -p rbd ls |sort
ceph osd pool get rbd pg_num
ceph osd pool get rbd pgp_num
ceph osd pool set rbd pg_num 1024
ceph osd pool set rbd pgp_num 1024

3. rbd相关:

rbd create --size {megabytes} {pool-name}/{image-name}
rbd list
rbd info RBD_NAME
rbd feature disable RBD_NAME FEATURE1 FEATURE1 …
rbd map RBD_NAME #映射到系统内核
rbd showmapped #查看rbd映射条目
rbd unmap /dev/rbd0 # 取消内核映射
rbd resize --size 2048 RBD_NAME # to increase
rbd resize --size 2048 RBD_NAME --allow-shrink #to decrease
rbd du {RBD_NAME} -p rbd #查看某个或所有Image的容量,-p 指定pool名
rbd diff RBD_NAME | awk ‘{ SUM += $2 } END { print SUM/1024/1024/1024 " GB" }’ #查看rbd image当前占用大小

4. 修改:

ceph tell # 使用tell命令手动临时修改组件的配置

例如:集群状态恢复涉及数据回填时,加速回填速度。

ceph tell ‘osd.*’ injectargs ‘–osd-max-backfills 16’ #默认为1
ceph tell ‘osd.*’ injectargs ‘–osd-recovery-max-active 8’ #默认为4

4、部署ceph集群

注意版本更新非常快,有问题看官方文档。

官方文档:Welcome to Ceph — Ceph Documentation

流程:

​1. 部署luminous(ceph12.2.10的版本代号);

2. 配置dashboard;

3. 客户端使用rbd;

部署环境
系统版本:centos7.5 x86_64 server
ceph版本:ceph 12.2.10(luminous)
硬件配置:5台vm,1核1G内存,每台node角色的机器至少挂载1块为osd准备的空闲盘主机名             ip                                  roleadmin            192.168.245.135          admin  管理多个minitornode1            192.168.245.136          mon / mgr / osd   类似minitornode2            192.168.245.137          osdnode3            192.168.245.138          osdclient             192.168.245.10

​1. 准备工作

1.1 开启网络(所有节点,root用户)
1.2 修改主机名/互相解析(所有节点,root用户)
1.3 创建用户(所有节点,root用户)在所有节点上执行如下操作:1)创建用户名:cephu,设置密码:# useradd cephu# passwd  cephu2)修改visudo文件,否则提示cephu不再sudoer列表中的错误。命令行输入visudo,在root ALL=(ALL) ALL下面添加:cephu  ALL=(ALL) ALL3)切换至cephu用户,为该用户增加root权限:su - cephu$ echo "cephu ALL=(root) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/cephu$ sudo  chmod 0440 /etc/sudoers.d/cephu
​
1.4 实现ssh无密码登录(admin节点)1)cephu用户下,生成秘钥: $ ssh-keygen2)cephu用户下,把生成的密钥拷贝到各Ceph节点:$ ssh-copy-id cephu@node1$ ssh-copy-id cephu@node2$ ssh-copy-id cephu@node33)root用户下,添加~/.ssh/config配置文件,并进行如下设置:Host node1Hostname node1User cephu
​Host node2Hostname node2User cephu
​Host node3Hostname node3User cephu1.5 添加下载源,安装ceph-deploy(admin节点,root用户)1)安装epel源:sudo yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
​2)导入repo仓库:cat << EOM > /etc/yum.repos.d/ceph.repo[ceph-noarch]name=Ceph noarch packagesbaseurl=https://download.ceph.com/rpm-{ceph-stable-release}/el7/noarchenabled=1gpgcheck=1type=rpm-mdgpgkey=https://download.ceph.com/keys/release.ascEOM#注意这里的{ceph-stable-release}要换成对应的版本号,如我这里就是:cat << EOM > /etc/yum.repos.d/ceph.repo[ceph-noarch]name=Ceph noarch packagesbaseurl=https://download.ceph.com/rpm-octopus/el7/noarchenabled=1gpgcheck=1type=rpm-mdgpgkey=https://download.ceph.com/keys/release.ascEOM3) 然后更新yum repo:​yum clean allyum repolist4) 安装yum插件sudo yum install yum-plugin-priorities1.6 设置TTY(所有节点)注意:此设置由官方文档指出,但是并未在这里找不到此配置行,不用做此步# sudo visudo   找到 Defaults requiretty 注释掉
​
1.7 关闭selinux(所有节点)setenforce 0sed -i 's/^SELINUX=enforcing$/SELINUX=disabled/' /etc/selinux/config# 也可以直接修改/etc/selinux/config文件1.8 防火墙中放行端口sudo firewall-cmd --zone=public --add-service=ceph-mon --permanent# on monitorssudo firewall-cmd --zone=public --add-service=ceph --permanent# on OSDs and MDSssudo firewall-cmd --reload
也可以直接关闭或禁用防火墙
​
1.9 安装ntp(所有节点)选择任何一台机器当ntp时间服务器,其他的节点当时间服务器的客户端跟服务器同步时间admin上:# yum install -y ntp    # vim /etc/ntp.conf //有4行server的位置,把那4行server行注释掉,填写以下两行server 127.127.1.0     # local clockfudge  127.127.1.0 stratum 10    # systemctl start ntpd # systemctl status ntpd  //确认打开NTP服务其他所有节点:# yum install ntpdate  -y# ntpdate  时间服务器ip1.10  安装python工具sudo yum install python-setuptools

注意:

这里我们需要创建一个用户专门用来给ceph-deploy部署,使用ceph-deploy部署的时候只需要加上--username选项即可指定用户,需要注意的是:

  • 不建议使用root
  • 不能使用ceph为用户名,因为后面的部署中需要用到该用户名,如果系统中已存在该用户则会先删除掉该用户,然后就会导致部署失败
  • 该用户需要具备超级用户权限(sudo),并且不需要输入密码使用sudo权限
  • 所有的节点均需要创建该用户
  • 该用户需要在ceph集群中的所有机器之间免密ssh登录

2. 部署ceph集群

没有特别说明以下所有操作均是在admin节点,cephu用户下执行。

2.1 安装ceph-deploysudo yum updatesudo yum install ceph-deploy
​
2.2 创建ceph集群创建ceph操作目录:$ mkdir my-cluster  //切记不可用sudo创建$ cd my-cluster       //之后,所有ceph-deploy命令操作必须在该目录下执行创建集群:$ ceph-deploy new node1创建成功会有三个文件:ceph.conf, ceph.mon.keyring, and a log file在所有的节点上都安装ceph$ ceph-deploy new node1 node2 node3
2.3 安装luminous(12.2.9):  luminous理解为12.2.9的另一个叫法,即版本号的另一个叫法。目标:在node1,node2,node3三个节点上安装ceph和ceph-radosgw主包
​方法1:利用官方脚本全自动安装脚本会帮助node1,node2,node3创建epel源和ceph源,并且自动安装ceph和ceph-radosgw主包$ ceph-deploy install --release luminous node1 node2 node3 client这一步实际上是给3个节点安装两个软件:如果ceph和ceph-radosgw安装不上,则采用方法2在千锋做实验要注意epel的源(切记)
​测试是否安装完成:分别在node1 node2 node3中确认安装版本为12.2.9$ ceph --version方法2:手动部署安装1)安装epel源2)创建Ceph源,内容如下:[Ceph]name=Ceph packages for $basearchbaseurl=http://download.ceph.com/rpm-luminous/el7/$basearchenabled=1gpgcheck=1type=rpm-mdgpgkey=https://download.ceph.com/keys/release.ascpriority=1
​[Ceph-noarch]name=Ceph noarch packagesbaseurl=http://download.ceph.com/rpm-luminous/el7/noarchenabled=1gpgcheck=1type=rpm-mdgpgkey=https://download.ceph.com/keys/release.ascpriority=1
​[ceph-source]name=Ceph source packagesbaseurl=http://download.ceph.com/rpm-luminous/el7/SRPMSenabled=1gpgcheck=1type=rpm-mdgpgkey=https://download.ceph.com/keys/release.ascpriority=13)分别在node1,node2,node3节点执行下面命令安装软件可以完全手动安装,但需要yum的ceph缓存目录结构$sudo yum install ceph ceph-radosgw  -y    如果因为速度慢导致安装失败可以按ctrl+c,利用它创建的yum缓存目录,手动把安装包下载下来 保存到缓存目录/var/cache/yum/x86_64/Ceph/packages目录下
​再次执行安装命令:$sudo yum install ceph ceph-radosgw  -y
​分别在node1 node2 node3中确认安装版本为12.2.1:$ ceph --version
​
2.4 初始化mon:$ ceph-deploy mon create-initial
#顺利执行后会在当前目录下生成一系列相关的密钥文件2.5 使用ceph-deploy复制admin配置文件和密钥,赋予各个节点使用命令免用户名权限:$ ceph-deploy admin node1 node2 node3
​
2.6 部署manager,安装ceph-mgr:只有luminous才有,为使用dashboard做准备$ ceph-deploy mgr create node1
​
2.7 添加osd:#这里我们添加三个节点上面的共计6个硬盘到ceph集群中作为osd注意:各个节点上提供存储空间的磁盘大小不能太小,最好5G以上
​     $ ceph-deploy osd create --data /dev/sda node1(12.2.10版本是这条命令,分开给各节点安装)$ ceph-deploy osd create --data /dev/sda node2$ ceph-deploy osd create --data /dev/sda node3$ ceph-deploy osd create --data /dev/sdb node1$ ceph-deploy osd create --data /dev/sdb node2$ ceph-deploy osd create --data /dev/sdb node3命令中/dev/sdb是在各个节点上为osd准备的空闲磁盘(无需分区格式化,如果有分区需要指定具体分区),通过如下命令查看:$ ssh node1 lsblk -f    最后通过如下命令查看集群状态:$ sudo ceph health$ ssh node1 sudo ceph -s如果显示health_ok,3个osd up就成功了$ ceph osd tree

注意:由于我们这里的虚拟机每台都有两个网卡,因此我们需要指定ceph集群用于通信的网卡所在的网段。

3. Dashboard 配置

Dashboard 理解为展示界面,在node1上操作,把 ceph-mgr 和 ceph-mon 安装在同一个主机上,最好只有一个ceph-mgr。

详细的官网部署文档:Ceph Dashboard — Ceph Documentation

3.1 创建管理域秘钥:$ sudo ceph auth get-or-create mgr.node1 mon 'allow profile mgr' osd 'allow *' mds 'allow *'
​
3.2 开启 ceph-mgr 管理域:$ sudo ceph-mgr -i node1
​
3.3 查看ceph的状态:$ sudo ceph status确认mgr的状态为active
​
3.4 打开dashboard模块:$ sudo ceph mgr module enable dashboard3.5 禁用ssl加密ceph config set mgr mgr/dashboard/ssl false3.6 重启ceph-dashboardceph mgr module disable dashboardceph mgr module enable dashboard3.7 绑定开启dashboard模块的ceph-mgr节点的ip地址:ceph config set mgr mgr/dashboard/$name/server_addr $IPceph config set mgr mgr/dashboard/$name/server_port $PORTceph config set mgr mgr/dashboard/$name/ssl_server_port $PORT$IP地址为mgr节点的ip地址3.8 创建dashboard用户ceph dashboard ac-user-create <username> <password> administrator
​
3.8 web登录:浏览器地址栏输入:mgr地址:7000

4. 配置客户端使用 rbd

创建块设备之前需要创建存储池,存储池相关命令需要在mon节点执行。

4.1 创建存储池:$ sudo ceph osd pool create rbd 128 128
​
4.2 初始化存储池:$ sudo rbd pool init rbd
​
4.3 准备客户端client:另备一台主机,系统centos7用来作为client。主机名为client,ip:192.168.245.10。修改hosts文件实现和admin节点的主机名互通。
1)升级client内核到4.x,方法在子目录中
Centos7升级内核
更新前,内核版本为:#uname -r  3.10.0-327.10.1.el7.x86_64
​
升级方法
导入key:  #rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
​
安装elrepo的yum源:  #rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm
​
查看可用的系统内核包
yum --disablerepo="*" --enablerepo="elrepo-kernel" list available
​
安装内核:#yum --enablerepo=elrepo-kernel install  kernel-ml-devel kernel-ml
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
当前为4.4.4:
============================================================Package        架构                版本                       源                          大小
============================================================
正在安装:
kernel-ml   x86_64     4.4.4-1.el7.elrepo elrepo-kernel  38M
kernel-ml-devel x86_64 4.4.4-1.el7.elrepo elrepo-kernel  10M
​
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
​
​查看默认启动顺序  #awk -F\' '$1=="menuentry " {print $2}' /etc/grub2.cfg  CentOS Linux (4.4.4-1.el7.elrepo.x86_64) 7 (Core)  CentOS Linux (3.10.0-327.10.1.el7.x86_64) 7 (Core)  CentOS Linux (0-rescue-c52097a1078c403da03b8eddeac5080b) 7 (Core)
​默认启动的顺序是从0开始,新内核是从头插入(目前位置在0,而4.4.4的是在1),所以需要选择0。#grub2-set-default 0
​然后reboot重启,使用新的内核,下面是重启后使用的内核版本:#uname -r  4.4.4-1.el7.elrepo.x86_64  5、删除旧的内核  #yum remove kernel  2)为client安装ceph:1.参考2.3           在做2.3之前先在client上做1.3的三步2.还要做着一步 否则报错  #yum  -y install python-setuptools
​
3)配置client防火墙(直接关闭):
$ sudo firewall-cmd --zone=public --add-service=ceph --permanent
$ sudo firewall-cmd --reload
​
4)在admin节点赋予client使用命令免用户名权限:$ ceph-deploy admin client
​
5)修改client下该文件的读权限:$ sudo chmod +r /etc/ceph/ceph.client.admin.keyring
​
6)修改client下的ceph配置文件:这一步是为了解决映射镜像时出错问题$ sudo vi /etc/ceph/ceph.conf   在global section下添加:rbd_default_features = 1
​
4.4 client节点创建块设备镜像:单位是M,这里是4个G$ rbd create foo --size 4096
​
4.5 client节点映射镜像到主机:$ sudo rbd map foo --name client.admin
​
4.6 client节点格式化块设备:$ sudo mkfs.ext4 -m 0 /dev/rbd/rbd/foo
​
4.7 client节点mount块设备:$ sudo mkdir /mnt/ceph-block-device$ sudo mount /dev/rbd/rbd/foo /mnt/ceph-block-device$ +

客户端重起之后,设备需要重新作映射,不然可能会卡死。

5、ceph安装问题集锦

问题一:

[cephu@centos7u3_1 my-cluster]$ ceph-deploy new node1
Traceback (most recent call last):File "/bin/ceph-deploy", line 18, in <module>from ceph_deploy.cli import mainFile "/usr/lib/python2.7/site-packages/ceph_deploy/cli.py", line 1, in <module>import pkg_resources
ImportError: No module named pkg_resources

重新安装python的distribution:

下载 distribution : https://pypi.python.org/pypi/distribute
cd distribution-0.7.3/
sudo python setup.py install
​
distribution下载地址:
https://files.pythonhosted.org/packages/5f/ad/1fde06877a8d7d5c9b60eff7de2d452f639916ae1d48f0b8f97bf97e570a/distribute-0.7.3.zip

​问题二:

[ERROR ] admin_socket: exception getting command descriptions: [Errno 2] No such file or dir
cat /etc/ceph/ceph.conf
添加
public_network= 192.168.122.0/24
推送
ceph-deploy --overwrite-conf config push admin node1 node2 node3

问题三:

ceph-deploy mon create-initial
```
[node1][INFO  ] Running command: sudo ceph --cluster=ceph --admin-daemon /var/run/ceph/ceph-mon.node1.asok mon_status
[node1][ERROR ] no valid command found; 10 closest matches:
[node1][ERROR ] perf reset <var>
[node1][ERROR ] perf histogram schema
[node1][ERROR ] log reopen
[node1][ERROR ] log flush
[node1][ERROR ] perf histogram dump {<logger>} {<counter>}
[node1][ERROR ] perf dump {<logger>} {<counter>}
[node1][ERROR ] git_version
[node1][ERROR ] get_command_descriptions
[node1][ERROR ] log dump
[node1][ERROR ] help
[node1][ERROR ] admin_socket: invalid command
[node1][WARNIN] monitor: mon.node1, might not be running yet
[node1][INFO  ] Running command: sudo ceph --cluster=ceph --admin-daemon /var/run/ceph/ceph-mon.node1.asok mon_status
[node1][ERROR ] no valid command found; 10 closest matches:
[node1][ERROR ] perf reset <var>
[node1][ERROR ] perf histogram schema
[node1][ERROR ] log reopen
[node1][ERROR ] log flush
[node1][ERROR ] perf histogram dump {<logger>} {<counter>}
[node1][ERROR ] perf dump {<logger>} {<counter>}
[node1][ERROR ] git_version
[node1][ERROR ] get_command_descriptions
[node1][ERROR ] log dump
[node1][ERROR ] help
[node1][ERROR ] admin_socket: invalid command
[node1][WARNIN] monitor node1 does not exist in monmap
```

​原因: 第一次在做的时候没有修改主机名是就生成了公私钥,结果拷贝的公钥有问题,在问题二推送配置的时候,排查后发现主机名的问题。之后初始化mon的时候出错,排错两个小时,差点怀疑人生的时候突然发现,想起主机名的事情,就检查了以下公私钥,结果发现生成的公私钥是以原主机名生成的,删除后生成新的公私钥,传送公钥后,还是失败。

但是感觉已经找到了问题所在,继续排查,到node1查看日志发现,地址被占用,平复以下自己激动的心,然后冷静的杀掉进程,重新初始化OK

​问题四:

ceph-deploy osd create --data /dev/vdc node3
[node1][WARNIN] ceph-volume lvm create: error: GPT headers found, they must be removed on: /dev/vdb
[node1][ERROR ] RuntimeError: command returned non-zero exit status: 2
[ceph_deploy.osd][ERROR ] Failed to execute command: /usr/sbin/ceph-volume --cluster ceph lvm create --bluestore --data /dev/vdb
[ceph_deploy][ERROR ] GenericError: Failed to create 1 OSDs

​千万不要分区,然后重新加磁盘,重新做。

文档说加上参数也不行:

ceph-deploy osd create --data /dev/vdc  --fs-type xfs node3

​问题五:

rdb map出错rbd sysfs write failed。

创建了一个rbd镜像$ rbd create --size 4096 docker_test
然后,在Ceph client端将该rbd镜像映射为本地设备时出错。$ rbd map docker_test --name client.admin
​rbd: sysfs write failedRBD image feature set mismatch. You can disable features unsupported by the kernel with "rbd feature disable".In some cases useful info is found in syslog - try "dmesg | tail" or so.

原因:

rbd镜像的一些特性,OS kernel并不支持,所以映射失败。我们查看下该镜像支持了哪些特性。
$ rbd info docker_test
rbd image 'docker_test':
size 4096 MB in 1024 objects
order 22 (4096 kB objects)
block_name_prefix: rbd_data.43702ae8944a
format: 2
features: layering, exclusive-lock, object-map, fast-diff, deep-flatten
flags:
可以看到特性feature一栏,由于我OS的kernel只支持layering,其他都不支持,所以需要把部分不支持的特性disable掉。

方法一: 直接diable这个rbd镜像的不支持的特性:

$ rbd feature disable docker_test exclusive-lock object-map fast-diff deep-flatten

方法二: 创建rbd镜像时就指明需要的特性,如:

$ rbd create --size 4096 docker_test --image-feature layering

方法三: 如果还想一劳永逸,那么就在执行创建rbd镜像命令的服务器中:

修改Ceph配置文件/etc/ceph/ceph.conf,
在global section下,增加rbd_default_features = 1
再创建rdb镜像。$ rbd create --size 4096 docker_test

通过上述三种方法后,查看rbd镜像的信息:

    $ rbd info docker_test
​rbd image 'docker_test':size 4096 MB in 1024 objectsorder 22 (4096 kB objects)block_name_prefix: rbd_data.43a22ae8944aformat: 2features: layeringflags:
​
再次尝试映射rdb镜像到本地块设备,成功!$ rbd map docker_test --name client.admin  /dev/rbd0

问题六:

[cephu@client ~]$ sudo  rbd map docker_test --name client.admin
​
​
rbd: sysfs write failed
In some cases useful info is found in syslog - try "dmesg | tail".
rbd: map failed: (110) Connection timed out

解决方案:

[cephu@client ~]$ sudo ceph osd crush tunables hammer
adjusted tunables profile to hammer
​
然后重新
[cephu@client ~]$ sudo  rbd map docker_test --name client.admin
/dev/rbd0
​
成功

问题七:

Error: Package: 2:librbd1-12.2.12-0.el7.x86_64 (Ceph)            Requires: liblttng-ust.so.0()(64bit)

方法1:

sudo yum install -y yum-utils && sudo yum-config-manager --add-repo https://dl.fedoraproject.org/pub/epel/7/x86_64/ &&sudo  yum install --nogpgcheck -y epel-release &&sudo  rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7 &&sudo  rm -f /etc/yum.repos.d/dl.fedoraproject.org*

方法二:

yum install epel-release   -y
wget https://dl.fedoraproject.org/pub/epel/7/x86_64/Packages/e/epel-release-7-12.noarch.rpm
rpm -Uvh epel-release*rpm
yum install lttng-ust -y
​

问题八:

ceph:health_warn clock skew detected on mon

造成集群状态health_warn:clock skew detected on mon节点的原因有两个,一个是mon节点上ntp服务器未启动,另一个是ceph设置的mon的时间偏差阈值比较小。

排查时也应遵循先第一个原因,后第二个原因的方式。

第一步:确认ntp服务是否正常工作
​
第二步:修改ceph配置中的时间偏差阈值
1. 在admin部署节点修改配置参数:
# vi ~/my-cluster/ceph.conf在global字段下添加:
mon clock drift allowed = 2
mon clock drift warn backoff = 30
​
2. 向需要同步的mon节点推送配置文件:
# ceph-deploy --overwrite-conf config push node{1..3}这里是向node1 node2 node3推送,也可以后跟其它不联系节点3. 重启mon服务(centos7环境下)
# systemctl restart ceph-mon.target4.验证:
# ceph -s显示health_ok说明问题解决

问题九:

有些场景下,对osd进行一些操作,但是并不想要集群进行数据恢复,此时,可以通过设置noout标志来实现:

[root@node3 ~]# ceph osd set noout
noout is set
[root@node3 ~]# ceph -scluster:id:     b8b4aa68-d825-43e9-a60a-781c92fec20ehealth: HEALTH_WARNnoout flag(s) setservices:mon: 1 daemons, quorum node1mgr: node1(active)osd: 6 osds: 6 up, 6 inflags nooutdata:pools:   0 pools, 0 pgsobjects: 0 objects, 0 bytesusage:   6339 MB used, 55100 MB / 61440 MB availpgs:     去除noout标志命令:[root@node3 ~]# ceph osd unset noout
noout is unset
[root@node3 ~]# ceph -scluster:id:     b8b4aa68-d825-43e9-a60a-781c92fec20ehealth: HEALTH_OKservices:mon: 1 daemons, quorum node1mgr: node1(active)osd: 6 osds: 6 up, 6 indata:pools:   0 pools, 0 pgsobjects: 0 objects, 0 bytesusage:   6339 MB used, 55100 MB / 61440 MB availpgs:     

6、RBD操作

环境:

IP地址 主机名
192.168.118.14 ceph-node1
192.168.118.15 ceph-node2
192.168.118.16 ceph-node3
192.168.118.17 ceph-client

注意:所有节点更新为最新内核版本!

1. 创建 RBD

① 服务器端操作

创建 pool:

[root@ceph-node1 ~/mycluster]#ceph osd pool create rbd 64
pool 'rbd' created

创建客户端帐号:

# 创建客户端用户
[root@ceph-node1 ~/mycluster]#ceph auth get-or-create client.rbd mon 'allow r' osd 'allow class-read object_prefix rbd_children,allow rwx pool=rbd'# 查看用户及权限
[root@ceph-node1 ~/mycluster]#ceph auth get client.rbd
exported keyring for client.rbd
[client.rbd]key = AQB6OAhfMN4jFhAAPmO17m5Z5gP5YC11JOJcTA==caps mon = "allow r"caps osd = "allow class-read object_prefix rbd_children,allow rwx pool=rbd"# 导出客户端keyring
[root@ceph-node1 ~/mycluster]#ceph auth get client.rbd -o ./ceph.client.rbd.keyring
exported keyring for client.rbd

pool 启动 RBD:

[root@ceph-node1 ~/mycluster]#ceph osd pool application enable rbd rbd
enabled application 'rbd' on pool 'rbd'

② 客户端操作

安装 ceph-common:

[root@ceph-client ~]#yum install ceph-common -y

从 ceph-node1 拷贝 ceph.conf 和 认证 keyring:

[root@ceph-node1 ~/mycluster]#scp ceph.conf  ceph.client.rbd.keyring ceph-client:/etc/ceph/
[root@ceph-client ~]#ls /etc/ceph/
ceph.client.rbd.keyring  ceph.conf  rbdmap# 使用 创建的用户 rbd 查看集群状态
[root@ceph-client ~]#ceph -s --user rbdcluster:id:     45757634-b5ec-4172-957d-80c5c9f76d52health: HEALTH_OKservices:mon: 3 daemons, quorum ceph-node1,ceph-node2,ceph-node3 (age 65m)mgr: no daemons activeosd: 0 osds: 0 up, 0 indata:pools:   0 pools, 0 pgsobjects: 0 objects, 0 Busage:   0 B used, 0 B / 0 B availpgs:

创建 image:

# 创建 image
[root@ceph-client ~]#rbd create rbd1 -p rbd --size 1G --user rbd
[root@ceph-client ~]#rbd create rbd/rbd2 --size 2G --user rbd# 查看创建的 image
[root@ceph-client ~]#rbd ls -l --user rbd
NAME SIZE  PARENT FMT PROT LOCK
rbd1 1 GiB          2
rbd2 2 GiB          2# 通过json格式查看
[root@ceph-client ~]#rbd ls -p rbd -l --format json --user rbd --pretty-format
[{"image": "rbd1","size": 1073741824,"format": 2},{"image": "rbd2","size": 2147483648,"format": 2}
]# 显示 image 的详细信息
[root@ceph-client ~]#rbd info rbd1 --user rbd
rbd image 'rbd1':size 1 GiB in 256 objectsorder 22 (4 MiB objects)snapshot_count: 0id: 112fe2290ad6block_name_prefix: rbd_data.112fe2290ad6format: 2features: layering, exclusive-lock, object-map, fast-diff, deep-flattenop_features:flags:create_timestamp: Sat Jul 11 09:14:18 2020access_timestamp: Sat Jul 11 09:14:18 2020modify_timestamp: Sat Jul 11 09:14:18 2020

禁止 image 的特性,默认 image 的特性包括:

features: layering, exclusive-lock, object-map, fast-diff, deep-flatten

作为rbd一般只需要 layering ,需要把其他的特性全部禁止掉:

# 禁止 image 特性
[root@ceph-client ~]#rbd feature disable rbd/rbd1 exclusive-lock, object-map, fast-diff, deep-flatten --user rbd
[root@ceph-client ~]#rbd feature disable rbd/rbd2 exclusive-lock, object-map, fast-diff, deep-flatten --user rbd# 查看详细信息
[root@ceph-client ~]#rbd info rbd/rbd1 --user rbd
rbd image 'rbd1':size 1 GiB in 256 objectsorder 22 (4 MiB objects)snapshot_count: 0id: 112fe2290ad6block_name_prefix: rbd_data.112fe2290ad6format: 2features: layeringop_features:flags:create_timestamp: Sat Jul 11 09:14:18 2020access_timestamp: Sat Jul 11 09:14:18 2020modify_timestamp: Sat Jul 11 09:14:18 2020
[root@ceph-client ~]#rbd info rbd/rbd2 --user rbd
rbd image 'rbd2':size 2 GiB in 512 objectsorder 22 (4 MiB objects)snapshot_count: 0id: 11342244e27fblock_name_prefix: rbd_data.11342244e27fformat: 2features: layeringop_features:flags:create_timestamp: Sat Jul 11 09:14:47 2020access_timestamp: Sat Jul 11 09:14:47 2020modify_timestamp: Sat Jul 11 09:14:47 2020

客户端挂载 Image:

[root@ceph-client ~]#lsblk
NAME            MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sr0              11:0    1  4.4G  0 rom  /mnt/centos7
vda             252:0    0  100G  0 disk
├─vda1          252:1    0    1G  0 part /boot
└─vda2          252:2    0   99G  0 part├─centos-root 253:0    0   50G  0 lvm  /├─centos-swap 253:1    0  7.9G  0 lvm  [SWAP]└─centos-home 253:2    0 41.1G  0 lvm  /home
[root@ceph-client ~]#rbd ls -l --user rbd
NAME SIZE  PARENT FMT PROT LOCK
rbd1 1 GiB          2
rbd2 2 GiB          2# RBD 映射到客户端主机
[root@ceph-client ~]#rbd map rbd/rbd1 --user rbd
/dev/rbd0
[root@ceph-client ~]#lsblk
NAME            MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sr0              11:0    1  4.4G  0 rom  /mnt/centos7
vda             252:0    0  100G  0 disk
├─vda1          252:1    0    1G  0 part /boot
└─vda2          252:2    0   99G  0 part├─centos-root 253:0    0   50G  0 lvm  /├─centos-swap 253:1    0  7.9G  0 lvm  [SWAP]└─centos-home 253:2    0 41.1G  0 lvm  /home
rbd0            251:0    0    1G  0 disk

初始化文件系统:

# 格式化磁盘
[root@ceph-client ~]#mkfs.xfs /dev/rbd0
meta-data=/dev/rbd0              isize=512    agcount=8, agsize=32768 blks=                       sectsz=512   attr=2, projid32bit=1=                       crc=1        finobt=0, sparse=0
data     =                       bsize=4096   blocks=262144, imaxpct=25=                       sunit=1024   swidth=1024 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
log      =internal log           bsize=4096   blocks=2560, version=2=                       sectsz=512   sunit=8 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
[root@ceph-client ~]#mkdir -pv /mnt/ceph-disk1
mkdir: created directory ‘/mnt/ceph-disk1’# 挂载文件系统
[root@ceph-client ~]#mount /dev/rbd0 /mnt/ceph-disk1/
[root@ceph-client ~]#df -Th
Filesystem              Type      Size  Used Avail Use% Mounted on
devtmpfs                devtmpfs  3.9G     0  3.9G   0% /dev
tmpfs                   tmpfs     3.9G     0  3.9G   0% /dev/shm
tmpfs                   tmpfs     3.9G  8.6M  3.9G   1% /run
tmpfs                   tmpfs     3.9G     0  3.9G   0% /sys/fs/cgroup
/dev/mapper/centos-root xfs        50G  1.9G   49G   4% /
/dev/vda1               xfs      1014M  149M  866M  15% /boot
/dev/mapper/centos-home xfs        42G   33M   42G   1% /home
/dev/sr0                iso9660   4.4G  4.4G     0 100% /mnt/centos7
tmpfs                   tmpfs     783M     0  783M   0% /run/user/0
/dev/rbd0               xfs      1014M   33M  982M   4% /mnt/ceph-disk1

客户端卸载磁盘:

[root@ceph-client ~]#umount /dev/rbd0# 查看本地 image 映射
[root@ceph-client ~]#rbd showmapped --user rbd
id pool namespace image snap device
0  rbd            rbd1  -    /dev/rbd0# 卸载 image
[root@ceph-client ~]#rbd unmap rbd/rbd1 --user rbd
[root@ceph-client ~]#lsblk
NAME            MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sr0              11:0    1  4.4G  0 rom  /mnt/centos7
vda             252:0    0  100G  0 disk
├─vda1          252:1    0    1G  0 part /boot
└─vda2          252:2    0   99G  0 part├─centos-root 253:0    0   50G  0 lvm  /├─centos-swap 253:1    0  7.9G  0 lvm  [SWAP]└─centos-home 253:2    0 41.1G  0 lvm  /home

扩展 image 大小:

[root@ceph-client ~]#rbd resize -s 5G rbd/rbd1 --user rbd
Resizing image: 100% complete...done.
[root@ceph-client ~]#rbd ls -l --user rbd
NAME SIZE  PARENT FMT PROT LOCK
rbd1 5 GiB          2
rbd2 2 GiB          2

删除 image:

[root@ceph-client ~]#rbd ls -l --user rbd
NAME SIZE  PARENT FMT PROT LOCK
rbd1 5 GiB          2
rbd2 2 GiB          2# 删除 rbd2
[root@ceph-client ~]#rbd rm rbd2 --user rbd
Removing image: 100% complete...done.
[root@ceph-client ~]#rbd ls -l --user rbd
NAME SIZE  PARENT FMT PROT LOCK
rbd1 5 GiB          2

image 放进回收站:

[root@ceph-client ~]#rbd ls -l --user rbd
NAME SIZE  PARENT FMT PROT LOCK
rbd1 5 GiB          2# 将 rbd1 放进回收站
[root@ceph-client ~]#rbd trash move rbd/rbd1 --user rbd
[root@ceph-client ~]#rbd ls -l --user rbd# 查看回收站
[root@ceph-client ~]#rbd trash list -p rbd --user rbd
112fe2290ad6 rbd1

回收站恢复 image:

[root@ceph-client ~]#rbd trash list -p rbd --user rbd
112fe2290ad6 rbd1# 恢复 rbd1
[root@ceph-client ~]#rbd trash restore -p rbd --image rbd1 --image-id 112fe2290ad6 --user rbd
[root@ceph-client ~]#rbd ls -l --user rbd
NAME SIZE  PARENT FMT PROT LOCK
rbd1 5 GiB          2

2. RBD 快照

快照前准备工作:

[root@ceph-client ~]#lsblk
NAME            MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sr0              11:0    1  4.4G  0 rom  /mnt/centos7
vda             252:0    0  100G  0 disk
├─vda1          252:1    0    1G  0 part /boot
└─vda2          252:2    0   99G  0 part├─centos-root 253:0    0   50G  0 lvm  /├─centos-swap 253:1    0  7.9G  0 lvm  [SWAP]└─centos-home 253:2    0 41.1G  0 lvm  /home
[root@ceph-client ~]#rbd map rbd/rbd1 --user rbd
/dev/rbd0
[root@ceph-client ~]#lsblk
NAME            MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sr0              11:0    1  4.4G  0 rom  /mnt/centos7
vda             252:0    0  100G  0 disk
├─vda1          252:1    0    1G  0 part /boot
└─vda2          252:2    0   99G  0 part├─centos-root 253:0    0   50G  0 lvm  /├─centos-swap 253:1    0  7.9G  0 lvm  [SWAP]└─centos-home 253:2    0 41.1G  0 lvm  /home
rbd0            251:0    0    5G  0 disk
[root@ceph-client ~]#mount /dev/rbd0 /mnt/ceph-disk1/
[root@ceph-client ~]#echo 'this test-1' >> /mnt/ceph-disk1/1.txt
[root@ceph-client ~]#echo 'this test-2' >> /mnt/ceph-disk1/2.txt
[root@ceph-client ~]#ls /mnt/ceph-disk1/
1.txt  2.txt

创建快照:

[root@ceph-client ~]#rbd snap create rbd/rbd1@snap1 --user rbd
[root@ceph-client ~]#rbd snap list rbd/rbd1 --user rbd
SNAPID NAME  SIZE  PROTECTED TIMESTAMP4 snap1 5 GiB           Sat Jul 11 09:41:19 2020

还原快照:

[root@ceph-client ~]#ls /mnt/ceph-disk1/
1.txt  2.txt# 为了检验快照恢复后数据正确性,这里删除 2.txt 文件
[root@ceph-client ~]#rm -rf /mnt/ceph-disk1/2.txt
[root@ceph-client ~]#ls /mnt/ceph-disk1/
1.txt# 卸载image
[root@ceph-client ~]#umount /dev/rbd0
[root@ceph-client ~]#rbd unmap rbd/rbd1 --user rbd
[root@ceph-client ~]#lsblk
NAME            MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sr0              11:0    1  4.4G  0 rom  /mnt/centos7
vda             252:0    0  100G  0 disk
├─vda1          252:1    0    1G  0 part /boot
└─vda2          252:2    0   99G  0 part├─centos-root 253:0    0   50G  0 lvm  /├─centos-swap 253:1    0  7.9G  0 lvm  [SWAP]└─centos-home 253:2    0 41.1G  0 lvm  /home
[root@ceph-client ~]#rbd snap list rbd/rbd1 --user rbd
SNAPID NAME  SIZE  PROTECTED TIMESTAMP4 snap1 5 GiB           Sat Jul 11 09:41:19 2020# 还原快照
[root@ceph-client ~]#rbd snap rollback rbd/rbd1@snap1 --user rbd
Rolling back to snapshot: 100% complete...done.# 映射image
[root@ceph-client ~]#rbd map rbd/rbd1 --user rbd
/dev/rbd0
[root@ceph-client ~]#lsblk
NAME            MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sr0              11:0    1  4.4G  0 rom  /mnt/centos7
vda             252:0    0  100G  0 disk
├─vda1          252:1    0    1G  0 part /boot
└─vda2          252:2    0   99G  0 part├─centos-root 253:0    0   50G  0 lvm  /├─centos-swap 253:1    0  7.9G  0 lvm  [SWAP]└─centos-home 253:2    0 41.1G  0 lvm  /home
rbd0            251:0    0    5G  0 disk
[root@ceph-client ~]#mount /dev/rbd0 /mnt/ceph-disk1/# 数据恢复到快照前
[root@ceph-client ~]#ls /mnt/ceph-disk1/
1.txt  2.txt

删除快照:

[root@ceph-client ~]#rbd snap list rbd/rbd1 --user rbd
SNAPID NAME  SIZE  PROTECTED TIMESTAMP4 snap1 5 GiB           Sat Jul 11 09:41:19 2020
[root@ceph-client ~]#rbd snap rm rbd/rbd1@snap1 --user rbd
Removing snap: 100% complete...done.
[root@ceph-client ~]#rbd snap list rbd/rbd1 --user rbd

快照次数限制:

[root@ceph-client ~]#rbd snap limit set rbd/rbd1 --limit 10 --user rbd

清除快照次数限制:

[root@ceph-client ~]#rbd snap limit clear rbd/rbd1 --user rbd

3. 克隆

这里主要做的是基于快照的克隆,克隆所采用的也是 cow,叫做 copy on write 也就是常说的 “写时复制”,更贴切的说法叫“写的时候,再复制”。这里的克隆就是基于快照创建的克隆只创建了映射到源的逻辑,还没有给克隆分配真实的物理空间。这里要理解这一点。虽然快照是只读的,但是基于快照创建的克隆是可读可写的。当我们对克隆的镜像执行写操作的时候,系统才会真正的给克隆的镜像分配物理空间。克隆的镜像或者被写过的克隆镜像都是可以正常使用的和镜像本身是一样的。这就是所谓的 cow。当对克隆的镜像没有写而是读的时候,那么读取的是被克隆的快照,明白了上面的道理所有我们知道从快照克隆的镜像是依赖于快照的,一旦快照被删除则这个克隆镜像也就毁了,所以我们要保护这个快照。

创建克隆:

# 创建克隆前,第一步要保护快照,以下错误提示要求先执行保护快照
[root@ceph-client ~]#rbd clone rbd/rbd1@snap1 rbd/rbd1-snap1-clone --user rbd
2020-07-11 10:05:48.783 7fb34f7fe700 -1 librbd::image::CloneRequest: 0x5647acbcf850 validate_parent: parent snapshot must be protected
rbd: clone error: (22) Invalid argument# 执行保护快照
[root@ceph-client ~]#rbd snap protect rbd/rbd1@snap1  --user rbd
[root@ceph-client ~]#rbd snap list rbd/rbd1 --user rbd
SNAPID NAME  SIZE  PROTECTED TIMESTAMP8 snap1 5 GiB yes       Sat Jul 11 10:04:34 2020# 创建克隆
[root@ceph-client ~]#rbd clone rbd/rbd1@snap1 rbd/rbd1-snap1-clone --user rbd# 查看克隆
[root@ceph-client ~]#rbd ls -l --user rbd
NAME             SIZE  PARENT         FMT PROT LOCK
rbd1             5 GiB                  2
rbd1@snap1       5 GiB                  2 yes
rbd1-snap1-clone 5 GiB rbd/rbd1@snap1   2# 查看克隆的详细信息
[root@ceph-client ~]#rbd info rbd1-snap1-clone --user rbd
rbd image 'rbd1-snap1-clone':size 5 GiB in 1280 objectsorder 22 (4 MiB objects)snapshot_count: 0id: 12613ea38941block_name_prefix: rbd_data.12613ea38941format: 2features: layeringop_features:flags:create_timestamp: Sat Jul 11 10:07:20 2020access_timestamp: Sat Jul 11 10:07:20 2020modify_timestamp: Sat Jul 11 10:07:20 2020parent: rbd/rbd1@snap1overlap: 5 GiB

克隆成功的镜像是依赖于快照的,能看到 parent 和 overlap。

比如想要 克隆独立存在,不依赖于快照,就需要对克隆和快照做一个合并:

# 对克隆进行合并
[root@ceph-client ~]#rbd flatten rbd/rbd1-snap1-clone --user rbd
Image flatten: 100% complete...done.# 查看克隆是否独立存在,没有了 parent 和 overlap
[root@ceph-client ~]#rbd info rbd1-snap1-clone --user rbd
rbd image 'rbd1-snap1-clone':size 5 GiB in 1280 objectsorder 22 (4 MiB objects)snapshot_count: 0id: 12613ea38941block_name_prefix: rbd_data.12613ea38941format: 2features: layeringop_features:flags:create_timestamp: Sat Jul 11 10:07:20 2020access_timestamp: Sat Jul 11 10:07:20 2020modify_timestamp: Sat Jul 11 10:07:20 2020

如果快照不在时候用这里就可以直接删除快照:

注意:这里删除快照需要先解除保护模式。

[root@ceph-client ~]#rbd info rbd/rbd1@snap1 --user rbd
rbd image 'rbd1':size 5 GiB in 1280 objectsorder 22 (4 MiB objects)snapshot_count: 1id: 112fe2290ad6block_name_prefix: rbd_data.112fe2290ad6format: 2features: layeringop_features:flags:create_timestamp: Sat Jul 11 09:14:18 2020access_timestamp: Sat Jul 11 13:44:17 2020modify_timestamp: Sat Jul 11 09:14:18 2020protected: True# 解除对快照的保护
[root@ceph-client ~]#rbd snap unprotect rbd/rbd1@snap1 --user rbd
[root@ceph-client ~]#rbd info rbd/rbd1@snap1 --user rbd
rbd image 'rbd1':size 5 GiB in 1280 objectsorder 22 (4 MiB objects)snapshot_count: 1id: 112fe2290ad6block_name_prefix: rbd_data.112fe2290ad6format: 2features: layeringop_features:flags:create_timestamp: Sat Jul 11 09:14:18 2020access_timestamp: Sat Jul 11 13:44:17 2020modify_timestamp: Sat Jul 11 09:14:18 2020protected: False[root@ceph-client ~]#rbd ls -l --user rbd
NAME             SIZE  PARENT FMT PROT LOCK
rbd1             5 GiB          2
rbd1@snap1       5 GiB          2
rbd1-snap1-clone 5 GiB          2# 删除快照
[root@ceph-client ~]#rbd snap rm rbd/rbd1@snap1 --user rbd
Removing snap: 100% complete...done.
[root@ceph-client ~]#rbd ls -l --user rbd
NAME             SIZE  PARENT FMT PROT LOCK
rbd1             5 GiB          2
rbd1-snap1-clone 5 GiB          2

五、Ceph RBD块存储

1、块存储

块设备可理解成一块硬盘,用户可以直接使用不含文件系统的块设备(裸设备),也可以将其格式化成特定的文件系统,由文件系统来组织管理存储空间,从而为用户提供丰富而友好的数据操作支持。

块存储将信息存储在固定大小的块中,每个块都有自己的地址,可以在块设备的任意位置读取一定长度的数据。以sd开头的块设备文件对应的是scsi接口的硬盘;以hd开头的块设备文件对应的是IDE接口的硬盘。当系统检测到多个scsi硬盘时,会根据检测到的顺序对硬盘设备将那些字母顺序的命名。

注:系统按检测顺序命名硬盘会导致盘符漂移的问题。

块存储接口通常以 QEMU Driver 或者 Kernel Module 的方式存在,这种接口需要实现 Linux 的 Block Device 的接口或者 QEMU 提供的 Block Driver 接口,如 Sheepdog,AWS 的 EBS,青云的云硬盘和阿里云的盘古系统,还有 Ceph 的 RBD(RBD是Ceph面向块存储的接口)。

在常见的存储中 DAS、SAN 提供的也是块存储、openstack的cinder存储、iscsi的存储。

2、RBD块存储

rbd是由Ceph集群提供出来的块设备,可以直接作为磁盘挂载,内置了容灾机制。

sda和hda都是通过数据线连接到真实的硬盘,而rbd是通过网络连接到ceph集群中的一块存储区域,往rbd设备文件写入数据,最终会被保存到ceph集群的这块区域区域中。

rbd,有 kernel 和 librbd 两种使用方式,支持快照、克隆,相当于一块硬盘挂载到本地,用法和用途一样。

3、Ceph块存储实战

1. 创建和删除池

使用Ceph块存储前,先创建一个池。在创建池之后,对存储进行定义,并创建属于该池的块存储
设备。以下操作实现池的创建和删除。

1)查看池。

[root@installer ~]# ceph df
--- RAW STORAGE ---
CLASS SIZE AVAIL USED RAW USED %RAW USED
hdd 90 GiB 90 GiB 212 MiB 212 MiB 0.23
TOTAL 90 GiB 90 GiB 212 MiB 212 MiB 0.23
--- POOLS ---
POOL ID PGS STORED OBJECTS USED %USED MAX AVAIL
device_health_metrics 1 32 0 B 0 0 B
cephfs_data 2 32 0 B 0 0 B
cephfs_metadata 3 128 9.2 KiB 22 112 KiB
.rgw.root 4 32 1.3 KiB 4 48 KiB
default.rgw.log 5 32 23 KiB 335 1.9 MiB
default.rgw.control 6 32 0 B 8 0 B
default.rgw.meta 7 128 1.1 KiB 7 72 KiB
default.rgw.buckets.index 8 32 11 KiB 11 34 KiB
default.rgw.buckets.data 9 32 427 B 1 12 KiB

2)创建RDB池。

[root@installer ~]# ceph osd pool create rbd 24
Error ERANGE: pg_num 24 size 3 would mean 1512 total pgs, which exceeds
max 1500 (mon_max_pg_per_osd 250 * num_in_osds 6)
提示放置组数量超出了当前最大限制,增大每个OSD中最大放置组限制数
[root@installer ~]# ceph config set mon mon_max_pg_per_osd 500
[root@installer ~]# ceph osd pool create rbd 24
pool 'rbd' created
[root@installer ~]# ceph df
--- RAW STORAGE ---
CLASS SIZE AVAIL USED RAW USED %RAW USED
hdd 90 GiB 90 GiB 221 MiB 221 MiB 0.24
TOTAL 90 GiB 90 GiB 221 MiB 221 MiB 0.24
--- POOLS ---
POOL ID PGS STORED OBJECTS USED %USED MAX AVAIL
device_health_metrics 1 32 0 B 0 0 B 0 28
cephfs_data 2 32 0 B 0 0 B 0 28
cephfs_metadata 3 128 9.2 KiB 22 112 KiB 0 28
.rgw.root 4 32 1.3 KiB 4 48 KiB 0 28 d
efault.rgw.log 5 32 23 KiB 335 1.9 MiB 0 28
efault.rgw.control 6 32 0 B 8 0 B 0 28
default.rgw.meta 7 128 1.1 KiB 7 72 KiB 0 28
default.rgw.buckets.index 8 32 11 KiB 11 34 KiB 0 28
default.rgw.buckets.data 9 32 427 B 1 12 KiB 0 28
rbd 11 24 0 B 0 0 B 0

3)要删除池必须设置--mon-allow-pooldelete=true参数,否则指定的池无法删除。因为这
是不可逆操作,所有执行命令时一定要非常清楚自己的目的,否则会产生严重后果。

[root@installer ~]# ceph tell mon.\* injectargs '--mon-allow-pool-delete=mon.mon1: mon_allow_pool_delete = 'true'
mon.mon1: {}
mon.mon2: mon_allow_pool_delete = 'true'
mon.mon2: {}
mon.mon3: mon_allow_pool_delete = 'true'
mon.mon3: {}
[root@installer ~]# ceph config show mon.mon2|grep allow
mon_allow_pool_delete true
[root@installer ~]# ceph osd pool delete rbd rbd --yes-i-really-really-mean-
pool 'rbd' removed

4)直接写文件到池。

[root@installer ~]# dd if=/dev/zero of=./testfile2 bs=5M count=8
8+0 records in
8+0 records out
41943040 bytes (42 MB) copied, 0.0303137 s, 1.4 GB/s
[root@installer ~]# rados -p rbd put testfile2 /root/testfile2
[root@installer ~]# rados -p rbd ls
rbd_data.380ffb8c8c9d.000000000000000d
rbd_header.380ffb8c8c9d
rbd_data.380ffb8c8c9d.0000000000000020
rbd_data.380ffb8c8c9d.0000000000000030
testfile2

2. RBD设备的配置及使用

创建完池后,你可以在其中创建RBD设备。RBD设备的大小可以指定。

1)在RBD池中创建256MB的RBD设备。

[root@installer ~]# rbd create rbd/image1 --size=256M
[root@installer ~]# rbd info rbd/image1
rbd image 'image1':
size 256 MiB in 64 objects
order 22 (4 MiB objects)
snapshot_count: 0
id: 380ffb8c8c9d
block_name_prefix: rbd_data.380ffb8c8c9d
format: 2
features: layering, exclusive-lock, object-map, fast-diff, deep-op_features:
flags:
create_timestamp: Sat Mar 20 23:49:55 2021
access_timestamp: Sat Mar 20 23:49:55 2021
modify_timestamp: Sat Mar 20 23:49:55 2021

2)映射RBD设备。

块设备创建完毕后保存在Ceph的池中。如果你要使用,需要在想要挂载的块设备的客户端执行映
射操作。客户端也要安装必要的Ceph客户端组件ceph-common。本例以Installer为客户端,客户端相关组件在安装Ceph集群时已经默认安装完毕,无须重复安装。如果在生产环境下指定的客户端上没有相关客户端组件,请使用图形界面或者命令行在客户端节点安装客户端组件,之后才能与RBD设备映射。

[root@installer ~]# rbd map rbd/image1
rbd: sysfs write failed
RBD image feature set mismatch. You can disable features unsupported by kernel with "rbd feature disable image1 object-map fast-diff deep-flatten".
In some cases useful info is found in syslog - try "dmesg | tail".
rbd: map failed: (6) No such device or address

3)如果提示错误,查看dmesg输出,修改RBD特征。

[root@installer ~]# dmesg |tail
[42091.375093] libceph: client14381 fsid f99134e9-c5fb-4917-b7e5-372ab4d6a8f0
[42091.385092] rbd: image image1: image uses unsupported features: 0x38
[root@installer ~]# rbd feature disable image1 object-map fast-diff deep

4)查看映射后的块设备/dev/rbd0。

[root@installer ~]# rbd map rbd/image1
/dev/rbd0
[root@installer ~]# rbd showmapped
id pool namespace image snap device
0 rbd image1 - /dev/rbd0

5)格式化并挂载文件系统。

[root@installer ~]# mkfs.xfs /dev/rbd0
Discarding blocks...Done.
meta-data=/dev/rbd0 isize=512 agcount=8, agsize=8192 blks= sectsz=512
realtime=none extsz=4096 blocks=0, rtextents=0
[root@installer ~]# mount /dev/rbd0 /mnt
[root@installer ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/rbd0 254M 14M 241M 6% /mnt

6)写文件测试。

[root@installer ~]# dd if=/dev/zero of=/mnt/testfile bs=5M count=6
6+0 records in
6+0 records out
31457280 bytes (31 MB) copied, 0.0156438 s, 2.0 GB/s
[root@installer ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/rbd0 254M 44M 211M 18% /mnt
[root@installer ~]# ls -l /mnt
total 30720
-rw-r--r--. 1 root root 31457280 Mar 20 23:55 testfile
[root@installer ~]# rbd du rbd/image1
warning: fast-diff map is not enabled for image1. operation may be slow.
NAME PROVISIONED USED
image1 256 MiB 68 MiB
[root@installer ~]# ceph df
--- RAW STORAGE ---
CLASS SIZE AVAIL USED RAW USED %RAW USED
hdd 90 GiB 89 GiB 678 MiB 678 MiB 0.74
TOTAL 90 GiB 89 GiB 678 MiB 678 MiB 0.74
--- POOLS ---
POOL ID PGS STORED OBJECTS USED %USED MAX AVAIL
device_health_metrics 1 32 0 B 0 0 B 0 28
cephfs_data 2 32 0 B 0 0 B 0 28
cephfs_metadata 3 128 9.2 KiB 22 112 KiB 0 28
.rgw.root 4 32 1.3 KiB 4 48 KiB 0 28
default.rgw.log 5 32 23 KiB 335 1.9 MiB 0 28
default.rgw.control 6 32 0 B 8 0 B 0 28
default.rgw.meta 7 128 1.1 KiB 7 72 KiB 0 28
default.rgw.buckets.index 8 32 11 KiB 11 34 KiB 0 28
default.rgw.buckets.data 9 32 427 B 1 12 KiB 0 28
rbd 11 24 73 MiB 22 219 MiB 0

3. RBD快照

Ceph为RBD设备提供了快照功能,以保证回放RBD状态。

1)创建名为snap_1的RBD快照。

[root@installer ~]# rbd snap create rbd/image1@snap_1
[root@installer ~]# rbd snap ls rbd/image1
SNAPID NAME SIZE PROTECTED TIMESTAMP
4 snap_1 256 MiB Mon Mar 22 16:23:47 2021

2)映射快照设备。

[root@installer ~]# rbd map rbd/image1@snap_1
/dev/rbd1
[root@installer ~]# rbd showmapped
id pool namespace image snap device
0 rbd image1 - /dev/rbd0
1 rbd image1 snap_1 /dev/rbd1

3)设置快照是只读设备。

[root@installer ~]# blockdev --getro /dev/rbd0
0 [
root@installer ~]# blockdev --getro /
dev/rbd1
1

快照设备与原始设备使用相同的UUID,如果需要同时挂载/dev/rbd0与/dev/rbd1,使用nouuid选
项。

[root@installer ~]# mkdir /snap
[root@installer ~]# mount /dev/rbd1 /snap
mount: /dev/rbd1 is write-protected, mounting read-only
mount: wrong fs type, bad option, bad superblock on /dev/rbd1,
missing codepage or helper program, or other error
In some cases useful info is found in syslog - try
dmesg | tail or so.
[root@installer ~]# dmesg |tail
[190507.270887] XFS (rbd1): Filesystem has duplicate UUID 22c53fb4-d5dd-
42d3-9c07-90acb6784803 - can't mount
[root@installer ~]# mount -o nouuid /dev/rbd1 /snap
mount: /dev/rbd1 is write-protected, mounting read-only
[root@installer ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/rbd0 254M 54M 201M 21% /mnt
/dev/rbd1 254M 41M 214M 16% /snap

或者在挂载snap rbd1之前先挂载umount /dev/rbd0。

[root@installer ~]# umount /mnt
[root@installer ~]# ls /snap
testfile
[root@installer ~]# lsblk -f
NAME FSTYPE LABEL UUID MOUNTPOINT
rbd0 xfs 22c53fb4-d5dd-42d3-9c07-90acb6784803
rbd1 xfs 22c53fb4-d5dd-42d3-9c07-90acb6784803
[root@installer ~]# mount -o noatime /dev/rbd1 /snap
mount: /dev/rbd1 is write-protected, mounting read-only

4)使用快照还原RBD内容。

①删除/dev/rbd0设备中的文件。

[root@installer ~]# ls /mnt/
testfile2
[root@installer ~]# rm -f /mnt/testfile2
[root@installer ~]# umount /mnt

②还原删除的文件。

[root@installer ~]# rbd snap rollback rbd/image1@snap_1
Rolling back to snapshot: 0% complete...failed.
rbd: rollback failed: (30) Read-only file system

③取消映射,否则会报错。

[root@installer ~]# rbd unmap rbd/image1
[root@installer ~]# rbd snap rollback rbd/image1@snap_1
Rolling back to snapshot: 100% complete...done.
[root@installer ~]# rbd map rbd/image1
/dev/rbd0
[root@installer ~]# mount /dev/rbd0 /mnt
[root@installer ~]# ls -l /mnt
total 40960
-rw-r--r--. 1 root root 41943040 Mar 22 17:34 testfile2

5)删除快照。

5)删除快照。
[root@installer ~]# rbd snap purge rbd/image1
Removing all snapshots: 100% complete...done.

4. RBD Image克隆

RBD设备还提供了克隆功能。下面提供了RBD Image克隆的参考方法。

[root@installer ~]# rbd clone rbd/image1@snap_1 rbd/clone_1
2021-03-22 19:11:50.975 7fef3dffb700 -1 librbd::image::CloneRequest:
0x55b11a0b2260 validate_parent: parent snapshot must be protected
rbd: clone error: (22) Invalid argument
[root@installer ~]# rbd snap protect rbd/image1@snap_1
[root@installer ~]# rbd clone rbd/image1@snap_1 rbd/clone_1
[root@installer ~]# rbd map rbd/clone_1
/dev/rbd3
[root@installer ~]# rbd showmapped
id pool namespace image snap device
0 rbd image1 - /dev/rbd0
1 rbd image1 snap_1 /dev/rbd1
3 rbd clone_1 - /dev/rbd3
[root@installer ~]# mount -o nouuid /dev/rbd3 /clone/
[root@installer ~]# ls /clone/
testfile2
[root@installer ~]# rbd unmap /dev/rbd3
[root@installer ~]# rbd rm rbd/clone_1
Removing image: 100% complete...done.
[root@installer ~]# rbd snap unprotect rbd/image1@snap_1

5. RBD Image数据的导入/导出

RBD Image数据的导入/导出常用于RBD块设备的简单备份与恢复,请参考如下命令实现Image数
据的导入/导出。

[root@installer ~]# rbd export rbd/image1 rbd_image1.dat
[root@installer ~]# rbd import ./rbd_image1.dat rbd/image1
rbd: image creation failed2021-03-22 17:52:03.754 7f12d4670c80 -1 librbd:
rbd image image1 already exists
Importing image: 0% complete...failed.
rbd: import failed: (17) File exists
[root@installer ~]# rbd import ./rbd_image1.dat rbd/image_recovery
Importing image: 100% complete...done.
[root@installer ~]# rbd ls
image1
image1_snap1_dat
image_recovery
[root@installer ~]# rbd map rbd/image_recovery
rbd: sysfs write failed
RBD image feature set mismatch. You can disable features unsupported by kernel with "rbd feature disable image_recovery object-map fast-diff
deep-flatten".
In some cases useful info is found in syslog - try "dmesg | tail".
rbd: map failed: (6) No such device or address
[root@installer ~]# rbd feature disable image_recovery object-map fast-diff
deep-flatten
[root@installer ~]# rbd map rbd/image_recovery
/dev/rbd2
[root@installer ~]# mount /dev/rbd2 /mnt
[root@installer ~]# ls -l /mnt
total 40960
-rw-r--r--. 1 root root 41943040 Mar 22 17:34 testfile2

六、Ceph对象存储

1、对象存储

对象存储概念出现得晚,存储标准化组织SINA早在2004年就给出了定义,但早期多出现在超大规模系统,所以并不为大众所熟知,相关产品一直也不温不火。一直到云计算和大数据的概念全民强推,才慢慢进入公众视野。块存储和文件存储,基本上都还是在专有的局域网络内部使用,而对象存储的优势场景却是互联网或者公网,主要解决海量数据,海量并发访问的需求。基于互联网的应用才是对象存储的主要适配(当然这个条件同样适用于云计算,基于互联网的应用最容易迁移到云上,因为没出现云这个名词之前,他们已经在上面了),基本所有成熟的公有云都提供了对象存储产品,不管是国内还是国外。

典型设备∶内置大容量硬盘的分布式服务器

对象存储最常用的方案,就是多台服务者内置大容重硬盘,再装上对象存储软件,然后再搞几台作为管理节点,安装上对象存储管理软件。管理节点可以管理其他服务器对外提供读写访问功能。

之所以出现对象存储这种东西,是为了克服块存储与文件存储各自的缺点,发扬各自的优点。简单来说,块存储读写快,不利于共享,丈件存储读写慢,利于共享,能否弄个读写快且利于共享存储的,于是就有了对象存储。

而对象存储则将元数据独立出来了,控制节点叫元数据服务器(服务器+对象存储管理软件),里面主要负责存储对象的属性(主要是对象的数据被打散存放到了那几台分布式服务器中的信息)而其他负责存储数据的分布式服务器叫做OSD,主要负责存储文件的数据部分。当用户访问对象,会先访问元数据服务器,元数据服务器只负责对象存储在哪个OSD,假设文件A存在B、C、D三台OSD,那么用户就会再去直接访问3台OSD服务器去读取数据。

这时候由于是3台OSD同时对外传输数据,所以传输的速度就会加快了,当OSD服务器数量越多,这种读写速度的提升就越大,通过比种方式,实现了读写快的目的。

另一方面,对象存储软件是有专门的文件系统,所以OSD对外又相当于文件服务器,那么就不存在共享方面的困难了,也解决了文件共享方面的问题。所以对象存储的出现,很好的结合了块存储和文件存储的优点

为什么对象存储兼具块存储和文件存储的好处,还要使用块存储和文件存储呢?

(1) 有一类应用是需要存储直接裸盘映射的,例如数据库。因为数据需要存储蓄映射给自己后,再根据自己的数据库文件系统来对裸盘进行格式化的,所以是不能够采用其他已经被格式化为其种文件系统来存储的,此类应用更合适使用块存储。

(2)对象存储的成本比起普通的文件存储还要较高,需要购买专门的对象存储软件以及大容量硬盘,如果对数据量要求不是海量,只是为了做文件共享的时候,直接用文件存储就好了,性价比高。

对象存储也就是键值存储,通过其接口指令(GET、PUT、DEL、其他拓展指令),代表主要有 Swift 、S3 以及 Gluster 等。向存储服务上传下载数据等,对象存储中所有数据读背认为时一个对象,任何数据都可以存入对象存储服务器(如图片、视频、音频等)。

对象存储接口通常以 QEMU Driver 或者 Kernel Module 的方式存在,这种接口需要实现 Linux 的 Block Device 的接口或者 QEMU 提供的 Block Driver 接口,如 Swift 、S3 以及 Gluster、Sheepdog,AWS 的 EBS,青云的云硬盘和阿里云的盘古系统,还有 Ceph 的 RADOSGW。

2、Ceph RADOSGW

Ceph的对象存储通过RADOSGW来实现:

1)RADOSGW即Rados Gateway的全称;
2)RADOSGW是Ceph对象存储网关,用户向客户端应用程序提供存储界面,提供RESTful API 访问接口;
3)RADOSGW可以部署多台作为高可用和负载均衡;

RADOSGW提供RESTful接口,也提供多种编程语言绑定,兼容S3(是AWS里的对象存储)、Swift(是openstack里的对象存储)。

3、Ceph对象存储实战

在生产环境下,为了提高对象存储接口的访问性能,建议部署多个对象网关,并且对象网关节点
尽量不要和其他角色的节点复用。以下操作因服务器数量限制而采用了复用部署方式。

1. 部署对象网关

1)重新启动Cockpit Ceph Installer,添加rgwmds节点,充当RGW角色。

2)选择S3网络。

注意 S3网络使用公网作为集群对外访问的网络。

3)配置之后,执行安装。

4)安装完成后,通过仪表盘(Dashboard)可以看到已经有1个Object Gateways

5)通过Ceph客户端命令也可以看到当前已经部署好一个RGW节点。

[root@installer ~]# ceph -s
cluster:
id: f99134e9-c5fb-4917-b7e5-372ab4d6a8f0
health: HEALTH_OK
services:
mon: 3 daemons, quorum mon1,mon2,mon3 (age 3h)
mgr: mon2(active, since 2d), standbys: mon1, mon3
mds: cephfs:1 {0=rgw-mds=up:active}
osd: 6 osds: 6 up (since 2d), 6 in (since 2d)
rgw: 1 daemon active (rgw-mds.rgw0)
data:
pools: 7 pools, 416 pgs
objects: 339 objects, 28 KiB
usage: 228 MiB used, 90 GiB / 90 GiB avail
pgs: 416 active+clean

6)登录RGW节点,查看下载的镜像以及启动的容器。

[root@rgw-mds ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/ceph/daemon latest-master 14af70de1efb 2 weeks ago 1.14 docker.io/prom/node-exporter v0.17.0 b3e7f67a1480 2 years ago 21 MB
[root@rgw-mds ~]# docker ps
CONTAINER ID IMAGE
daf8393b6f0d docker.io/prom/node-exporter:v0.17.0
e690f7d59657 docker.io/ceph/daemon:latest-master
21ea58a9d47c docker.io/ceph/daemon:latest-master
COMMAND CREATED STATUS NAMES
"/bin/node_exporte..." About a minute ago Up node-exporter
"/opt/ceph-contain..." About a minute ago Up ceph-rgw-rgw-mds-rgw0
"/opt/ceph-contain..." 2 minutes ago Up ceph-mds

7)进入RGW节点中的容器,查看启动的服务。

[root@rgw-mds ~]# docker exec -it e690 /bin/sh
sh-4.4# ps -ewwf
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 20:21? 00:00:00 /bin/bash
/opt/ceph-container/bin/entrypoint.ceph 100 1 0 20:21 ? 00:00:33 /usr/bin/radosgw --cluster ceph --setuser ceph --setgroup ceph --default-log-to-stderr=true --err-tostderr=true --default-log-to-file=false --foreground -n client.rgw.rgwmds.rgw0 -k /var/lib/ceph/radosgw/ceph-rgw.rgw-mds.rgw0/keyring

8)在8080端口启动网关服务。

[root@rgw-mds ~]# ss -antlp
State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN
0 128 192.168.122.182:8080 *:* users:(("radosgw",pid=8422,fd=58))

9)在Ceph客户端检查网关服务的连通性。

[root@installer ~]# curl http://192.168.122.182:8080
<?xml version="1.0" encoding="UTF-8"?><ListAllMyBucketsResult xmlns="http://
s3.amazonaws.com/doc/2006-03-01/"><Owner><ID>anonymous</ID><DisplayName>
</DisplayName></Owner><Buckets></Buckets></ListAllMyBucketsResult>

2. 通过S3接口使用对象存储

Ceph对象存储接口兼容S3接口,因此对象存储接口和S3接口的使用方式完全相同。Ceph提供了专有命令来访问S3接口提供的存储,具体操作如下。

1)在installer机器上创建S3访问的Access Key 与Secret Key。

[root@installer ~]# radosgw-admin user create --uid='test' --display-name=
'Test User' --access-key='s3user' --secret-key='test1234'
{
"user_id": "test",
"display_name": "Test User",
"email": "",
"suspended": 0,
"max_buckets": 1000,
"subusers": [],
"keys": [
{
"user": "test",
"access_key": "s3user",
"secret_key": "test1234"
}
],
"swift_keys": [],
"caps": [],
"op_mask": "read, write, delete",
"default_placement": "",
"default_storage_class": "",
"placement_tags": [],
"bucket_quota": {
"enabled": false,
"check_on_raw": false,
"max_size": -1,
"max_size_kb": 0,
"max_objects": -1
},
"user_quota": {
"enabled": false,
"check_on_raw": false,
"max_size": -1,
"max_size_kb": 0,
"max_objects": -1
},
"temp_url_keys": [],
"type": "rgw",
"mfa_ids": []
}

2)查看运行对应的配置。

[root@installer ~]# radosgw-admin user info --uid='test'
{
"user_id": "test",
"display_name": "Test User",
"email": "",
"suspended": 0,
"max_buckets": 1000,
"subusers": [],
"keys": [
{
"user": "test",
"access_key": "s3user",
"secret_key": "test1234"
}
],
"swift_keys": [],
"caps": [],
"op_mask": "read, write, delete",
"default_placement": "",
"default_storage_class": "",
"placement_tags": [],
"bucket_quota": {
"enabled": false,
"check_on_raw": false,
"max_size": -1,
"max_size_kb": 0,
"max_objects": -1
},
"user_quota": {
"enabled": false,
"check_on_raw": false,
"max_size": -1,
"max_size_kb": 0,
"max_objects": -1
},
"temp_url_keys": [],
"type": "rgw",
"mfa_ids": []
}

访问S3对象存储的客户端工具有很多种,比较简单、通用的客户端工具为s3cmd,当然也有很多
图形界面的工具。本节以s3cmd作为客户端访问Ceph对象存储的工具。

3)下载并配置最新的s3cmd客户端工具。

注意 以下s3cmd的配置文件中的Access Key和Secret Key即刚刚创建用户时产生的两个
Key。S3 Endpoint为对象网关地址和端口号的组合。

# wget https://sourceforge.net/projects/s3tools/files/s3cmd/2.1.0/s3cmd-
2.1.0.tar.gz
# tar -xzvf s3cmd-2.1.0.tar.gz
# cd s3cmd-2.1.0/
[root@installer s3cmd-2.1.0]# ./s3cmd --configure
Enter new values or accept defaults in brackets with Enter.
Refer to user manual for detailed description of all options.
Access key and Secret key are your identifiers for Amazon S3. Leave them
empty for using the env variables.
Access Key: s3user
Secret Key: test1234
Default Region [US]:
Use "s3.amazonaws.com" for S3 Endpoint and not modify it to the target Amazon S3 Endpoint [s3.amazonaws.com]: rgw-mds.ceph.com:8080
Use "%(bucket)s.s3.amazonaws.com" to the target Amazon S3. "%(bucket)s"
and "%(location)s" vars can be used
if the target S3 system supports dns based buckets.
DNS-style bucket+hostname:port template for accessing a bucket [%(bucket)
s.s3.amazonaws.com]: rgw-mds.ceph.com:8080
Encryption password is used to protect your files from reading
by unauthorized persons while in transfer to S3
Encryption password:
Path to GPG program [/usr/bin/gpg]:
When using secure HTTPS protocol all communication with Amazon S3
servers is protected from 3rd party eavesdropping. This method is
slower than plain HTTP, and can only be proxied with Python 2.7 or newer
Use HTTPS protocol [Yes]: no
On some networks all internet access must go through a HTTP proxy.
Try setting it here if you can't connect to S3 directly
HTTP Proxy server name:
New settings:
Access Key: s3user
Secret Key: test1234
Default Region: US
S3 Endpoint: rgw-mds.ceph.com:8080
DNS-style bucket+hostname:port template for accessing a bucket: %(bucket)
s.rgw-mds.ceph.com:8080
Encryption password:
Path to GPG program: /usr/bin/gpg
Use HTTPS protocol: False
HTTP Proxy server name:
HTTP Proxy server port: 0
Test access with supplied credentials? [Y/n] y
Please wait, attempting to list all buckets...
Success. Your access key and secret key worked fine:-)
Now verifying that encryption works...
Not configured. Never mind.
Save settings? [y/N] y
Configuration saved to '/root/.s3cfg'

4)确认配置文件.s3cfg中的以下两个参数为对象网关和端口号的组合。

host_base = rgw-mds.ceph.com:8080
host_bucket = rgw-mds.ceph.com:8080

5)创建Bucket。

[root@installer s3cmd-2.1.0]# ./s3cmd mb s3://mybuck
Bucket 's3://mybuck/' created

6)向Bucket写入数据。

[root@installer s3cmd-2.1.0]# dd if=/dev/random of=/root/test.file bs=1M dd: warning: partial read (115 bytes); suggest iflag=fullblock
0+5 records in
0+5 records out
427 bytes (427 B) copied, 0.000682428 s, 626 kB/s
[root@installer s3cmd-2.1.0]# ./s3cmd put /root/test.file s3://mybuck
WARNING: Module python-magic is not available. Guessing MIME types based file extensions.
upload: '/root/test.file' -> 's3://mybuck/test.file' [1 of 1]
427 of 427 100% in 2s 198.97 B/s done
[root@installer s3cmd-2.1.0]# ./s3cmd ls s3://mybuck
2021-03-13 16:38 427 s3://mybuck/test.file

7)用户也可以通过Dashboard创建Bucket。

七、Ceph文件存储

1、文件存储

文件系统存储典型设备:FTP、NFS服务器。

为了克服文件无法共享的问题,所以有了文件存储。

文件存储也有软硬一体化的设备,但是其实一台普通的PC机,只要装上台适的操作系统和软件,就可以提供FTP与NFS服务了,架上该类服务之后的服务器,就是文件存储的一种了。主机A可以直接对文件存储进行文件的上传和下载,与块存储不同,主机A是不需要再对文件存储进行格式化的,因为文件管理功能已经由文件存储自己搞定了。

优点

(1)造价低随便一台机器就可以,另外普通的以太网就可以,根本不需要专用的SAN网络,所以造价低。

(2)方便文件共享。

缺点

(1)读写速率低,传输速率慢; 以太网,上传下载速度较慢,另外所有读写都要1台服务器里面的硬盘来承受, 相比起磁盘阵列动不动就十几上百块硬盘同时读写, 速率慢了许多。

与传统的文件系统如EXT4是一个类型的,但区别在于分布式存储提供了并行化的能力,如 Ceph 的 CephFS (CephFS是Ceph面向文件存储的接口),但是有时候又会把 GlusterFS ,HDFS 这种非POSIX接口的类文件存储接口归入此类,当然 NFS、NAS也是属于文件系统存储;

Ceph的文件系统弥补了Ceph的块设备在共享方面的不足,分布式存储提供了并行化的能力。

Ceph的文件系统符合POSIX 标准,用户就可以像使用本地存储目录一样使用Ceph的文件系统的挂载目录,即无需修改你的程序,就可以将程序的底层存储换成空间无线并可以多出共享读写的Ceph集群文件系统。

如Ceph的CephFS (CephFS是Ceph面向文件存储的接口),但是有时候又会把 GlusterFS、HDFS 这种非POSIX接口的类文件存储接口归入此类,当然 NFS、NAS也是属于文件系统存储。

2、Ceph FS

Ceph网络文件系统(Ceph FS)是一个POSIX兼容的文件系统,可以将ceph集群看作一个共享文件系统挂载到本地,使用ceph的存储集群来存储数据,同时支持用户空间文件系统FUSE,可以像NFS或者SAMBA那样,提供共享文件夹,客户端通过挂载目录的方式使用Ceph提供的存储。

在Ceph FS 中,与对象存与块存储最大的不同就是在集群中增加了文件系统元数据服务节点MDS(Ceph Metadata Server),MDS也支持多台机器分布式的部署,以实现系统的高可用性,文件系统客户端需要安装对应的Linux内核模块Ceph FS Kernel Object或者Ceph FS FUSE组件。

CephFS专注于高性能、大容量存储。

因为应用场景的不同,Ceph的块设备具有优异的读写性能,但不能多出挂载同时读写,目前主要用在OpenStackk上作为虚拟磁盘,而Ceph的文件系统接口读写性能较块设备接口差,但具有优异的共享性。

文件系统的结构状态时维护在各用户机中:

如上图:

假设Ceph块设备同时挂载到用户机1和用户机2,当在用户机1上的文件系统写入数据后,更新了用户机1中的文件系统状态,最终数据保存到了Ceph集群中,但此时用户机2中的文件系统并不能得知底层Ceph集群数据已经变化而位置数据结构不变,用因此用户无法从用户机2上读取用户机1上新写入的数据。

如上图:

文件系统的结构状态是维护在远端Ceph集群中的,Ceph文件系统同时挂载用户机1和用户机2,当往用户机1的挂载点写入数据后,远端Ceph集群中的系统文件状态结构随之更新,当从用户机2的挂载点访问数据时会去远端Ceph集群取数据,由于远端Ceph集群已更新,用户机2能够获取最新的数据。

3、Ceph文件存储实战

在生产环境下,为了提高文件存储的访问性能,建议部署多个元数据服务器,并且元数据服务
器节点尽量不要和其他角色的节点复用。以下操作由于服务器数量限制采用了复用的部署方式。

1. 部署MDS

MDS节点主要提供ceph-mds守护进程,用来管理CephFS中存储的文件的元数据等信息。本节主要以图形界面的方式介绍MDS部署,具体步骤如下。

1)重新启动Cockpit Ceph Installer,添加MDS节点。

2)配置之后,执行安装。

3)安装完成后,通过Dashboard可以看到已经有1个MDS处于active状态。

4)使用Ceph客户端命令查看当前已经部署好的MDS。

[root@installer ~]# ceph -s
cluster:
id: f99134e9-c5fb-4917-b7e5-372ab4d6a8f0
health: HEALTH_OK
services:
mon: 3 daemons, quorum mon1,mon2,mon3 (age 3h)
mgr: mon2(active, since 2d), standbys: mon1, mon3
mds: cephfs:1 {0=rgw-mds=up:active}
osd: 6 osds: 6 up (since 2d), 6 in (since 2d)
rgw: 1 daemon active (rgw-mds.rgw0)
data:
pools: 7 pools, 416 pgs
objects: 339 objects, 28 KiB
usage: 228 MiB used, 90 GiB / 90 GiB avail
pgs: 416 active+clean

5)登录MDS节点,查看已下载的镜像以及启动的容器。

[root@rgw-mds ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/ceph/daemon latest-master 14af70de1efb 2 weeks ago 1.14 docker.io/prom/node-exporter v0.17.0 b3e7f67a1480 2 years ago 21 MB
[root@rgw-mds ~]# docker ps
CONTAINER ID IMAGE
daf8393b6f0d docker.io/prom/node-exporter:v0.17.0
e690f7d59657 docker.io/ceph/daemon:latest-master
21ea58a9d47c docker.io/ceph/daemon:latest-master
COMMAND CREATED STATUS PORTS NAMES
"/bin/node_exporte..." About a minute ago Up node-exporter
"/opt/ceph-contain..." About a minute ago Up ceph-rgw-rgw-mds-rgw0
"/opt/ceph-contain..." 2 minutes ago Up ceph-mds-rgw-mds

2. 使用CephFS

通过部署的MON节点的6789端口访问CephFS。你需要在Ceph集群中创建两个池,cephfs_data、cephfs_metadata,分别用于存储数据和元数据。

1)查看CephFS的两个池。

[root@installer ~]# ceph df
--- RAW STORAGE ---
CLASS SIZE AVAIL USED RAW USED %RAW USED
hdd 90 GiB 89 GiB 1.4 GiB 1.4 GiB 1.59
TOTAL 90 GiB 89 GiB 1.4 GiB 1.4 GiB 1.59
--- POOLS ---
POOL ID PGS STORED OBJECTS USED %USED MAX AVAIL
device_health_metrics 1 32 0 B 0 0 B 0 28 GiB
cephfs_data 2 32 0 B 0 0 B 0 28 GiB
cephfs_metadata 3 128 9.2 KiB 22 112 KiB 0 28 GiB
[root@installer ~]# ceph fs status cephfs
cephfs - 0 clients
======
RANK STATE MDS ACTIVITY DNS INOS DIRS CAPS
0 active rgw-mds Reqs: 0 /s 10 13 12 0
POOL TYPE USED AVAIL
cephfs_metadata metadata 112k 27.8G
cephfs_data data 0 27.8G

2)在客户端创建ceph-secret文件并挂载到CephFS。

[root@installer ~]# ceph auth get-key client.admin >ceph_secret
[root@installer ~]# mount -t ceph 192.168.122.161:6789:/ /mnt -o name=
admin,secretfile=/root/ceph_secret
[root@installer ~]# df -h
Filesystem Size Used Avail Use% Mounted on
192.168.122.161:6789:/ 28G 0 28G 0% /mnt

3)写入数据测试。

[root@installer ~]# mkdir /mnt/test_dir
[root@installer ~]# ls -La /mnt/
. .. test_dir
[root@installer ~]# ls -la /mnt/
total 0
drwxr-xr-x 1 root root 1 Mar 22 22:02 .
dr-xr-xr-x. 20 root root 261 Mar 22 19:12 ..
drwxr-xr-x 1 root root 0 Mar 22 22:02 test_dir
[root@installer ~]# dd if=/dev/zero of=/mnt/test_dir/testfile bs=1M count=10+0 records in
10+0 records out
10485760 bytes (10 MB) copied, 0.0327782 s, 320 MB/s
[root@installer ~]# ls -la /mnt/test_dir/
total 10240
drwxr-xr-x 1 root root 1 Mar 22 22:03 .
drwxr-xr-x 1 root root 1 Mar 22 22:02 ..
-rw-r--r-- 1 root root 10485760 Mar 22 22:03 testfile

3. CephFS扩展属性

文件布局可控制文件内容映射到各Ceph RADOS对象。你可以通过扩展属性(xattrs)来读写文件布局。我们可使用ceph.file.layout进行文件布局,使用ceph.dir.layout进行目录布局。

下面提供了操作CephFS扩展属性的示例:

1)查看文件扩展属性。

[root@installer ~]# getfattr -n ceph.file.layout /mnt/test_dir/testfile
getfattr: Removing leading '/' from absolute path names
# file: mnt/test_dir/testfile
ceph.file.layout="stripe_unit=4194304 stripe_count=1 object_size=4194304
pool=cephfs_data"

2)默认文件夹没有设置扩展属性。

[root@installer ~]# getfattr -n ceph.dir.layout /mnt/test_dir
/mnt/test_dir: ceph.dir.layout: No such attribute

3)配置文件夹扩展属性。

[root@installer ~]# setfattr -n ceph.dir.layout.stripe_count -v 2 /mnt/test_[root@installer ~]# getfattr -n ceph.dir.layout /mnt/test_dir
getfattr: Removing leading '/' from absolute path names
# file: mnt/test_dir
ceph.dir.layout="stripe_unit=4194304 stripe_count=2 object_size=4194304
pool=cephfs_data"

4)文件夹配置的新属性只对新创建的文件有效。

[root@installer ~]# getfattr -n ceph.file.layout /mnt/test_dir/testfile
getfattr: Removing leading '/' from absolute path names
# file: mnt/test_dir/testfile
ceph.file.layout="stripe_unit=4194304 stripe_count=1 object_size=4194304
pool=cephfs_data"

5)新创建的文件使用目录配置的新属性。

[root@installer ~]# touch /mnt/test_dir/new_file
[root@installer ~]# getfattr -n ceph.file.layout /mnt/test_dir/new_file
getfattr: Removing leading '/' from absolute path names
# file: mnt/test_dir/new_file
ceph.file.layout="stripe_unit=4194304 stripe_count=2 object_size=4194304
pool=cephfs_data"

6)修改新文件属性。

[root@installer ~]# setfattr -n ceph.file.layout.stripe_count -v 3 /mnt/
test_dir/new_file
[root@installer ~]# getfattr -n ceph.file.layout /mnt/test_dir/new_file
getfattr: Removing leading '/' from absolute path names
# file: mnt/test_dir/new_file
ceph.file.layout="stripe_unit=4194304 stripe_count=3 object_size=4194304
pool=cephfs_data"

7)内容不为空的文件无法修改扩展属性。

[root@installer ~]# echo "test begin" >/mnt/test_dir/new_file
[root@installer ~]# setfattr -n ceph.file.layout.stripe_count -v 4 /mnt/
test_dir/new_file
setfattr: /mnt/test_dir/new_file: Directory not empty

8)清除文件夹属性。

[root@installer ~]# setfattr -x ceph.dir.layout /mnt/test_dir/

八、Ceph集群管理

配置完Ceph集群后,我们即可对Ceph集群进行数据存储。在后续使用过程中,Ceph提供了常用的命令对Ceph集群进行必要的运维。常见的集群状态查看、磁盘使用率查看、添加磁盘、删除坏盘等操作。

详情可参考:Welcome to Ceph — Ceph Documentation

1、Ceph的常用命令

本节给出的Ceph常用命令可以作为最基本的集群运维命令。

1)查看集群状态命令。

[root@installer ~]# ceph -s
cluster:
id: f99134e9-c5fb-4917-b7e5-372ab4d6a8f0
health: HEALTH_WARN
1 pool(s) do not have an application enabled
1 pool(s) have non-power-of-two pg_num
too many PGs per OSD (252 > max 250)
services:
mon: 3 daemons, quorum mon1,mon2,mon3 (age 2d)
mgr: mon2(active, since 2d), standbys: mon3, mon1
mds: cephfs:1 {0=rgw-mds=up:active}
osd: 6 osds: 6 up (since 2d), 6 in (since 11d)
rgw: 1 daemon active (rgw-mds.rgw0)
data:
pools: 10 pools, 504 pgs
objects: 443 objects, 106 MiB
usage: 1.5 GiB used, 88 GiB / 90 GiB avail
pgs: 504 active+clean
[root@installer ~]# ceph health
HEALTH_WARN 1 pool(s) do not have an application enabled; 1 pool(s) have
non-power-of-two pg_num; too many PGs per OSD (252 > max 250)
[root@installer ~]# ceph health detail
HEALTH_WARN 1 pool(s) do not have an application enabled; 1 pool(s) have
non-power-of-two pg_num; too many PGs per OSD (252 > max 250)
[WRN] POOL_APP_NOT_ENABLED: 1 pool(s) do not have an application enabled
application not enabled on pool 'rbd'
use 'ceph osd pool application enable <pool-name> <app-name>', where
<app-name> is 'cephfs', 'rbd', 'rgw', or freeform for custom applications.
[WRN] POOL_PG_NUM_NOT_POWER_OF_TWO: 1 pool(s) have non-power-of-two pg_num
pool 'rbd' pg_num 24 is not a power of two
[WRN] TOO_MANY_PGS: too many PGs per OSD (252 > max 250)

2)修复health命令提示的RBD问题。

[root@installer ~]# ceph osd pool application enable rbd rbd
enabled application 'rbd' on pool 'rbd'
[root@installer ~]# ceph osd dump |grep rbd
pool 11 'rbd' replicated size 3 min_size 2 crush_rule 0 object_hash
rjenkins pg_num 21 pgp_num 20 pg_num_target 16 pgp_num_target 16 pg_
num_pending 20 autoscale_mode on last_change 576 lfor 0/576/576 flags
hashpspool,nodelete,selfmanaged_snaps stripe_width 0 application rbd
[root@installer ~]# ceph health detail
HEALTH_WARN 1 pools have too few placement groups
POOL_TOO_FEW_PGS 1 pools have too few placement groups
Pool cephfs_data has 8 placement groups, should have 32

3)修复health命令提示的放置组不足问题。

[root@installer ~]# ceph osd pool set cephfs_data pg_num 32
set pool 1 pg_num to 32
[root@installer ~]# ceph osd pool get cephfs_data pg_num
pg_num: 32
[root@installer ~]# ceph health detail
HEALTH_WARN 1 pools have too few placement groups
POOL_TOO_FEW_PGS 1 pools have too few placement groups
Pool cephfs_data has 8 placement groups, should have 32
[root@installer ~]# ceph osd pool scrub cephfs_data
[root@installer ~]# ceph health detail
HEALTH_OK

4)查看PG状态。

[root@installer ~]# ceph pg stat
544 pgs: 544 active+clean; 216 MiB data, 2.7 GiB used, 87 GiB / 90 GiB avail
[root@installer ~]# ceph pg ls
PG OBJECTS DEGRADED MISPLACED UNFOUND BYTES OMAP_BYTES*
1.0 0 0 0 0 0 0
1.1 0 0 0 0 0 0
OMAP_KEYS* LOG STATE SINCE VERSION REPORTED UP
0 0 active+clean 3h 0'0 685:721 [3,2,4]p3
0 0 active+clean 3h 0'0 685:65 [5,1,0]p5
ACTING SCRUB_STAMP DEEP_SCRUB_STAMP
[3,2,4]p3 2021-03-22T22:34:39.727853+0800 2021-03-20T12:15:37.162110+
[5,1,0]p5 2021-03-22T21:28:34.059464+0800 2021-03-20T12:15:52.391857+

5)查看MON节点状态。

[root@installer ~]# ceph mon dump
dumped monmap epoch 1
epoch 1
fsid f99134e9-c5fb-4917-b7e5-372ab4d6a8f0
last_changed 2021-03-09T16:39:48.998849+0800
created 2021-03-09T16:39:48.998849+0800
min_mon_release 17 (quincy)
election_strategy: 1
0: [v2:192.168.122.161:3300/0,v1:192.168.122.161:6789/0] mon.mon1
1: [v2:192.168.122.162:3300/0,v1:192.168.122.162:6789/0] mon.mon2
2: [v2:192.168.122.163:3300/0,v1:192.168.122.163:6789/0] mon.mon3

6)查看OSD通用命令。

[root@installer ~]# ceph osd tree
ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF
-1 0.08784 root default
-5 0.02928 host osd1
0 hdd 0.01949 osd.0 up 1.00000 1.00000
3 hdd 0.00980 osd.3 up 1.00000 1.00000
-7 0.02928 host osd2
2 hdd 0.01949 osd.2 up 1.00000 1.00000
5 hdd 0.00980 osd.5 up 1.00000 1.00000
-3 0.02928 host osd3
1 hdd 0.01949 osd.1 up 1.00000 1.00000
4 hdd 0.00980 osd.4 up 1.00000 1.00000

7)查看OSD容量。

[root@installer ~]# ceph osd df
ID CLASS WEIGHT REWEIGHT SIZE RAW USE DATA
0 hdd 0.01949 1.00000 20 GiB 335 MiB 89 MiB
3 hdd 0.00980 1.00000 10 GiB 187 MiB 27 MiB
2 hdd 0.01949 1.00000 20 GiB 346 MiB 93 MiB
5 hdd 0.00980 1.00000 10 GiB 175 MiB 24 MiB
1 hdd 0.01949 1.00000 20 GiB 355 MiB 99 MiB
4 hdd 0.00980 1.00000 10 GiB 170 MiB 18 MiB
OMAP META AVAIL %USE VAR PGS STATUS
11 KiB 246 MiB 20 GiB 1.64 0.96 330 up
5 KiB 160 MiB 9.8 GiB 1.83 1.07 166 up
12 KiB 253 MiB 20 GiB 1.69 0.99 322 up
4 KiB 152 MiB 9.8 GiB 1.71 1.01 174 up
7 KiB 256 MiB 20 GiB 1.74 1.02 328 up
9 KiB 152 MiB 9.8 GiB 1.66 0.98 168 up
TOTAL 90 GiB 1.5 GiB 350 MiB 50 KiB 1.2 GiB 88 GiB 1.70
MIN/MAX VAR: 0.96/1.07 STDDEV: 0.06

8)查看OSD池。

[root@installer ~]# ceph osd lspools
1 device_health_metrics
2 cephfs_data
3 cephfs_metadata
4 .rgw.root
5 default.rgw.log
6 default.rgw.control
7 default.rgw.meta
8 default.rgw.buckets.index
9 default.rgw.buckets.data
11 rbd

9)写入文件测试。

[root@installer ~]# ceph df
--- RAW STORAGE ---
CLASS SIZE AVAIL USED RAW USED %RAW USED
hdd 90 GiB 88 GiB 1.5 GiB 1.5 GiB 1.70
TOTAL 90 GiB 88 GiB 1.5 GiB 1.5 GiB 1.70
--- POOLS ---
POOL ID PGS STORED OBJECTS USED %USED MAX AVAIL
rbd 11 16 92 MiB 50 276 MiB 0.32 28 GiB
[root@installer ~]# dd if=/dev/zero of=./testfile bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10 MB) copied, 0.00372667 s, 2.8 GB/s
[root@installer ~]# for i in $(seq 0 10); do rados -p rbd put file.$i ./
testfile; done
[root@installer ~]# ceph df
--- RAW STORAGE ---
CLASS SIZE AVAIL USED RAW USED %RAW USED
hdd 90 GiB 88 GiB 2.3 GiB 2.3 GiB 2.52
TOTAL 90 GiB 88 GiB 2.3 GiB 2.3 GiB 2.52
--- POOLS ---
POOL ID PGS STORED OBJECTS USED %USED MAX AVAIL
rbd 11 16 202 MiB 61 606 MiB 0.71 27 GiB

10)查看池属性。

[root@installer ~]# ceph osd dump |grep rbd
pool 11 'rbd' replicated size 3 min_size 2 crush_rule 0 object_hash
rjenkins pg_num 24 pgp_num 24 autoscale_mode on last_change 560 flags
hashpspool,nodelete,selfmanaged_snaps stripe_width 0 application rbd
[root@installer ~]# ceph osd pool stats rbd
pool rbd id 11
nothing is going on
[root@installer ~]# ceph osd pool get rbd pg_num
pg_num: 24
[root@installer ~]# ceph osd pool get rbd size
size: 3
[root@installer ~]# ceph osd pool get rbd min_size
min_size: 2

11)设置池删除保护属性。

[root@installer ~]# ceph osd pool get rbd nodelete
nodelete: false
[root@installer ~]# ceph osd pool set rbd nodelete 1
set pool 11 nodelete to 1
[root@installer ~]# ceph osd pool delete rbd rbd --yes-i-really-really-mean-Error EPERM: pool deletion is disabled; you must unset nodelete flag for 

12)设置OSD。

[root@installer ~]# ceph osd tree
ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF
-1 0.08784 root default
-5 0.02928 host osd1
0 hdd 0.01949 osd.0 up 1.00000 1.00000
3 hdd 0.00980 osd.3 up 1.00000 1.00000
-7 0.02928 host osd2
2 hdd 0.01949 osd.2 up 1.00000 1.00000
5 hdd 0.00980 osd.5 up 1.00000 1.00000
-3 0.02928 host osd3
1 hdd 0.01949 osd.1 up 1.00000 1.00000
4 hdd 0.00980 osd.4 up 1.00000 1.00000

13)查看映射过程,testfile文件最后映射到 osd.1。

[root@installer ~]# ceph osd map rbd testfile
osdmap e595 pool 'rbd' (11) object 'testfile' -> pg 11.551a2b36 (11.6) ->
up ([1,3,2], p1) acting ([1,3,2], p1)

14)修改osd.1的特性值。

[root@installer ~]# ceph osd primary-affinity 1 0.3
set osd.1 primary-affinity to 0.3 (8196602)
[root@installer ~]# ceph osd tree
ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF
-1 0.08784 root default
-5 0.02928 host osd1
0 hdd 0.01949 osd.0 up 1.00000 1.00000
3 hdd 0.00980 osd.3 up 1.00000 1.00000
-7 0.02928 host osd2
2 hdd 0.01949 osd.2 up 1.00000 1.00000
5 hdd 0.00980 osd.5 up 1.00000 1.00000
-3 0.02928 host osd3
1 hdd 0.01949 osd.1 up 1.00000 0.29999
4 hdd 0.00980 osd.4 up 1.00000 1.00000

15)重新查看testfile文件的映射过程,最后映射到 osd.3。

[root@installer ~]# ceph osd map rbd testfile
osdmap e597 pool 'rbd' (11) object 'testfile' -> pg 11.551a2b36 (11.6) ->
up ([3,1,2], p3) acting ([3,1,2], p3)

16)还原初始设置。

[root@installer ~]# ceph osd primary-affinity 1 1
set osd.1 primary-affinity to 1 (8655362)
[root@installer ~]# ceph osd map rbd testfile
osdmap e599 pool 'rbd' (11) object 'testfile' -> pg 11.551a2b36 (11.6) ->
up ([1,3,2], p1) acting ([1,3,2], p1)

2、配置CRUSH Map

Ceph可以调整集群的映射图,以实现对节点的磁盘存储资源的合理管控,例如实现合理的磁盘分
组和故障域划分,以避免磁盘或者节点损坏带来的风险。本节介绍配置集群的映射图,步骤如下。

1)导出当前CRUSH Map。

[root@installer ~]# mkdir crush
[root@installer ~]# cd crush/
[root@installer crush]# ceph osd getcrushmap -o ./crushmap_orig.bin
5 [
root@installer crush]# ls -
lh
total 4.0K
-rw-r--r--. 1 root root 944 Mar 23 11:21 crushmap_orig.bin

2)将CRUSH Map的导出结果转成txt文件。

[root@installer crush]# yum install ceph-base
[root@installer crush]# crushtool -d ./crushmap_orig.bin -o crushmap_orig.[root@installer crush]# echo $?
0

3)查看当前具体设置。

[root@installer crush]# cat crushmap_orig.txt
# begin crush map
tunable choose_local_tries 0
tunable choose_local_fallback_tries 0
tunable choose_total_tries 50
tunable chooseleaf_descend_once 1
tunable chooseleaf_vary_r 1
tunable chooseleaf_stable 1
tunable straw_calc_version 1
tunable allowed_bucket_algs 54
# devices
device 0 osd.0 class hdd
device 1 osd.1 class hdd
device 2 osd.2 class hdd
device 3 osd.3 class hdd
device 4 osd.4 class hdd
device 5 osd.5 class hdd
# types
type 0 osd
type 1 host
type 2 chassis
type 3 rack
type 4 row
type 5 pdu
type 6 pod
type 7 room
type 8 datacenter
type 9 zone
type 10 region
type 11 root
# buckets
host osd3 {
id -3
id -4 class hdd
# weight 0.029
alg straw2
hash 0 # rjenkins1
item osd.1 weight 0.019
item osd.4 weight 0.010
} host osd1 {
id -5
id -6 class hdd
# weight 0.029
alg straw2
hash 0 # rjenkins1
item osd.0 weight 0.019
item osd.3 weight 0.010
} host osd2 {
id -7
id -8 class hdd
# weight 0.029
alg straw2
hash 0 # rjenkins1
item osd.2 weight 0.019
item osd.5 weight 0.010
} root default {
id -1
id -2 class hdd
# weight 0.088
alg straw2
hash 0 # rjenkins1
item osd3 weight 0.029
item osd1 weight 0.029
item osd2 weight 0.029
}
# rules
rule replicated_rule {
id 0
type replicated
min_size 1
max_size 10
step take default
step chooseleaf firstn 0 type host
step emit
}
# end crush map

4)以命令方式获取集群osd tree。

[root@installer crush]# ceph osd tree
ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF
-1 0.08784 root default
-5 0.02928 host osd1
0 hdd 0.01949 osd.0 up 1.00000 1.00000
3 hdd 0.00980 osd.3 up 1.00000 1.00000
-7 0.02928 host osd2
2 hdd 0.01949 osd.2 up 1.00000 1.00000
5 hdd 0.00980 osd.5 up 1.00000 1.00000
-3 0.02928 host osd3
1 hdd 0.01949 osd.1 up 1.00000 1.00000
4 hdd 0.00980 osd.4 up 1.00000 1.00000

5)备份当前设置。

[root@installer crush]# cp crushmap_orig.txt crushmap_new.txt

6)修改CRUSH Map设置,添加SSD规则,将 osd2.ceph.com使用SSD规则删除default中的osd2,添加SSD。

root default {
id -1 # do not change unnecessarily
id -2 class hdd # do not change unnecessarily
# weight 0.088
alg straw2
hash 0 # rjenkins1
item osd3 weight 0.029
item osd1 weight 0.029
item osd2 weight 0.029
}
root ssd {
id -9
# weight 0.061
alg straw2
hash 0 # rjenkins1
item osd2 weight 0.061
}

7)添加新规则。

rule ssd-first {
ruleset 1
type replicated
min_size 1
max_size 10
step take ssd
step chooseleaf firstn 1 type host
step emit
step take default
step chooseleaf firstn -1 type host
step emit
}
rule replicated_rule {

8)测试新的CRUSH Map。

[root@installer crush]# crushtool -c ./crushmap_new.txt -o crushmap_new.[root@installer crush]# crushtool --test -i ./crushmap_new.bin --num-rep --rule 1 --show-mappings
… CRUSH rule 1
x
1014 [
2,3,1]
CRUSH rule 1 x 1015 [2,4,3]
CRUSH rule 1 x 1016 [5,0,4]
CRUSH rule 1 x 1017 [5,1,0]
CRUSH rule 1 x 1018 [5,1,0]
CRUSH rule 1 x 1019 [2,1,3]
CRUSH rule 1 x 1020 [5,0,1]
CRUSH rule 1 x 1021 [5,1,0]
CRUSH rule 1 x 1022 [5,0,1]
CRUSH rule 1 x 1023 [2,1,0]

规定优先使用osd2 host上的osd.2与osd.5。

9)应用新的CRUSH Map。

[root@installer crush]# ceph osd setcrushmap -i ./crushmap_new.bin
6

10)等待变更。

[root@installer crush]# ceph -s
cluster:
id: f99134e9-c5fb-4917-b7e5-372ab4d6a8f0
health: HEALTH_OK
services:
mon: 3 daemons, quorum mon1,mon2,mon3 (age 2d)
mgr: mon2(active, since 2d), standbys: mon3, mon1
mds: cephfs:1 {0=rgw-mds=up:active}
osd: 6 osds: 6 up (since 2d), 6 in (since 12d); 496 remapped pgs
rgw: 1 daemon active (rgw-mds.rgw0)
data:
pools: 10 pools, 496 pgs
objects: 457 objects, 216 MiB
usage: 2.4 GiB used, 88 GiB / 90 GiB avail
pgs: 0.202% pgs not active
551/1371 objects misplaced (40.190%)
484 active+clean+remapped
9 active+remapped+backfill_wait
2 active+remapped+backfilling
1 remapped+peering
io:
client: 7.0 KiB/s rd, 1.4 KiB/s wr, 7 op/s rd, 4 op/s wr
recovery: 651 KiB/s, 0 keys/s, 7 objects/s

11)查看新的集群映射图。

[root@installer crush]# ceph osd tree
ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF
-9 0.06099 root ssd
-7 0.06099 host osd2
2 hdd 0.01900 osd.2 up 1.00000 1.00000
5 hdd 0.00999 osd.5 up 1.00000 1.00000
-1 0.05798 root default
-5 0.02899 host osd1
0 hdd 0.01900 osd.0 up 1.00000 1.00000
3 hdd 0.00999 osd.3 up 1.00000 1.00000
-3 0.02899 host osd3
1 hdd 0.01900 osd.1 up 1.00000 1.00000
4 hdd 0.00999 osd.4 up 1.00000

12)查看RBD池的CRUSH Rule。

[root@installer crush]# ceph osd pool get rbd crush_rule
crush_rule: replicated_rule
[root@installer crush]# ceph osd map rbd testfile
osdmap e614 pool 'rbd' (11) object 'testfile' -> pg 11.551a2b36 (11.6) -> ([1,3], p1) acting ([1,3,2], p1)

13)修改RBD池并使用新的CRUSH Rule,文件映射到主机 osd2上的osd.2或者osd.5。

[root@installer crush]# ceph osd pool set rbd crush_rule ssd-first
set pool 11 crush_rule to ssd-first
[root@installer crush]# ceph osd pool get rbd crush_rule
crush_rule: ssd-first
[root@installer crush]# ceph osd map rbd testfile
osdmap e625 pool 'rbd' (11) object 'testfile' -> pg 11.551a2b36 (11.36) up ([2,1,3], p2) acting ([2,1,3], p2)

14)还原缺省设置。

[root@installer crush]# ceph osd pool set rbd crush_rule replicated_rule
set pool 11 crush_rule to replicated_rule
[root@installer crush]# ceph osd setcrushmap -i ./crushmap_orig.bin

3、添加磁盘

在Ceph集群中添加磁盘是最基本的功能,也是最常见的操作,通常在扩容或者坏盘更换的时候都
可能会执行此类操作。本节将使用ansible命令更新集群,向指定节点添加磁盘,具体操作步骤如下。

1)在osd3机器上添加vdd磁盘。

[root@osd3 ~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
vdb 252:16 0 20G 0 disk
└─ceph--27bce4f0--af57--4310--baae--d890216fb33e-osd--block--b0e16697--7950
--4df9--9398--a927fd3fd013
253:2 0 20G 0 lvm
vdc 252:32 0 10G 0 disk
└─ceph--05f0ba85--1951--4ce0--b9c1--de7f09abf3dc-osd--block--e5411155--8ffc
--452c--9158--b2caec5aa969
253:3 0 10G 0 lvm
vdd

2)在installer机器上进入ansible-runner-service容器。

[root@installer ~]# docker exec -it 9dba /bin/sh
sh-4.2# cd /usr/share/ceph-ansible/
添加代理设置,以更快下载的容器镜像
sh-4.2# cat group_vars/all.yml
---
ceph_origin: repository
ceph_repository: community
ceph_stable_release: nautilus
ceph_version_num: 14
cluster_network: 192.168.122.0/24
configure_firewall: false
containerized_deployment: true
dashboard_admin_password: kdq1qaz@WSX
dashboard_enabled: true
docker_pull_timeout: 600s
grafana_admin_password: kdq1qaz@WSX
ip_version: ipv4
Monitor_address_block: 192.168.122.0/24
public_network: 192.168.122.0/24
radosgw_address_block: 192.168.122.0/24
ceph_docker_http_proxy: "http://192.168.122.1:1080"
ceph_docker_https_proxy: "http://192.168.122.1:1080"
ceph_docker_no_proxy: "localhost,127.0.0.1"

3)修改osd3配置文件,添加vdd磁盘。

sh-4.2# cat host_vars/osd3
---
devices:
- /dev/vdb
- /dev/vdc
- /dev/vdd

4)运行ansible-playbook,更新osd3节点。

sh-4.2# /usr/local/bin/ansible-playbook --private-key /usr/share/ansiblerunner-
service/env/ssh_key -i /usr/share/ansible-runner-service/
inventory site-container.yml --limit osd3

5)等待ansible-playbook执行完毕,登录osd3节点查看vdd磁盘状态。

[root@osd3 ~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sr0 11:0 1 4.4G 0 rom
vda 252:0 0 30G 0 disk
├─vda1 252:1 0 500M 0 part /boot
└─vda2 252:2 0 29.5G 0 part
├─rhel-lv_root 253:0 0 28.5G 0 lvm /
└─rhel-lv_swap 253:1 0 1G 0 lvm [SWAP]
vdb 252:16 0 20G 0 disk
└─ceph--fc18db00--d14f--41ef--a882--0dc285e8bf8a-osd--block--b346a552--ce21
--433d--959c--71bd46c0ef98 253:2 0 20G 0 lvm
vdc 252:32 0 10G 0 disk
└─ceph--2bceb33d--0b64--4a91--94f5--2d773c179969-osd--block--9757a95c--0a86
--406e--a631--c428457e759c 253:3 0 10G 0 lvm
vdd 252:48 0 10G 0 disk
└─ceph--e2439633--40a3--4d50--a141--0ec327a2cd60-osd--block--3d605506--d46b
--454c--b79f--257981626a46 253:4 0 10G 0 lvm
[root@osd3 ~]# docker ps
CONTAINER ID IMAGE
338c5f9b3a4b docker.io/ceph/daemon:latest-nautilus
45a06eee5c86 docker.io/ceph/daemon:latest-nautilus
890f5833b5dc prom/node-exporter:v0.17.0
c4d234b03307 docker.io/ceph/daemon:latest-nautilus
4c951abc9db5 docker.io/ceph/daemon:latest-nautilus
COMMAND CREATED STATUS PORTS NAMES
"/opt/ceph-contain..." 50 seconds ago Up 49 seconds ceph-osd-6
"/usr/bin/ceph-crash" 2 minutes ago Up 2 minutes ceph-crash-osd3
"/bin/node_exporte..." 2 hours ago Up 2 hours node-exporter
"/opt/ceph-contain..." 2 hours ago Up 2 hours ceph-osd-4
"/opt/ceph-contain..." 2 hours ago Up 2 hours ceph-osd-1

6)查看集群状态图。

[root@installer ~]# ceph osd tree
ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF
-1 0.09764 root default
-5 0.02928 host osd1
0 hdd 0.01949 osd.0 up 1.00000 1.00000
3 hdd 0.00980 osd.3 up 1.00000 1.00000
-7 0.02928 host osd2
2 hdd 0.01949 osd.2 up 1.00000 1.00000
5 hdd 0.00980 osd.5 up 1.00000 1.00000
-3 0.03908 host osd3
1 hdd 0.01949 osd.1 up 1.00000 1.00000
4 hdd 0.00980 osd.4 up 1.00000 1.00000
6 hdd 0.00980 osd.6 up 1.00000 1.00000

4、删除磁盘

Ceph集群中出现坏盘故障十分常见。如果磁盘寿命到期或者意外损坏,底层没有做RAID,我们
必须将此盘从集群中删除,然后添加新的磁盘。本节介绍在ansible-runner-service容器中删除对应的OSD的方法。

1)在installer机器上进入ansible-runner-service容器。

[root@installer ~]# docker exec -it 9dba /bin/sh
sh-4.2# cd /usr/share/ceph-ansible/

2)执行命令删除osd1节点上osd.3进程对应的磁盘。

sh-4.2# /usr/local/bin/ansible-playbook --private-key /usr/share/ansiblerunner-
service/env/ssh_key -i /usr/share/ansible-runner-service/inventory
infrastructure-playbooks/shrink-osd.yml -e osd_to_kill=3
PLAY [gather facts and check the init system] *****************************
TASK [Gathering Facts] **************************************************
Wednesday 24 March 2021 10:51:12+0000 (0:00:00.137) 0:00:00.137 *******
ok: [osd1]
ok: [osd2]
ok: [osd3]
TASK [debug] ************************************************************
Wednesday 24 March 2021 10:51:13+0000 (0:00:01.073) 0:00:01.211 *******
ok: [mon1] =>
msg: gather facts on all Ceph hosts for following reference
ok: [mon2] =>
msg: gather facts on all Ceph hosts for following reference
ok: [mon3] =>
msg: gather facts on all Ceph hosts for following reference
ok: [osd1] =>
msg: gather facts on all Ceph hosts for following reference
ok: [osd2] =>
msg: gather facts on all Ceph hosts for following reference
ok: [osd3] =>
msg: gather facts on all Ceph hosts for following reference
Are you sure you want to shrink the cluster? [no]: yes
… TASK [
show ceph osd tree] *************************************************
Wednesday 24 March 2021 11:19:55+0000 (0:00:00.603) 0:00:17.544 *******
ok: [mon1]
PLAY RECAP *************************************************************
mon1:ok=19 changed=3 unreachable=0 failed=0 skipped=11 rescued=0 ignored=mon2:ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=mon3:ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=osd1:ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=osd2:ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=osd3:ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 

3)在mon1节点上安装ceph-common客户端工具。

[root@mon1 ~]# yum -y install centos-release-ceph-nautilus.noarch
[root@mon1 ~]# yum update ceph-common

4)在osd1节点上安装ceph-osd工具,查看删除后的磁盘状态。

[root@osd1 ~]# yum install centos-release-ceph-nautilus
[root@osd1 ~]# yum install ceph-osd
[root@osd1 ~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sr0 11:0 1 4.4G 0 rom
vda 252:0 0 30G 0 disk
├─vda1 252:1 0 500M 0 part /boot
└─vda2 252:2 0 29.5G 0 part
├─rhel-lv_root 253:0 0 28.5G 0 lvm /
└─rhel-lv_swap 253:1 0 1G 0 lvm [SWAP]
vdb 252:16 0 20G 0 disk
└─ceph--d76f1977--776b--49ff--b684--72f54e83b290-osd--block--9af73fee--465d
--4e08--8635--b309c9d39f38 253:2 0 20G 0 lvm
vdc 252:32 0 10G 0 disk
[root@installer ~]# ceph osd tree
ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF
-1 0.08784 root default
-5 0.01949 host osd1
0 hdd 0.01949 osd.0 up 1.00000 1.00000
-7 0.02928 host osd2
2 hdd 0.01949 osd.2 up 1.00000 1.00000
5 hdd 0.00980 osd.5 up 1.00000 1.00000
-3 0.03908 host osd3
1 hdd 0.01949 osd.1 up 1.00000 1.00000
4 hdd 0.00980 osd.4 up 1.00000 1.00000
6 hdd 0.00980 osd.6 up 1.00000 1.00000

5、使用Dashboard管理Ceph

环境:

IP地址 主机名
192.168.118.14 ceph-node1
192.168.118.15 ceph-node2
192.168.118.16 ceph-node3
192.168.118.17 ceph-client

Ceph 版本:ceph version 14.2.10 nautilus (stable)

注意:所有节点更新为最新内核版本!

[root@ceph-node1 ~]#ceph -scluster:id:     2bfda893-adf6-4396-8f1a-035fda5afbe3health: HEALTH_OKservices:mon: 3 daemons, quorum ceph-node1,ceph-node2,ceph-node3 (age 4h)mgr: ceph-node1(active, since 4h)osd: 3 osds: 3 up (since 4h), 3 in (since 4h)data:pools:   0 pools, 0 pgsobjects: 0 objects, 0 Busage:   3.0 GiB used, 6.0 TiB / 6.0 TiB availpgs:

创建 dashboard

1. 安装 ceph-mgr-dashboard

[root@ceph-node1 ~]#yum install ceph-mgr-dashboard -y

2. 开启 dashboard module

[root@ceph-node1 ~]#ceph mgr module enable dashboard

3. 禁止 SSL

(这里没必要使用不信任的https)

[root@ceph-node1 ~]#ceph config set mgr mgr/dashboard/ssl false

4. 设置监听地址和端口

[root@ceph-node1 ~]#ceph config set mgr mgr/dashboard/server_addr 0.0.0.0
[root@ceph-node1 ~]#ceph config set mgr mgr/dashboard/server_port 8080

5. 设定用户名和密码

[root@ceph-node1 ~]#ceph dashboard set-login-credentials admin admin
******************************************************************
***          WARNING: this command is deprecated.              ***
*** Please use the ac-user-* related commands to manage users. ***
******************************************************************
Username and password updated

6. 查看 mgr 访问路径

# 重新启动 mgr 服务
[root@ceph-node1 ~]#systemctl restart ceph-mgr@*
[root@ceph-node1 ~]#ceph mgr services
{"dashboard": "http://ceph-node1:8080/"
}

通过浏览器访问:

通过 dashboard 可以进行很多操作 比如 osd 、pool 都可以通过 dashboard 直接进行管控。

九、Ceph容灾

容灾即灾难恢复、容灾备份或灾备,是数据中心业务连续性和可靠性中非常重要的考量指标。如
果在生产系统上线后还没有做好容灾方案,那么一旦数据中心出现区域性故障,轻则业务中断,重则数据丢失。而容灾更多是指IT系统在遭受自然灾害、人为操作失误等情况下对业务数据的恢复能
力。

Ceph集群建设完毕后,单集群模式可以通过副本或者纠删码方式实现数据的高可用性,保证数据
盘在部分损坏(可容许损坏数量范围内)的情况下,仍然能够持续提供服务,不会导致数据丢失。
但是在单集群整体故障的情况下,实现数据可靠就需要提出完整的容灾方案。

Ceph的使用接口主要包括三种:对象存储接口、块存储接口、文件存储接口。除了这三种传统接口外,Ceph还提供了在这三种接口上封装的其他服务,比如iSCSI、NFS、Samba等。对于不同接口保存的数据,你都需要对其设计相应的容灾方案,保证在数据中心单Ceph集群出现故障后,相应存储接口保存的数据在远端容灾集群中有副本。典型的Ceph容灾方案要求有两个Ceph集群:一个集群提供业务,另一个集群提供备份。

1、对象存储容灾

对象存储是Ceph中最重要的存储形态,如果你在生产环境下使用了Ceph对象存储,那么在容灾场
景下需要有方案实现对象的容灾复制,保证远端包含相同的对象副本。本节会介绍对象存储的容灾复制方案,指导你在生产环境下实现两个Ceph集群配置,实现对象的容灾复制。配置完成后的容灾对象复制将由Ceph自身实现。

Ceph对象存储容灾是通过Ceph多站点方式实现的。RGW多数据站点旨在实现异地双活,提供容
灾备份的能力。

主站点在对外提供服务时,用户数据在主站点落盘后即向用户回应写成功应答,然后实时记录数
据变化的相关日志信息。备站点实时比较主备份数据差异,并及时将差异数据拉回备节点。异步复制技术适用于远距离的容灾方案,对系统性能影响较小。因此,Ceph的对象多站点容灾技术是一种异步容灾方案。

① Ceph对象网关多站点介绍

要了解多站点设置,首先需要了解一些多站点的关键组件:Realm、Zone、Zonegroup和Period。

Realm:代表由一个或多个Zonegroup组成的唯一的全局命名空间。每个Zonegroup包含一个或
多个Zone,每个Zone包含存储对象数据的桶。Realm还包含Period,每个Period展示某一时间段内Zonegroup和Zone配置的状态。

Period:每个Period展示唯一的ID和Epoch。每次提交操作都会增加Period中的Epoch。每个Realm都有一个关联的当前Period,其中包含Zonegroup和存储策略的当前配置状态。每次更改Zonegroup或Zone时操作Period并提交。每个Cluster Map都保留其版本的历史记录。这些版本中的每一个版本都称为一个Epoch。

Zone:由一个或多个Ceph对象网关实例组成的逻辑组。Zone的配置不同于典型的Ceph配置,因
为并非所有设置最终都存储在Ceph配置文件中。Zonegroup中必须指定一个Zone为主Zone。主Zone将处理所有桶和用户请求。从Zone可以接收桶和用户请求,但会将它们重定向到主Zone。如果主Zone崩溃,桶和用户请求处理失败。我们可以将从Zone升级为主Zone。但是,升级从Zone为主Zone是一项复杂的操作,建议仅在主Zone长时间崩溃时执行。

Zonegroup:由多个Zone组成,应该有一个主Zonegroup来处理对系统配置的更改。

Ceph多站点构成关系示意图:

② 配置多站点对象网关实现容灾

在配置多站点对象网关之前,假定你已经安装了两个集群,并且每个集群都正常工作。同时,每
个集群都有独立的对象网关。

如下图所示,主站点集群有3个节点,server a、server b、server c,灾备集群有3个节点,server 1、server 2、server 3。每个节点都安装了对象网关。接下来按照图配置多站点对象网关,实现Ceph对象存储容灾方案。

1)检查集群运行状态。

① 检查集群dc1的运行状态。

[root@0bastion ~]# ceph -s --cluster dc1
cluster:
id: e4ddfba3-c51c-40da-b57f-9d16ba1ac1f2
health: HEALTH_OK
services:
mon: 3 daemons, quorum cepha,cephb,cephc
mgr: cephb(active), standbys: cepha, cephc
osd: 6 osds: 6 up, 6 in
rgw: 3 daemons active
data:
pools: 4 pools, 32 pgs
objects: 206 objects, 2.76KiB
usage: 6.05GiB used, 53.9GiB / 60.0GiB avail
pgs: 32 active+clean

② 检查集群dc2的运行状态。

[root@0bastion ~]# ceph -s --cluster dc2
cluster:
id: e4ddfba3-c51c-40da-b57f-9d16ba1ac1f2
health: HEALTH_WARN
3 osds down
services:
mon: 3 daemons, quorum ceph1,ceph2,ceph3
mgr: ceph3(active), standbys: ceph1
osd: 6 osds: 3 up, 6 in
rgw: 3 daemons active
data:
pools: 4 pools, 32 pgs
objects: 207 objects, 3.08KiB
usage: 6.03GiB used, 54.0GiB / 60.0GiB avail
pgs: 32 active+clean

2)在集群dc1上创建名为realmdr的Realm。

[root@0bastion ~]# radosgw-admin realm create --rgw-realm=realmdr --default
--cluster dc1
{
"id": "f928689d-c15c-4f7e-a862-987e73c67a8a",
"name": "realmdr",
"current_period": "dac086e0-b290-4c7e-b943-c9ed118c133c",
"epoch": 1
}

3)删除集群dc1上的default Zonegroup。

[root@0bastion ~]# radosgw-admin zonegroup delete --rgw-zonegroup=default
--cluster dc1

4)在集群dc1上创建名为groupdr的Zonegroup。

[root@0bastion ~]# radosgw-admin zonegroup create --rgw-zonegroup=groupdr
--endpoints=http://cepha:8080,http://cephb:8080,http://cephc:8080
--master --default --cluster dc1
{
"id": "3236ae57-130a-40ee-bc47-1e3d50ba34b2",
"name": "groupdr",
"api_name": "groupdr",
"is_master": "true",
"endpoints": [
"http://cepha:8080",
"http://cephb:8080",
"http://cephc:8080"
],
"hostnames": [],
"hostnames_s3website": [],
"master_zone": "",
"zones": [],
"placement_targets": [],
"default_placement": "",
"realm_id": "f928689d-c15c-4f7e-a862-987e73c67a8a"
}

5)在集群dc1上创建名为main的主Zone。

[root@0bastion ~]# radosgw-admin --cluster dc1 zone create --rgwzonegroup=
groupdr --rgw-zone=main --endpoints==http://cepha:8080,
http://cephb:8080,http://cephc:8080 --master --default
{
"id": "7790fbbd-36a2-4c3b-8fb4-f472cd776fda",
"name": "main",
"domain_root": "main.rgw.meta:root",
"control_pool": "main.rgw.control",
"gc_pool": "main.rgw.log:gc",
"lc_pool": "main.rgw.log:lc",
"log_pool": "main.rgw.log",
"intent_log_pool": "main.rgw.log:intent",
"usage_log_pool": "main.rgw.log:usage",
"reshard_pool": "main.rgw.log:reshard",
"user_keys_pool": "main.rgw.meta:users.keys",
"user_email_pool": "main.rgw.meta:users.email",
"user_swift_pool": "main.rgw.meta:users.swift",
"user_uid_pool": "main.rgw.meta:users.uid",
"system_key": {
"access_key": "",
"secret_key": ""
},
"placement_pools": [
{
"key": "default-placement",
"val": {
"index_pool": "main.rgw.buckets.index",
"data_pool": "main.rgw.buckets.data",
"data_extra_pool": "main.rgw.buckets.non-ec",
"index_type": 0,
"compression": ""
}
}
],
"metadata_heap": "",
"tier_config": [],
"realm_id": "f928689d-c15c-4f7e-a862-987e73c67a8a"
}

6)在集群dc1上检查创建结果。

[root@0bastion ~]# radosgw-admin --cluster dc1 realm list
{
"default_info": "f928689d-c15c-4f7e-a862-987e73c67a8a",
"realms": [
"realmdr"
]
}
[root@0bastion ~]# radosgw-admin --cluster dc1 zonegroup list
{
"default_info": "3236ae57-130a-40ee-bc47-1e3d50ba34b2",
"zonegroups": [
"groupdr"
]
}
[root@0bastion ~]# radosgw-admin --cluster dc1 zone list
{
"default_info": "7790fbbd-36a2-4c3b-8fb4-f472cd776fda",
"zones": [
"main",
"default"
]
} [
root@0bastion ~]# radosgw-admin --cluster dc1 zonegroup get groupdr| grep
-A 3 endpoints
"endpoints": [
"http://cepha:8080",
"http://cephb:8080",
"http://cephc:8080"
--
"endpoints": [
"http://cepha:8080",
"http://cephb:8080",
"http://cephc:8080"

7)在集群dc1上创建同步用户syncuser。

[root@0bastion ~]# radosgw-admin --cluster dc1 user create --uid=syncuser
--display-name="Synchronization User" --access-key=synckey
--secret=synckey --system
{
"user_id": "syncuser",
"display_name": "Synchronization User",
"email": "",
"suspended": 0,
"max_buckets": 1000,
"auid": 0,
"subusers": [],
"keys": [
{
"user": "syncuser",
"access_key": "synckey",
"secret_key": "synckey"
}
],
"swift_keys": [],
"caps": [],
"op_mask": "read, write, delete",
"system": "true",
"default_placement": "",
"placement_tags": [],
"bucket_quota": {
"enabled": false,
"check_on_raw": false,
"max_size": -1,
"max_size_kb": 0,
"max_objects": -1
},
"user_quota": {
"enabled": false,
"check_on_raw": false,
"max_size": -1,
"max_size_kb": 0,
"max_objects": -1
},
"temp_url_keys": [],
"type": "rgw"
}

8)在集群dc1上将同步用户syncuser分配给主Zone。

[root@0bastion ~]# radosgw-admin --cluster dc1 zone modify --rgw-zone=main
--access-key=synckey --secret=synckey {
"id": "7790fbbd-36a2-4c3b-8fb4-f472cd776fda",
"name": "main",
"domain_root": "main.rgw.meta:root",
"control_pool": "main.rgw.control",
"gc_pool": "main.rgw.log:gc",
"lc_pool": "main.rgw.log:lc",
"log_pool": "main.rgw.log",
"intent_log_pool": "main.rgw.log:intent",
"usage_log_pool": "main.rgw.log:usage",
"reshard_pool": "main.rgw.log:reshard",
"user_keys_pool": "main.rgw.meta:users.keys",
"user_email_pool": "main.rgw.meta:users.email",
"user_swift_pool": "main.rgw.meta:users.swift",
"user_uid_pool": "main.rgw.meta:users.uid",
"system_key": {
"access_key": "synckey",
"secret_key": "synckey"
},
"placement_pools": [
{
"key": "default-placement",
"val": {
"index_pool": "main.rgw.buckets.index",
"data_pool": "main.rgw.buckets.data",
"data_extra_pool": "main.rgw.buckets.non-ec",
"index_type": 0,
"compression": ""
}
}
],
"metadata_heap": "",
"tier_config": [],
"realm_id": "f928689d-c15c-4f7e-a862-987e73c67a8a"
}

9)保存Zonegroup和存储配置策略的当前状态,并提交到Period。

[root@0bastion ~]# radosgw-admin --cluster dc1 period update --commit
{
"id": "1ada6d63-4d0a-4ac4-b39b-71f65565d8fd",
"epoch": 1,
"predecessor_uuid": "dac086e0-b290-4c7e-b943-c9ed118c133c",
"sync_status": [],
"period_map": {
"id": "1ada6d63-4d0a-4ac4-b39b-71f65565d8fd",
"zonegroups": [
{
"id": "3236ae57-130a-40ee-bc47-1e3d50ba34b2",
"name": "groupdr",
"api_name": "groupdr",
"is_master": "true",
"endpoints": [
"http://cepha:8080",
"http://cephb:8080",
"http://cephc:8080"
],
"hostnames": [],
"hostnames_s3website": [],
"master_zone": "7790fbbd-36a2-4c3b-8fb4-f472cd776fda",
"zones": [
{
"id": "7790fbbd-36a2-4c3b-8fb4-f472cd776fda",
"name": "main",
"endpoints": [
"http://cepha:8080",
"http://cephb:8080",
"http://cephc:8080"
],
"log_meta": "false",
"log_data": "false",
"bucket_index_max_shards": 0,
"read_only": "false",
"tier_type": "",
"sync_from_all": "true",
"sync_from": []
}
],
"placement_targets": [
{
"name": "default-placement",
"tags": []
}
],
"default_placement": "default-placement",
"realm_id": "f928689d-c15c-4f7e-a862-987e73c67a8a"
}
],
"short_zone_ids": [
{
"key": "7790fbbd-36a2-4c3b-8fb4-f472cd776fda",
"val": 3731757859
}
]
},
"master_zonegroup": "3236ae57-130a-40ee-bc47-1e3d50ba34b2",
"master_zone": "7790fbbd-36a2-4c3b-8fb4-f472cd776fda",
"period_config": {
"bucket_quota": {
"enabled": false,
"check_on_raw": false,
"max_size": -1,
"max_size_kb": 0,
"max_objects": -1
},
"user_quota": {
"enabled": false,
"check_on_raw": false,
"max_size": -1,
"max_size_kb": 0,
"max_objects": -1
}
},
"realm_id": "f928689d-c15c-4f7e-a862-987e73c67a8a",
"realm_name": "realmdr",
"realm_epoch": 2
}

10)在集群dc1上修改cepha、cephb、cephc三个节点的配置文件。

注意:三个节点都要修改,并添加如下加粗内容。

[root@cepha ~]# vim /etc/ceph/ceph.conf
...output omitted...
[client.rgw.cepha]
debug_civetweb = 0/1
host = cepha
keyring = /var/lib/ceph/radosgw/ceph-rgw.cepha/keyring
log file = /var/log/ceph/ceph-rgw-cepha.log
rgw frontends = civetweb port=10.0.0.11:8080 num_threads=1024
rgw_enable_apis = s3,admin
rgw_thread_pool_size = 1024
rgw_zone = main
rgw_dynamic_resharding = false
[client.rgw.cephb]
debug_civetweb = 0/1
host = cephb
keyring = /var/lib/ceph/radosgw/ceph-rgw.cephb/keyring
log file = /var/log/ceph/ceph-rgw-cephb.log
rgw frontends = civetweb port=10.0.0.12:8080 num_threads=1024
rgw_enable_apis = s3,admin
rgw_thread_pool_size = 1024
rgw_zone = main
rgw_dynamic_resharding = false
[client.rgw.cephc]
debug_civetweb = 0/1
host = cephc
keyring = /var/lib/ceph/radosgw/ceph-rgw.cephc/keyring
log file = /var/log/ceph/ceph-rgw-cephc.log
rgw frontends = civetweb port=10.0.0.13:8080 num_threads=1024
rgw_enable_apis = s3,admin
rgw_thread_pool_size = 1024
rgw_zone = main
rgw_dynamic_resharding = false

11)重启集群dc1上的3个对象网关:cepha、cephb、cephc。

[root@bastion ceph-ansible]# cd ~/dc1/ceph-ansible/
[root@0bastion ceph-ansible]# for i in a b c; do ansible -b -i inventory
-m shell -a "systemctl restart ceph-radosgw@rgw.ceph${i}.service"
ceph${i}; done
cepha | SUCCESS | rc=0 >>
cephb | SUCCESS | rc=0 >>
cephc | SUCCESS | rc=0 >>

12)在集群dc1上获取对象网关的运行状态。

[root@0bastion ceph-ansible]# ceph --cluster dc1 -s | grep -i rgw
rgw: 3 daemons active

13)在集群dc2上拉取集群dc1中创建的 Realm。

[root@0bastion ceph-ansible]# radosgw-admin --cluster dc2 realm pull
--url=http://cepha:8080 --access-key=synckey --secret=synckey --rgwrealm=
realmdr
2021-03-15 09:13:55.270445 7f3c8ff25e00 1 error read_lastest_epoch .rgw.
root:periods.1ada6d63-4d0a-4ac4-b39b-71f65565d8fd.latest_epoch
2021-03-15 09:13:55.329264 7f3c8ff25e00 1 Set the period's master zonegroup
3236ae57-130a-40ee-bc47-1e3d50ba34b2 as the default
{
"id": "f928689d-c15c-4f7e-a862-987e73c67a8a",
"name": "realmdr",
"current_period": "1ada6d63-4d0a-4ac4-b39b-71f65565d8fd",
"epoch": 2
}

14)在集群dc2上设置拉取的Realm为默认Realm。

[root@0bastion ceph-ansible]# radosgw-admin --cluster dc2 realm default
--rgw-realm=realmdr

15)在集群dc2上执行命令,实现从集群dc1上拉取Period信息。

[root@0bastion ceph-ansible]# radosgw-admin --cluster dc2 period pull
--url=http://cepha:8080 --access-key=synckey --secret=synckey
2021-03-15 09:19:03.131932 7f93a95e9e00 1 found existing latest_epoch 1 given epoch 1, returning r=-17
{
"id": "1ada6d63-4d0a-4ac4-b39b-71f65565d8fd",
"epoch": 1,
"predecessor_uuid": "dac086e0-b290-4c7e-b943-c9ed118c133c",
"sync_status": [],
"period_map": {
"id": "1ada6d63-4d0a-4ac4-b39b-71f65565d8fd",
"zonegroups": [
{
"id": "3236ae57-130a-40ee-bc47-1e3d50ba34b2",
"name": "groupdr",
"api_name": "groupdr",
"is_master": "true",
"endpoints": [
"http://cepha:8080",
"http://cephb:8080",
"http://cephc:8080"
],
"hostnames": [],
"hostnames_s3website": [],
"master_zone": "7790fbbd-36a2-4c3b-8fb4-f472cd776fda",
"zones": [
{
"id": "7790fbbd-36a2-4c3b-8fb4-f472cd776fda",
"name": "main",
"endpoints": [
"http://cepha:8080",
"http://cephb:8080",
"http://cephc:8080"
],
"log_meta": "false",
"log_data": "false",
"bucket_index_max_shards": 0,
"read_only": "false",
"tier_type": "",
"sync_from_all": "true",
"sync_from": []
}
],
"placement_targets": [
{
"name": "default-placement",
"tags": []
}
],
"default_placement": "default-placement",
"realm_id": "f928689d-c15c-4f7e-a862-987e73c67a8a"
}
],
"short_zone_ids": [
{
"key": "7790fbbd-36a2-4c3b-8fb4-f472cd776fda",
"val": 3731757859
}
]
},
"master_zonegroup": "3236ae57-130a-40ee-bc47-1e3d50ba34b2",
"master_zone": "7790fbbd-36a2-4c3b-8fb4-f472cd776fda",
"period_config": {
"bucket_quota": {
"enabled": false,
"check_on_raw": false,
"max_size": -1,
"max_size_kb": 0,
"max_objects": -1
},
"user_quota": {
"enabled": false,
"check_on_raw": false,
"max_size": -1,
"max_size_kb": 0,
"max_objects": -1
}
},
"realm_id": "f928689d-c15c-4f7e-a862-987e73c67a8a",
"realm_name": "realmdr",
"realm_epoch": 2
}

16)在集群dc2上创建名为fallback的从Zone。

[root@0bastion ceph-ansible]# radosgw-admin --cluster dc2 zone create --groupdr --rgw-zone=fallback --endpoints=http://ceph1:8080,
http://ceph2:8080,http://ceph3:8080 --access-key=synckey --secret=synckey
2021-03-15 09:24:10.424588 7f828b790e00 0 failed reading obj info from.
rgw.root:zone_info.7790fbbd-36a2-4c3b-8fb4-f472cd776fda: (2) No such
file or directory
2021-03-15 09:24:10.424727 7f828b790e00 0 WARNING: could not read zone
params for zone id=7790fbbd-36a2-4c3b-8fb4-f472cd776fda name=main
{
"id": "b6531f6d-4236-40c3-9054-4beac97e76aa",
"name": "fallback",
"domain_root": "fallback.rgw.meta:root",
"control_pool": "fallback.rgw.control",
"gc_pool": "fallback.rgw.log:gc",
"lc_pool": "fallback.rgw.log:lc",
"log_pool": "fallback.rgw.log",
"intent_log_pool": "fallback.rgw.log:intent",
"usage_log_pool": "fallback.rgw.log:usage",
"reshard_pool": "fallback.rgw.log:reshard",
"user_keys_pool": "fallback.rgw.meta:users.keys",
"user_email_pool": "fallback.rgw.meta:users.email",
"user_swift_pool": "fallback.rgw.meta:users.swift",
"user_uid_pool": "fallback.rgw.meta:users.uid",
"system_key": {
"access_key": "synckey",
"secret_key": "synckey"
},
"placement_pools": [
{
"key": "default-placement",
"val": {
"index_pool": "fallback.rgw.buckets.index",
"data_pool": "fallback.rgw.buckets.data",
"data_extra_pool": "fallback.rgw.buckets.non-ec",
"index_type": 0,
"compression": ""
}
}
],
"metadata_heap": "",
"tier_config": [],
"realm_id": "f928689d-c15c-4f7e-a862-987e73c67a8a"
}

17)在集群dc2上提交Period信息。一旦Period信息提交成功,主Zone中的dc1就知道它有从Zone
信息要同步。

[root@0bastion ceph-ansible]# radosgw-admin --cluster dc2 period update 2021-03-15 09:27:31.639020 7fb096385e00 1 Cannot find zone id=b6531f6d-
4236-40c3-9054-4beac97e76aa (name=fallback), switching to local
zonegroup configuration
Sending period to new master zone 7790fbbd-36a2-4c3b-8fb4-f472cd776fda
{
"id": "1ada6d63-4d0a-4ac4-b39b-71f65565d8fd",
"epoch": 2,
"predecessor_uuid": "dac086e0-b290-4c7e-b943-c9ed118c133c",
"sync_status": [],
"period_map": {
"id": "1ada6d63-4d0a-4ac4-b39b-71f65565d8fd",
"zonegroups": [
{
"id": "3236ae57-130a-40ee-bc47-1e3d50ba34b2",
"name": "groupdr",
"api_name": "groupdr",
"is_master": "true",
"endpoints": [
"http://cepha:8080",
"http://cephb:8080",
"http://cephc:8080"
],
"hostnames": [],
"hostnames_s3website": [],
"master_zone": "7790fbbd-36a2-4c3b-8fb4-f472cd776fda",
"zones": [
{
"id": "7790fbbd-36a2-4c3b-8fb4-f472cd776fda",
"name": "main",
"endpoints": [
"http://cepha:8080",
"http://cephb:8080",
"http://cephc:8080"
],
"log_meta": "false",
"log_data": "true",
"bucket_index_max_shards": 0,
"read_only": "false",
"tier_type": "",
"sync_from_all": "true",
"sync_from": []
},
{
"id": "b6531f6d-4236-40c3-9054-4beac97e76aa",
"name": "fallback",
"endpoints": [
"http://ceph1:8080",
"http://ceph2:8080",
"http://ceph3:8080"
],
"log_meta": "false",
"log_data": "true",
"bucket_index_max_shards": 0,
"read_only": "false",
"tier_type": "",
"sync_from_all": "true",
"sync_from": []
}
],
"placement_targets": [
{
"name": "default-placement",
"tags": []
}
],
"default_placement": "default-placement",
"realm_id": "f928689d-c15c-4f7e-a862-987e73c67a8a"
}
],
"short_zone_ids": [
{
"key": "7790fbbd-36a2-4c3b-8fb4-f472cd776fda",
"val": 3731757859
},
{
"key": "b6531f6d-4236-40c3-9054-4beac97e76aa",
"val": 2712233240
}
]
},
"master_zonegroup": "3236ae57-130a-40ee-bc47-1e3d50ba34b2",
"master_zone": "7790fbbd-36a2-4c3b-8fb4-f472cd776fda",
"period_config": {
"bucket_quota": {
"enabled": false,
"check_on_raw": false,
"max_size": -1,
"max_size_kb": 0,
"max_objects": -1
},
"user_quota": {
"enabled": false,
"check_on_raw": false,
"max_size": -1,
"max_size_kb": 0,
"max_objects": -1
}
},
"realm_id": "f928689d-c15c-4f7e-a862-987e73c67a8a",
"realm_name": "realmdr",
"realm_epoch": 2
}

18)在集群dc2上修改ceph1、ceph2、ceph3节点的配置文件。

注意:这三个节点都要修改,并添加如下加粗内容。

[root@ceph1 ~]# vim /etc/ceph/ceph.conf
...output omitted...
[client.rgw.ceph1]
debug_civetweb = 0/1
host = ceph1
keyring = /var/lib/ceph/radosgw/ceph-rgw.ceph1/keyring
log file = /var/log/ceph/ceph-rgw-ceph1.log
rgw frontends = civetweb port=172.16.0.11:8080 num_threads=1024
rgw_enable_apis = s3,admin
rgw_thread_pool_size = 1024
rgw_zone = fallback
rgw_dynamic_resharding = false
[client.rgw.ceph2]
debug_civetweb = 0/1
host = ceph2
keyring = /var/lib/ceph/radosgw/ceph-rgw.ceph2/keyring
log file = /var/log/ceph/ceph-rgw-ceph2.log
rgw frontends = civetweb port=172.16.0.12:8080 num_threads=1024
rgw_enable_apis = s3,admin
rgw_thread_pool_size = 1024
rgw_zone = fallback
rgw_dynamic_resharding = false
[client.rgw.ceph3]
debug_civetweb = 0/1
host = ceph3
keyring = /var/lib/ceph/radosgw/ceph-rgw.ceph3/keyring
log file = /var/log/ceph/ceph-rgw-ceph3.log
rgw frontends = civetweb port=172.16.0.13:8080 num_threads=1024
rgw_enable_apis = s3,admin
rgw_thread_pool_size = 1024
rgw_zone = fallback
rgw_dynamic_resharding = false

19)在集群dc2上重启3个对象网关。

[root@0bastion ceph-ansible]# cd ~/dc2/ceph-ansible/
[root@0bastion ceph-ansible]# for i in 1 2 3 ; do ansible -b -i inventory
-m shell -a "systemctl restart ceph-radosgw@rgw.ceph${i}.service"
ceph${i}; done
ceph1 | SUCCESS | rc=0 >>
ceph2 | SUCCESS | rc=0 >>
ceph3 | SUCCESS | rc=0 >>

20)检查同步状态。

[root@0bastion ceph-ansible]# radosgw-admin --cluster dc1 sync status
realm f928689d-c15c-4f7e-a862-987e73c67a8a (realmdr)
zonegroup 3236ae57-130a-40ee-bc47-1e3d50ba34b2 (groupdr)
zone 7790fbbd-36a2-4c3b-8fb4-f472cd776fda (main)
metadata sync no sync (zone is master)
data sync source: b6531f6d-4236-40c3-9054-4beac97e76aa (fallback)
syncing
full sync: 0/128 shards
incremental sync: 128/128 shards
data is caught up with source
[root@0bastion ceph-ansible]# radosgw-admin --cluster dc2 sync status
realm f928689d-c15c-4f7e-a862-987e73c67a8a (realmdr)
zonegroup 3236ae57-130a-40ee-bc47-1e3d50ba34b2 (groupdr)
zone b6531f6d-4236-40c3-9054-4beac97e76aa (fallback)
metadata sync syncing
full sync: 0/64 shards
incremental sync: 64/64 shards
metadata is caught up with master
data sync source: 7790fbbd-36a2-4c3b-8fb4-f472cd776fda (main)
syncing
full sync: 0/128 shards
incremental sync: 128/128 shards
data is caught up with source

21)使用s3cmd在集群dc1上创建Bucket。

[root@0bastion ~]# s3cmd -c s3-dc1.cfg mb s3://my-first-bucket
Bucket 's3://my-first-bucket/' created

22)使用s3cmd在集群dc2上查看Bucket。

[root@0bastion ~]# s3cmd -c s3-dc2.cfg ls
2021-03-15 14:07 s3://my-first-bucket

至此,我们实现了Ceph的对象容灾复制。

2、RBD块存储容灾

RBD Mirror的核心原理是使用日志回放(Journal Replay)功能保证主集群RBD和次集群
RBD的数据副本一致。注意,这里的日志并不是Ceph OSD日志。配置RBD映像可以在不同的Ceph集群之间实现RBD块设备的异步复制,以实现容灾。此机制使用异步操作在网络上将主RBD Image复制到目标从RBD Image。

如果主RBD Image的集群不可用,你可以使用远程集群上的从RBD Image,然后重新启动该映像的应用程序。从Source RBD Image故障转移到Mirror RBD Image时,必须降级Source RBD Image,同时升级Target RBD Image。Image降级后,将变为锁定且不可用状态;升级后,将进入读写模式,可被使用。RBD映像功能需要rbd-mirror软件包。该软件包需要安装在两个集群的服务器上,并且每个Ceph集群必须至少配置一个Mirror Agent。

① 数据复制方向

RBD Mirror支持两种复制:单向复制、双向复制。在单向复制下,主集群的RBD Image读/写可
用,而远程从集群仅容纳镜像,并不提供对外服务。Mirror agent仅在从集群上,Mirror是从集群上
运行的Mirror Agent远程拉取主集群上的RBD Image。此模式下,你可以配置多个辅从集群。

RBD Mirror单向复制的数据流向:

在双向复制下,每个RBD Mirror实例必须能够同时连接到另一个Ceph集群。此外,网络必须在两
个数据中心站点之间具有足够的带宽,以处理镜像。

下是双向复制模式下的数据流向。这里要强调的是,虽然是双向复制模式,但是并不是业务双活,不能同时在两个集群中对相同的RBD数据进行读写。因为Ceph的RBD Mirror是异步的。双向复制模式要求单向写入,一旦主集群不可写,就可以配置从集群作为读写集群,待主集群恢复后,从集群RBD映射到主集群。本质上,双向复制和单向复制操作机制一样。

RBD Mirror双向复制数据流向:

②  数据复制模式

RBD Mirror有两种复制模式:Pool和Image。在Pool模式下,Mirror Pool中创建的每个RBD
Image自动启动Mirror开始同步。在主站点Mirror Pool中创建Image后,远程备站点自动创建副本
Image。

在Image模式下,必须为每个RBD Image分别启动Mirror,并且必须明确指定要在两个集群之间复制的RBD Image。

③ 配置RBD Mirror

配置双向复制和单向复制的方法非常类似,只是在单向复制的基础上,反向配置一次即可。本节
将只以配置单向复制为例进行讲解。配置开始前,假定两个Ceph集群(分别叫dc1和dc2)已经安装完毕,功能都正常开启。dc1有3个节点,cepha、cephb、cephc;dc2有3个节点,ceph1、ceph2、ceph3。另外有一台部署服务器bastion。你可以将bastion作为在两个集群上安装基础服务软件的客户端。

服务器规划结构:

配置RBD Mirror的方式有多种,你可以通过ceph-ansible中提供的playbook快速配置。为了了解
playbook中具体的配置,这里使用命令行进行配置。

1)在集群dc2上安装rbd-mirror。

在集群dc2内规划一个客户端–服务器,安装rbd-mirror包。通过在该客户端–服务器上配置rbdmirror功能,实现将dc1中的Image同步到dc2内相同的池中。为了简化操作,这里选择在集群dc2的ceph1节点上安装rbd-mirror服务。

[root@0bastion ceph-ansible]# ansible -b -i inventory -m shell -a "yum
install -y rbd-mirror" ceph1
ceph1 | SUCCESS | rc=0 >>
Loaded plugins: search-disabled-repos
Resolving Dependencies
--> Running transaction check
---> Package rbd-mirror.x86_64 2:12.2.8-89.el7cp will be installed
--> Finished Dependency Resolution
...output omitted...
Complete!Repository 'rhel-7-server-extras-rpms' is missing name in
configuration, using id
Repository 'rhel-7-server-rpms' is missing name in configuration, using Repository 'rhel-7-server-rhceph-3-tools-rpms' is missing name in
configuration, using id

2)在两个集群上创建要同步的池名称,本例为rbd。

[root@0bastion ceph-ansible]# ceph osd pool create rbd 128 128 --cluster pool 'rbd' created
[root@0bastion ceph-ansible]# ceph osd pool application enable rbd rbd
--cluster dc1
enabled application 'rbd' on pool 'rbd'
[root@0bastion ceph-ansible]# ceph osd pool create rbd 128 128 --cluster pool 'rbd' created
[root@0bastion ceph-ansible]# ceph osd pool application enable rbd rbd
--cluster dc2
enabled application 'rbd' on pool 'rbd'

3)设置单复制模式为Pool模式。

[root@0bastion ceph-ansible]# rbd mirror pool enable rbd pool --cluster [root@0bastion ceph-ansible]# rbd mirror pool enable rbd pool --

4)在集群dc1和dc2中创建同步用户。

[root@0bastion ceph-ansible]# ceph auth get-or-create client.dc1 mon
'profile rbd' osd 'profile rbd pool rbd' -o /etc/ceph/dc1.client.dc1.
keyring --cluster dc1
[root@0bastion ceph-ansible]# ceph auth get-or-create client.dc2 mon
'profile rbd' osd 'profile rbd pool rbd' -o /etc/ceph/dc2.client.dc2.
keyring --cluster dc2

5)将创建的keyring复制到集群dc1和dc2的MON节点上。

[root@0bastion dc1]# cd /root/dc1/ceph-ansible/
[root@0bastion ceph-ansible]# for i in a b c; do ansible -b -i inventory copy -a "src=/etc/ceph/ dest=/etc/ceph/" ceph${i};done
cepha | SUCCESS => {
"changed": true,
"dest": "/etc/ceph/",
"src": "/etc/ceph/"
}
cephb | SUCCESS => {
"changed": true,
"dest": "/etc/ceph/",
"src": "/etc/ceph/"
} cephc |
SUCCESS => {
"changed": true,
"dest": "/etc/ceph/",
"src": "/etc/ceph/"
} [
root@0bastion ceph-ansible]# cd /
root/dc2/ceph-ansible/
[root@0bastion ceph-ansible]# for i in 1 2 3; do ansible -b -i inventory copy -a "src=/etc/ceph/ dest=/etc/ceph/" ceph${i};done
ceph1 | SUCCESS => {
"changed": true,
"dest": "/etc/ceph/",
"src": "/etc/ceph/"
} ceph2 |
SUCCESS => {
"changed": true,
"dest": "/etc/ceph/",
"src": "/etc/ceph/"
} ceph3 |
SUCCESS => {
"changed": true,
"dest": "/etc/ceph/",
"src": "/etc/ceph/"
}

6)修改复制文件的权限。

[root@0bastion ceph-ansible]# cd /root/dc2/ceph-ansible/
[root@0bastion ceph-ansible]# for i in 1 2 3; do ansible -b -i inventory shell -a "chown ceph:ceph /etc/ceph/*" ceph${i};done
[WARNING]: Consider using file module with owner rather than running chown
ceph1 | SUCCESS | rc=0 >>
[WARNING]: Consider using file module with owner rather than running chown
ceph2 | SUCCESS | rc=0 >>
[WARNING]: Consider using file module with owner rather than running chown
ceph3 | SUCCESS | rc=0 >>
[root@0bastion ceph-ansible]# cd /root/dc1/ceph-ansible/
[root@0bastion ceph-ansible]# for i in a b c; do ansible -b -i inventory shell -a "chown ceph:ceph /etc/ceph/*" ceph${i};done
[WARNING]: Consider using file module with owner rather than running chown
cepha | SUCCESS | rc=0 >>
[WARNING]: Consider using file module with owner rather than running chown
cephb | SUCCESS | rc=0 >>
[WARNING]: Consider using file module with owner rather than running chown
cephc | SUCCESS | rc=0 >>

7)在集群dc2中使能和启动rbd-mirror功能。

步骤1)中规划的RBD Mirror服务所在节点为ceph1节点,因此在ceph1节点中启动RBD Mirror服
务。

[root@0bastion ceph-ansible]# ansible -b -i inventory -m shell -a "systemctl
enable ceph-rbd-mirror.target;systemctl enable ceph-rbd-mirror@dc2;
systemctl start ceph-rbd-mirror@dc2" ceph1
ceph1 | SUCCESS | rc=0 >>
Created symlink from /etc/systemd/system/multi-user.target.wants/ceph-rbdmirror.
target to /usr/lib/systemd/system/ceph-rbd-mirror.target.
Created symlink from /etc/systemd/system/ceph.target.wants/ceph-rbd-mirror.
target to /usr/lib/systemd/system/ceph-rbd-mirror.target.
Created symlink from /etc/systemd/system/ceph-rbd-mirror.target.wants/cephrbd-
mirror@dc2.service to /usr/lib/systemd/system/ceph-rbd-mirror@.service.

8)登录ceph1节点,修改/usr/lib/systemd/system/ceph-rbd-mirror@.service,设置CLUSTER环境变量为dc2。

[Unit]
Description=Ceph rbd mirror daemon
After=network-online.target local-fs.target
Wants=network-online.target local-fs.target
PartOf=ceph-rbd-mirror.target
[Service]
LimitNOFILE=1048576
LimitNPROC=1048576
EnvironmentFile=-/etc/sysconfig/ceph
Environment=CLUSTER=dc2
ExecStart=/usr/bin/rbd-mirror -f --cluster ${CLUSTER} --id %i --setuser
ceph --setgroup ceph
ExecReload=/bin/kill -HUP $MAINPID
PrivateDevices=yes
ProtectHome=true
ProtectSystem=full
PrivateTmp=true
Restart=on-failure
StartLimitInterval=30min
StartLimitBurst=3
TasksMax=infinity
[Install]
WantedBy=ceph-rbd-mirror.target

9)重启ceph1节点的ceph-rbdmirror@dc2.service服务。

[root@0bastion ceph-ansible]# ansible -b -i inventory -m shell -a "systemctl
daemon-reload;systemctl restart ceph-rbd-mirror@dc2" ceph1
ceph1 | SUCCESS | rc=0 >>

10)指定RBD池进行两集群配对同步,在集群 dc2上执行不同命令。

[root@0bastion ceph-ansible]# rbd --cluster dc2 mirror pool peer add rbd
client.dc1@dc1 -n client.dc2
c5702aab-0321-4758-8c02-c46809348ab2
[root@0bastion ceph-ansible]# rbd mirror pool status rbd --cluster dc2
health: OK
images: 0 total
[root@0bastion ceph-ansible]# rbd mirror pool status rbd --cluster dc1
health: OK
images: 0 total

11)在dc1的RBD池中创建Image,开启exclusive-lock,journaling功能特性。

[root@0bastion ceph-ansible]# rbd create image1 --size 1024 --pool rbd
--image-feature exclusive-lock,journaling --cluster dc1
[root@0bastion ceph-ansible]# rbd ls -p rbd --cluster dc1
image1

12)查看同步状态。

[root@0bastion ceph-ansible]# rbd mirror image status rbd/image1 --cluster image1:
global_id: a405f5f1-82f4-4ede-b975-0c8922f9f765
state: down+unknown
description: status not found
last_update:
[root@0bastion ceph-ansible]# rbd mirror image status rbd/image1 --cluster image1:
global_id: a405f5f1-82f4-4ede-b975-0c8922f9f765
state: up+replaying
description: replaying, master_position=[object_number=3, tag_tid=1,
entry_tid=3], mirror_position=[object_number=3, tag_tid=1, entry_tid=entries_behind_master=0
last_update: 2021-03-21 06:00:57
[root@0bastion ceph-ansible]# rbd ls --cluster dc2
image1

至此,我们已经配置好了rbd-mirror,在集群dc2上已经看到集群dc1上创建的块设备image1。

3、文件存储容灾

Ceph没有专门为CephFS设置容灾备份的集成方案,而是考虑到CephFS已经是文件形式的存储,
用户的最终使用习惯和操作系统上的一样,所以考虑使用网络备份软件来设置容灾的集成方案。如果CephFS的元数据损坏,Ceph提供了修复工具cephfs-journal-tool。

具体可以通过第三方NBU方案实现备份。

十、Ceph调优

开发人员经过多年的研究,已经在Linux操作系统和Ceph自身性能上进行了优化。但是,每套Ceph集群的规模配置都有差别,很难给出一个万能的参数让性能达到预期。因此,你需要在Ceph集群建设完毕后对集群的性能进行测试,获取相应的测试指标,并针对测试指标对Ceph集群进行调优。

当然,要综合考虑各方面因素进行调优,避免调好了一个性能指标,而使另一个性能指标降低,始终不能获得良好的整体性能。理想的情况是,尽量减少软件层面带来的性能损耗,尽可能大地发挥硬件的性能优势。

1、性能指标

性能调优是为Ceph集群定制一个或多个系统的过程,以便使Ceph具有最佳的响应时间或吞吐量。
衡量Ceph集群的性能有3个维度:延迟、IOPS和吞吐量。

(1)延迟

有人误以为磁盘延迟和响应时长是一回事,实际上磁盘延迟涉及设备功能,响应时长涉及整个服
务器功能。对于使用旋转盘片的硬盘驱动器,磁盘延迟包括两个部分:搜索时间、旋转等待时间。

1)搜索时间:驱动器磁头放置在盘片的正确轨道上所花费的时间,通常为0.2至0.8毫秒。

2)旋转等待时间:该轨道上正确的起始扇区在驱动器磁头下通过所花费的时间,该值取决于驱
动速度。对于5400 RPM硬盘,旋转等待时间为5.6毫秒;对于7200 RPM硬盘,旋转等待时间为4.2毫秒;对于10000 RPM硬盘,旋转等待时间为3毫秒;对于15000 RPM硬盘,旋转等待时间为2毫秒。

驱动器在定位磁头后向磁盘传输数据,数据传输速率很重要。对于固态驱动器(SSD),等效指标是存储的随机访问延迟,通常低于毫秒。

(2)IOPS

系统每秒处理的读写请求数在很大程度上取决于存储设备的功能和应用程序。当应用程序发出请
求时,操作系统会将请求传输到设备,并等待处理直到完成。你可以使用iostat -x命令在await列查看每个设备的等待时间。r_await和w_await列给出了读取和写入请求的等待时间。%iowait列给出了系统的全局等待时间。

(3)吞吐量

吞吐量是指系统每秒可以读取或写入的实际字节数。块的大小和数据传输速率会影响吞吐量。磁
盘块容量越大,数据传输速率越高。你还可以测量从客户端到服务器网络甚至整个系统的吞吐量。

2、性能测试工具

为了测试Ceph集群的性能,首先要有必要的工具。

下面列出常用的集群性能测试工具:

1)Fio:灵活的I/O测试工具,通过其广泛的配置选项,测试各种复杂的I/O性能。它拥有适用于
本地块设备和RBD的插件,这意味着可以直接从Ceph集群测试RBD,也可以通过Linux内核驱动程
序将RBD映射到客户端,然后使用Fio对通过客户端映射的块设备进行I/O性能测试。

2)S3bench:提供了针对兼容S3接口的基本吞吐量测试功能。它执行一系列put操作,然后执行一
系列get操作,并显示相应的统计信息。该工具使用AWS Go SDK。

3)Ping:除了能够诊断许多网络问题外,Ping对网络连接的延迟测试也非常有用。

4)iPerf:其允许进行一系列网络测试,以确定两台服务器之间的带宽。该工具是最常用的网络
性能测试工具。

5)RADOS:Ceph自带的性能测试工具,包括对带宽等指标的全面测试。

3、RBD测试用例

针对RBD设备的性能测试,你可以设置具体的性能指标。通过这些指标可以综合衡量Ceph集群中
RBD的极限性能。可以参考下表的测试项目对RBD进行性能测试。

1)使用Fio测试Ceph RBD设备随机写4KB文件的IOPS性能。

[root@mon1 ~]# fio --name=4krandwrite_iops --filename=/dev/rbd0 --numjobs=--bs=4k --ioengine=libaio --direct=1 --randrepeat=0 --norandommap
--rw=randwrite --group_reporting --iodepth=512 --iodepth_batch=128
--iodepth_batch_complete=128 --gtod_reduce=1 --runtime=10
4krandwrite_iops: (g=0): rw=randwrite, bs=(R) 4096B-4096B, (W) 4096B-4096B,
(T) 4096B-4096B, ioengine=libaio, iodepth=512
...
fio-3.19
Starting 8 processes
Jobs: 8 (f=8): [w(8)][100.0%][w=285MiB/s][w=72.9k IOPS][eta 00m:00s]
4krandwrite_iops:(groupid=0, jobs=8): err= 0: pid=365014: Mon Jan 18 11:write: IOPS=77.1k, BW=301MiB/s (316MB/s)(3165MiB/10505msec); 0 zone resets
bw (KiB/s): min=112411, max=529745, per=100.00%, avg=315936.70, stdev=
14137.52, samples=160
...output omitted...

2)使用Fio测试Ceph RBD设备顺序写4KB文件的IOPS性能。

[root@mon1 ~]# fio --name=4kwrite_iops --filename=/dev/rbd0 --numjobs=8
--bs=4k --ioengine=libaio --direct=1 --randrepeat=0 --norandommap
--rw=write --group_reporting --iodepth=512 --iodepth_batch=128
--iodepth_batch_complete=128 --gtod_reduce=1 --runtime=10
4kwrite_iops: (g=0): rw=write, bs=(R) 4096B-4096B, (W) 4096B-4096B, (T) ...
fio-3.19
Starting 8 processes
Jobs: 8 (f=8): [W(8)][100.0%][w=726MiB/s][w=186k IOPS][eta 00m:00s]
4kwrite_iops: (groupid=0, jobs=8): err= 0: pid=365088: Mon Jan 18 11:19:write: IOPS=179k, BW=699MiB/s (733MB/s)(7014MiB/10028msec); 0 zone resets
bw (KiB/s): min=165362, max=1020928, per=100.00%, avg=726150.00, stdev=samples=152
...output omitted...

3)使用Fio测试Ceph RBD设备顺序读4KB文件的IOPS性能。

[root@mon1 ~]# fio --name=4kread_iops --filename=/dev/rbd0 --numjobs=8
--bs=4k --ioengine=libaio --direct=1 --randrepeat=0 --norandommap ----group_reporting --iodepth=512 --iodepth_batch=128 --iodepth_batch_
complete=128 --gtod_reduce=1 --runtime=10
4kread_iops: (g=0): rw=read, bs=(R) 4096B-4096B, (W) 4096B-4096B,
(T) 4096B-4096B, ioengine=libaio, iodepth=512
...
fio-3.19
Starting 8 processes
Jobs: 8 (f=8): [R(8)][100.0%][r=765MiB/s][r=196k IOPS][eta 00m:00s]
4kread_iops: (groupid=0, jobs=8): err= 0: pid=365173: Mon Jan 18 11:21:17 read: IOPS=251k, BW=982MiB/s (1030MB/s)(8192MiB/8339msec)
bw (KiB/s): min=623360, max=1219584, per=100.00%, avg=1015564.19, stdev=
19328.03, samples=128
...output omitted...

4)使用Fio测试Ceph RBD设备随机读4KB文件的IOPS性能。

[root@mon1 ~]# fio --name=4krandread_iops --filename=/dev/rbd0 --numjobs=--bs=4k --ioengine=libaio --direct=1 --randrepeat=0 --norandommap
--rw=randread --group_reporting --iodepth=512 --iodepth_batch=128
--iodepth_batch_complete=128 --gtod_reduce=1 --runtime=10
4krandread_iops: (g=0): rw=randread, bs=(R) 4096B-4096B, (W) 4096B-4096B,
(T) 4096B-4096B, ioengine=libaio, iodepth=512
...
fio-3.19
Starting 8 processes
Jobs: 8 (f=8): [r(8)][100.0%][r=744MiB/s][r=190k IOPS][eta 00m:00s]
4krandread_iops:(groupid=0, jobs=8): err= 0: pid=365248: Mon Jan 18 11:22:read: IOPS=190k, BW=743MiB/s (780MB/s)(7443MiB/10011msec)
bw (KiB/s): min=724406, max=792863, per=100.00%, avg=761468.26,
stdev=2249.65, samples=152
...output omitted...

5)使用Fio测试Ceph RBD设备写4MB文件的极限带宽性能。

[root@mon1 ~]# fio --name=4mwrite-bw --filename=/dev/rbd0 --numjobs=8
--bs=4m --ioengine=libaio --direct=1 --randrepeat=0 --norandommap
--rw=write --group_reporting --iodepth=512 --iodepth_batch=128
--iodepth_batch_complete=128 --gtod_reduce=1 --runtime=10
4mwrite-bw: (g=0): rw=write, bs=(R) 4096KiB-4096KiB, (W) 4096KiB-4096KiB,
(T) 4096KiB-4096KiB, ioengine=libaio, iodepth=512
...
fio-3.19
Starting 8 processes
Jobs: 5 (f=5): [_(3),W(5)][47.4%][w=2046MiB/s][w=511 IOPS][eta 00m:10s]
4mwrite-bw: (groupid=0, jobs=8): err= 0: pid=365538: Mon Jan 18 11:24:34 write: IOPS=268, BW=1073MiB/s (1126MB/s)(8192MiB/7632msec); 0 zone resets
...output omitted...

6)使用Fio测试Ceph RBD设备顺序写4KB文件的延迟性能。

[root@mon1 ~]# fio --name=4kwrite_lat --filename=/dev/rbd0 --numjobs=8
--bs=4k --ioengine=sync --direct=1 --randrepeat=0 --norandommap
--rw=write --group_reporting --runtime=10
4kwrite_lat: (g=0): rw=write, bs=(R) 4096B-4096B, (W) 4096B-4096B,
(T) 4096B-4096B, ioengine=sync, iodepth=1
...
fio-3.19
Starting 8 processes
Jobs: 8 (f=8): [W(8)][100.0%][w=51.8MiB/s][w=13.3k IOPS][eta 00m:00s]
4kwrite_lat: (groupid=0, jobs=8): err= 0: pid=365941: Mon Jan 18 11:33:46 write: IOPS=13.6k, BW=53.2MiB/s (55.8MB/s)(533MiB/10001msec); 0 zone resets
clat (usec): min=288, max=27800, avg=585.95, stdev=303.33
lat (usec): min=288, max=27800, avg=586.07, stdev=303.33
clat percentiles (usec):
...output omitted...

7)使用Fio测试Ceph RBD设备顺序读4KB文件的延迟性能。

root@mon1 ~]# fio --name=4kread_lat --filename=/dev/rbd0 --numjobs=8 --bs=--ioengine=sync --direct=1 --randrepeat=0 --norandommap --rw=read
--group_reporting --runtime=10
4kread_lat: (g=0): rw=read, bs=(R) 4096B-4096B, (W) 4096B-4096B,
(T) 4096B-4096B, ioengine=sync, iodepth=1
...
fio-3.19
Starting 8 processes
Jobs: 8 (f=8): [R(8)][100.0%][r=102MiB/s][r=26.1k IOPS][eta 00m:00s]
4kread_lat: (groupid=0, jobs=8): err= 0: pid=366031: Mon Jan 18 11:35:59 read: IOPS=30.2k, BW=118MiB/s (124MB/s)(1180MiB/10001msec)
clat (usec): min=71, max=222820, avg=264.11, stdev=1274.76
lat (usec): min=71, max=222820, avg=264.19, stdev=1274.76
clat percentiles (usec):
...output omitted...

8)使用Fio测试Ceph RBD设备随机读4KB文件的延迟性能。

[root@mon1 ~]# fio --name=4krandread_lat --filename=/dev/rbd0 --numjobs=--bs=4k --ioengine=sync --direct=1 --randrepeat=0 --norandommap
--rw=randread --group_reporting --runtime=10
4krandread_lat: (g=0): rw=randread, bs=(R) 4096B-4096B, (W) 4096B-4096B,
(T) 4096B-4096B, ioengine=sync, iodepth=1
...
fio-3.19
Starting 8 processes
Jobs: 8 (f=8): [r(8)][100.0%][r=49.6MiB/s][r=12.7k IOPS][eta 00m:00s]
4krandread_lat: (groupid=0, jobs=8): err= 0: pid=366109: Mon Jan 18 11:36:read: IOPS=8560, BW=33.4MiB/s (35.1MB/s)(335MiB/10005msec)
clat (usec): min=83, max=225226, avg=932.73, stdev=4721.87
lat (usec): min=83, max=225226, avg=932.87, stdev=4721.87
clat percentiles (usec):
...output omitted...
9

9)使用Fio测试Ceph RBD设备随机写4KB文件的延迟性能。

[root@mon1 ~]# fio --name=4krandwrite_lat --filename=/dev/rbd0 --numjobs=--bs=4k --ioengine=sync --direct=1 --randrepeat=0 --norandommap
--rw=randwrite --group_reporting --runtime=10
4krandwrite_lat: (g=0): rw=randwrite, bs=(R) 4096B-4096B, (W) 4096B-4096B,
(T) 4096B-4096B, ioengine=sync, iodepth=1
...
fio-3.19
Starting 8 processes
Jobs: 8 (f=8): [w(8)][100.0%][w=38.7MiB/s][w=9918 IOPS][eta 00m:00s]
4krandwrite_lat: (groupid=0, jobs=8): err= 0: pid=366173: Mon Jan 18
11:37:35 2021
write: IOPS=10.0k, BW=39.1MiB/s (41.0MB/s)(391MiB/10001msec); 0 zone resets
clat (usec): min=296, max=26629, avg=796.53, stdev=313.26
lat (usec): min=296, max=26629, avg=796.73, stdev=313.27
clat percentiles (usec):
...output omitted...

4、网络测试用例

假定在Ceph集群的mon1节点部署iPerf服务器,你可以通过对任意节点和此节点建立通信来测
试网络性能。

测试步骤如下:

1)启动iPerf服务器。

[root@mon1]# iperf -s

2)测试节点间网络性能。

[root@osd1]# iperf -c mon1

5、对象存储测试

下面给出使用S3bench测试对象存储性能的用例。

[root@mon1 s3bench-master]# ./s3bench -accessKey=LS8C2E8YBHV0L7O5WN0F
-accessSecret=Awvh5hEICyXil69VYvBDgSVAgsX7mLchxNyXZopy -bucket=tb1
-endpoint=http://mon1.ceph1.example.com:8080,http://mon2.ceph1.example.
com:8080,http://mon3.ceph1.example.com:8080 -numClients=3 -numSamples=
10 -objectSize=838860800
Test parameters
endpoint(s): [http://mon1.ceph1.example.com:8080 http://mon2.ceph1.
example.com:8080 http://mon3.ceph1.example.com:8080]
bucket: tb1
objectNamePrefix: loadgen_test_
objectSize: 800.0000 MB
numClients: 3
numSamples: 10
verbose: %!d(bool=false)
Generating in-memory sample data... Done (4.186294652s)
Running Write test...
Running Read test...
Test parameters
endpoint(s): [http://mon1.ceph1.example.com:8080 http://mon2.ceph1.
example.com:8080 http://mon3.ceph1.example.com:8080]
bucket: tb1
objectNamePrefix: loadgen_test_
objectSize: 800.0000 MB
numClients: 3
numSamples: 10
verbose: %!d(bool=false)
Results Summary for Write Operation(s)
Total Transferred: 8000.000 MB
Total Throughput: 527.54 MB/s
Total Duration: 15.165 s
Number of Errors: 0
------------------------------------
Write times Max: 4.201 s
Write times 99th %ile: 4.201 s
Write times 90th %ile: 4.201 s
Write times 75th %ile: 4.047 s
Write times 50th %ile: 3.855 s
Write times 25th %ile: 3.742 s
Write times Min: 3.636 s
Results Summary for Read Operation(s)
Total Transferred: 8000.000 MB
Total Throughput: 937.33 MB/s
Total Duration: 8.535 s
Number of Errors: 0
------------------------------------
Read times Max: 2.556 s
Read times 99th %ile: 2.556 s
Read times 90th %ile: 2.556 s
Read times 75th %ile: 2.403 s
Read times 50th %ile: 2.231 s
Read times 25th %ile: 2.138 s
Read times Min: 2.032 s
Cleaning up 10 objects...
Deleting a batch of 10 objects in range {0, 9}... Succeeded
Successfully deleted 10/10 objects in 95.942386ms

6、RADOS测试用例

下面给出3种针对Ceph池的scbench测试用例。

1)写入速率测试。

[root@mon1 home]# rados bench -p scbench 10 write --no-cleanup
hints = 1
Maintaining 16 concurrent writes of 4194304 bytes to objects of size 4194304 Object prefix: benchmark_data_mon1.ceph1.example.com_358307
sec Cur ops started finished avg MB/s cur MB/s last lat(s) avg lat(0 0 0 0 0 0 - 1 16 257 241 963.86 964 0.0481077 0.064388
2 16 531 515 1029.84 1096 0.0423452 0.0608791
3 16 810 794 1058.5 1116 0.0394996 0.0597475
4 16 1086 1070 1069.84 1104 0.0632946 0.0592671
5 16 1366 1350 1079.84 1120 0.0571393 0.0589689
6 16 1645 1629 1085.84 1116 0.0350042 0.0586529
7 16 1923 1907 1089.55 1112 0.0355203 0.058414
8 16 2202 2186 1092.83 1116 0.0519929 0.0583325
9 16 2481 2465 1095.39 1116 0.0797031 0.0582389
10 16 2752 2736 1094.23 1084 0.0673506 0.0582318
Total time run: 10.0358
Total writes made: 2753
Write size: 4194304
Object size: 4194304
Bandwidth (MB/sec): 1097.28
Stddev Bandwidth: 47.1857
Max bandwidth (MB/sec): 1120
Min bandwidth (MB/sec): 964
Average IOPS: 274
Stddev IOPS: 11.7964
Max IOPS: 280
Min IOPS: 241
Average Latency(s): 0.0583025
Stddev Latency(s): 0.0154346
Max latency(s): 0.160514
Min latency(s): 0.0256778

2)顺序读速率测试。

[root@mon1 ~]# rados bench -p scbench 10 seq
hints = 1
sec Cur ops started finished avg MB/s cur MB/s last lat(s) avg 0 0 0 0 0 0 - 1 16 102 86 343.922 344 0.0194463 0.163491
2 16 300 284 567.905 792 0.0384775 0.107908
3 16 564 548 730.562 1056 0.0621824 0.0857732
4 16 835 819 818.892 1084 0.079814 0.076916
5 16 1106 1090 871.889 1084 0.0691304 0.0722352
6 16 1378 1362 907.889 1088 0.0384274 0.0694858
7 16 1653 1637 935.318 1100 0.0644025 0.0675508
8 16 1925 1909 954.383 1088 0.0421438 0.0661623
9 16 2199 2183 970.101 1096 0.0467061 0.0651821
10 16 2471 2455 981.878 1088 0.0635384 0.0643742
Total time run: 10.0595
Total reads made: 2472
Read size: 4194304
Object size: 4194304
Bandwidth (MB/sec): 982.947
Average IOPS: 245
Stddev IOPS: 60.6708
Max IOPS: 275
Min IOPS: 86
Average Latency(s): 0.0644502
Max latency(s): 0.485071
Min latency(s): 0.0140948

3)随机读速率测试。

[root@mon1 ~]# rados bench -p scbench 10 rand
hints = 1
sec Cur ops started finished avg MB/s cur MB/s last lat(s) 0 0 0 0 0 0 - 1 15 289 274 1095.83 1096 0.0191153 0.0561554
2 16 566 550 1099.83 1104 0.0652593 0.0566128
3 16 843 827 1102.52 1108 0.0225136 0.0567262
4 16 1122 1106 1105.86 1116 0.055824 0.0567892
5 16 1399 1383 1106.27 1108 0.0374183 0.0567316
6 16 1678 1662 1107.87 1116 0.0522988 0.0567514
7 16 1958 1942 1109.58 1120 0.0373669 0.0567544
8 16 2239 2223 1111.36 1124 0.0406238 0.0567281
9 15 2518 2503 1112.31 1120 0.0479201 0.056726
10 16 2799 2783 1113.07 1120 0.0816771 0.0567165
Total time run: 10.0527
Total reads made: 2800
Read size: 4194304
Object size: 4194304
Bandwidth (MB/sec): 1114.13
Average IOPS: 278
Stddev IOPS: 2.21359
Max IOPS: 281
Min IOPS: 274
Average Latency(s): 0.0567781
Max latency(s): 0.42347
Min latency(s): 0.0120634

7、推荐的调优方向

通过提供的测试用例,我们可以分析出性能指标。针对性能指标,我们可以从软硬件层面对Ceph集群和所有Linux服务器进行性能调优。

1)硬件调优

1. CPU调优

由于Ceph是由软件定义的存储,因此其性能在很大程度上受到OSD节点中CPU速度的影响。CPU
主频越高,意味着运行代码的速度越快,同时处理每个I/O请求的时间也会越短,因此建议使用高主频的处理器。

2. 磁盘调优

① 磁盘I/O

Linux内核支持多种I/O调度算法,包括CFQ、Noop、Deadline等。根据不同的磁盘应用场景选择不同的I/O调度算法可提升I/O性能。I/O调度算法的选择既取决于硬件特征,也取决于应用场景。对于传统的SAS盘,CFQ、Deadline、Noop算法都是不错的选择。对于专属的数据库服务器,Deadline算法在吞吐量和响应时间方面都表现良好。然而在新兴的固态硬盘比如SSD上,最简单的Noop算法反而可能是最好的,因为其他两种算法的优化是基于缩短寻道时间,而固态硬盘没有所谓的寻道时间且I/O响应时间非常短。

上面3种调度算法适用的场景如下:

CFQ:对于固态硬盘,不推荐使用该调度算法;对于其他类型的硬盘如SAS/SATA且I/O请求较
多,需要均衡调度时,可考虑使用该调度算法。如果在固态硬盘上使用该调度算法,需要设置如下参数进行调优。

设置/sys/block/devname/queue/ionice/slice_idle为0
设置/sys/block/devname/queue/ionice/quantum为64
设置/sys/block/devname/queue/ionice/group_idle为1

Noop:在要求对某类I/O请求优先处理,且I/O请求类型少,或者使用了类似SSD的固态硬盘时,
可考虑使用该调度算法。

Deadline:Deadline的核心思想是最大化I/O吞吐量,同时在一定范围内保证读写的响应时间。
Deadline相对于Noop算法的最大优势在于,添加了前向合并和所谓的批操作,大大减少了磁头的移动,使读写效率得到提高。使用该算法时,调优参数如下表所示。

更改磁盘调度算法时,我们可以使用如下命令:

·echo noop > /sys/block/{your devicename}/queue/scheduler
·echo cfq > /sys/block/{your devicename}/queue/scheduler
·echo deadline > /sys/block/{your devicename}/queue/scheduler

② 磁盘数量

在参数和硬件配置相同的情况下,大量的I/O请求会向Ceph OSD节点写入数据,同时会向其他
OSD节点写入数据副本。待数据副本写入完毕后,本次数据存储结束。如果OSD节点数量过少,在生产环境下会带来性能的损耗,因此在某种程度上增加OSD数量对Ceph的写操作性能提升有帮助。

③ 磁盘转速

如果使用传统机械盘做存储,选择7200RPM以上的SATA或者SAS。

④ Non-RAID配置

为了避免对底层磁盘使用RAID,Ceph通过副本或者纠删码方式对数据副本进行保护。如果使用
RAID,不仅浪费容量,也因多一层底层计算而降低Ceph整体存储性能。

2)网络调优

(1)使用万兆网卡

Ceph集群内部网络带宽是影响数据读写和数据恢复性能的关键因素。高带宽可以带来更快的读
写。如果使用千兆以太网卡,性能指标会很低。以千兆网络为例,复制1TB数据的时间在18秒左右。如果使用万兆网络复制相同的数据副本,完成时间仅为1.8秒,因此大规模集群一定要使用万兆以上的网络。

(2)多网卡聚合负载均衡

提升Ceph性能的主要手段是将多网卡聚合进行负载均衡,达到带宽叠加的效果。配置多网卡聚合
可以使用Bonding和Teaming技术。这里不提供这两种技术的详细过程。我们可以考虑通过配置4端口万兆网络提升随机写性能。

(3)Jumbo Frame

以太网具有标准的最大传输数据包大小,称为最大传输单元(Maximum Transmission Unit,
MTU)。以太网标准中,其大小为1500字节。Jumbo Frame是一种巨型帧。为了提高吞吐量并减
少处理开销,允许设备发送和接收比标准MTU大的帧。这意味着发送一个巨型帧比发送几个小帧传输相同数据的效率更高。

巨型帧的官方最大传输单元大小为9000字节,但某些设备支持更大的帧。注意,连接到以太网的所有设备都需要支持所需大小的巨型帧,并且需要在该网络上为所有经过的链路节点上的以太网接口配置相同大小的巨型帧。链路节点包括客户端计算机、网络交换机(配置支持接收巨型帧)、Ceph节点以及该以太网上的任何其他设备。如果流量必须穿过路由器到达另一个以太网,路由器接口和另一个以太网还需要支持至少大小相同的巨型帧,这样才能从巨型帧中完全受益。

(4)内核参数

Linux为每个TCP / IP连接缓冲区,但是默认值可能不适用于所有连接。

以下参数用来管理缓冲区:

·net.ipv4.tcp_wmem:设置操作系统的接收缓冲区值。
·net.ipv4.tcp_rmem:设置操作系统的发送缓冲区值。
·net.ipv4.tcp_mem:定义与内存使用有关的

TCP堆栈行为:

·net.core_wmem_max:操作系统接收的所有类型的连接的最大接收缓冲区大小。
·net.core_rmem_max:操作系统接收的所有类型的连接的最大发送缓冲区大小。

配置net.ipv4.tcp_wmem和net.ipv4.tcp_rmem参数时,需要按照固定格式进行。它们都由3个值构
成,第一个值表示内核单个TCP套接字的最小缓冲区空间,第二个值表示内核单个TCP套接字的默认缓冲区空间,第三个值表示内核单个TCP套接字的最大缓冲区空间。对于net.ipv4.tcp_mem参数,第一个值表示内核较低的阈值,第二个值表示内核何时开始增加内存使用量,第三个值表示内核最大内存页数,参数调整示例如下(参数值根据实际情况调整):

[root@mon1]# vim /etc/sysctl.d/99-ceph.conf
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 16384 16777216
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216

3)内存调优

下面描述了几个内存调优参数,读者可根据具体情况进行设置。如果你的系统中使用透明大页,建议考虑将其关闭。

(1)vm.dirty_ratio/vm.dirty_bytes

这两个参数可以实现对内存回写磁盘的控制。当脏页数量达到一定比例(系统总内存占比)或者
具体的阈值时,触发Linux内核强制回写磁盘数据。这时,进程的所有I/O操作将被阻塞,这也是
造成磁盘I/O性能瓶颈的重要因素。我们可以尝试将这个比例或者阈值设置得大一些。比例和阈值只需要设置其中一个即可。

(2)vm.dirty_backgroud_ratio/vm.dirty_backgroud_bytes

当系统的脏页数量达到一定比例(系统总内存占比)或者具体的阈值时,将激活pdflush/flush/kdmflush后台进程清理脏数据,异步执行回写磁盘数据操作。我们可以尝试将此比例设置得较小一些,比如5%,这样可以保证系统数据平滑地回写到磁盘。

(3)vm.min_free_kbytes

这是为操作系统预留的内存,不论应用程序使用多少内存,这部分内存不受影响,以保证系统有
足够的内存运行。但是,其值不是越大越好,如果预留太大会导致空闲使用内存不足,迫使内核频繁进行内存回收,严重影响性能。在超48GB RAM系统上,我们可将m.min_free_kbytes参数设置为4194303(4GB)或者以上。

(4)vm.swappiness

vm.swappiness决定了应用内存来自页交换分区还是直接从页缓存中回收内存的程度。
vm.swappiness取值范围为0到100,一般将swappiness设置为100。与从页缓存中回收内存相
比,系统更喜欢交换页面到磁盘,以空出更多内存。如果将其设置为1,系统将尽可能少地将内存
页交换到交换分区,而是优先从页缓存中回收内存页。在Ceph节点上,重要的是Ceph进程必须保留在内存中而不被交换出去,推荐不要将该参数值设置得太大,否则会影响性能,可以考虑将
vm.swappiness值设置为10。

4)Scrub

Scrub是Ceph验证存储在RADOS中的对象是否一致并防止数据损坏的方法。Scrub有两种模式:
普通模式和深度模式。

在普通模式下,Scrub操作会读取某个放置组中的所有对象,并比较副本,以确保它们的大小和属性值一致。在深度模式下,Scrub操作将更进一步,比较对象的实际数据内容。

与普通模式相比,深度模式下的Scrub操作会产生更多I/O。普通模式下的Scrub操作每天执行一次,而深度模式下的Scrub操作每周执行一次。

Scrub操作会对客户端I/O产生影响,因此,可以对OSD设置进行调整,以指导对Ceph集群进行清洗。

Ceph中的两个参数:osd_scrub_begin_hour和osd_scrub_end_hour,决定了Scrub操作的始末时间。默认情况下,它设置为允许在全天进行Scrub操作。你可以调整Scrub的开始和结束时间,让Ceph在业务非高峰期执行清洗。

5)Ceph配置参数调优

做好对Ceph的配置参数的调整会带来部分性能提升,其中使用BlueStore相比使用Filestore会带来
更高的性能提升。针对BlueStore,我们有很多可以进行优化的参数,具体如下:

1)调整rocksdb和wal。以下两个参数的具体数值根据实际情况而定,不能一概而论。这需要在系
统部署时候规划好。

·bluestore_block_db_size
·bluestore_block_wal_size

2)调整Allocation Size。在混合工作负载条件下,调整alloc_size会略微提高小型对象的写入性
能。将alloc_size减小到4KB有助于减少对小型对象的写入放大,但此更改需要在OSD部署之前完成。如果部署之后更改,必须重新部署OSD,以使其生效。建议机械盘设置为64KB,SSD / NVMe设置为4KB。

·min_alloc_size_ssd=4096
·min_alloc_size_hdd=65536

关于其他调优参数,你可以根据实际情况进行分析,并逐步调优。本章目的在于给出一些调优思
路。

十一、Ceph故障排查

分布式存储集群的可靠性已经很高,但在大容量集群环境下,出现任何故障都可能带来集群性能
问题或者数据安全隐患,因此要做好对集群状态监控及故障恢复。当故障发生后,我们要及时使用正确的处理方式排除故障。

1、获取集群状态

集群状态有3种,具体如下:

·HEALTH_OK:表示集群运行良好。

·HEALTH_WARN:表示警告。在某些情况下,Ceph状态会从HEALTH_WARN状态自动返回
到HEALTH_OK状态,例如,Ceph集群完成再平衡时。但是,如果集群处于HEALTH_WARN状态的时间很长,就需要排查是否存在问题。

·HEALTH_ERR:表示出现更严重的问题。你可以使用ceph health detail和ceph -s命令来获取更详
细的输出。

除了掌握Ceph集群的基本状态,当出现问题时,你要能准确地找到相关报错信息和日志,以便
快速定位问题。默认情况下,Ceph将其日志存储在/var/log/ceph/目录下,CLUSTER_NAME.log包含全局事件的主存储集群日志。默认情况下,日志文件名为ceph.log,只有MON节点包括主存储集群日志。

每个OSD和MON节点都有其独立的日志文件,名称分别为CLUSTER_NAMEosd.NUMBER.log和CLUSTER_NAMEmon.HOSTNAME.log。当提高Ceph子系统的调试级别时,Ceph也会为这些子系统生成新的日志文件。

通常,Ceph不会将存储在内存中的日志输出,只有在以下情况才会输出日志:

·发出致命信号。
·触发源代码中的断言。
·用户发出请求。

你可以为每个Ceph组件进程设置不同的值。

Ceph日志记录级别范围为1到20,其中1表示简洁,20表示冗长。对于定位复杂的问题,你可以适当将日志级别提高。

Ceph组件的默认日志级别:

调整日志级别有两种方法。

1)在线调整。使用tell命令,直接调整debug级别:

ceph tell TYPE.ID injectargs --debug-SUBSYSTEM VALUE [--NAME VALUE]

例如,调整osd.0的日志级别:

# ceph tell osd.0 injectargs --debug-osd 0/5

修改完毕,在线查看配置是否生效:

# ceph daemon osd.0 config show | less

2)修改配置文件进行调整。如果需要全局生效,在/etc/ceph/ceph.conf中的[global]字段下添加配
置。对于特定守护进程的子系统,在守护进程字段下添加配置,例如[mon][osd]或[mds],修改之后重启相应服务使其生效。

[global]
debug_ms = 1/5
[mon]
debug_mon = 20
debug_paxos = 1/5
debug_auth = 2
[osd]
debug_osd = 1/5
debug_monc = 5/20
[mds]
debug_mds = 1

2、诊断Monitor问题

通常,常见的Monitor问题有三种:Monitor失去仲裁后转为down状态问题、时钟问题、存储容量
问题。

接下来简单分析相关问题发生的原因:

1)Monitor失去仲裁后转为down状态问题。

· 如果ceph-mon守护进程未运行,则可能是存储已损坏或其他错误阻止了该守护进程启动。另
外,/var/分区可能已满,ceph-mon无法对默认位于/var/lib/ceph/monSHORT_HOST_NAME/store.db中的数据执行任何操作。

· 如果ceph-mon守护进程正在运行,但CephMonitor失去仲裁,标记为down,这可能是网络问
题或者时钟不同步导致的。

通常,你可以查看日志或者ceph-mon守护进程的状态来获取问题定位信息。下面给出几个查看相
关日志分析中Monitor状态为down问题的命令。

[root@mon ~]# systemctl status ceph-mon@HOST_NAME
[root@mon ~]# systemctl start ceph-mon@HOST_NAME
[root@mon ~]# cat /var/log/ceph/ceph-mon.HOST_NAME.log
[root@mon ~]# ceph daemon mon.a mon_status

2)时钟问题。

通常,时钟问题会以告警的形式(HEALTH_WARN)出现。你可以通过ceph-s或者
ceph health detail命令查看。其也会以HEALTH_ERR的形式出现,比如将Ceph的时钟服
务器关闭几个小时或者一天,然后再启动。

这时,每个节点的时钟已经远远领先于NTP服务器的时间,Ceph存储节点的OSD会出现down状态,集群的状态变成HEALTH_ERR。而检查时钟时,发现时钟的偏差时间很大,但是在微调后,时钟重新同步,集群也能恢复正常。期间,集群是不能提供服务的。为了快速恢复服务,应该重启每个节点的时钟服务(NTP/Chrony),或者手动强制执行同步。

通常,时钟问题信息如下:

mon.a (rank 0) addr 127.0.0.1:6789/0 is down (out of quorum)
mon.a addr 127.0.0.1:6789/0 clock skew 0.08235s > max 0.05s (latency 0.0045s)

3)存储容量问题。

mon.ceph1 store is getting too big! 48031 MB >= 15360 MB -- 62% avail

当Ceph报告以上问题时,说明LevelDB数据量过大。Ceph Monitor存储是一个LevelDB数据库,
将条目存储为键–值对。该数据库包括一个集群,默认情况下位于/var/lib/ceph/mon/CLUSTER_NAMESHORT_HOST_NAME/store.db。

查询Ceph Monitor上的存储可能需要一些时间,因此Ceph Monitor可能会延迟响应客户端查询。为了解决这类问题,我们就需要对数据进行压缩。

可以参考如下命令:

# ceph tell mon.host1 compact

3、诊断对象问题

当对象丢失的时候,你可以使用cephobjectstore-tool实用工具查看并修复存储在Ceph OSD节点中丢失的对象,示例如下。

1)查看丢失的对象:

[root@osd ~]# ceph-objectstore-tool --data-path /var/lib/ceph/osd/ceph-0
--op fix-lost --dry-run

2)修复丢失的对象:

[root@osd ~]# ceph-objectstore-tool --data-path /var/lib/ceph/osd/ceph-0
--op fix-lost

4、数据平衡

当OSD发生故障或主动将某OSD进程停止时,CRUSH算法会自动启动数据平衡功能,以保证数
据在其余OSD中重新分配。数据平衡会耗费时间和资源,因此请考虑在故障排除或OSD维护期间停止数据平衡。在故障排除和OSD维护期间,停止运行的OSD中的放置组会处于degraded状态,但是依旧可以正常访问数据。

1)请在停止运行OSD之前设置noout标志。

[root @ mon~]#ceph osd set noout

2)完成故障排除或OSD维护后,取消设置noout标志,以重新启动数据平衡功能。

[root @ mon~]#ceph osd unset noout

5、重要文件目录

Ceph集群中有很多重要的文件,请慎重保存,并谨慎修改。

(1)Ceph配置文件

/etc/ceph/ceph.conf文件轻易不要改动,尤其是Monitor节点的IP,改动了可能导致Ceph系统出现严重异常。

/etc/ceph/rbdmap文件是RBD的自动挂载配置文件。为了保证系统重启后能正常挂载,新建的RBD
要向该文件中写内容(只需要在你的RBD客户端节点写)。

/etc/ceph/ceph.client.admin.keyring文件是在增加节点时,将此文件复制到新节点的相同目录下,
以便生成证书。

(2)Ceph日志文件

/var/log/ceph/*文件用于存放每个节点的日志,以便于用户根据具体的角色查找相应的日志。例
如:ceph-osd1.log文件为osd1进程对应的日志文件。

任何节点出现异常时,先查看日志,根据日志定位问题。

(3)Ceph节点的安装信息文件

/var/lib/ceph/中有mon、osd、mds等文件夹,以bootstrap命名的文件夹尽量不要动。根据节点角色的不同,相关节点的核心配置文件会分布在不同的文件夹中。

·mon文件夹中存放的是Monitor节点的安装信息。如果这些信息删除了,节点将不能工作,需要
重新添加节点。但是,删除节点的操作绝不是删除这个文件夹,否则会导致系统异常。

·osd文件夹中存放的是OSD节点的安装信息。文件夹中的子文件夹对应磁盘信息,即对应每个osd子文件夹下的keyring,轻易不要改动。

·mds文件夹中存放的是MDS节点的安装信息。

6、使用Ceph集群的注意事项

在使用Ceph集群的过程中注意以下事项,以避免不必要的误操作。

·/etc/ceph/ceph.conf文件尽量不要改动,否则会出现严重问题,除非你明确知道改动的后果。

·/var/lib/ceph/*文件尽量不要改动,除非你非常明确改动的后果。

·RBD测试后不要再执行挂载等操作。

·删除和添加OSD时要慎重,需要注意CRUSH Map也要一并操作。

·不要同时关闭3个Monitor,否则将导致集群不能写入数据。

·cephfs_metadata和cephfs_data一定不要删除。

它们是CephFS的资源池,如果删除,CephFS保存的数据将全部丢失。

Ceph分布式存储详解相关推荐

  1. CEPH(详解+配置)

    1.简介: CEPH:统一的分布式存储系统: 存储类型:文件存储,块存储,对象存储: 优点:统一的(支持以上三种存储类型),分布式(在集群中,没有中心节点,所有的节点的地位相等),扩展性强,可靠性高: ...

  2. 分布式存储系统之Ceph(理论详解)

    目录 Ceph 简介 ceph的构成 ceph 集群基础: Monitor(ceph-mon):ceph 监视器 Managers(ceph-mgr)的功能: Ceph OSDs(对象存储守护程序 c ...

  3. ceph搭建及使用详解

    第1章 ceph介绍 1.1 Ceph的主要特点 统一存储 无任何单点故障 数据多份冗余 存储容量可扩展 自动容错及故障自愈 1.2 Ceph三大角色组件及其作用 在Ceph存储集群中,包含了三大角色 ...

  4. Ceph分布式存储 原理+架构图详解

    分布式存储Ceph ceph介绍 ceph是一个统一的.分布式的存储系统,设计初衷式提供较好的性能(io).可靠性(没有单点故障)和可扩展性(未来可以理论上无限扩展集群规模),这三点也是集群架构所追求 ...

  5. ceph存储原理_赠书 | Linux 开源存储全栈详解——从Ceph到容器存储

    // 留言点赞赠书我有书,你有故事么?留言说出你的存储故事留言点赞前两名,免费送此书截止日期12.27号12.30号公布名单 // 内容简介 本书致力于帮助读者形成有关Linux开源存储世界的细致的拓 ...

  6. 【ceph】Ceph之PG状态详解--研读笔记

    原文:分布式存储Ceph之PG状态详解 - 简书 Ceph中一些PG相关的状态说明和基本概念说明.故障模拟_pansaky的博客-CSDN博客 1. PG介绍 继上次分享的<Ceph介绍及原理架 ...

  7. ceph命令系列(一):ceph-deploy/ceph/rados/rbd 常用命令详解

    ceph-deploy 常用命令详解 命令 描述 ceph-deploy new [mon-node ...] 指定node(s)为monitor,开始部署一个新的ceph集群,并且在当前目录创建ce ...

  8. 关于分布式存储,这是你应该知道的(图文详解)(关于存储的一些好文转载--1)

    转自:http://stor.51cto.com/art/201711/556946.htm 关于分布式存储,这是你应该知道的(图文详解) 前言 分布式存储存在的风险,其实就是因为"共享&q ...

  9. Ceph 中的 PG 状态详解

    1. PG介绍 这次主要来分享Ceph中的PG各种状态详解,PG是最复杂和难于理解的概念之一,PG的复杂如下: 在架构层次上,PG位于RADOS层的中间. a. 往上负责接收和处理来自客户端的请求. ...

  10. Ceph优化系列(二):Ceph主要配置参数详解

    转载:Ceph配置参数详解 概述 Ceph的配置参数很多,从网上也能搜索到一大批的调优参数,但这些参数为什么这么设置?设置为这样是否合理?解释的并不多 本文从当前我们的ceph.conf文件入手,解释 ...

最新文章

  1. 对于java程序语言的单例设计模式讲解
  2. 20180625笔记
  3. 1084. Broken Keyboard (20)
  4. 手机端调试console.log,直接引入一个js文件
  5. 贺利坚老师汇编课程25笔记:LOOP指令看CX
  6. 职场奇袭!3分钟完成一天工作
  7. CDH运维常见问题-cloudera-scm-agent 已死,但 pid 文件存在
  8. MATLAB如何输出高分辨率图片?
  9. CSR系列开发板的编程器/烧写器
  10. 采购模板html5,新建采购单.html
  11. cocos2dx检测及预防外挂加速
  12. 成都及周边景点5日游
  13. 【MATLAB笔记】对矩阵进行满秩分解
  14. Semantic Proximity Search on Heterogeneous Graph by Proximity Embedding
  15. 高潮再次来袭:马云,东哥两位电商大佬,强行助攻 996
  16. html 悬停 div,关于html:如何在div悬停时影响其他元素
  17. Studing Day4 - python基础4
  18. 软件测试面试要注意的细节以及处理(自我介绍篇)
  19. S7-1200PLC—实验六 四节传送带控制模拟
  20. 基于Logistic回归的麻雀搜索算法

热门文章

  1. 使用python建立一个网站:笔记3 建立自己网站主页
  2. 圣杯布局和双飞翼布局
  3. 【马三北漂记】之终章
  4. 2012-07《信息资源管理 02378》真卷解析,逐题解析+背诵技巧
  5. 2020年腾讯实习生C++面试题及答案持续更新中(4)
  6. ”不怎么动的运动“塑造完美翘臀
  7. Linux 内核工作队列之work_struct 学习总结
  8. CCNA(思科网络攻城狮) 滴水之力05
  9. 服务器数据恢复;IBM V7000数据恢复方法
  10. 世界著名的十大定律,你都知道吗