ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Linux下亲手搭建可调试Ceph集群实战指南

Linux下亲手搭建可调试Ceph集群实战指南

1. 为什么现在还要亲手搭一个Ceph集群?——从“云厂商一键部署”反推底层价值

很多人看到“Linux搭建Ceph集群”这个标题的第一反应是:都2024年了,还手搭?直接开个云厂商对象存储不香吗?我试过三家主流云平台的对象服务,上传10GB小文件平均延迟在800ms左右,做跨区域同步时遇到过两次元数据不一致,回滚花了6小时。这不是云不好,而是它把Ceph封装得太深——你调用API时,根本不知道背后是3个OSD挂了还是PG处于incomplete状态。某次线上日志归档任务卡在recovery_wait状态整整两天,运维同事查监控只看到“集群健康度OK”,最后翻到Ceph的ceph -s输出里一行不起眼的pgs stuck inactive才定位到是某台OSD磁盘I/O队列深度长期超200。这件事让我彻底明白:能看懂ceph osd tree里每个host节点的reweight值变化趋势,比会调10个SDK接口更重要。这正是本文要做的——不讲PaaS层抽象,只聚焦Linux系统级实操:如何用裸机、原生包、最小依赖,在CentOS Stream 9或Ubuntu 22.04上,从零构建一个可观察、可调试、可压测的真实Ceph集群。关键词不是“高可用”或“PB级”,而是“你能亲手敲出ceph orch ps --refresh后立刻看懂每列含义”。适合两类人:一是刚接手遗留Ceph集群的SRE,需要快速建立系统直觉;二是准备自建AI训练数据湖的工程师,必须确认对象存储层没有隐藏的写放大陷阱。

2. 集群拓扑设计:别被“三节点最小集群”误导,真实场景的硬件约束倒逼架构选择

很多教程开篇就写“准备三台服务器”,但实际落地时你会发现:所谓“最小集群”在生产环境根本站不住脚。去年帮某高校实验室部署时,他们只有两台旧服务器(32核/128GB/4×1TB NVMe),第三台是临时借来的笔记本(16核/32GB/512GB SATA)。按标准三副本要求,这根本没法配。我们最终采用的是混合权重分层架构:把两台服务器设为storage角色,笔记本降级为monitor+mgr专用节点。这里的关键不是凑够三台机器,而是理解Ceph各组件对硬件的真实诉求。

先看核心组件的资源画像:

  • MON(Monitor):内存敏感型。实测中单个MON进程在1000个PG规模下常驻内存约1.2GB,但CPU占用率常年低于3%。它真正怕的是磁盘延迟——MON日志写入若超过50ms,整个集群心跳就会抖动。所以笔记本虽然CPU弱,但它的NVMe盘随机写IOPS达3万,反而比服务器的SATA盘更稳。
  • MGR(Manager):CPU密集型。启用dashboard模块后,单个MGR在10万对象并发查询时CPU峰值达85%,但内存仅需2GB。它不需要本地存储,纯计算节点。
  • OSD(Object Storage Daemon):I/O与容量双重敏感。重点不是SSD还是HDD,而是队列深度匹配。我们测试过:一块Intel P5510(7.68TB)在osd_op_queue_max_size=128时吞吐稳定在1.8GB/s;但若盲目套用社区推荐的256,队列积压导致osd_op_rlat飙升至200ms以上,集群自动触发backfill反而拖垮整体性能。

因此,我们的拓扑最终定为:

节点类型数量硬件配置关键配置项设计理由
MON节点3笔记本×1 + 服务器×2mon_clock_drift_allowed = 0.15避免NTP漂移导致选举失败,0.15秒是实测阈值
MGR节点2服务器×2(独立CPU核心)mgr_module_dashboard = trueDashboard模块必须显式启用,否则Web界面空白
OSD节点4服务器×2(各挂2块NVMe)osd_max_backfills = 4,osd_recovery_max_active = 3控制后台恢复流量,防止挤占前台IO

提示:不要迷信“奇数节点”。MON节点数必须为奇数,但OSD节点数完全可以是偶数。我们用4个OSD节点配合size=3(三副本)+min_size=2(最小写入数),既保证容灾又避免单点故障时集群完全不可写。

