做CephFS的人早晚都要亲手面对OSD部署这件事。我第一次在生产环境把CephFS挂起来的时候MDS起了、文件系统也建了以为大功告成结果业务一跑ls一个目录都要卡半天。排查到最后才发现问题根本不在MDS层而是集群里有几个OSD状态不对承载文件数据的PG一直卡在degraded。从那时起我就形成了一个判断CephFS的上层语义再花哨最后还是要靠底层那堆OSD来兑现。这篇文章不打算只给一份命令清单而是把CephFS场景下OSD部署相关的容量规划、故障域设计、系统准备、手动部署的弯路、ceph-volume标准流程、pool与MDS的衔接以及我踩过的真实坑完整串起来。无论你是刚搭测试集群还是准备扩生产环境都可以照着这条链路走一遍。1. 先搞清楚OSD在CephFS里到底扮演什么角色1.1 从一次“CephFS挂载卡死”说起OSD为何是命门那次故障的现象很典型客户端把CephFS挂载到/mnt/cephfs之后执行任何文件操作都会hang住连stat都等不到返回。我一开始以为是MDS的元数据性能问题把MDS日志翻了个底朝天结果MDS完全正常。后来回到集群侧排查ceph -s一打出来就明白了大量PG处于activedegraded部分对象的副本数不足。CephFS和普通文件系统最大的区别是它把文件内容拆成对象丢进RADOS集群对象真正的承载单位是OSD。MDS只负责文件系统语义这一层比如inode、目录项、文件layout但用户读写文件内容的IO路径是客户端直接打到OSD上的。所以一个OSD掉线哪怕MDS再健康文件内容所在的PG照样会降级客户端读写就会超时或阻塞。这也是我一直建议把OSD部署当成CephFS项目的第一优先级来做的原因。很多人在搭建CephFS时注意力都放在MDS怎么规划、多少个active、多少个standby实际上底层OSD的个数、分布、容量和健康程度才是决定CephFS能不能长期稳定跑下去的关键。1.2 OSD在CephFS数据面做的事情和两个池的不同脾气OSD的工作远比“存数据”这三个字复杂。它既要响应客户端的读写请求又要在多个副本之间做复制和一致性协商它要参与PG的peering决定谁是primary、谁是replica它还要周期性地做scrub校验保证数据没被静默损坏集群扩容或故障恢复时新对象会通过backfill和rebalance在OSD之间重新分布。可以说OSD是整个Ceph集群里干活最重、状态最多的组件。放到CephFS场景下OSD还要额外背一个包袱CephFS至少需要两个池一个存元数据一个存文件数据两者的IO特征完全不同。metadata pool知识点目录遍历、rename、权限修改、文件创建删除全是小IO、随机IO、高并发。这个池对延迟极其敏感承载它的OSD最好挂在SSD或NVMe上或者至少要让block.db落在快盘上。data pool知识点大文件顺序写为主但也免不了随机读。容量需求大单盘大了没关系但要注意恢复时间。所以部署OSD之前先想想你手上的盘怎么分组是全部混用还是把一小部分高性能盘专门给元数据池。我在生产环境里吃过亏最初把所有机械盘一锅烩结果CephFS的目录操作明显发木后来硬是把metadata pool的OSD换成SSD才缓过劲。1.3 动手前必须算清的三个数字副本数、PG数、故障域老话说得好没有规划就没有升级。OSD部署前有三个数字必须先定下来。副本数CephFS场景下我基本只用replicated副本数默认3。3副本意味着有效容量只有总物理空间的1/3这个账要提前算。2副本不是不能跑但单盘故障时对象只剩一个副本数据处于极脆弱状态但凡再坏一块盘整个PG就彻底不可读了。小规模实验集群可以用2生产环境别碰。PG数PG数不是越大越好也不是越小越好。经验公式是PG数 ≈ (OSD总数 × 期望每OSD的PG数) / 副本数期望每OSD的PG数通常取100到200之间。举个例子10个OSD、3副本、期望每OSD 100个PG(10 × 100) / 3 ≈ 333然后向上取到接近的2的幂比如384或512。PG数太少会导致单个PG过大、恢复粒度粗PG数太多会白白吃掉内存和CPUmon和OSD之间的心跳开销也变大。我的做法是宁可取小一档后面再靠pool的PG调整来处理别一开始堆太高。故障域故障域决定了副本到底分布在多散的范围内。如果故障域是host那一个对象的两三个副本会分别落在不同主机上单节点宕机不丢数据如果故障域是rack副本会跨机柜分布单机柜断电也不影响。OSD部署时要让每个OSD知道自己所在的host、rack甚至datacenter否则CRUSH可能把两个副本塞到同一台机器上故障域设计就成了摆设。Ceph里可以用ceph osd crush add-bucket和create-or-move来整理位置但最好在部署OSD之前就把机房拓扑想清楚。2. 部署OSD前的软硬件准备少一步后面都很难受2.1 磁盘与控制器别让慢盘拖垮整个PGOSD本质上就是一个进程加一块盘或一个逻辑卷。磁盘选型直接影响CephFS体验。数据盘方面HDD做容量型没问题但每盘容量别贪太大。单块22TB的盘重建一个OSD要跑很久期间整个PG都处于降级状态。我更喜欢单盘4TB到10TB宁可多几个OSD把故障爆炸半径控制在可接受范围内。如果预算允许全闪集群会让CephFS的元数据和数据操作都顺畅很多但成本和寿命要考虑清楚。block.db是另一个必须提前规划的点。Bluestore引擎下OSD的元数据和WAL会写到block.db这个设备对延迟要求很高。机械盘做数据盘时强烈建议抠一块SSD或NVMe专门放block.db。经验配比大致是每TB数据盘准备10到20GB的db空间不用太多但千万不能没有。我见过有人128GB的NVMe给4块4TB HDD当db跑两周就满了OSD性能直接掉到谷底。控制器方面RAID卡的直通模式JBOD几乎是硬性要求。不要在RAID卡里组RAID5、RAID6阵列后再丢给Ceph那样做等于在Ceph下面多套了一层不可感知的故障域而且阵列写惩罚会拖慢随机IO。如果主板自带SATA口不够用优先选IT模式的HBA卡让系统直接看到每一块物理盘。2.2 网络与内核参数OSD之间数据流的隐形瓶颈网络规划容易被低估。Ceph的3副本写入路径是这样的客户端写primary OSDprimary OSD再分别写给两个副本OSD。也就是说一份写入实际占用的网络带宽约为三份。千兆网络跑小规模测试都勉强生产CephFS建议至少万兆起步有条件就上25GbE或更高速。我习惯把public网络和cluster网络分开。public网络承载客户端请求、mon和mgr的通信cluster网络承载OSD之间的复制、心跳和恢复流量。两套网段隔离后即使一把火把业务网烧了OSD之间的恢复流量也不受影响。MTU方面如果交换机支持并全链路统一开启9000字节巨型帧就配上不支持就算了强行配会造成更诡异的分片问题。内核参数也要提前调否则OSD多了之后各种莫名其妙的问题都会冒出来。我常用的配置如下写入/etc/sysctl.conf后sysctl -p生效vm.max_map_count 262144 fs.aio-max-nr 1048576 net.core.rmem_max 33554432 net.core.wmem_max 33554432 net.ipv4.tcp_rmem 4096 87380 33554432 net.ipv4.tcp_wmem 4096 65536 33554432vm.max_map_count这个参数尤其重要。Bluestore大量使用mmap映射文件默认值65530在OSD数量一多时很容易耗尽导致OSD启动直接报错。fs.aio-max-nr影响异步IO请求队列调大之后高并发读写不容易出现submit报错。2.3 系统杂项主机名、时钟、盘符标识这几项不算核心技术但每个都能在关键时刻坑你一把。主机名必须统一用短主机名还是FQDN都行但所有节点的/etc/hosts要全部写清楚避免Ceph组件间解析失败。时间同步用chrony即可所有节点指向同一套时间源。Ceph的mon和OSD之间有很多基于时间戳的判断时钟漂移太厉害会出现心跳误判、lease异常。盘符标识是关键中的关键。永远不要直接在脚本或ceph.conf里引用/dev/sdb这种盘符因为Linux内核在重启后可能重新枚举设备今天的/dev/sdb明天就变成/dev/sdc。操作磁盘前先看/dev/disk/by-id或/dev/disk/by-path用稳定的设备标识来区分每一块盘。另外每次扩容前我强烈建议先做一张映射表把物理槽位、by-id路径、计划用途列清楚避免到时候一个手滑把数据盘给zap了。3. 手动创建OSD的完整命令流程以及为什么我建议你少走这条路3.1 手动部署看起来很简单注册、授权、mkfs、拉起早期没有ceph-volume这类工具的时候部署OSD确实是一条命令一条命令敲进去的。流程大致是这样在集群侧注册一个OSD得到OSD编号。为这个OSD生成身份认证。在目标机器上准备好数据目录并把目录owner改成ceph用户。用ceph-osd命令执行mkfs初始化本地存储。启动并设置开机自启。对应到命令上大概长这样这是很老的流程现在的生产环境不建议照抄# 注册OSD返回编号 OSD_ID$(ceph osd create) # 生成并保存keyring ceph auth get-or-create osd.${OSD_ID} \ mon allow profile osd \ mgr allow profile osd \ osd allow * \ -o /var/lib/ceph/osd/ceph-${OSD_ID}/keyring # 创建数据目录并授权 mkdir -p /var/lib/ceph/osd/ceph-${OSD_ID} chown -R ceph:ceph /var/lib/ceph/osd/ceph-${OSD_ID} # 初始化OSD本地数据 ceph-osd -i ${OSD_ID} --mkfs --mkkey # 启动并设置开机自启 systemctl enable ceph-osd${OSD_ID} systemctl start ceph-osd${OSD_ID}这套流程单看确实不难注册编号、写keyring、mkfs、起服务四步看起来清清楚楚。但真正在几十台机器上操作时每一步都有隐藏的地雷。3.2 手动部署踩过的坑几乎都是新手必踩第一个坑是目录权限。用root创建完/var/lib/ceph/osd/ceph-0这个目录之后如果忘了chown给ceph用户OSD进程起来时会在日志里刷一堆Permission denied服务反复重启集群侧看到的OSD状态就是down。新手很容易忽略因为服务不是起不来而是起来后又自己退出了日志要翻半天才看到根因。第二个坑是keyring路径。有些人图省事直接把ceph.client.admin.keyring复制过去用而没有为每个OSD单独生成keyring。OSD之间认证不通过PG peering根本没法完成集群里会反复刷osd.0 auth errors。第三个坑是bluestore的block.db没配。手动部署时如果不额外指定block.db设备bluestore会把metadata和WAL全塞到数据盘上。机械盘跑CephFS元数据池这种小IO负载延迟瞬间飙升业务侧看起来就是“整个文件系统很慢”。第四个坑就是盘符漂移。脚本里写死/dev/sdb机器重启后变成/dev/sdc如果脚本里再有格式化或者mkfs动作轻则OSD起不来重则把另一块有数据的盘给抹了。手动流程里所有设备都得靠by-id来引用但很多人第一次根本想不到这一点。3.3 手动流程没有白走排障能力就是这样练出来的虽然我强烈不建议在生产环境手动建OSD但我还是建议每个负责Ceph的人至少完整走一遍手动流程。为什么因为手动流程能让你搞清楚OSD的内部结构。当你遇到ceph-volume自动创建的OSD启动失败时排障思路和手动流程完全一致先看日志journalctl -u ceph-osdN -n 200。再看数据目录结构/var/lib/ceph/osd/ceph-N下面有没有keyring、fsid、block等文件。再确认权限ls -l看owner是不是ceph用户。这些事如果你没手动部署过根本不知道要查哪里。我后来很多次处理生产故障靠的都是这份对OSD目录结构和启动流程的直觉。4. 用ceph-volume部署OSD这是当前最稳的路径4.1 lvm batch一条命令完成批量部署现代Ceph环境里我基本只用ceph-volume来做OSD部署。它把注册、认证、LVM卷创建、bluestore初始化、服务启动全部封装好了还顺手解决了设备标识问题。最常用的是lvm batch命令适合批量接管整块磁盘ceph-volume lvm batch --bluestore \ /dev/sdb /dev/sdc /dev/sdd执行之后ceph-volume会自动把每块盘变成LVM物理卷创建对应的逻辑卷为每块盘生成一个OSD然后初始化bluestore并启动服务。整个过程结束后ceph osd tree里就能看到新OSD了。如果要给这一批OSD统一指定SSD做block.db命令可以这样写ceph-volume lvm batch --bluestore \ --db-devices /dev/nvme0n1 \ /dev/sdb /dev/sdc /dev/sddceph-volume会在那块NVMe上划分出多个db逻辑卷按比例分给每个数据盘。这个操作如果手动做要写一堆LVM命令batch一条命令就全搞定了。4.2 lvm create需要精细控制时的手动玩法batch适合整盘taken跑但当你需要更精细的控制时可以用lvm create。比如你不想让ceph-volume自动创建卷想自己规划LVM布局或者你只想给某一块盘单独建OSD不想动其他磁盘。先由你手工创建好LVM卷再交给ceph-volume# 在数据盘上创建LV pvcreate /dev/sdb vgcreate vg_data /dev/sdb lvcreate -L 4T -n osd-data-1 vg_data # 在SSD上创建db LV pvcreate /dev/nvme0n1 vgcreate vg_db /dev/nvme0n1 lvcreate -L 60G -n osd-db-1 vg_db然后执行create命令ceph-volume lvm create --bluestore \ --data vg_data/osd-data-1 \ --block.db vg_db/osd-db-1这种方式适合对磁盘规划有洁癖的人。注意一点如果没有单独的wal设备需求就不要加--wal-devices参数。Bluestore默认会把WAL放进block.db里单独拆分wal反而多了一个故障点收益不大。4.3 部署后的检查清单别急着挂CephFSOSD部署完成不等于一切正常我会按下面这张清单逐项确认检查内容命令预期结果设备映射是否正常ceph-volume lvm list每块数据盘对应一个OSDblock.db位置符合预期OSD是否上树并显示weightceph osd treeOSD状态为upweight不为0集群状态是否健康ceph -sHEALTH_OK或正在rebalancing各PG是否收敛ceph pg statactiveclean比例持续上升直至全部正常OSD容量分布ceph osd df各OSD利用率不要差太远特别提醒一点新OSD加入集群后会触发backfill大量PG开始重新分布对象。这个时候ceph -s里会有很多recovery状态属正常不要慌。但要盯着业务影响如果高峰期扛不住就暂时别继续往集群里塞新盘了。5. OSD就绪之后从存储池到CephFS挂载5.1 先建两个PoolPG数和副本策略要分开想OSD真正能用起来得先有存储池。CephFS部署的关键是建立两个池一个存元数据一个存数据。命令如下ceph osd pool create cephfs_data 512 replicated ceph osd pool create cephfs_metadata 32 replicated ceph osd pool application enable cephfs_data cephfs ceph osd pool application enable cephfs_metadata cephfs注意这两个池的PG数我故意不一样。数据池的PG按规模取512或更高元数据池只要32或64就够了。原因是元数据池的数据量本来就小不需要那么多PGPG太多反而让MDS在元数据操作时承担多余的开销。元数据池必须用replicated模式不能用erasure code。元数据操作对一致性和延迟要求太高EC的编码和解码开销会把目录操作拖慢。数据池在新技术下虽然也能用EC但涉及文件layout复杂度和性能取舍中小集群没必要自找麻烦replicated 3副本最省心。5.2 fs new之后MDS部署与挂载验证两个池建好之后创建CephFS文件系统只有一条命令ceph fs new cephfs cephfs_metadata cephfs_data紧接着需要MDS进程。如果用的是cephadm直接安排MDS服务ceph orch apply mds cephfs手动环境则安装ceph-mds包并启动对应的mds实例。MDS至少要有一个生产环境我建议配2个以上一主一备避免MDS故障时整个文件系统无法提供元数据服务。CephFS创建完成并有了MDS之后就可以挂载验证了mkdir -p /mnt/cephfs mount -t ceph \ 10.0.0.1:6789,10.0.0.2:6789,10.0.0.3:6789:/ \ /mnt/cephfs \ -o nameadmin,secretfile/etc/ceph/ceph.client.admin.keyring挂载成功后df -h /mnt/cephfs能看到容量这个容量其实就是data pool里OSD可提供的有效容量。我习惯立刻做一个冒烟测试往目录里写一个1GB文件再随便创建几百个目录文件然后看看ceph -s里的PG有没有波动。如果一切平稳说明OSD、pool、MDS这条链路已经打通了。6. 部署与运维中的常见坑按真实排查链路走一遍6.1 盘符漂移今天叫sdb明天叫sdc我一直强调用by-id引用设备就是因为盘符漂移这件事几乎一定会发生。真实场景里某台机器重启后OSD服务起不来了systemctl status ceph-osd5显示失败journal日志里报设备不存在。lsblk一看原本的/dev/sdh变成了/dev/sdi逻辑卷路径没变但裸盘引用却跑偏了。如果OSD的数据卷是LVM逻辑卷通常问题不大因为LVM有自己稳定的UUID标识。但如果你的部署方式里直接引用了裸盘partition那风险就大了。这也是为什么我坚持用ceph-volume lvm方案而不是手动给整块盘做文件系统再交给ceph-osd。遇到这种故障修复方式取决于你原本的记录如果映射表里记得数据盘的by-id重新绑定路径就能恢复如果根本不知道哪块盘对应哪个OSD恭喜你进入地狱级排障模式。6.2 一次性加太多OSD引发的backfill风暴扩容时最容易犯的错是一次性把十多块盘全加进集群。当时ceph -s里全是recovery和backfillOSD的op每秒飙到几千业务端延迟直接破表。原因是每加入一个新的OSDCRUSH就会重新计算对象分布大量PG需要迁移对象到新盘。如果一次加太多迁移量瞬间爆发。我从那以后就学乖了扩容永远分批做一次2到3块盘等PG重新activeclean之后再加下一批。同时可以在扩容期间临时限制恢复速度ceph config set osd osd_max_backfills 2 ceph config set osd osd_recovery_max_active 4别担心参数调低会拖慢扩容速度慢一点总比把在线业务搞崩要好。6.3 你以为还有空间Ceph却说写不进去了另一个迷惑场景是CephFS里写文件报No space left on device但df一看还有几百GB空闲。这个坑的根本原因是Ceph的容量判断并不看文件系统剩余空间而是看OSD的利用率。默认配置下单个OSD利用率超过nearfull_ratio典型值0.85会触发告警超过full_ratio典型值0.95会直接阻塞写入。排查时用ceph osd df能很快找到利用率偏高的那块盘尤其是整个集群某个OSD数据分布不均时很容易出现“总量看起来还有空间个别盘已经塞满”的局面。遇到这种问题短期只能加盘扩容或者清数据长期则要把CRUSH weight调整和rebalance做成常态化管理。我的操作习惯是让每个OSD的利用率尽量控制在70%到80%以内给恢复和负载波动留缓冲。6.4 另外两个让我头疼过的怪象这里顺便提两个不太常见但遇到了就很棘手的情况。一个是OSD进程明明活着mon却把它标记成down。排查下来多半是cluster网络丢包或MTU不一致导致心跳包没有按预期到达mon。检查mon日志里有没有heartbeat timeout记录同时检查网卡、交换机侧有没有丢包计数器基本能把问题揪出来。另一个是OSD被误操作从CRUSH里删掉之后即使数据盘还在也不会自动回到集群。这时候需要手动把OSD的weight加回去常见的做法是ceph osd crush set osd.NW VALUELOCATION把原weight值填回去。一旦weight恢复且OSD启动了PG会重新归位数据不会丢。但这类操作一定要在低峰期做因为又是一个大范围的PG重新分布过程。说到底OSD部署这件事看着是体力活实际上是整个CephFS的地基。我现在的流程已经固定成规划容量和故障域确认硬件和系统参数用ceph-volume批量接盘然后建池、建文件系统、验证挂载。每一步踩过的坑最后都变成了检查清单上的固定项。特别是盘符漂移和backfill风暴这两个坑希望你读完这篇之后能直接绕过去。