想象一下,你是一家大型连锁超市的老板,分店遍布全国,每天要处理海量的货物和订单。你发现单靠一个仓库已经装不下了,而且如果仓库着火,所有货品都会毁于一旦。于是你决定租下多个城市的仓库,把货物分散存放,这就是“分布式存储”的雏形——但问题来了:这么多仓库,货品到底该怎么分配?如果某个仓库坏了,怎么保证还能查到货物?客人下单时,又该去哪个仓库取货? 在IT世界里,Ceph和GlusterFS就是两位风格迥异的“仓库管理员”,都帮你管理海量文件,但它们的“分货逻辑”和“协调方式”截然不同。Ceph像一位精密的“数学规划大师”,它把数据切成无数小方块,用一套复杂的算法决定每块放到哪个磁盘上;而GlusterFS更像一位“货架管理员”,它不拆碎你的文件,而是把整个文件当作一个“箱子”,按照目录规则放到某个服务器上。这篇文章,我们就跟着这两位“管理员”的不同工作方式,看看分布式文件系统背后的架构智慧,以及它们在云原生时代各自扮演的角色。

岗位关联

学会对比Ceph与GlusterFS的架构差异,能帮助你在真实项目中做出合理的存储选型决策,避免“存储架构设计失误”带来的扩容难、故障多、成本失控等灾难性后果。

目录
  1. 可视化演示
  2. 分布式存储前世
  3. Ceph架构剖析
  4. GlusterFS架构
  5. 一致性设计对比
  6. 扩展性横向对比
  7. 云原生场景适配
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

对比Ceph(RADOS/CRUSH多层架构)与GlusterFS(DHT对等环拓扑)的架构设计、数据分布方式与一致性模型,展示两种分布式文件系统的核心差异。

本节配有交互动效(进入视口后自动加载,约 3KB)。

架构对比模式 Ceph采用MON/OSD/MDS三层架构,通过CRUSH算法实现数据伪随机分布与多副本 GlusterFS采用DHT无中心对等拓扑,所有brick节点平等,客户端直连数据节点 Ceph: 强一致性 | GlusterFS: 最终一致性 Ceph适合统一存储场景,GlusterFS适合简单扩展的大文件存储。

分布式存储前世

回到超市的例子。当你的超市只有一家店时,货品全堆在一个仓库里,找货方便、管理简单。但当门店扩展到几十家,同一个仓库既要服务线上下单又要服务门店补货,仓库开始不堪重负:空间不够、吞吐跟不上、一旦停电或火灾,整个生意都瘫痪。这时候,你需要在多个城市设置多个仓库,把货品分散存放。这就是分布式存储诞生的根本动力——单机存储瓶颈。

在IT领域,单台服务器的磁盘容量、I/O带宽、网络吞吐都有上限。当文件数量达到亿级、容量达到PB级,一台机器无论如何也扛不住。企业需要多个存储节点协同工作,对外呈现为一个统一的大型文件系统,这就是分布式共享存储需求的由来。共享意味着所有服务器都能访问同一份数据,就像所有分店都能查询总仓库存货一样。

2000年代中后期,开源社区涌现出两大主流方案:Ceph和GlusterFS。前者由Sage Weil在博士论文中提出,后者诞生于Gluster公司。它们都致力于解决海量文件存储问题,但选择了截然不同的技术路径。就像两位能力出众但性格迥异的仓库管理员,一位偏好精密的数学编排,一位崇尚简单的规则分发。

理解了分布式存储的“前世”,就像看到超市扩张的必经之路:单仓库不够用,就需要多仓库协同。Ceph和GlusterFS,正是为解决这一需求而生的两种“多仓库管理模式”,接下来的章节将逐一拆解它们的设计哲学。

分布式存储核心目标=lim⁡N→∞存储容量N≈单节点容量×N\text{分布式存储核心目标}=\lim_{N\to\infty}\frac{\text{存储容量}}{N}\approx \text{单节点容量}\times N
简单的扩容模型:存储系统总的容量约等于单个节点容量乘以节点数量,但这只是理论上限,实际受数据分布策略和一致性开销制约。
  1. 存储容量分布式存储的最终目标,是所有节点容量的总和,用分子表示。
    存储容量\text{存储容量}
  2. 节点数量存储系统中参与工作的服务器数量,用 \(N\) 表示。
    N→∞N\to\infty
  3. 总容量估算当节点数量足够大时,总容量约等于单节点容量乘以节点数,但这需要数据分布足够均匀。
    ≈单节点容量×N\approx \text{单节点容量}\times N