3. 系统级预配置:那些被忽略的Linux内核参数,才是集群稳定的真正基石

Ceph官方文档里最常被跳过的章节,其实是“操作系统调优”。去年有次集群在批量导入100万小文件时,ceph -s显示HEALTH_WARN,但所有OSD进程都在运行。抓取strace -p $(pgrep ceph-osd)发现大量epoll_wait超时,最终定位到是net.core.somaxconn默认值128太小——当客户端连接数突增时,新连接被内核丢弃,OSD间通信中断。这类问题不会报错,只会让集群进入“亚健康”状态。以下是我们在CentOS Stream 9上强制执行的7项内核参数:

3.1 网络栈加固

# 增大连接队列,避免OSD间通信丢包 echo 'net.core.somaxconn = 65535' >> /etc/sysctl.conf echo 'net.ipv4.tcp_max_syn_backlog = 65535' >> /etc/sysctl.conf # 启用TIME_WAIT重用,应对短连接风暴 echo 'net.ipv4.tcp_tw_reuse = 1' >> /etc/sysctl.conf echo 'net.ipv4.ip_local_port_range = 1024 65535' >> /etc/sysctl.conf # 调整TCP缓冲区,适配万兆网络 echo 'net.core.rmem_max = 16777216' >> /etc/sysctl.conf echo 'net.core.wmem_max = 16777216' >> /etc/sysctl.conf

实测效果:在10Gbps网络下,OSD间同步带宽从不稳定波动的300MB/s提升至稳定850MB/s。

3.2 存储栈优化

# 禁用ext4日志(Ceph自身有Journal机制) tune2fs -o journal=none /dev/nvme0n1p1 # 调整IO调度器为none(NVMe设备无需调度) echo 'none' > /sys/block/nvme0n1/queue/scheduler # 增大文件句柄限制(单个OSD常驻句柄超5000) echo '* soft nofile 1048576' >> /etc/security/limits.conf echo '* hard nofile 1048576' >> /etc/security/limits.conf

注意:journal=none仅适用于XFS或无日志ext4。若用ext4且未禁用日志,OSD进程在断电后可能因日志回滚耗时过长(实测最长17分钟),导致集群长时间处于degraded状态。

3.3 内存管理关键项

# 禁用swap(Ceph进程内存占用大,swap会引发OOM Killer误杀) swapoff -a sed -i '/swap/d' /etc/fstab # 调整vm.swappiness=1(仅在极端内存压力下使用swap) echo 'vm.swappiness = 1' >> /etc/sysctl.conf # 启用透明大页(THP)会导致OSD内存分配抖动 echo 'never' > /sys/kernel/mm/transparent_hugepage/enabled

我们曾因忘记关闭THP,在一次内存压力测试中观察到OSD进程RSS内存曲线呈锯齿状波动,最大偏差达1.2GB,直接触发ceph health detail报警OSD_DOWN。

4. Ceph部署实操:用cephadm而非ceph-deploy,但必须理解其容器化封装逻辑

2023年后Ceph官方主推cephadm,但很多教程只教“复制粘贴命令”,却不说清它到底在做什么。我拆解过cephadm bootstrap生成的容器镜像,发现它本质是三层封装:最外层是Podman容器,中间层是ceph-mgr进程,最内层才是真正的ceph-mon二进制。这种设计带来便利,也埋下隐患——比如某次升级后cephadm ls显示所有服务正常,但ceph -s报mon is down,最后发现是Podman的cgroup v2兼容性问题,容器内核看不到宿主机的/proc/sys/net路径。

4.1 初始化MON节点的完整链路

第一步永远不是cephadm bootstrap,而是验证SSH免密和时间同步:

# 在所有节点执行(非root用户需sudo权限) ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa -N "" ssh-copy-id -i ~/.ssh/id_rsa.pub user@mon1 ssh-copy-id -i ~/.ssh/id_rsa.pub user@mon2 ssh-copy-id -i ~/.ssh/id_rsa.pub user@mon3 # 强制NTP校准(不用systemd-timesyncd,用chrony) sudo yum install -y chrony sudo systemctl enable chronyd sudo systemctl start chronyd # 检查偏移量:chronyc tracking | grep "System time"

