一、ceph架构
ceph生态系统分为四个部分:
客户端:数据用户
元数据服务器:缓存和同步分布式元数据
对象存储集群
ceph客户端
ceph使用一个有趣的备选,而不是依赖分配选项(将磁盘上的块映射到指定文件的元数据)。
Linux透视图中的一个文件会分配到一个来自元数据服务器的inode number(INO),对于文件这是一个唯一的标识符。然后文件被推入一些对象中(根据文件大小)。使用INO和Object Number,每个对象被分配一个对象ID(OID)。在OID上使用一个简单的哈希,每个对象被分配到一个放置组。放置组(PGID)是一个对象的概念容器。最后,放置组到存储设备的映射是一个伪随机映射,叫做Controlled Replication Under Scalable Hashing(CRUSH)的算法。这样一来,放置组(以及副本)到存储设备的映射就不用依赖任何元数据,而是依赖一个伪随机的映射函数。这种操作是理 想的,因为它把存储的开销最小化,简化了分配和数据查询。
ceph元数据服务器
元数据服务器的工作就是管理文件系统的名称空间
ceph监视器
包含集群映射管理的监视器,当对象存储设备发生故障或者新设备添加时,监视器就检测和维护一个有效的集群映射
ceph对象存储
存储设备安全管理对象到块的映射
另,
查看日志:
vim /var/log/ceph/ceph.log
二、CRUSH算法
CRUSH算法在一致性hash基础上很好的考虑了容灾域的隔离,能够实现各域的副本放置规则,例如:跨机房,机架感知等
分布式块存储RBD、分布式对象存储RADOS GateWay
RADOS采用强一致性设计,即Write-All-Read-One,读取效率高,工程难度低,适合读多写少的系统
Write-All-Read-One的特点是必须等待所有的副本全部写入完毕才算是写入成功,实际上对系统硬件的可靠性要求较高,如果在写入过程中硬件发生故障,则写入过程会受影响,通常表现为卡顿,一般是数秒级,时间的长短和判断故障的机制,以及恢复过程中IO的处理策略相关。
三、问题
ceph osd dump | grep test-pool
通过查看pool的策略,从test-pool中看出副本策略为最大3副本,最小两幅本
即:当一个磁盘损坏的时候,集群认为是健康的,还可以进行IO
如果将最小副本设置为3,当一个磁盘损坏的时候,集群认为是不健康的,不能进行IO
快照相关
对image进行snapshot操作,以便将来可以随时恢复到当时状态
libvirt
libvirt大体就是一个中间层,与rbd配合使用的关系如下:
libvirt-->qemu-->librbd-->librados-->osds
|--->monitors
四、硬件推荐
1. ceph守护进程和其他进程恰当分布,推荐在一台机器上运行一种类型的守护进程
把数据集群的进程(如OpenStack、CloudStack)安装在别的机器上
2. cpu
ceph元数据服务器对CPU敏感,会动态重分布它们的负载,需要足够的处理能力(4核或更强)
ceph的osd运行着RADOS服务,CRUSH算法,需要一定的处理能力(双核)
监视器运行着集群运行图的副本,对CPU不敏感,如果运行ceph集群以外的CPU密集型任务,就需要保留足够的能力。
3.RAM
元素据服务器和监视器必须尽快提供它们的数据,需要足够的内存,至少1G
OSD日常运行不需要那么多内存,每进程500M差不多了;然而在恢复期间占用内存比较大,(每进程每TB数据需要约1G内存)。通常内存越多越好
因为 Ceph 发送 ACK 前必须把所有数据写入日志(至少对 xfs 和 ext4 来说是),因此均衡日志和 OSD 性能相当重要。
4.硬盘驱动器
OSD应该有足够的空间用于存储对象数据,建议容量大于1TB的硬盘,单个驱动器容量越大,其对应的OSD所需内存就越大,特别是在重均衡、回填、恢复期间。
Tip:不顾分区而在单个硬盘上运行多个OSD,这样不明智!
Tip:不顾分区而在运行了OSD的硬盘上同时运行监视器或元数据服务器也不明智!
推荐使用独立的驱动器用于安装操作系统和软件,另外每个osd占用一个驱动器
建议将osd日志存储在ssd上
Ceph 最佳实践指示,你应该分别在单独的硬盘运行操作系统、 OSD 数据和 OSD 日志。
5.固态硬盘
评估SSD 时,顺序读写性能很重要,在为多个 OSD 存储日志时,有着 400MB/s 顺序读写吞吐量的 SSD 其性能远高于 120MB/s 的。
Important:我们建议发掘 SSD 的用法来提升性能。然而在大量投入 SSD 前,我们强烈建议核实 SSD 的性能指标,并在测试环境下衡量性能。
把 OSD 的日志存到 SSD 、把对象数据存储到独立的硬盘可以明显提升性能。
提升CephFS文件系统性能的一种方法是从CephFS文件内容里分离出元数据,ceph提供默认的metadat存储池来存储CephFS元数据,所以你不需要给CephFS元数据创建存储池,但是可以给他创建一个仅指向某主机SSD的CRUSH运行图。
控制器
控制器对写的吞吐量也有显著影响,要谨慎地选择,以免产生性能瓶颈
其他注意事项
你可以在一台机器上运行多个OSD,但是要确保硬盘总吞吐量不超过为客户端提供读写服务器所需的网络带宽;还要考虑每台主机上所存储的数据占总体的百分比,如果一台主机所占百分比太大而它挂了,就可能导致诸如full ratio的问题,此问题会使Ceph中止运作以防止数据丢失。
OSD数量太多(如20个以上)的主机会派生出大量线程,尤其是在恢复和重均衡期间,很多linux内核默认的最大线程数较小(如32k个),可以将kernel.pid_max值调高些,理论值4194303,把下面行加入到 /etc/sysctl.conf 文件
网络
建议每台机器最少两个千兆网卡,分别用于公网(前端)和集群网络(后端)
五、操作系统推荐
如果想在btrfs上运行Ceph,推荐使用一个最新的linux内核
玩转 Ceph 的正确姿势
本文先介绍 Ceph, 然后会聊到一些正确使用 Ceph 的姿势;在集群规模小的时候,Ceph 怎么玩都没问题;但集群大了(到PB级别),这些准则可是保证集群健康运行的不二法门;
Ceph 最初的目标是做一个分布式文件系统,直到现在这个目标也不能算完美实现;目前官网上对它的文件系统还是谨慎推荐的态度(不建议对线上核心业务部署);
业界使用 Ceph ,大多是用它的对象存储;
Ceph 客户端
Ceph 支持三种存储接口:对象存储 RGW(rados gateway)、块存储 RBD(rados block device) 和文件存储 CephFS;
这三个接口只是在客户端的封装库不同,到服务端了都是对象存储;
对象存储(RGW:RADOS gateway)
Ceph 对象存储服务提供了 REST 风格的 API ,它有与 Amazon S3 和 OpenStack Swift 兼容的接口。也就是通常意义的键值存储,其接口就是简单的GET、PUT、DEL和其他扩展;
块存储(RBD:RADOS block device)
RBD 是通过librbd库对应用提供块存储,主要面向云平台的虚拟机提供虚拟磁盘;RBD类似传统的SAN存储,提供数据块级别的访问;
目前 RBD 提供了两个接口,一种是直接在用户态实现, 通过 QEMU Driver 供 KVM 虚拟机使用。 另一种是在操作系统内核态实现了一个内核模块。通过该模块可以把块设备映射给物理主机,由物理主机直接访问。
文件存储
Ceph 文件系统服务提供了兼容 POSIX 的文件系统,可以直接挂载为用户空间文件系统。它跟传统的文件系统如Ext4是一个类型,区别在于分布式存储提供了并行化的能力;
原生接口
除了以上3种存储接口, 还可以直接使用 librados 的原生接口,直接和RADOS通信;
原生接口的优点是是它直接和和应用代码集成,操作文件很方便;但它的问题是它不会主动为上传的数据分片;一个1G的大对象上传,落到 Ceph 的存储磁盘上就是1G的文件;
而以上三个接口是具有分片功能(即:条带化 file-striping)
PS:两个对象的区分
需要说明下,这里提到两个对象的概念:一个是 RGW中的对象存储,一个是 Ceph 的后端存储的对象;这两个需要区分:
第一个对象面向用户,是用户接口能访问到的对象;
第二个对象是ceph 服务端操作的对象;
eg:使用RGW接口,存放一个1G的文件,在用户接口看到的就是存放了一个对象(1);而通过RGW 分片成多个对象(2)后最终存储到磁盘上;
Ceph 服务端
服务端 RADOS 集群主要由两种节点组成:一种是为数众多的、负责完成数据存储和维护功能的OSD(Object Storage Device),另一种则是若干个负责完成系统状态检测和维护的monitor。
Monitor
Monitor 集群提供了整个存储系统的节点信息等全局的配置信息,通过 Paxos 算法保持数据的一致性。
Pool 、PG和OSD
Pool是存储对象的逻辑分区,它规定了数据冗余的类型和对应的副本分布策略;支持两种类型:副本(replicated)和 纠删码( Erasure Code);目前我们公司内部使用的Pool都是副本类型(3副本);
PG( placement group)是一个放置策略组,它是对象的集合,该集合里的所有对象都具有相同的放置策略;简单点说就是相同PG内的对象都会放到相同的硬盘上; PG是 ceph的核心概念, 服务端数据均衡和恢复的最小粒度就是PG;
OSD是负责物理存储的进程,一般配置成和磁盘一一对应,一块磁盘启动一个OSD进程;
下面这张图形象的描绘了它们之间的关系:
- 一个Pool里有很多PG,
- 一个PG里包含一堆对象;一个对象只能属于一个PG;
- PG有主从之分,一个PG分布在不同的OSD上(针对三副本类型)
讲究的PG
一个Pool里设置的PG数量是预先设置的,PG的数量不是随意设置,需要根据OSD的个数及副本策略来确定:
Total PGs = ((Total_number_of_OSD * 100) / max_replication_count) / pool_count
线上尽量不要更改PG的数量,PG的数量的变更将导致整个集群动起来(各个OSD之间copy数据),大量数据均衡期间读写性能下降严重;
良好的工程实践建议(掉坑后的教训):
预先规划Pool的规模,设置PG数量;一旦设置之后就不再变更;后续需要扩容就以 Pool 为维度为扩容,通过新增Pool来实现(Pool通过 crushmap实现故障域隔离);
对象的寻址过程
查找对象在集群中的存储的位置,具体分为两步:
第一步,对象到PG的映射;将对象的id 通过hash映射,然后用PG总数对hash值取模得到pg id:
pg_ id = hash( object_ id ) % pg_num
第二步,PG到osd列表映射; 通过crush算法计算PG 上的对象分布到哪些OSD硬盘上;
CRUSH(PG_ID) =? OSD
CRUSH算法是 ceph的精华所在;
crush的目标
先看看crush算法的希望达成的目标:
- 数据均匀的分布到集群中;
- 需要考虑各个OSD权重的不同(根据读写性能的差异,磁盘的容量的大小差异等设置不同的权重)
- 当有OSD损坏需要数据迁移时,数据的迁移量尽可能的少;
crush算法
简单说下crush算法的过程:
第一步输入PG id、可供选择的OSD id 列表,和一个常量,通过一个伪随机算法,得到一个随机数,伪随机算法保证了同一个key总是得到相同的随机数,从而保证每次计算的存储位置不会改变;
CRUSH_HASH( PG_ID, OSD_ID, r ) = draw
第二步将上面得到的随机数和每个OSD的权重相乘,然后挑出乘积最大的那个OSD;
( draw &0xffff ) * osd_weight = osd_straw
在样本容量足够大之后,这个随机数对挑中的结果不再有影响,起决定性影响的是OSD的权重,也就是说,OSD的权重越大,被挑中的概率越大。
到这里了我们再看看crush算法如何达成的目标:
通过随机算法让数据均衡分布,乘以权重让挑选的结果考虑了权重;而如果出现故障OSD,只需要恢复这个OSD上的数据,不在这个节点上的数据不需移动;
crush优缺点
聊到这里,crush算法的优缺点就明显了:
优点如下:
- 输入元数据( cluster map、 placement rule) 较少, 可以应对大规模集群。
- 可以应对集群的扩容和缩容。
- 采用以概率为基础的统计上的均衡,在大规模集群中可以实现数据均衡。
缺点呢:
- 在小规模集群中, 会有一定的数据不均衡现象(权重的影响低,主要起作用的是伪随机算法)。
看清楚了寻址的过程,就明白为啥PG不能轻易变更了;PG是寻址第一步中的取模参数,变更PG会导致对象的PG id 都发生变化,从而导致整个集群的数据迁移;
这里只是做个引子,关于crush算法,这篇文章讲的通俗直白,有兴趣的移步:大话Ceph--CRUSH那点事儿
Ceph 是Sega本人的博士论文作品, 其博士论文被整理成三篇短论文,其中一篇就是 CRUSH,
CRUSH论文标题为《CRUSH: Controlled, Scalable, Decentralized Placement of Replicated Data》,介绍了CRUSH的设计与实现细节。
(PS:另外两篇是 RADOS和 CephFS, 分别讲 Ceph 的服务器实现和 Ceph 文件系统的细节实现)
故障域的划分
刚开始接触 Ceph,通常会忽略 crushmap,因为即使对它不做任何设置,也不影响我们的正常使用;
一旦集群大了,没有它集群就处于一个危险的运行状态中;
没有故障域的划分,整个集群就处于一个未隔离的资源池中;
一个对象存过去,可能落在 500个OSD硬盘的任意三个上;
如果一块硬盘坏了,可能带来的是全局影响(副本copy,这个硬盘上丢失的PG副本可能分布在全局各个硬盘上);
使用crushmap 将整个集群的OSD 划分为一个个故障域,类似将一个集群按业务划分成为了多个小集群;每个Pool 只会用到特定的 OSD,这样,一旦某个OSD 损坏,影响的只是某个业务的某个Pool,将故障的范围控制在一个很小的范围内。
良好的工程实践建议:
使用crushmap 划分故障域,将pool限制在特定的osd list上,osd的损坏只会引起这个pool内的数据均衡,不会造成全局影响;
服务端对象的存储
对象是数据存储的基本单元, 一般默认 4MB 大小(这里指的是RADOS的底层存储的对象,非RGW接口的对象)。
对象的组成分为3部分:key 、value、元数据;
- 元数据可直接存在文件的扩展属性中(必须是标准的文件属性),也可存到levelDb中;
- value 就是对象数据,在本地文件系统中用一个文件存储;
对于大文件的存储,Ceph 提供的客户端接口会对大文件分片(条带化)后存储到服务端;这个条带化操作是在客户端接口程序完成的,在 Ceph 存储集群内存储的那些对象是没条带化的。客户端通过 librados 直接写入 Ceph 存储的数据不会分片。
良好的工程实践建议:
对于对象存储,只使用 Ceph 提供的 RGW 接口, 不使用 librados原生接口;不仅有分片功能,扩展也更容易(RGW是无状态的,可水平扩展);大量大对象直接存放到 Ceph中会影响 Ceph 稳定性(存储容量达到60%后);
总结
上线 Ceph 前,先规划未来一年的预期使用量,为每个 pool 一次性设置 PG之后不再变更; 使用crushmap 设置故障域隔离,将磁盘故障后带来的数据平衡控制在一个小的范围之内。接口方面推荐只使用Ceph 提供的RGW 接口,不使用 librados原生接口。做好这些, 你的 Ceph 用起来会省心很多。
参考
Ceph官网
Ceph 中文文档
《Ceph源码剖析》
对Ceph在OpenStack中的价值进行简要介绍,并且对Ceph和Swift进行对比。
对于一个IaaS系统,涉及到存储的部分主要是块存储服务模块、对象存储服务模块、镜像管理模块和计算服务模块。具体针对OpenStack而言,则分别对应为其中的Cinder、Swift、Glance和Nova四个项目[1]。
在块存储服务部分,Ceph目前是Cinder项目的默认存储后端。前已述及,Red Hat也已经利用自己在KVM/QEMU社区中的影响力,将RBD驱动直接集成在QEMU中。这样,虚拟机访问基于RBD实现的块设备的性能将得到优化。
在对象存储部分,Swift是OpenStack自带的对象存储实现方案。但Ceph也已经成为了Swift最强有力的竞争对手。目前Swift也在考虑采用Ceph作为自己的存储后端。关于Ceph和Swift的故事将在6.2节详细展开。
在镜像管理部分,目前Glance已经支持将Ceph作为自己的本地镜像文件缓存。
在计算服务部分,United Stack目前正在推动将Ceph FS作为Nova计算节点的本地文件系统。
整体而言,Ceph事实上是目前OpenStack生态系统中呼声最高的开源存储解决方案。这一点从笔者在OpenStack 2013 HongKong Summit上的亲身体验可以得到印证。目前,以HP、Dell、Intel等为代表的企业IT领导厂商,和以Mirantis、eNovance、United Stack为代表的若干OpenStack社区新兴厂商,都将Ceph作为重要的乃至于首选的开源存储解决方案。
笔者认为,Ceph之所以在诞生多年不温不火的情况下,迅速在OpenStack社区中受到关注,除了其他一些明显优点之外,应该还是和其支持统一存储的能力有关。这一特性恰恰是OpenStack社区所需要的。
OpenStack项目设计的准则之一就是灵活可扩展。同时,其各个成员项目的背景也不尽相同。这也就导致各个项目在涉及存储系统时所采取的选择各有差异。但是,这一现状势必导致OpenStack的部署和运维面临一定的挑战。特别是对于一些规模不大的OpenStack部署实例,如果让块存储、对象存储、镜像缓存、计算节点本地存储等模块分别采用三四种不同的后端解决方案,则一方面其部署十分麻烦,另一方面运维人员的后续工作也很繁琐。在这种情况下,如果能够采用Ceph作为一种统一存储后端,则确实可以有效缓解这一问题。当然,这只是笔者的一家直言。任何技术选择必然都有其复杂的背后原因,这里的信息仅供参考。
Ceph与Swift:不能不说的故事,不能不作的比较
首先对Swift项目的来龙去脉进行简单介绍,以便大家更好地了解这个项目的特性,及其背后隐藏的原因。此处关于Swift的信息主要引自[2]。
Swift最早起源于2008年,本来是Rackspace公司内部开发的用于支撑其公有云对象存储业务的后端系统。当时,Amazon的S3服务已经颇受欢迎,因此,Rackspace决定开发Swift以提供对应业务作为回应。也正是因为这个原因,Swift的设计目标十分纯粹,就是一个优秀的、可以和S3相媲美的对象存储系统。其他要求纯属多余,因此完全不在Swift开发者的考虑之列。
Swift的开发大致历时一年,并在Rackspace成功上线运营。此后,OpenStack项目于2010年正式发布。Rackspace贡献了Swift,而NASA贡献了Nova,二者成为了OpenStack最早的两个项目。其后,若干Swift开发团队的核心成员独立创业,成立了SwiftStack公司,依然活跃在相关社区。
由此可见,Swift正是一个典型的起源于公司内部的、作为正式产品开发的开源项目。从这一点而言,Swift和“学院范儿”的Ceph可谓截然不同。也正是因为这个原因,Swift获得了一个得天独厚的优势:不缺启动用户,一开始就有生产环境下的大规模部署应用案例。事实上,相对成熟、web场景下应用案例多,是Swift社区目前依然反复强调的一个优势。
从技术上讲,Swift的特点主要体现在设计目标明确,就是要做一个纯粹的对象存储系统,因此不会考虑Ceph所强调的统一存储特性。同时,为了便于和其他项目、应用集成,Swift选择了Python语言进行开发。
与之相比,Ceph同时考虑了对象存储、块存储和文件系统存储能力,且目前在OpenStack中应用最多的场景事实上是块存储。同时,Ceph在选择开发语言时,很可能主要考虑的是性能因素,因而选择了C++语言。而能够被用于块存储场景这一点,也部分印证了其性能确实比较优秀。
由此可见,Ceph和Swift的区别,本质上是由其产生背景和应用目标所导致的。对这二者进行对比,并进行技术上的评判,并不非常公平。
事实上,作为开源分布式存储系统中的两个优秀代表,Ceph和Swift的设计和特性之中,也有着不少的相通之处:
首先,二者都强调良好的可扩展性,因此都采用了无中心点结构。只不过Swift的架构中有元数据服务器,只是通过多节点扩展的方式尽可能解决了其可靠性和性能顾虑。
第二,二者都能提供可配置的高可靠性。在两者的集群中,数据的备份数都可以选择,在常见生产环境中,也都使用三备份的方式。
第三,二者都强调自动化的集群管理。Swift同样引入了自动化的集群维护能力。
由此可见,简单地强调这两者之中的某一个更为优秀,是不合理的,也是没有实际意义的。
当然,在实际使用中,毕竟还是需要进行方案选择。结合[3]文中的观点,笔者认为,合适的选择或许如下:
*如果需要一个纯粹的对象存储系统,则选择Swift;
*如果需要一个纯粹的块存储系统,则只能选择Ceph;
*如果是一个小规模的、希望控制系统复杂度的OpenStack部署方案,则选择Ceph;
*如果是一个规模较大的系统,块存储和对象存储分别有较大的业务需求,则可以考虑将二者分离,分别采用Ceph和Swift。
到本篇为止,这一系列文章对于Ceph技术内容的介绍已经基本完成。后面一篇文章,将主要是笔者学习Ceph过程中的一些思考,供有兴趣的读者一同品评。