Ceph架构剖析

Ceph这位“管理员”的思路非常硬核:它把所有文件切成小块——默认4MB大小的对象,然后像发牌一样,通过一个名为CRUSH的算法,把每个对象均匀地撒到整个集群的磁盘上。这里没有“中央调度员”在每次写入时询问“该放哪”,而是所有节点都用同一个算法算出答案,就像所有分店经理都拿着同一本数学公式手册,算出同一道题的结果,谁都不用打电话请示总部。

具体来说,Ceph的架构由三部分构成。首先是OSD(对象存储守护进程),每个OSD管理一块磁盘,负责存储对象和处理数据的复制、恢复、平衡。其次是MON(监控节点),负责维护整个集群的元数据,包括哪些OSD在线、CRUSH映射表版本等。最后是元数据服务器(MDS),仅在文件系统模式下需要,用于管理文件路径到对象的映射。

Ceph的读写路径相当高效。客户端写入文件时,先计算文件的CRUSH映射,确定对象应存放的OSD组合,然后直接与这些OSD通信,无需经过任何中间代理。为了保障数据安全,Ceph默认将每个对象复制三份,副本分布在不同的故障域中——比如不同机架——防止整柜断电导致数据丢失。

Ceph的这套设计堪称精妙:通过算法代替查询,所有人“心算”出同一个结果,省去了元数据查询的瓶颈。但代价是,这套系统非常复杂,部署和调优的门槛较高。就像那位精密的数学规划大师,他能精准调度每件货品,但你得先花时间学会他那套复杂的公式体系。

PG=hash(object ID) mod 2M\text{PG}=\text{hash}(\text{object ID})\bmod 2^{M}
OSD 集合=fCRUSH(PG ID,cluster map,规则)\text{OSD 集合}=f_{\text{CRUSH}}(\text{PG ID}, \text{cluster map}, \text{规则})
CRUSH 算法分为两步:先将对象哈希到PG(Placement Group),再通过CRUSH映射PG得到对应的OSD集合。
  1. 对象哈希每个文件对象有一个唯一ID,通过哈希函数得到一个数值,该数值决定对象属于哪个PG。
    hash(object ID)\text{hash}(\text{object ID})
  2. 取模运算用哈希值对PG总数(\(2^{M}\))取模,得到PG编号,这就是对象的“逻辑家址”。
     mod  2M\bmod\,2^{M}
  3. CRUSH映射拿到PG编号后,集群中的每个节点根据cluster map和存储规则,计算出该PG对应的OSD列表,从而定位数据。
    fCRUSH(PG ID,cluster map,规则)f_{\text{CRUSH}}(\text{PG ID}, \text{cluster map}, \text{规则})

GlusterFS架构

GlusterFS则走了另一条路。它更像一位“货架管理员”:不拆碎你的文件,而是把每个文件当作一个完整的“箱子”,按照某种规则直接放到某个存储服务器上。它没有中心化的元数据服务器,所有节点都是平等的,通过弹性哈希算法(Elastic Hash)计算出某个文件路径应该由哪台服务器负责。这意味着客户端和服务器都能独立算出文件位置,不需要询问“总部”。

GlusterFS的基本单元是brick,即一台服务器上的一个导出目录。多个brick组合成一个卷(volume),卷是客户端挂载的存储单元。根据卷的类型不同,数据分布方式也有所不同:分布卷(distribute)数据散落在各brick上,副本卷(replicate)提供数据的多份拷贝,条带卷(stripe)则把文件分块写入多个brick。实际部署中,最常用的是分布+副本的组合模式。

由于没有中心节点,GlusterFS的架构格外简洁:没有独立的MON集群,没有复杂的CRUSH映射维护,只要保证所有节点运行同一套算法即可。客户端通过FUSE内核模块挂载卷,数据读写路径是“客户端 → 本地FUSE → 目标brick”,链路上的跳数极少,因此小文件的顺序读写性能相当不错。