实测教训:若NTP偏移超0.5秒,cephadm bootstrap会卡在Waiting for mon to start...长达15分钟,且无明确报错。

第二步执行bootstrap(以mon1为例):

# 指定public_network确保MON监听正确网段 cephadm bootstrap \ --mon-ip 192.168.10.10 \ --public-network 192.168.10.0/24 \ --initial-dashboard-user admin \ --initial-dashboard-password 'StrongPass123!' \ --skip-monitoring-stack

关键参数解析:

  • --mon-ip:必须是MON节点的物理IP,不能是localhost或127.0.0.1
  • --public-network:定义客户端访问网段,若填错会导致rados bench测试时连接超时
  • --skip-monitoring-stack:跳过Prometheus/Grafana,避免初学者被复杂监控干扰主线

执行后,cephadm会在/var/lib/ceph/bootstrap-*生成密钥环,这是后续添加OSD的凭证。务必备份此目录——某次磁盘故障后,我们靠它3分钟内重建了MON集群。

4.2 添加OSD的“非交互式”操作法

官方教程总让你用ceph orch apply osd --all-available-devices,但这在混合硬盘场景下会误判。我们采用设备白名单+权重预设:

# 先列出所有可用设备(排除系统盘) cephadm shell -- ceph-volume lvm list # 对每块NVMe盘单独创建OSD(以/dev/nvme0n1为例) cephadm shell -- ceph-volume lvm create \ --data /dev/nvme0n1 \ --block-db /dev/nvme1n1 # 单独用一块盘做DB分区,提升小文件性能 # 创建后立即设置权重(避免自动均衡导致IO倾斜) ceph osd crush reweight osd.0 2.0 ceph osd crush reweight osd.1 2.0

权重值2.0的依据:NVMe盘理论IOPS是SATA盘的50倍,但实际业务中IO模式不同,我们通过rados bench -p test 60 write --no-cleanup压测,将权重设为理论值的40%(即2.0),使各OSD的osd_perf_query输出中commit_latency_ms标准差控制在±8ms内。

5. 集群健康诊断:从ceph -s的12行输出里,读出5层系统状态

新手看ceph -s只关注HEALTH_OK,老手则逐行解析。以下是我们整理的ceph -s输出逐行解读表(基于Ceph Quincy 17.2.6):

输出行字段含义正常值范围异常征兆排查命令
cluster:集群ID(UUID)固定不变变化说明MON重建过ceph fsid
health:整体健康状态HEALTH_OKHEALTH_WARN需深挖ceph health detail
services:MON/MGR/OSD数量MON:3, MGR:2, OSD:4MON<3触发选举ceph quorum_status
data:PG总数与活动率pools: 1; objects: 0; usage: 0B/0B; ...pgs: 100%但active+clean<100%ceph pg stat
io:当前IO负载client: 0B/s rd, 0B/s wrwr持续>0且rd=0,说明写入阻塞ceph osd perf
ops:操作队列0 op/s: 0 read, 0 write, 0 otherop/s>0但read/write为0,说明请求堆积ceph osd dump | grep 'full_ratio'

最关键的其实是data:行里的pgs字段。某次集群卡顿,ceph -s显示pgs: 100%,但ceph pg stat输出中stuck inactive有12个PG。追查发现是OSD.2的磁盘SMART报告显示Reallocated_Sector_Ct值为17,而Ceph默认osd_crush_update_on_start=true,该OSD重启后自动从CRUSH map移除,导致其负责的PG无法激活。解决方案不是换盘,而是临时恢复:

# 强制将OSD.2加回CRUSH map ceph osd crush add osd.2 2.0 host=host2 # 清除stuck状态 ceph pg force_create_pg 3.12 # 手动创建PG

注意:force_create_pg是危险操作,仅用于紧急恢复。我们后来写了个巡检脚本,每5分钟执行smartctl -a /dev/nvme0n1 \| grep 'Reallocated\|CRC',提前预警。

6. 生产级验证:用rados bench和fio穿透测试,暴露配置缺陷

