1. 从“一块盘”到“一个宇宙”:为什么Ceph值得被当作一个生态系统来看
接触Ceph的人,最初往往是被它的一个功能吸引过来的:想用几台普通服务器搭一个分布式存储,能够同时提供块存储、文件存储和对象存储。但用着用着就会发现,你其实并不是在用一个软件,而是在进入一个庞大的、由无数组件和周边工具构成的技术生态。这个生态里有负责数据落盘的底层服务,有负责集群监控的组件,有处理客户端接入的网关层,还有无数第三方项目围绕它做备份、迁移、监控、编排。就像你买了一辆车,结果慢慢发现自己在研究整个交通系统。
Ceph从诞生到今天已经有超过十五年的历史。很多人在2016年左右第一次接触它,是因为OpenStack社区把它当作默认的后端存储。那时候的Ceph集群,三节点起步,副本数默认两份,跑一个几十TB的测试环境,create pool、rbd create、map到客户端,能跑通就算入门了。但后来随着生产环境规模越做越大,Ceph本身也在快速演化:从最初只支持RADOS底层对象存储,到后来有了RBD、RGW、CephFS三大接口,再到Kernel模块、librbd、cephadm、Crimson、RADOS Gateway多站点同步、EC纠删码、NVMe over Fabrics这些高级特性,这个系统已经远远超出“分布式存储软件”这个范畴。
这篇文章想做的事情,不是再讲一遍Ceph怎么安装、怎么配一个三节点的集群,而是把Ceph作为一个完整的生态系统来拆解。我会从整体架构、核心组件、接口协议、运维经验、生态周边、选型避坑几个维度,把我这些年实际用下来的体会和踩过的坑一起梳理出来。适合的人群有两类:一类是正准备把Ceph引入生产环境,需要搞清楚它到底由哪些部分组成、哪些部件容易出问题;另一类是已经在用Ceph,但主要停留在“会敲命令”层面,想对整个系统有一个更完整认知的运维和开发同学。看完这篇文章,你至少能做到:听到任何一个Ceph生态里的名词,能马上知道它处在哪个层级、解决什么问题、和哪些组件有依赖关系。
为什么我说“生态系统”比“开源软件”更准确?因为Ceph的复杂性不在于单个组件的难度,而在于组件之间的关联。很多人一开始在ceph-deploy时代被monitor和osd的关系绕晕,后来又在新版cephadm里被daemon的概念搞得一头雾水,再到后面接触prometheus监控、ceph-csi、Rook Operator、Velero备份这些生态项目,会发现每一个方向都是一座小山坡。而这座山的核心脉络,如果你从生态的视角去看,会清晰得多。
2. 核心架构与数据通路:读懂Ceph的“中央厨房”
2.1 从Mon到OSD,一次读请求到底经历了什么
Ceph生态里最重要的一对关系,是Monitor和OSD的关系。早年刚入门的时候,我最常被问的问题就是:“为什么Ceph既要有Monitor,又要有OSD?它们不都是存数据的吗?”答案其实很符合直觉:Monitor不管你的真实业务数据,它管的是集群的“元信息”——谁在集群里、有多少个OSD、当前处于什么状态、数据应该怎么分布。而OSD才是真正干活的人,每个OSD负责管理一块磁盘,一份数据写进来的时候,由OSD把数据落盘、复制副本、做心跳上报、参与数据平衡。
把整个系统类比成中央厨房就好理解了。Monitor是前台领位员和调度台,它知道现在后厨有几位大厨、哪口锅空着、哪条出菜通道堵了。客户点单(客户端请求)进来,先找领位员确认“这个菜该找谁做”,然后后厨的OSD大厨们才开始动手。如果领位员挂了,后厨还在,但所有新来的客人都不知道该找谁,整个餐厅就瘫痪了。所以Ceph要求Monitor必须是奇数个,推荐三个起步,目的很简单:多个领位员之间通过选举机制保证即使一两个出问题,整个调度体系仍然有效。
一次标准读请求的完整路径是这样的:客户端进程(比如KVM虚拟机里的qemu进程)通过librbd库发出读请求,librbd会根据对象名、pool的pg_num等参数,用CRUSH算法计算出这个对象对应哪个PG、这个PG的主OSD在哪台机器上,然后直接向该OSD发起请求。如果客户端开启了cephx认证,所有通信还会包一层加密认证。这里有个关键点:读路径上Monitor只在两个时机被用到,一个是客户端初始化时获取集群map,另一个是当集群map发生变化(比如某个OSD挂了、PG发生迁移)时获取最新版本。一旦拿到了集群map,客户端和OSD之间就是“直连”关系,不再经过Monitor中转。理解这一点,对排查高延迟问题特别重要——如果你发现某个客户端读写很慢,但Monitor负载并不高,那问题大概率出在网络链路或OSD所在的磁盘本身,而不在Monitor。
2.2 CRUSH算法与PG:为什么数据能自动分布,又不会乱成一团
Ceph最让新接触分布式存储的人惊叹的一个设计,就是数据分布不需要查元数据中心,而是纯靠计算。这个机制的核心是CRUSH(Controlled Replication Under Scalable Hashing)算法。你可能会问:“不做元数据记录,数据写到哪里怎么知道呢?”答案是一套基于层级结构和随机哈希的组合算法。
打个比方,CRUSH就像一个超级稳定的抽奖机,你给它的输入是对象名、pool的副本数、集群的OSD拓扑结构,它每次都能稳定地输出一组OSD编号,决定这个对象的主副本和从副本分别落在哪里。这里有两个关键词:一个叫“稳定”,同一个对象无论什么时候计算,结果都一样;另一个叫“分散”,不同对象的计算结果尽量均匀地分布到所有OSD上。CRUSH算法还支持很细的故障域控制——你可以规定副本必须分布在不同主机、不同机架,甚至不同机房,这就实现了数据级的高可用,而不用依赖上层应用做任何感知。
PG(Placement Group)是CRUSH算法和真实OSD之间的“中间层”。如果直接让几百万个对象各自做一次CRUSH计算映射到OSD,性能开销会非常大,而且每次集群拓扑变化都要重算海量数据。Ceph的做法是把对象先映射到PG(用对象名哈希取模),再把PG通过CRUSH算法映射到OSD。一个pool默认的pg_num通常是几百到几千,每个PG里又会包含许多对象。这个设计有点像图书馆的索引卡片:几百万本书(对象)不用每本都记住自己在哪个书架(OSD),只需要记住自己属于哪个类别(PG),然后按类别找书架就行。只要pg_num设置相对合理、后续随着集群扩容适当调整,整个系统的数据分布就能保持相对均匀。关于pg_num的计算,我见过最常被引用的一个经验公式是:(OSD总数 × 100) / 副本数,但这个公式只适合中小规模集群做初始估算。真正到了大规模环境,还需要结合每个OSD承载PG的数量上限来看,这个我后面在参数调优部分会详细展开。
2.3 数据写路径与日志策略:先写Journal还是直接写底层
早年Ceph的写路径和现在有比较大的区别,了解这段演进过程对理解“写放大”“延迟”这些概念非常有帮助。传统模式下,一个写请求到OSD之后,要先写入OSD对应的Journal(也就是一块独立的SSD或者NVMe盘),然后才确认给客户端“写成功了”,后台再把Journal中的数据刷入数据盘。这样做的好处是延迟低,因为Journal盘的随机写性能远高于HDD;坏处是逻辑复杂、对Journal盘可靠性要求高,而且多了一层写放大。
后来Ceph引入了BlueStore这个底层存储引擎,它直接把原本由文件系统(早期是ext4/xfs)管理的数据落盘方式,改成在裸设备上自行管理,并引入WAL(Write-Ahead Logging)和RocksDB作为元数据存储。BlueStore极大地解决了双写放大问题,同时通过自带的空间管理、校验和机制,把单盘性能推到了一个新的高度。现在新部署的集群,默认都是BlueStore,以前那套独立Journal的概念基本退出了历史舞台。但底层逻辑你想通了会发现没变:为了保证性能和可靠性,写路径上依然需要“先写日志后落数据”的思想,只不过现在的WAL默认就放在OSD所在机器的SSD或NVMe高性能盘上,不需要你再单独划分一个journal分区。所以如果你在网上翻到五年、八年前的老教程,里面教你分journal盘区的操作,可以不用再照做了。
这里我想分享一个很重要的经验:因为BlueStore默认使用RocksDB管理元数据,如果你用HDD做数据盘,强烈建议给RocksDB配一块小容量SSD(通常几十GB到几百GB就够),否则元数据随机读会成为明显的瓶颈。很多刚接触Ceph的人想省成本,直接几块HDD组集群,结果IOPS惨不忍睹,然后说Ceph不行。其实不是Ceph不行,是你没有理解它的生态里“慢速数据盘+快速元数据盘”这个经典搭配。
3. 三大存储接口与周边组件:块、文件、对象,同源不同脸
3.1 RBD块存储:云平台和虚拟化的默认选择
Ceph的块存储接口叫RBD(RADOS Block Device),它提供的是裸设备级别的存储能力,使用方式类似一块虚拟硬盘。你可以把RBD设备映射到Linux主机上,做成文件系统;也可以接到QEMU/KVM虚拟机上,作为虚拟机的系统盘;还能被OpenStack Cinder、Kubernetes CSI、Proxmox VE这些上层平台直接调用。RBD最核心的价值在于:它在分布式系统之上给了你一块“本地的盘”的使用体验,同时又具备快照、克隆、动态扩容这些企业级存储功能。
我自己在Kubernetes环境里给应用挂载RBD存储的次数非常多。现在的标准流程是用ceph-csi这个驱动,StorageClass里指定好pool和文件系统类型,Kubernetes就会自动通过librbd创建RBD块设备、在节点上挂载、完成格式化,然后给Pod用。相比传统的static PV手动创建块设备再挂载,这个流程完全自动化,而且支持快照、克隆、扩容。生产环境里我会额外注意一点:RBD的在线扩容虽然可以做,但要触发文件系统感知底层块设备变大了,往往还需要在Pod或者虚机内部跑一次resize命令,所以应用层要预留相应的自动resize机制,不然存到最后才发现文件系统没扩展,那种“盘浪费了但业务不知道”的情况很常见。
RBD还有一个容易被忽略的特性是layering。基于块设备做快照之后,可以把这个快照克隆成一个独立的块设备,这在开发测试环境里特别好用:给每个开发分支拉一个相同的数据环境的块设备,秒级完成,不需要各自拷贝一份完整镜像。克隆采用copy-on-write机制,底层数据页只在写入时才按需复制,既省空间又加快速度。但要提醒一下:COW克隆出来的块设备和快照之间有依赖关系,如果快照被删了,克隆出来的块设备可能就会直接失效。所以生产环境一定要有清晰的快照保留策略,别随手删。
3.2 CephFS文件存储:共享文件系统的正确打开方式
CephFS是基于Ceph提供的POSIX兼容分布式文件系统。它适合的场景是“多个客户端需要共享同一份数据,且能像操作本地文件一样操作远程文件”,比如多个容器需要共享配置文件、大数据平台多个计算节点需要访问同一份数据集、传统应用通过NFS/CIFS网关使用CephFS路径。相比RBD那种一块盘只能挂给一个主机的模式,CephFS天然就是多头读写共享,语义上更接近NFS,但性能和扩展性要比传统NFS好得多。
CephFS的正常工作依赖两类守护进程:MDS(Metadata Server)负责管理文件的目录树和inode元数据,数据本身则按类似对象的逻辑存放在RADOS里。MDS是可以多活部署的,通过rank机制实现多主节点并行服务,单点瓶颈比传统NFS要小很多。早期很多人不敢在线上用CephFS,是因为MDS曾经过出稳定性问题,尤其是出现递归目录扫描、大量小文件操作的时候,内存容易失控。但新版Ceph(尤其是Quadruple O之前推出的MDS多活能力和更大的元数据缓存调优参数)已经把这些短板补得差不多了,生产使用完全可行。
使用CephFS的时候我最想强调的一点是:它不适合承载超大量小文件的随机读写场景,你的应用最好是连续IO为主、单个文件体积别太小。CephFS在大文件顺序读写的表现很不错,但如果你把它当成一个存放几十亿个几KB小图片的仓库,MDS的压力会非常大,体验会明显下降。对象存储RGW才是小文件海量沉降更合适的场景。很多团队踩坑,就是因为没分清“共享文件系统”和“海量小文件对象存储”的定位差异。
3.3 RGW对象存储:兼容S3的那条最宽的路
RGW(RADOS Gateway)是Ceph生态里用户面最广、生态兼容性最好的接口。它提供的是Amazon S3和OpenStack Swift兼容的RESTful API,也就是说,你完全可以把Ceph RGW当成一个自建的S3来用,包括AWS SDK、S3CMD、MinIO Client、各类备份工具,只要支持S3协议,都能直接连上去。我用RGW接得最多的场景有:应用备份文件存放、静态资源存储、容器镜像仓库的存储后端、大数据分析结果归档。
RGW的部署单元是radosgw实例,它们的前端本质上是Civetweb或Beast这类HTTP服务进程。每个radosgw实例可以配置不同的realm、zonegroup、zone,从而构建从单站点、多站点同步到异地双活的复杂拓扑。RGW还支持用户体系、Bucket策略、生命周期管理(比如自动清理过期对象)、CORS规则、静态网站托管等功能,这些功能对于从AWS S3迁移过来的团队来说几乎是无痛的。
多站点同步这个方向,我自己觉得是Ceph生态里最复杂也最需要小心的部分之一。比如你配置了异地双活,两个数据中心的RGW做双向同步,看起来很美好,但一旦出现网络分区,两边同时写入同一个对象,冲突策略需要提前设计清楚;另外,如果某一个数据中心长时间断连,恢复后的增量同步也可能产生巨大的数据追赶任务,容易拖垮集群带宽。所以我的建议是:如果不是业务必须强一致的多活,尽量优先做“主-备”架构,主站点正常服务,备站点异步同步数据,出问题可以快速切换,运维的复杂度会大大降低。
3.4 从三个接口反推底层统一:为什么说生态价值大于单一功能
很多人会问:RBD、CephFS、RGW这三个接口,底层真的是一套存储吗?答案是肯定的。无论你用哪个接口,最终的数据都按照对象的形式存储在RADOS层,由OSD负责持久化。这种“一个核心,多接口”的设计有一个很大的生态价值:你不需要为块存储、文件存储、对象存储分别采购不同的硬件或者维护不同的软件栈,一套Ceph集群可以同时提供三种能力,还共用一套监控、认证、扩缩容和运维体系。
但要注意,共用底层也意味着共享资源池。比如你把RBD pool、CephFS数据pool、RGW数据pool都放在同一个Ceph集群里,那么某一个pool的突发流量会占用底层OSD的CPU和带宽,可能会影响其他pool的延迟。生产环境我见过很多团队的做法是:用同一个Ceph集群承载所有接口,但通过不同pool的osd_perf_op线程数、客户端QoS、甚至独立的节点组(比如为RGW单独划分一部分OSD)来做资源隔离。如果你预算充足、规模足够大,多集群分离是更好的方案;如果规模中等,单集群多pool加QoS控制也够用。关键是别图省事把三个接口混在同一个默认pool里不管。
4. 部署选择与运维体系:cephadm时代,别再走老路了
4.1 从ceph-deploy到cephadm,最大的变化不是命令而是思路
如果你翻到2018年以前的Ceph安装教程,大概率会看到ceph-deploy,然后一条命令一条命令地安装monitor、osd。这个工具的时代已经过去了。Ceph在Nautilus版本之后主推cephadm,它是基于容器化的部署工具,所有Ceph守护进程都跑在容器里,由cephadm统一拉取镜像、生成systemd单元、管理升级。这个变化带来的好处是非常明显的:环境依赖不再碎片化,你不需要手动装一堆Python依赖、修改OSD的初始化脚本;升级时cephadm可以滚动替换容器镜像,加上health check机制,比以前手动升级要稳很多。
cephadm最重要的一个概念是bootstrap。执行ceph bootstrap命令后,它会自动在当前主机上拉起一个最小的Monitor集群和一个MGR(Manager)节点,然后给你一串dashboard的访问地址和登录凭据。之后要用ceph orch命令添加主机、添加OSD。这里的思路变化在于:以前你是手动定义哪些节点是什么角色,现在你更像是在“声明”集群想要什么状态,cephadm去负责“实现”这个状态。比如你想让某个节点加入集群,用ceph orch host add把主机加进来,然后用ceph orch apply osd把该节点的磁盘纳入管理。这种声明式管理一开始需要适应,但用顺手了以后,尤其在做大规模集群扩容的时候,省心很多。
这里有一个新手特别容易踩的坑:cephadm要求所有节点的hostname必须能互相解析,而且时间必须同步。容器化部署对时钟偏移尤其敏感,因为ceph-mon之间靠心跳和选举维持共识,时间差一旦达到几百毫秒就可能出现频繁的leader切换,集群状态会各种“打摆子”。我见过不止一次,ceph -s显示所有daemon都health但客户端写入不稳定,最后排查发现是NTP没配置好。所以无论你用什么方式部署Ceph,第一件事永远是检查各节点之间的时间同步,第二件事才是容器镜像版本。
4.2 Dashboards、Prometheus与监控告警:从“能跑”到“看着它跑”
一个Ceph集群能不能算生产可用,我的判断标准不只是功能能跑,更在于它有没有一套完整的可观测体系。Ceph生态在这方面已经相当成熟了:cephadm部署的集群默认自带Prometheus模块和Grafana Dashboard,MGR里面内置了一个prometheus模块,主动把集群监控指标抓取暴露出来,然后由Prometheus做时序存储和告警规则触发。Ceph Dashboard本身直接集成了Prometheus数据源,你在浏览器里能看到OSD健康状态、PG状态分布、性能指标、RGW请求延迟等,不用再另外搭一套监控。
从我个人实践来看,每天必看的核心指标有这么几项:PG的状态分布是否出现inactive/degraded(这是故障信号,要立即处理);osd的latency指标(特别是commit latency和apply latency,如果明显上涨,优先排查磁盘是否出现慢盘);集群的总带宽和客户端IOPS趋势,用来做容量规划。Ceph自带的告警规则覆盖了大部分常见的故障类型,比如OSDDown、PGDegraded、MonDown、MgrDown,你需要做的只是把告警推送到企业IM或邮件。这里我踩过的坑是:默认告警规则里部分阈值不适合小集群,比如某些性能类告警在小规模集群上会频繁误报,建议针对自己的实际规模调整阈值,不然告警疲劳很快就会让人麻木。
4.3 备份、迁移与容灾:Ceph生态里那些容易被忽略的周边
Ceph生态并不只是“存储服务本身”,围绕生命周期管理,还有一批非常实用的周边工具。比如rbd命令自带export/import,可以导出整个块设备为镜像文件再导入,这个在测试环境迁移、灾难恢复演练时很实用,但生产环境大规模镜像导出导入的效率很一般,更适合小容量块设备。RGW本身就支持S3协议,所以你可以直接用各种S3生态备份工具做跨站点同步,或者把RGW的数据备份到另一套对象存储里。CephFS则是通过snapshot机制做快照,然后定期把快照差异导出备份。
如果你在Kubernetes里使用Ceph,还要了解Velero配合RBD快照做应用一致性备份的方案。Velero可以通过Ceph的CSI快照能力,对一个包含多个PVC的应用做时间点一致的备份,这在云原生环境里几乎是标准做法。我自己的经验是:Ceph的快照能力非常强大,但真正的备份体系需要你主动把它串起来。快照不是备份,快照只存在于同一个Ceph集群里,如果集群整体故障,快照也一样丢。所以对关键业务,仍需把数据做一次跨集群或者跨数据中心的复制。很多人误以为有了Ceph快照就等于有异地灾备,这个认知是危险的。
4.4 容器化运维的底层逻辑与心智模型:从进程到daemon到service
容器化部署另一个必须理解的心智模型升级,是“进程”概念转变成了“daemon”和“service”。以前你看到一个node上跑着ceph-osd,你心里想的是“哦,有一个进程”。但用cephadm之后,你会看到服务编排层面的“service”和调度层面的“daemon”——比如你ceph orch apply osd之后,cephadm不是直接创建固定的OSD容器,而是创造了一个“目标状态”,集群的编排器会持续检查每个节点的OSD数量是否达到预期,如果某个OSD容器启动失败,它可能会重新创建容器,或者报告daemon异常。这个“持续协调”的模型对运维心态的要求是:你要学会看service状态,而不是只盯某个容器进程。
还有一个常见问题是“容器内的配置在哪”。cephadm每启动一个daemon,都会根据集群配置动态生成一份ceph.conf以及keyring等文件,挂在到容器内。所以最好不要手动去改容器内的配置文件,所有配置都该通过ceph config set或者dashboard来做,才能保证编排器重建容器时配置不丢。这个点我见过很多以前做物理机部署的运维踩坑:他们习惯性ssh到节点上、进到容器里vim配置,结果节点一重启,容器被编排器重建,改的东西全部没了。
5. 性能调优与故障排查:让集群稳定并跑出应有的速度
5.1 关键参数选择:从pg_num到OSD内存,哪些参数值得认真对待
Ceph生态里,参数调整是永远绕不开的主题。但参数多、且很多参数之间有联动关系,贸然改动可能反而引起问题。我建议先从这些最关键、风险相对可控的参数入手:
首先是pool的pg_num。新建pool之前,尽量根据池内预估的对象数量把pg_num设在一个合适的值。常见计算方法是:数据量几十TB、OSD数十个的集群,pg_num可以从128起步,上限设置到512左右;大规模集群可以逐步增加。需要注意的是,pg_num一旦设定,虽然在线可以更改,但会触发数据重分布,产生较大的集群负载。所以上线前就应该做相对准确的容量估算,而不是上线后频繁调。
其次是OSD的memory target。BlueStore的缓存层默认会尽量占用节点可用内存,osd_memory_target这个参数控制了每个OSD进程期望使用的内存量。你如果在一个64GB内存的节点上部署了4个OSD,默认情况下每个OSD可能都想拿取较多内存,很容易出现节点OOM。合理的做法是:根据节点物理内存除以OSD数量,设定一个保守的osd_memory_target,比如每个OSD 8GB或16GB,并注意系统本身还要预留一部分内存给别的进程。调这个参数的时候不要一次拉满,要给RocksDB和系统自身留出余量。
另外,网络层面的配置也常常被忽略。如果节点之间有多个网卡,尽量把集群的cluster network和public network分开,让数据复制和客户端流量走不同的物理通道,避免相互争抢带宽。新版Ceph支持msgr2协议,加密通信可选用cephx,但开启msgr2的压缩和相关加密特性时要注意CPU开销,如果集群CPU不算富余,建议只开认证,不要开消息压缩。
5.2 慢盘、慢请求与PG异常:一套通用的排查路线
即便集群已经跑得挺稳定,也架不住某一天某个OSD开始变慢。慢盘在Ceph生态里是最常见的故障源头之一。你会发现集群发出很多“slow ops”告警,客户端侧表现为写延迟升高甚至超时。排查步骤我建议按这个顺序走:先看ceph -s确认哪些PG异常、是否出现inactive状态;再用ceph osd tree看OSD状态是否down;接着用ceph daemon osd.x perf dump看该OSD的提交延迟和操作延迟;最后落到系统层面,用iostat检查盘是否出现util 100%、await飙升、svctm异常。
如果确认是慢盘导致的PG peering异常,最直接的处理是把这个OSD从集群中临时out掉,让数据先迁移到其他OSD,然后对物理盘做进一步检查。这里要特别注意:osd out之后不要立刻destroy,要确认它上面的PG已经完成重分布且集群状态恢复,再决定是否清盘重新加入。我见过有人图省事,out之后直接把OSD zap了,结果集群还在迁移过程中缺数据副本,风险很高。
还有一个高频问题:某个OSD进程反复重启,表现为docker inspect看到容器restart次数不断增加。通常原因有三类:磁盘出现IO错误触发OSD崩溃;ceph-osd与monitor之间网络不稳导致被判定异常自杀重启;进程内存超过限制被OOM kill。对应的排查方向分别是:dmesg看硬件错误日志、检查网络丢包、检查osd_memory_target与真实内存消耗。如果反复重启且无法自愈,把OSD标记为out并止损,比一直重启进程更稳妥。
5.3 扩容、缩容与数据平衡:什么时候动存储节点是安全的
Ceph集群扩容是运维日常里比较提心吊胆的操作。扩容OSD看起来只是加机器,但背后涉及数据自动迁移、集群负载瞬时升高、甚至可能触发部分PG迁移失败。我的建议非常简单:扩容前务必确认集群当前没有异常PG,尤其是不要存在degraded或peering卡住的状态,否则数据迁移会把问题放大。扩容时逐个节点执行ceph orch apply osd,每完成一批OSD加入,观察集群的rebalance状态和迁移速度,等稳定后再加下一批。这个“稳步推进”的做法虽然慢,但远比你一次加几十个OSD,结果集群整体性能雪崩靠谱。
缩容比扩容更危险。如果你要下掉一个OSD,正规流程是ceph osd out,等它包含的PG全部迁移到其他OSD、且集群进入active+clean状态后,再ceph osd crush remove、ceph auth del、最后ceph osd rm。如果要做的是整机下线,还要注意节点上的monitor或mgr角色要先平滑转移。很多生产事故都是缩容时图快,没有等待数据落完就强行拔盘,导致数据只剩一份副本甚至丢失。记住一句话:Ceph的自我修复能力源于副本,而副本的安全建立在“迁移完成”这个前提上。
5.4 性能基线速查表:给你的集群一次客观的“体检”
为了评估集群是否健康,我给自己的集群定期做性能基线测试,包括RBD顺序写、随机写、顺序读、随机读和RGW对象上传下载。测试工具有很多,比如用fio配合librbd直接测RBD,用cosbench测RGW,用小文件压测脚本测CephFS。测试要产生能横向对比的结果,关键是要固定参数:fio的block size、iodepth、numjobs、runtime尽量保持同一套;RGW测试则要固定并发数和对象大小。
一个小型三节点集群的典型基线参考如下:
- RBD顺序写(4MB块,iodepth 32):单卷约300MB/s左右,三卷并发时受网络瓶颈限制,每卷会下降但总带宽上升。
- RBD顺序读(4MB块,iodepth 32):单卷可达500MB/s以上,如果节点网卡是10Gb,基本都能跑满。
- RBD随机写(4KB块,iodepth 32):比较考验底层磁盘和WAL性能,如果OSD都是机械盘,IOPS可能只有几百,明显低于SSD。
- RGW单流上传一个大对象(100MB以上):延迟会包含HTTP解析和对象分片写入时间,通常单流几十MB/s,多流并发能拉高总吞吐。
需要强调,上面只是参考,不是标准答案。不同硬件、网络、副本数、PG数都会导致差异。关键是定期拿同一套方法跑一次,长期积累就能形成自己的“正常区间感”,一旦发现某次结果严重偏离历史基线,就说明集群哪里出了问题。
6. 现实中的Ceph:生产部署的选型建议与经验教训
6.1 硬件选型:别在Ceph身上省不该省的钱
Ceph对硬件的要求,其实没有传说中那么苛刻,但有一条底线必须守住:网络。Ceph的客户端读路径和OSD之间的复制路径,以及PG迁移路径,全部依赖网络。如果你用千兆网,小规模测试可以跑,生产环境无论块存储还是文件存储都基本没法用。至少万兆起步,数据库类应用或高并发场景建议25Gb甚至100Gb网络。存储节点之间的大流量复制完全依赖内部网络,网络一旦成为瓶颈,集群哪哪都慢。
磁盘选择上,我现在的建议是:数据盘优先用大容量NVMe或SATA SSD,机械盘只适合耐延迟场景或冷数据归档。不是机械盘不能装Ceph,而是Ceph里的元数据随机读、副本复制、数据校验这些额外开销会让HDD的短板放得很大。如果你确实预算有限必须用HDD,那一定要给每个OSD配一个小容量SSD作WAL和DB存储,而且这个SSD要是企业级的,否则寿命和IOPS都会跟不上。
内存方面,OSD数量乘以每个OSD的memory_target就是你需要的基础内存,再给系统、monitor、mgr、RGW这些留出余量。一个常见的预算方式:8个OSD的存储节点,每个OSD分配8GB缓存,加上系统预留16GB,这台机器至少64GB内存比较稳。别为了省内存把osd_memory_target设太低调过头,会影响缓存命中率,反而导致延迟升高。
6.2 与大厂云存储的对比:什么时候用Ceph,什么时候别用
Ceph生态最大的优势是“数据自主可控”和“多接口统一”,但也要承认它的运维门槛是真实的。如果你已经有成熟的运维团队,愿意投入时间去理解它的工作原理,Ceph能给你一套不依赖特定厂商的、可以持续演进的存储底座。反过来,如果你只有两三个人,业务量和数据量都不大,也不要求私有化部署,那么云平台的对象存储或者块存储其实更省心,不用管底层的故障转移、数据平衡、版本升级。
选型上我的判断标准是三条:第一,数据规模——十TB级以下,没必要上Ceph;百TB以上,私有化时Ceph是合理选择。第二,团队能力——有没有人能持续关注集群健康并处理慢盘、迁移、升级这些隐性工作。第三,接口需求——如果同时需要块存储、对象存储、文件存储且希望一套系统搞定,Ceph的价值就很大;如果只需要对象存储,MinIO在轻量场景下部署更简单,但多站点同步能力、大规模扩展能力不如Ceph稳定。
6.3 生产环境常见“隐形事故”回顾与应对
这些年我遇到过几个比较典型的隐形事故,在官方文档里都不太容易找到直接答案,分享出来提醒后来人。
第一个是“单机多OSD配置陷阱”。很多节点会插好几块盘做多个OSD,这本是常规操作,但如果你把同一块物理盘做成多个分区分别给不同OSD,一旦这块盘物理故障,所有相关OSD同时不可用,故障域直接塌房。这个操作完全违背了Ceph的故障隔离设计,任何情况下都不该这么干。
第二个是“PG数量不符导致的数据倾斜”。新建pool时pg_num设得偏小,随着对象数据量上涨,每个PG内的对象数量会严重不均匀,最终表现为一两个OSD磁盘使用率远超其他盘,触发nearfull告警。解决方法是上线前做好容量规划,后续调整要配合rebalance操作,别指望PG数量能随时无限调整而没有任何代价。
第三个是“多集群共用同一个公共网络”。两个Ceph集群如果共用同一组交换机,某个集群做数据重平衡或大规模备份时,会把其他集群的带宽挤垮。这个看起来简单,但在中小公司里非常常见。规划网络时,一定要把“测试集群”和“生产集群”之间的带宽争抢考虑进去,否则你半夜看到的延迟飙升可能根本不是自己集群内部的问题。
第四个是“备份未验证等于没有备份”。RBD快照、RGW跨站点同步、CephFS快照这些机制本身都可靠,但如果你从不做恢复演练,出故障时才发现快照链断裂或跨站点数据不一致,后果会非常严重。我给自己定的规矩是:每个季度做一次完整的恢复演练,必须在隔离环境里真实恢复出一个可用副本,验证能启动应用、能读到数据,而不是只看备份任务的状态是“成功”。
6.4 社区版本选择:L版本还是N版本,别追新
Ceph的版本命名规则是字母版本加数字,比如Reef(S)、Squid(T)这些,社区每两年有一个LTS(长期维护)版本,名字里带L的,比如Octopus、Pacific、Quincy都是LTS。生产环境我强烈建议选择LTS版本,而不是追新。新版本的功能通常会带来新的稳定性风险,而存储这类基础服务最怕不稳定。即使你用LTS,也要等小版本迭代到至少x.2之后再上生产,让社区把前期的主要bug修掉一部分。
从我做过的版本升级经验来看,Ceph滚动升级的机制已经比较成熟,cephadm可以以服务为单位依次升级monitor、mgr、osd、rgw,整个过程只要按官方文档走、按顺序来、每一步观察集群状态,一般都比较顺。最容易翻车的其实是跳过多个大版本直接升,比如从Octopus直接跨到Quincy,中间很多配置结构和容器镜像差异太大,容易出现不可预知的问题。正确做法是一级一级升,每升完一个大版本稳定跑一段时间再做下一步。
7. 周边的“卫星生态”:从Rook、CSI到S3工具链,Ceph不是孤岛
7.1 Kubernetes生态里的Ceph:Rook、CSI与StorageClass实践
在云原生环境下,Ceph最常见的接入方式是Rook,它把Ceph的部署和运维进一步封装成了Kubernetes的Operator模式。你可以通过一个简单的CRD定义来声明一个CephCluster资源,Rook会负责拉起monitor、osd、mgr这些Pod,并根据CephCluster的状态自动做故障恢复。Rook特别适合Kubernetes原生的团队,因为它的运维界面就是kubectl,不需要你再去单独维护cephadm命令行。但要注意,Rook管理Ceph集群时,底层仍然遵循Ceph的所有原理和运维逻辑,只是把ceph инструменты封装了一层。所以如果你搞不懂PG、OSD、MDS这些概念,用Rook只是换了个壳子,该踩的坑一个都不会少。
在Kubernetes里结合Ceph,我更常用的其实是直接部署Ceph集群,然后用ceph-csi接入PV。这样Ceph依然归存储团队管理,应用团队只是看到标准的PVC和StorageClass。ceph-csi支持RBD和CephFS两种类型,RBD对应块设备、CephFS对应共享文件系统。我建议你为不同场景建不同的StorageClass:状态型应用、数据库这类需要独占块设备用RBD;多个Pod共享读写配置、日志聚合目录用CephFS。StorageClass的parameters里有一些值得关注的调优项,比如mountOptions、csi.storage.k8s.io/fstype、encryption,需要根据业务按需配置,不要一个模板走天下。
7.2 周边工具全家桶:从radosgw-admin到S3客户端
Ceph生态的日常管理工具,核心就一个:ceph命令。但围绕不同接口,还有不少专用工具。RGW相关的有radosgw-admin,管理用户、bucket、配额、生命周期策略等都在这里;配合S3协议使用,S3CMD、AWS CLI、MinIO Client这些客户端都可以跨工具使用。CephFS有setfattr、getfattr辅助设置扩展属性和quota,RBD则有rbd命令做快照、克隆、export、import。这些工具的掌握程度直接影响运维效率,但它们的逻辑都很一致:先找到目标资源(用户、镜像、bucket、快照),然后查看或修改属性。
备份领域,rbd export/import的适用场景是小规模块设备迁移;RGW数据跨站点同步是官方支持的主力灾备方案;CephFS的快照调度可以用ceph fs snap schedule命令实现定时快照,再配合自定义脚本做差异同步。还有一个我特别喜欢的场景是:把Ceph RGW作为Kubernetes集群的Velero备份目标存储,既可以用S3兼容协议把整个集群的PV快照和数据包源源不断沉淀到Ceph里,又不用额外引入其他存储系统。
7.3 从单一存储到统一数据底座:Ceph和你的其他系统怎么配合
很多团队最初用Ceph只是为了解决一个具体问题,比如给OpenStack做块存储后端、给Kubernetes做PVC后端,但用久了之后,Ceph会逐渐成为整个基础设施的数据底座:虚拟化平台的虚拟磁盘在那里,容器平台的应用数据在那里,日志归档、备份镜像、大数据中间结果也都在那里。这个角色转变带来的影响是,Ceph的稳定性直接决定了所有上层业务的可用性,所以运维视角必须从“看某个存储系统”升级到“看全链路数据通路”。
把Ceph和监控报警平台联动、和自动化运维平台联动、和备份体系联动之后,你才真正把“Ceph生态”的潜力发挥了出来。比如Prometheus采集Ceph指标、Grafana展示集群大屏、Alertmanager推送告警到企业微信,这套链路可以让Ceph的异常在业务感知之前就被发现。再比如Ceph的RADOS对象存储天然适合做应用层的静态资源池、备份归档池,这样应用团队不再需要单独搭一套MinIO或者NFS来做临时文件存放,整体架构会简洁很多。
8. 写在最后的几点实在建议
如果你只是刚开始接触Ceph,不要一口气把所有概念都搞懂再动手。最好的路径是:先搭一个三节点的小集群,用cephadm部署,把RBD跑起来、挂载、格式化、写入文件,再创建几个快照做做克隆,接着配一个RGW,用S3客户端上传下载几个对象,最后再回头看这篇文章里讲到的架构和原理,你会觉得那些概念突然都活了。知识真的不是看出来的,是“摸”出来的——每一条命令都有它的意义,每一次故障都是一次学习机会。
如果你已经在生产环境用Ceph,我的建议是克制。不要频繁调整参数,不要盲目追新版本,不要随意改动pool配置,任何重大变更之前先做一次恢复演练。Ceph能给你的上限很高,但它的下限也取决于你的运维纪律。你会发现,真正难的不是安装一个集群,而是让它持续稳定地跑上三五年——每一次扩容、每一次升级、每一次故障处理,都是在给这个系统积累“信任分”。
在我实际接触过的众多存储系统里,Ceph可能是最“折腾”的一个,但也是回报最丰厚的一个。它逼着你把网络、磁盘、一致性、故障域这些基础概念真正理解透,而不是停留在“点按钮就能用”的表面。等到你能自如地在ceph、prometheus、kubernetes、S3工具链之间来回切换,你会发现你掌握的其实已经远超“Ceph”本身——你拥有了一套完整的分布式存储世界观。这套世界观,会一直伴随你的架构师之路。