GlusterFS的“简单哲学”让它成为很多中小型企业的首选:部署只需几步命令,扩容只需添加brick。但这份简单也有代价——由于以文件为粒度分布,一旦文件大小差异很大,可能出现某些服务器存储饱满而另一些空闲的“数据倾斜”问题,就像货架上有些层堆到顶、有些层空空如也。

文件位置=fhash(文件路径或文件名) mod N\text{文件位置}=f_{\text{hash}}(\text{文件路径或文件名})\bmod N
GlusterFS利用文件名或路径的哈希值对服务器数量取模,快速计算出文件所在的目标服务器,无需查询任何元数据。
  1. 哈希函数将文件路径(或文件名)作为输入,输出一个哈希整数,这是定位文件的唯一依据。
    fhash(文件路径或文件名)f_{\text{hash}}(\text{文件路径或文件名})
  2. 取模定位哈希值对服务器数量 \(N\) 取模,得到目标brick的编号,类似“根据门牌号找到对应货架”。
     mod  N\bmod\,N

一致性设计对比

一致性是分布式存储的核心难题,也是Ceph与GlusterFS最大的分水岭。想象两家分店同时接到同一个顾客的退货订单:一家把库存减掉,另一家还没同步消息,结果在线上查库存时出现了不一致的数据。分布式系统的“一致性”就是处理这种同步问题的能力。

Ceph选择了强一致模型。它采用主备(primary-backup)复制模式:每个PG有一个主OSD和多个从OSD,所有写操作先到达主OSD,由主OSD负责把数据同步给从OSD,全部成功后,才向客户端确认“写入完成”。这样,任何时刻客户端读到的数据都是最新版本。代价是每次写入都要等待副本确认,增加了延迟。

GlusterFS则更倾向于最终一致。在副本卷中,写操作只需写入本地brick即可返回,副本之间的同步通过后台异步完成。如果主brick在数据同步前宕机,从brick上的数据可能是旧的。不过GlusterFS的自愈机制会在后台修复不一致,最终达到各副本一致。这种设计换来了极低的写延迟,但也牺牲了读时的绝对准确性。

如果说Ceph像一家“每次结账都要等所有门店确认库存”的谨慎连锁店,那么GlusterFS就像一家“先给顾客承诺、后台再慢慢同步数据”的灵活小店。强一致带来的是数据可信赖,最终一致带来的是速度与简单。选谁,取决于你的业务能否容忍那一点点时间差。

Twrite, Ceph=Tprimary+max⁡(Treplica1,Treplica2,…)T_{\text{write, Ceph}}=T_{\text{primary}}+\max(T_{\text{replica}_1},T_{\text{replica}_2},\ldots)
Ceph的写入延迟是主节点写延迟加上最慢副本的同步延迟,多副本复制会显著增大等待时间,这是强一致的必然开销。
  1. 主节点写入客户端将数据发送给主OSD,主OSD负责协调本次写操作,这个时间是等待的基础。
    TprimaryT_{\text{primary}}
  2. 副本同步等待主OSD并行向多个副本OSD发送数据,等待所有副本完成后返回。整个时间受最慢副本制约。
    max⁡(Treplica1,Treplica2,…)\max(T_{\text{replica}_1},T_{\text{replica}_2},\ldots)
  3. 总延迟主节点写入与最慢副本同步时间之和,这就是Ceph写操作的整体延迟。
    Tprimary+max⁡(…)T_{\text{primary}}+\max(\ldots)

扩展性横向对比

超市扩张到一定规模时,不同管理模式的优劣就会显现。Ceph和GlusterFS在扩展性上的表现,就像两种截然不同的扩张策略。

Ceph的扩展性上限极高。由于OSD是分散的粒度,集群可以精确地“按磁盘”扩容——每次添加一个OSD,CRUSH算法会重新计算数据分布,将一定比例的数据自动平衡到新OSD上。纸面上,Ceph可以扩展到数千个OSD,存储容量达到EB级。但这份高上限伴随着高复杂度:数据重平衡会带来不小的网络负载,PG数量需要精心规划,集群越大,MON的协调压力也越大。