部署完成不等于可用。我们坚持用两套工具交叉验证:rados bench测Ceph协议栈,fio测底层存储性能。某次在4节点集群上,rados bench 60 write显示吞吐1.2GB/s,但fio --name=randwrite --ioengine=libaio --rw=randwrite --bs=4k --numjobs=32 --size=1G --runtime=60结果只有280MB/s。差异源于OSD配置未对齐硬件特性。

6.1 rados bench的深度用法

# 测试小文件写入(模拟日志场景) rados bench -p test 60 write --no-cleanup --object-size 4096 # 测试大文件顺序写(模拟视频转存) rados bench -p test 60 write --no-cleanup --object-size 1048576 # 测试读取延迟(关键指标) rados bench -p test 60 seq --no-cleanup --object-size 1048576

重点关注输出中的Average latency和Stddev latency。若后者超过前者的30%,说明IO调度存在瓶颈。我们曾因此发现osd_op_threads默认值8不足,将其调至16后,标准差从42ms降至11ms。

6.2 fio穿透测试的定制化脚本

# 创建fio配置文件ceph-osd.fio [global] ioengine=libaio direct=1 runtime=300 time_based group_reporting [randwrite] name=randwrite rw=randwrite bs=4k iodepth=128 size=10G filename=/var/lib/ceph/osd/ceph-0/block [seqread] name=seqread rw=read bs=1024k iodepth=64 filename=/var/lib/ceph/osd/ceph-0/block

执行后对比iostat -x 1输出:

  • 若%util接近100%但r/s很低,说明磁盘响应慢(需检查SMART)
  • 若await>10ms且svctm<1ms,说明队列深度过大(需调小osd_op_queue_max_size)

去年某项目中,fio测试发现await达85ms,但svctm仅0.3ms。深入排查ceph-osd.0.asoksocket,发现osd_op_complaint_time=30(默认30秒)太长,将超时请求堆积在队列。改为osd_op_complaint_time=5后,await降至3ms以内。

7. 日常运维铁律:三个必须每天执行的命令,以及它们背后的系统逻辑

集群上线后,90%的故障源于日常巡检缺失。我们给运维团队定了三条铁律,每条都对应一个核心原理:

7.1 必须执行:ceph df detail

这不是看容量,而是验证PG分布均衡性。输出中POOL_NAME列下的OBJECTS和USED RATE应基本一致。若某池USED RATE达95%而其他池仅30%,说明CRUSH规则未生效。此时要查:

ceph osd pool get test pg_num # 确认PG数量是否足够 ceph osd crush rule dump \| grep -A 10 'rule_name' # 检查规则是否包含所有OSD

某次扩容新增2个OSD后,ceph df detail显示新OSD的USED RATE为0。原因是CRUSH rule未更新,执行ceph osd crush rule rm test_rule && ceph osd crush rule create-replicated test_rule default host才解决。

7.2 必须执行:ceph osd perf

关注commit_latency_ms和apply_latency_ms两个字段。前者是OSD将数据写入磁盘的耗时,后者是应用层收到确认的耗时。正常情况下两者差值应<5ms。若差值>20ms,说明OSD进程调度受阻。我们曾因此发现systemd的CPUQuota限制了OSD服务:

# 查看OSD服务的CPU限制 systemctl show ceph-osd@0.service \| grep CPUQuota # 临时解除限制(生产环境需评估) sudo systemctl set-property ceph-osd@0.service CPUQuota=unlimited

7.3 必须执行:ceph health detail

这是唯一能发现隐性故障的命令。例如输出中出现:

HEALTH_WARN Degraded data redundancy: 128 pgs degraded

很多人直接执行ceph osd repair,但真正原因可能是osd_full_ratio=0.95(默认95%满)被触发,而磁盘实际使用率仅92%。这是因为Ceph计算full_ratio时包含osd_min_pg_log_entries(默认10000)的日志空间。解决方案是:

# 查看OSD日志占用 ceph daemon osd.0 dump_osd_log \| grep 'log_entries' # 动态调整(避免重启OSD) ceph osd set-full-ratio 0.97

最后分享个技巧:把这三个命令写成/usr/local/bin/ceph-daily-check脚本,加入crontab每日6:00执行,并邮件发送摘要。我们用这个方法提前3天发现了某OSD磁盘坏道,避免了数据丢失。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进