简介围绕GFS、HDFS与Minio等主流分布式存储技术展开的PDF综述面向大数据、云计算方向的学习者及后端开发人员帮助建立分布式文件系统、对象存储与块/文件/对象三类存储方式的知识框架。压缩包内仅1个PDF文件约1.39MB内容集中适合面试复习、课程补充或技术调研时通读。现有407人学习下载。文档从GFS主从架构、chunk多副本与中心化设计切入对照HDFS的容错恢复、顺序写入及批处理场景并延伸至Minio的S3兼容接口、对象ID访问和非结构化数据存储同时回顾网络文件系统、共享SAN文件系统、面向对象并行文件系统到云文件系统的演进讨论复制、纠错码与计算存储融合等方向。读者可据此理解不同系统在性能、扩展性与一致性上的取舍形成从架构到应用场景的完整认知并获取继续查阅经典论文和开源实现的线索。1. 从一块盘写满说起分布式存储到底在解决什么问题单机 4 TB 的盘写到 90% 那天几乎所有团队都会做同一件事先删日志再买硬盘然后发现机箱槽位不够。分布式存储要解决的核心问题从来不是「盘不够大」而是把容量、吞吐和可靠性这三件事从单机物理约束里拆出来——容量靠横向加节点吞吐靠并行访问可靠性靠副本或校验块。它适合这样一种场景数据量已经越过单机上限或者业务不能接受一次磁盘故障就停机。反过来说如果你的数据只有几 TB、团队里没有人愿意半夜起来处理报警硬上分布式存储大概率是给自己找麻烦一套 RAID 加定时备份更省心。真正决定要不要上的是三个数字现在有多少数据、三年后会有多少、能容忍多久的不可用。把这三个数字写在纸上比看十篇评测都管用。2. 三条主流路线的分野块存储、文件存储、对象存储各管什么2.1 接口形态决定了它能承载什么业务分布式存储谈选型第一步永远是先确定接口形态因为形态一旦定下来能承载的负载类型基本就被锁死了后面再谈性能参数意义不大。块存储对外暴露的是一块裸设备客户端拿到的是一串从 0 到 N 的扇区上面得自己建文件系统文件存储对外暴露的是 POSIX 目录树open/read/write/rename这一套语义完整可用对象存储对外暴露的是 HTTP 上的GET/PUT/DELETE键是扁平的全路径名没有目录、没有原地修改。这三种形态对应的业务差异极大。块存储适合数据库、虚拟机镜像、容器持久卷这类需要自己管理文件系统的负载延迟最低但客户端要承担文件系统的一致性责任。文件存储适合训练集、渲染农场、共享代码目录这类多机同时读写的场景好处是应用零改造。对象存储适合备份归档、数据湖、图片视频这类一次写入多次读取、单对象体量大、并发连接数高的场景代价是没有随机写、没有目录语义。形态典型访问方式适配负载单次请求延迟量级扩容粒度块存储iSCSI / NVMe-oF / 专用客户端数据库、虚机镜像、持久卷百微秒到毫秒按节点、按 PG文件存储mount后走 POSIX训练集、HPC、共享目录毫秒按节点对象存储HTTP(S) REST备份归档、数据湖、媒体资源十毫秒到百毫秒近乎线性延迟那一列只能当参考量级看同一形态不同实现能差一个数量级真正的数字必须自己压出来。2.2 代表性系统的能力边界对照把常见方案放在一张表里横向看比逐个读文档更容易发现差异点。下面这张表里的规模是「常见部署区间」不是能力上限很多系统理论上都能做到更大但运维成本会先撑不住。系统主形态数据分布方式元数据一致性常见规模主要短板Ceph块 / 文件 / 对象CRUSH 哈希无中心索引分布式MON MDS池内强一致百 TB 到数十 PB组件多小文件与元数据密集场景弱HDFS文件大文件固定大小块 副本集中式 NameNode追加写强一致PB 级不支持原地随机写小文件压垮 NameNodeMinIO对象纠删码集合无独立元数据服务读后写一致百 TB 到 PB跨站点能力弱语义严格绑定对象接口GlusterFS文件弹性哈希无中心无独立元数据节点取决于卷类型百 TB 级大目录与小文件性能衰减明显Lustre文件HPC对象存储目标 条带集中式 MDS强一致PB 级部署门槛高元数据节点压力集中JuiceFS文件兼容 POSIX数据落对象存储元数据落数据库外部元数据引擎取决于元数据引擎TB 到 PB强依赖外部数据库的可用性这张表里最值得盯的两列是「数据分布方式」和「元数据」。分布方式决定了扩容时的数据搬迁量元数据架构决定了小文件和海量目录能不能扛住。实际翻车案例里十次有七次栽在这两列上而不是栽在峰值带宽。2.3 选型时先算哪三笔账第一笔是容量账。三副本的裸容量利用率是 33%也就是说想拿到 100 TB 可用空间得准备 300 TB 的盘。纠删码 42 能到 66%83 能到 72%同样是 100 TB 可用83 只需要约 139 TB 裸容量。这个差距在 PB 级规模上就是几十台机器的采购预算绕不过去。第二笔是元数据账。把一百万个 4 KB 小文件塞进一套为大文件设计的系统得到的往往是灾难。判断方法很朴素统计一下现有数据里文件大小的中位数和总数如果中位数小于 1 MB、总数又超过千万就要专门去验证元数据路径的承载能力而不是只看顺序读写带宽。第三笔是运维账。Ceph 功能全但组件多、参数多一个没配好就可能出现「状态健康但业务超时」的情况团队里最好有一个人能长期盯它。对象存储类方案组件少但语义受限业务侧可能要改代码。这三笔账算完选型基本就只剩一两个候选了。3. 把一套最小集群跑起来Ceph 单机三节点的部署命令与必调参数3.1 三节点加十二块虚拟盘先把拓扑定下来实验环境不必上真机三台虚拟机加 loop 设备就够跑通全链路。关键是拓扑要能体现分布式特征三个 MON 保证仲裁OSD 分散在三台机器上这样后面测故障域才有意义。角色数量建议配置说明MON MGR32 核 4 GB与 OSD 混布奇数个保证仲裁OSD12每节点 4 块 20 GB实验用稀疏文件模拟MDS12 核 4 GB只有跑 CephFS 才需要在每台节点上各造 4 块实验盘# 三台节点各自执行制造 4 块 20G 的稀疏文件当作独立 OSD 盘 mkdir -p /var/lib/ceph-vol for i in 0 1 2 3; do truncate -s 20G /var/lib/ceph-vol/osd-${i}.img # 稀疏文件不实际占满磁盘 losetup -f --show /var/lib/ceph-vol/osd-${i}.img # 绑定成块设备输出形如 /dev/loop3 done # 确认块设备已就绪ROTA1 表示被识别为机械盘 lsblk -d -o NAME,SIZE,ROTAtruncate建的是稀疏文件ls -lh看着是 20 GB实际占用接近 0这一点在只有一块系统盘的虚拟机上很关键。losetup -f --show会自动找空闲的 loop 号并打印出来后面加 OSD 时直接引用这些/dev/loopN。提示loop 设备没有真实的掉电与坏道语义用它验证重建流程没问题但压出来的性能数字不能当作生产依据也不要拿它去对比不同硬件方案。3.2 cephadm bootstrap把第一个 MON 拉起来只在一号节点执行初始化其余节点由它纳管# 只安装管理工具不预装全部服务 apt-get install -y cephadm cephadm bootstrap \ --mon-ip 10.0.0.11 \ --cluster-network 10.0.1.0/24 \ --initial-dashboard-user admin \ --initial-dashboard-password ChangeMe_123 \ --skip-monitoring-stack几个参数值得逐条解释。--mon-ip必须是本机真实可达的地址写127.0.0.1后面加节点会全部失败。--cluster-network指定后端复制网络三副本的写放大流量全走这张网生产环境强烈建议物理分开实验环境用同网段不同子网也行。--skip-monitoring-stack跳过 Prometheus 和 Grafana 的部署能省下大量内存但这也意味着后面没有现成面板可看排障只能靠命令行。初始化完成后会生成/etc/ceph/ceph.conf和 admin keyring接着把另外两台拉进来# 把公钥推到其余节点cephadm 才能免密下发服务 ssh-copy-id -f -i /etc/ceph/ceph.pub rootnode2 ssh-copy-id -f -i /etc/ceph/ceph.pub rootnode3 ceph orch host add node2 10.0.0.12 ceph orch host add node3 10.0.0.13 # 补齐三个 MON仲裁才有意义 ceph orch apply mon --placementnode1,node2,node3 # 把所有空闲块设备一次性纳管成 OSD ceph orch apply osd --all-available-devices ceph -sceph orch apply是声明式下发命令返回很快但不代表服务已经起来中间有一段几分钟的收敛期这时候ceph -s会显示HEALTH_WARN属于正常现象。真正要等的是osd: 12 up, 12 in和pgs: activeclean这两个指标同时满足再开始建池。3.3 建池、置副本、跑通一次完整读写集群干净之后用一个 RBD 块设备把写入链路完整走一遍# 1) 建池两个数字分别是 pg_num 和 pgp_num ceph osd pool create demo-pool 64 64 ceph osd pool application enable demo-pool rbd # 2) 副本数设为 3最小可写副本设为 2 ceph osd pool set demo-pool size 3 ceph osd pool set demo-pool min_size 2 # 3) 建 10G 镜像并映射到本机 rbd create demo-pool/demo.img --size 10G rbd map demo-pool/demo.img # 4) 建文件系统并挂载 mkfs.xfs /dev/rbd0 mkdir -p /mnt/demo mount /dev/rbd0 /mnt/demo df -h /mnt/demopg_num是这个池的数据分片数64 在三节点十二 OSD 的小集群上够用但要注意建池之后再改pg_num会触发数据重平衡生产上最好一次估到位。size 3和min_size 2是一对前者决定写几份后者决定剩几份时还允许写。把min_size设成 1 看着「可用性更高」实际会在只剩单个副本时继续接受写入两个副本恢复后数据可能对不上属于典型的后悔药没处买。rbd map之后如果lsblk里看不到rbd0先确认内核模块rbd是否加载再确认客户端版本与服务端差异不要太大。3.4 上线前必须改的五个配置默认参数是给「跑起来」设计的不是给「跑得稳」设计的。下面这几项在实验环境可以不动生产环境建议逐条确认。参数默认倾向建议理由osd_pool_default_size3保持 3低于 3 在小集群上没有意义osd_pool_default_min_size2保持 2防止脑裂期间继续写入mon_osd_nearfull_ratio较宽松0.85提前预警别等写满才发现mon_osd_full_ratio较宽松0.90触顶后整个池拒写业务直接挂osd_max_backfills偏高1 到 2控制重建对业务的挤压osd_recovery_sleep_hdd00.1 左右给机械盘留出响应业务的时间改法统一用ceph config set例如# 全局生效如果只想对单块盘生效把 global 换成 osd.3 ceph config set global osd_max_backfills 1 ceph config set global osd_recovery_sleep_hdd 0.1 ceph config get osd.3 osd_max_backfills # 确认最终生效值最后那条config get很有必要因为 Ceph 的配置优先级有全局、守护进程、运行时三档config set写进去不代表运行时真的用了新值。养成改完立刻get一遍的习惯能省掉很多「明明改了却没生效」的排查时间。4. 数据落在哪CRUSH 映射与一致性哈希的差别到底在哪4.1 一次写请求的完整路径搞清楚路径排障时才知道该看哪一层。客户端写入一个对象时第一步是向 MON 要一份集群地图地图里包含了所有 OSD 的状态、权重和 CRUSH 规则拿到地图后客户端自己算出目标位置不依赖任何中心节点分配。计算过程是对象名或 RBD 的卷名加偏移经哈希落到某个 PGPG 再经 CRUSH 映射到一组 OSD其中排在第一个的是主 OSD。主 OSD 收到写请求后先把数据落到自己的 BlueStore同时把请求转发给两个从副本等从副本确认落盘主才向客户端返回成功。这条路径里有几个关键点值得记住客户端是直接跟 OSD 通信的MON 只负责发地图所以 MON 短暂不可用不影响已有数据的读写写成功的前提是最小副本数满足不是全部副本副本之间的复制流量走后端网络跟客户端流量是两条路。理解了这一点就能解释很多看似玄学的现象。比如「MON 全挂了但业务还在跑」正常「后端网络打满导致客户端超时」也正常因为复制没完成主 OSD 就不会返回。4.2 故障域与权重CRUSH 规则怎么写故障域这个词听起来抽象本质就是一个问题你希望同一份数据的多个副本最少隔开到什么程度。隔到主机级能扛单机故障隔到机柜级能扛整柜断电隔到机房级才能扛机房级事故。级别越高可用节点越少副本凑不齐的概率也越高。故障域能容忍的故障代价osd单盘几乎为零但没有实际保护意义host整机至少需要 3 台主机rack机柜断电至少需要 3 个机柜容量碎片化datacenter机房级跨机房延迟通常配合异步复制规则的创建命令很直接# 建一条三副本规则故障域取 host只使用带 ssd 标签的设备 ceph osd crush rule create-replicated ssd-rule default host ssd # 查看规则的完整内容确认 steps 里的层级顺序 ceph osd crush rule dump ssd-rule # 把已有的池切换到新规则上会触发重平衡 ceph osd pool set demo-pool crush_rule ssd-rulecreate-replicated后面的四个参数分别是规则名、根root、故障域类型、设备类。设备类是 Ceph 里区分 SSD 和 HDD 的常用手段但前提是 OSD 创建时正确打了标签用ceph osd tree能看到每个 OSD 所属的 class。最后那条切换命令要格外小心它会触发整个池的数据迁移PB 级规模下可能跑好几天。稳妥的做法是新建一个池、写好数据、业务切过去而不是原地改规则。4.3 副本还是纠删码按容量和延迟算一笔账副本和纠删码的取舍不是「先进与落后」的问题而是两种不同的成本结构。维度三副本EC 42EC 83空间利用率33%66%72%写放大3 倍1.5 倍1.375 倍恢复需读取1 份存活副本4 份分片8 份分片CPU 开销低中编解码中高随机小写表现好差读改写差适用场景数据库、虚机温数据、备份大对象归档写放大那一列的算法是写 1 份逻辑数据副本方案要落 3 份所以是 3 倍EC 42 要落 4 个数据块加 2 个校验块共 6 块而逻辑数据只占 4 块所以是 1.5 倍。看着 EC 更省但随机小写场景下 EC 需要先读出整个条带、改一个块、重新编码、再写回实际 IO 次数远高于这个理论值这也是它不适合数据库的根本原因。建 EC 池的命令# 定义 profile4 数据块 2 校验块故障域取 host ceph osd erasure-code-profile set ec42 k4 m2 crush-failure-domainhost # 建池并指定 profile ceph osd pool create ec-pool 32 32 erasure ec42 # RBD 用 EC 池时必须把元数据放在副本池数据放 EC 池 rbd create demo-pool/ec-demo.img --size 10G --data-pool ec-pool最后一条命令是关键细节EC 池不支持完整的 RBD 特性对象映射、快进差异等所以镜像头必须建在副本池上只有数据段落到 EC 池。这一步没做对后面rbd info会显示特性被自动关闭性能和功能都会打折。4.4 一致性模型什么时候会读到旧数据同一套系统里不同池、不同复制方式的一致性保证是不同的。单池内三副本写入返回时三个副本都已经落盘属于强一致跨站点异步复制时返回只代表本地写完远端可能落后几秒到几分钟这段时间内从远端读到的就是旧数据。比跨站点更容易被忽略的是缓存层。客户端的页缓存、文件系统的元数据缓存、对象存储前面的 CDN任何一层缓存都会引入「读己之写」的失效窗口。判断方法很简单写完之后立刻从另一台客户端读如果读不到说明有缓存或异步链路在中间。5. 排查清单分布式存储上线后最容易翻车的 5 个地方5.1 五条血泪记录现象、原因、解决第一条扩容之后延迟翻倍。现象是加了两台节点、业务代码一行没改P99 延迟从 8 ms 涨到 60 ms。原因是新 OSD 加入触发了大规模数据重平衡backfill 把磁盘带宽和网络带宽全吃掉了。解决分两步临时限速ceph config set osd osd_max_backfills 1和ceph config set osd osd_recovery_sleep_hdd 0.1让重建慢下来长期做法是把扩容安排在业务低峰并且提前用ceph osd tree确认新节点的权重设置合理权重给太高会导致新节点被塞进过多 PG。第二条ceph -s显示 HEALTH_OK业务却大面积超时。集群状态干净客户端rbd map也成功了但 fio 一跑全是超时。原因通常是网络而不是存储本身客户端到 OSD 的公网链路打满或者后端复制网络和客户端网络混跑在一张网卡上。排查时先看ceph health detail有没有 slow ops再用ceph osd perf看各 OSD 的提交延迟如果延迟正常但客户端超时问题基本就在网络侧。第三条小文件写入 IOPS 只有预期的十分之一。现象是写一万个 4 KB 文件测出来的 IOPS 远低于裸盘。原因是元数据路径成了瓶颈每个小文件都要走一次元数据事务而元数据服务通常只有一两个活跃实例。解决方向有三个业务侧把小文件打包成归档或合并成大对象系统侧给元数据服务加实例、调大缓存mds_cache_memory_limit或者干脆换一套为小文件设计的方案别硬扛。第四条一块盘掉了重建跑了两天还没完。现象是单盘故障后恢复速率极低。原因是重建要读取所有存活副本的完整数据而默认的恢复并发偏低加上业务流量挤占。临时可以把osd_recovery_max_active调高、把osd_recovery_sleep调低但要在业务低峰做。这条最值得提前算一块 8 TB 盘的重建时间取决于网络带宽和并发度按 200 MB/s 估算也要十几个小时如果是 EC 池恢复读取量还要乘以数据块数。第五条挂载点突然变成只读。现象是 CephFS 客户端报Read-only file system应用开始报错。可能的原因有两个池的使用率逼近 full ratio集群为了保护数据主动拒写或者客户端 session 超时被拉黑。前者用ceph df detail一看便知需要立刻扩容或清理后者用ceph osd blocklist ls能看到被拉黑的客户端地址确认网络确实恢复后再解除。这类问题最忌讳的处理方式是「先重启客户端试试」重启会丢掉未提交的元数据操作。5.2 面板还没搭起来的时候先看这几个指标没有监控面板的阶段几条命令就能覆盖大部分故障判断。指标命令异常信号集群整体状态ceph -s出现HEALTH_ERR或 PG 长期不 cleanPG 分布ceph pg stat大量undersized或staleOSD 延迟ceph osd perf个别盘 commit 延迟远高于同批容量水位ceph df detail单池使用率超过 85%慢请求ceph health detail持续出现 slow ops恢复进度ceph -s的 recovery 行长时间停滞不动的 objectsceph osd perf是这里面最被低估的一条。它能直接看出哪块盘在拖后腿而集群整体状态往往因为「还没到阈值」而显示正常。看到某块盘的 commit 延迟是其他盘的十倍以上就该考虑换盘了别等它彻底掉线。6. 用 rados bench 和 fio 压出真实上限6.1 两段脚本先测对象层再测块层压测要分层做先看存储引擎本身的上限再看加上协议栈之后的实际表现。# 1) 对象层顺序写4M 块16 并发跑 60 秒保留数据供后续读测试 rados bench -p demo-pool 60 write -b 4M -t 16 --no-cleanup # 2) 紧接着顺序读读的就是上一轮写下的对象 rados bench -p demo-pool 60 seq # 3) 对象层随机读 rados bench -p demo-pool 60 rand -t 16# 块层随机写走 RBD 协议贴近数据库负载 fio --namerandwrite \ --ioenginerbd --pooldemo-pool --rbdnamedemo.img \ --rwrandwrite --bs4k --iodepth32 --numjobs4 \ --direct1 --runtime120 --group_reporting参数含义需要逐条对照-b是单次 IO 大小4M 测的是带宽上限改成 4k 测的就是 IOPS-t是并发线程数它决定了客户端一侧能压出多少并发--no-cleanup保留测试对象否则读测试只能读到空池。fio 侧的--iodepth是队列深度--numjobs是进程数两者相乘才是总并发--direct1绕过页缓存否则测出来的全是内存速度。6.2 数字对不上时怎么反推瓶颈先做一次量纲换算带宽 IOPS × 块大小。如果 4K 随机写测出 5 万 IOPS对应带宽只有 200 MB/s这时候别怀疑网络先怀疑是不是被单盘 IOPS 卡住了。十二块盘的理论上限大约就是单盘 IOPS 乘以十二如果实测接近这个值说明瓶颈在盘上加客户端没用如果远低于这个值就往下查网络、CPUEC 池的编解码很吃 CPU、以及客户端的并发是否足够。我自己踩过最深的一次是拿一套 EC 池做随机小写压测跑出来的数字只有副本池的三分之一当时以为是网络问题查了两天才发现是读改写放大把并发全耗在了额外的读上。从那以后我的习惯是任何 EC 池上线前先用真实业务的 IO 模式跑一遍而不是只看顺序读写。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?