GlusterFS的扩展则更“粗放”。它按brick扩展,一个brick通常是一整块磁盘或目录,扩容粒度较大。由于没有CRUSH算法,当集群规模变化时,弹性哈希算法通常会导致“文件位置变动”——这意味着原有数据需要重新定位。GlusterFS的新版本引入了重平衡(rebalance)机制来迁移数据,但这同样会带来I/O开销。在接近PB级的规模下,GlusterFS的元数据查询效率和重平衡速度会明显下降。

Ceph像一家“每开一家分店,就把所有货品重新均匀调配一遍”的精密集团——迁移数据多,但最终会很均衡;GlusterFS像一家“新店开张,只把部分货架上的货搬过去”的快餐厅——迁移量少,但可能有些店货堆成山、有些店空荡荡。选择哪种扩展哲学,要看你能接受多大的运维复杂度。

扩容迁移数据量GlusterFS≈Nnew−NoldNnew×总数据量\text{扩容迁移数据量}_{\text{GlusterFS}}\approx \frac{N_{\text{new}}-N_{\text{old}}}{N_{\text{new}}}\times \text{总数据量}
横向扩容时,GlusterFS需要迁移大约“新增节点比例”的数据量;如果从3个节点扩到6个,大约一半数据需要重新分布,这是扩容成本高的原因。
  1. 新增与旧节点数\(N_{\text{new}}\) 是新集群总节点数,\(N_{\text{old}}\) 是旧集群节点数,它们的差就是新增节点数。
    Nnew−NoldN_{\text{new}}-N_{\text{old}}
  2. 迁移比例新增节点占总节点的比例,决定了有多少数据需要搬迁到新节点上。
    Nnew−NoldNnew\frac{N_{\text{new}}-N_{\text{old}}}{N_{\text{new}}}
  3. 迁移总量迁移比例乘以总数据量,得到扩容时需要移动的数据总量。
    × 总数据量\times\,\text{总数据量}

云原生场景适配

云原生时代,存储系统必须能够成为Kubernetes的“一块云硬盘”,让容器随时申请、释放存储资源。Ceph和GlusterFS都通过CSI插件接入了容器生态,但部署和运维方式各有千秋。

Ceph在云原生领域最大的功臣是Rook。Rook是一个Operator框架,它将Ceph的部署、配置、扩缩容和升级都封装为Kubernetes操作符。运维人员只需要声明一个CephCluster资源,Rook就会自动创建MON、OSD等组件,并根据集群状态自动修复故障。Rook的成熟度让Ceph成为很多生产环境的默认选择,特别是在云厂商托管的Kubernetes服务中。

GlusterFS则有Heketi作为其Kubernetes存储管理接口。Heketi对外提供RESTful API,帮助Kubernetes通过Volume插件动态创建和管理GlusterFS卷。不过相比Rook的活跃度和社区支持,Heketi的更新迭代较慢,这在一定程度上影响了GlusterFS在云原生领域的最终吸引力。此外,Ceph的块存储(RBD)和对象存储(RGW)能力使其能同时服务多种负载,而GlusterFS更专注于文件存储。

云原生场景下,Ceph像一位“自带管家”的贵族——Rook把一切都安排得妥妥当当,你只需要下达意图;GlusterFS则像一位“自助式”的实干家——Heketi能帮忙,但更多时候你需要自己操心。如果你已经深度使用Kubernetes,Rook托管Ceph无疑是最省心的路径。

CSI 调用链: Pod→Kubelet→CSI Plugin→Rook/Heketi→存储集群\text{CSI 调用链}:\ \text{Pod}\to\text{Kubelet}\to\text{CSI Plugin}\to\text{Rook/Heketi}\to\text{存储集群}
在Kubernetes中,Pod挂载存储的链路是:Kubelet调用CSI插件,CSI再调用Rook或Heketi等管理组件,最终与存储集群交互。这条链路让存储获得了“即插即用”的能力。
  1. Pod 发起请求容器运行时需要挂载存储卷,Pod 通过 Kubernetes API 请求卷资源。
    Pod\text{Pod}
  2. Kubelet 转发指令Kubelet 收到调度指令后,调用本节点的 CSI 插件完成挂载操作。
    →Kubelet\to\text{Kubelet}
  3. CSI 调用管理组件CSI 插件通过 Rook 或 Heketi 的接口获取卷信息,并下发创建/挂载指令。
    →CSI Plugin→Rook/Heketi\to\text{CSI Plugin}\to\text{Rook/Heketi}
  4. 存储集群响应最终由 Ceph 或 GlusterFS 集群提供实际存储能力,返回操作结果。
    →存储集群\to\text{存储集群}

AI 应用场景

AI训练数据集的分布式存储

阶段:数据准备与存储管理

解决的问题:AI训练需要海量数据集,单机磁盘无法承载,且多台训练服务器需要并发访问同一份数据。Ceph和GlusterFS提供统一命名空间,让所有GPU节点像读写本地文件一样访问训练数据。

具体案例:某自动驾驶公司拥有数十TB的标注图像数据集,数据分布在多台GPU训练服务器上。采用Ceph文件系统作为共享存储池,通过CSI接口挂载到Kubernetes集群中的训练Pod。当数据集版本更新时,新增数据通过Ceph的对象存储自动均衡分布到各OSD,无需手动搬移文件。

大规模日志与模型产物的归档存储

阶段:模型产出与日志归档

解决的问题:训练日志、模型检查点、推理结果通常以海量小文件形式存在,传统NFS在文件数量达到千万级后性能急剧下降。分布式文件系统通过数据分布和并行读写突破单机瓶颈。

具体案例:某大模型团队使用GlusterFS构建了归档存储集群,将每个训练任务的检查点文件按目录存放。由于GlusterFS对文件名哈希定位,模型文件写入可以快速找到目标brick,配合副本卷保证关键检查点不丢失。

Python 演示

python69 行
import hashlibimport struct class CephCRUSHSimulator:    def __init__(self, osd_list, replica_count=3):        self.osd_list = osd_list        self.replica_count = replica_count        self.pg_count = 128        self.pg_to_osd = self._build_pg_map()     def _build_pg_map(self):        pg_map = {}        for pg_id in range(self.pg_count):            osds = []            for r in range(self.replica_count):                h = hashlib.sha256(                    struct.pack('ii', pg_id, r)                ).hexdigest()                idx = int(h, 16) % len(self.osd_list)                osds.append(self.osd_list[idx])            pg_map[pg_id] = osds        return pg_map     def write(self, file_name):        obj_hash = int(hashlib.sha256(            file_name.encode()).hexdigest(), 16)        pg_id = obj_hash % self.pg_count        target_osds = self.pg_to_osd[pg_id]        print(f'文件 {file_name} -> PG {pg_id} -> OSD {target_osds}')     def distribution(self):        counts = {osd: 0 for osd in self.osd_list}        for osds in self.pg_to_osd.values():            for osd in osds:                counts[osd] += 1        return counts class GlusterHashMapper:    def __init__(self, bricks):        self.bricks = bricks     def locate(self, file_name):        h = int(hashlib.sha256(            file_name.encode()).hexdigest(), 16)        idx = h % len(self.bricks)        return self.bricks[idx]     def rebalance_cost(self, new_bricks):        moved = 0        for file_name in self.bricks:            h = int(hashlib.sha256(                file_name.encode()).hexdigest(), 16)            old_idx = h % len(self.bricks)            new_idx = h % len(new_bricks)            if old_idx != new_idx:                moved += 1        total = len(self.bricks)        return moved, total if __name__ == '__main__':    ceph = CephCRUSHSimulator(['osd-1', 'osd-2', 'osd-3', 'osd-4'])    ceph.write('model_epoch_10.pth')    ceph.write('train_data_001.bin')    print('Ceph OSD 分布:', ceph.distribution())     gluster = GlusterHashMapper(['brick-1', 'brick-2', 'brick-3'])    print('GlusterFS 定位:', gluster.locate('image_001.jpg'))    moved, total = gluster.rebalance_cost(['brick-1', 'brick-2', 'brick-3', 'brick-4'])    print(f'扩容迁移: {moved}/{total} 文件需要搬迁')
目的:用 Python 模拟 Ceph 的 CRUSH 数据分布与 GlusterFS 的哈希定位及扩容迁移成本,直观对比两种架构的核心机制。
  1. hashlib.sha256(file_name.encode()).hexdigest()对文件名做哈希,生成伪随机的整数分布,模拟两种存储系统的核心哈希操作。
  2. struct.pack('ii', pg_id, r)将PG编号和副本序号打包为二进制,作为哈希输入,确保同一PG不同副本分布在不同的OSD上。
  3. obj_hash % self.pg_count对哈希值取模,得到PG编号,这是Ceph从对象到PG的映射方式。
  4. self.pg_to_osd[pg_id]通过预计算的PG映射表,快速得到目标OSD列表,类似CRUSH查找过程。
  5. counts[osd] += 1统计每个OSD上的PG数量,用于观察数据分布的均匀性。
  6. h % len(self.bricks)GlusterFS的文件定位方式:对路径哈希后对砖块数取模,得到目标brick。
  7. old_idx != new_idx扩容后比较新旧索引是否变化,判断文件是否需要迁移,体现GlusterFS扩容的搬迁成本。

常见误区

误区我以为Ceph每次读写数据都要先问一下中心服务器“这个文件放在哪”,就像每次寄快递都要先打客服电话问网点地址,所以Ceph存在严重的中心化瓶颈。

正解实际上,Ceph的所有客户端和OSD都持有相同的cluster map和CRUSH规则,它们可以本地计算每个对象的位置,完全不需要查询中心元数据。这就好比每个快递员手里都有一本全市网点分布手册,自己就能算出目的地,无需打客服电话。MON节点只负责维护这些配置的一致性,并不参与数据通路。

为何常见:因为很多分布式系统都有中心元数据服务(如HDFS的NameNode),初学者容易把这种惯性思维套用到Ceph上,误以为Ceph的设计也是如此。

误区我听说GlusterFS是无中心的分布式文件系统,觉得它没有中心节点管理,应该也不会做数据备份。数据丢失只能靠运气。

正解GlusterFS支持副本卷,在创建卷时指定replica数量,数据会被同步写到多个brick上。它与Ceph的主要区别在于一致性强弱和故障切换的方式,而不是“有没有副本”。比如一个AFR(自动文件复制)卷会将文件同时写入两个brick,当一个brick故障时,另一个brick仍能提供完整数据。

为何常见:把“无中心架构”错误等同于“无复制保障”,忽略了GlusterFS卷类型多样性的设计。

误区既然Ceph架构那么高级、功能那么多,它的读写性能一定全面碾压GlusterFS吧?选型时直接无脑上Ceph就行。

正解性能取决于场景。对于小文件顺序读写且并发不高的场景,GlusterFS由于链路简单、无副本同步等待,延迟通常更低。Ceph的强一致复制在每次写入时都要等待副本确认,反而可能成为性能瓶颈。Ceph的优势在于大规模、高并发、多副本强一致场景下的均衡表现,而非绝对的速度优势。

为何常见:人们容易把“功能强大”与“性能好”划等号,忽略了系统复杂度和复制开销对性能的影响。

面试题

Q1. Ceph中负责实际存储数据的是哪个组件?

单选题 · easy

  • A.MON 监控节点
  • B.MDS 元数据服务器
  • C.OSD 对象存储守护进程← 正确答案
  • D.RGW 对象网关

答案:C。OSD直接管理磁盘并存储对象数据,是Ceph的数据平面核心。MON维护集群元数据,MDS管理文件系统目录树,RGW提供对象存储接口,它们都不直接存储用户数据。如同仓库中真正堆放货品的是货架,而不是门口登记册。

Q2. GlusterFS 中数据定位使用的主要技术是?

单选题 · easy

  • A.中心元数据查询
  • B.弹性哈希算法← 正确答案
  • C.CRUSH 算法
  • D.广播寻址

答案:B。GlusterFS通过弹性哈希对文件路径进行计算实现定位,无需查询中心节点。CRUSH是Ceph的算法,中心元数据查询是HDFS的典型方式。就像凭门牌号直接找到货架,而不必先到总台问路。

Q3. Ceph 采用哪种一致性模型?

单选题 · mid

  • A.弱一致
  • B.最终一致
  • C.强一致← 正确答案
  • D.无一致性保证

答案:C。Ceph的写操作必须在主OSD和所有副本成功后返回,读取永远是最新数据,这是强一致模型。最终一致是GlusterFS的设计倾向,弱一致适合缓存等场景。如同所有分店确认签收后,总店才告诉客户“下单成功”。

Q4. GlusterFS 的副本卷中,主副本故障时会发生什么?

单选题 · mid

  • A.数据永久丢失
  • B.从副本自动提供数据并后台自愈← 正确答案
  • C.集群立即停止服务
  • D.需要手动切换副本

答案:B。GlusterFS具备自愈机制,当主副本故障时,从副本仍可提供数据访问,后台通过自我修复恢复到一致状态。数据并非永久丢失,也无需手动干预切换。如同备用货架自动顶替主货架出库,同时后台补货。

Q5. 下列关于 Ceph 和 GlusterFS 的说法正确的有?

多选题 · mid

  • A.Ceph 是强一致系统← 正确答案
  • B.GlusterFS 是无中心架构← 正确答案
  • C.Ceph 扩容粒度是块设备
  • D.GlusterFS 保证最终一致← 正确答案

答案:ABD。Ceph强一致正确,GlusterFS无中心设计正确,GlusterFS最终一致正确。Ceph扩容粒度是OSD(对象存储设备),不是块设备。选项C偷换了扩容对象的概念,需留意设施与数据单位的区分。

Q6. Ceph 中 CRUSH 算法的主要作用是什么?

单选题 · hard

  • A.对文件内容进行压缩加密
  • B.将 PG 映射到一组 OSD← 正确答案
  • C.将文件转换成块设备
  • D.实现文件锁机制

答案:B。CRUSH接收PG编号、cluster map和存储规则作为输入,输出一组OSD编号。这个过程在客户端本地完成,无需查询元数据服务器。压缩加密、文件转换或文件锁都与CRUSH无关。如同数学公式直接算出货架号,无需问人。

Q7. 云原生场景下,Ceph 和 GlusterFS 的接入方式分别有哪些?

多选题 · mid

  • A.Rook 管理 Ceph← 正确答案
  • B.Heketi 服务 GlusterFS← 正确答案
  • C.CSI 插件统一接入← 正确答案
  • D.只能使用裸机部署

答案:ABC。Rook以Operator方式将Ceph融入Kubernetes,Heketi提供GlusterFS的动态卷管理,两者最终都通过CSI插件完成挂载。D项错误,二者均支持裸机与容器化部署。如同不同品牌的货架都可安装标准化的扫码出入库系统。

Q8. GlusterFS 扩容时可能带来什么额外开销?

单选题 · hard

  • A.数据自动压缩
  • B.新增节点比例的数据重新分布← 正确答案
  • C.所有文件写入延迟降低
  • D.数据格式自动转换

答案:B。当brick数量变化,弹性哈希的取模结果随之改变,导致部分文件映射到新brick,产生数据迁移。迁移量约等于新增节点比例。数据压缩、延迟降低和格式转换并非扩容固有行为。如同新货架加入后,一部分旧货需要重新搬到新位置。

Q9. Ceph 写入延迟高于 GlusterFS 的主要原因是?

单选题 · mid

  • A.Ceph 使用机械磁盘
  • B.Ceph 需要等待所有副本写入完成← 正确答案
  • C.Ceph 没有缓存机制
  • D.Ceph 文件体积更小

答案:B。Ceph的强一致要求主副本和所有从副本确认后才返回写成功,同步等待增加了延迟。GlusterFS可以先行返回,后台再异步复制。磁盘类型和缓存并非根因。如同必须等所有分店签收后才确认订单,自然比先接单再同步更慢。

Q10. 下列关于两种文件系统选型的说法正确的有?

多选题 · hard

  • A.海量小文件高并发场景适合 Ceph← 正确答案
  • B.中小规模运维简单场景适合 GlusterFS← 正确答案
  • C.Ceph 适合云原生 Kubernetes 环境← 正确答案
  • D.GlusterFS 适合 EB 级超大规模场景

答案:ABC。Ceph的强一致与优秀的均衡性适合海量小文件高并发,且Rook使其在云原生环境更成熟;GlusterFS的简单架构适合中小规模。EB级场景需要Ceph这类具备高扩展上限的设计,GlusterFS在超大集群中重平衡效率与元数据能力受限,D错误。如同小卖部用简易货架即可,连锁巨头则需要智能仓储系统。