GlusterFS 分布式文件系统实战:三节点复制卷搭建、自愈修复与个人站多机共享存储

为什么个人站长也需要 GlusterFS

很多人觉得「分布式文件系统」是互联网大厂才玩得起的东西,一台 VPS 跑个网站,本地磁盘够用就行了,搞什么集群存储?这个判断在单机场景下没问题,但只要你的站稍微长起来,就会连续撞上几个绕不过去的墙:

  • 网站文件、用户上传的附件、日志统一放在一台机器上,机器一坏,数据和服务一起没;
  • 图片和附件越来越多,单块盘塞满,扩容只能停机加盘、迁数据;
  • 做了负载均衡之后,两台 Web 服务器上的网站文件对不上,用户上传的图片在 A 机器能看到、跳到 B 机器就 404;
  • 想给站点做多机热备,却发现「网站目录」这个最核心的资产根本没法简单同步。

这些问题的共同点,是「文件该放在哪、怎么让多台机器看到同一份文件」。对象存储(MinIO)解决的是图片附件这类静态资源,数据库有主从复制,但一个普通网站最朴素的需求——多台服务器共享同一个目录,读写一致,一台挂了另一台照常服务——恰恰是对象存储和数据库复制都覆盖不到的。这正是 GlusterFS 的用武之地。

GlusterFS 是一个开源的分布式文件系统,它把多台服务器上的本地磁盘(术语叫「砖块」brick)聚合成一个统一的卷,挂载到客户端后就和你本地的一个普通目录一模一样。它的最大优点是对个人站长极其友好:没有元数据服务器这个单点,所有节点平等,部署简单,客户端用标准的 FUSE 或 NFS 挂载,应用代码一行不用改。

核心概念:砖块、卷与副本

在动手之前,先把三个关键概念说清楚,不然后面的配置会看得云里雾里。

Brick(砖块)是 GlusterFS 的最小存储单元,本质上就是服务器上的一个目录,比如 /data/brick1。每台服务器可以提供一个或多个砖块。砖块所在的文件系统建议单独分区,避免被根分区的其他数据干扰。

Volume(卷)是多个砖块按照某种规则组合起来的逻辑存储单元,客户端挂载的就是卷。卷的类型决定了数据怎么分布、怎么冗余,这是整套系统里最关键的决策。

Trusted Pool(可信存储池)是互相加为信任关系的节点集合。只有加入同一个池的节点,才能共同组成一个卷。

常见的卷类型有这几种,个人站长最常用的其实只有前两种:

  • 分布式卷(Distribute):文件按哈希分散到各个砖块,容量是所有砖块之和,但没有任何冗余,一个砖块挂了对应的文件就读不到了。适合存放可以随时重新生成、不怕丢的大文件,比如 CDN 缓存源。
  • 复制卷(Replicate):每个文件在多个砖块上各存一份,任意一份损坏都不影响使用。这是最符合「个人站多机热备」需求的类型,两副本起步,建议三副本。
  • 分布式复制卷(Distributed Replicate):先复制、再分散,兼顾容量和冗余,适合数据量大又要保证安全的生产环境。
  • 条带卷(Stripe):把单个大文件切块并发读写,提升大文件吞吐,但对小文件没意义,且一个砖块坏就整卷坏,个人站基本用不上。

三节点部署实录

下面用三台服务器搭一个三副本的复制卷,这是最稳妥的个人站配置。假设三台机器内网 IP 分别是 10.0.0.11、10.0.0.12、10.0.0.13,主机名对应 gfs1、gfs2、gfs3。

第一步,三台机器都加上互相的主机名解析,否则 GlusterFS 会因为主机名解析不一致而拒绝组池:

# 在 /etc/hosts 里三台都写同样的内容
10.0.0.11  gfs1
10.0.0.12  gfs2
10.0.0.13  gfs3

第二步,三台机器都安装 GlusterFS 服务端。Debian/Ubuntu 下:

apt update
apt install -y glusterfs-server
systemctl enable --now glusterd
systemctl status glusterd

第三步,在一台机器上把另外两台加进可信存储池:

# 只需在 gfs1 上执行
gluster peer probe gfs2
gluster peer probe gfs3

# 查看池状态,三台都应为 Peer in Cluster
gluster peer status

第四步,在每台机器上准备砖块目录。注意 bricks 目录建议单独挂载一块数据盘,这里以 /data/brick1 为例:

mkdir -p /data/brick1/gv0

第五步,在 gfs1 上创建三副本复制卷:

gluster volume create gv0 replica 3 \
  gfs1:/data/brick1/gv0 \
  gfs2:/data/brick1/gv0 \
  gfs3:/data/brick1/gv0 \
  force

gluster volume start gv0
gluster volume info gv0

replica 3 表示每个文件存三份。force 参数是当砖块目录所在的分区不是独立分区时绕开检查用的,生产环境建议真的用独立分区,这样更安全。

第六步,客户端挂载。任何需要访问这个共享目录的机器(包括 Web 服务器本身)都可以作为客户端:

apt install -y glusterfs-client
mkdir -p /mnt/webdata
mount -t glusterfs gfs1:/gv0 /mnt/webdata

挂上之后,ls /mnt/webdata 就和本地目录完全一样。往里面写一个文件,去另外两台机器的 brick 目录下也能看到,这就是复制卷在起作用。

让挂载开机自启并自动重连

手工 mount 重启就没了,写进 /etc/fstab 才能持久。但直接照抄网上的 fstab 写法有个大坑:GlusterFS 依赖 glusterd 服务,如果挂载发生在网络和 glusterd 启动之前,fstab 会卡住甚至进不了系统。正确的写法是加上 _netdev 和 x-systemd.automount:

gfs1:/gv0 /mnt/webdata glusterfs defaults,_netdev,x-systemd.automount,x-systemd.device-timeout=10 0 0

_netdev 告诉系统这是网络文件系统,等网络就绪后再挂;x-systemd.automount 让 systemd 在第一次访问该目录时才发起挂载,进一步避免开机卡死。

另外,GlusterFS 客户端默认开启自我修复(self-heal),当某个节点恢复后会异步补齐缺失的数据。可以用下面的命令随时查看是否需要修复:

gluster volume heal gv0 info
gluster volume heal gv0 info summary

如果有文件显示 Number of entries: 0 就说明健康,出现待修复条目时可以用 gluster volume heal gv0 full 手动触发全量修复。

性能调优与实用技巧

GlusterFS 默认的参数偏保守,个人站按下面的顺序调一调,能明显改善小文件读写性能。

开启卷级缓存和元数据缓存。GlusterFS 有两个很关键的选项服务于 Web 场景:

gluster volume set gv0 performance.cache-size 512MB
gluster volume set gv0 performance.md-cache-timeout 60
gluster volume set gv0 performance.stat-prefetch on
gluster volume set gv0 performance.read-ahead on
gluster volume set gv0 performance.write-behind on

performance.cache-size 是卷的读缓存,装网站文件这类读多写少的场景收益很大;performance.stat-prefetch 会预取文件的元数据,减少 stat() 带来的往返延迟,WordPress/Typecho 这类大量调用 stat 的 PHP 程序提升特别明显。

为 Web 小文件场景调整入口和线程。如果目录里全是几 KB 的 PHP 文件和缩略图,可以加大 brick 的 IO 线程:

gluster volume set gv0 client.event-threads 4
gluster volume set gv0 server.event-threads 4

一般设置为 CPU 核数即可,太高反而会因为上下文切换变慢。

日志相关。GlusterFS 的日志默认在 /var/log/glusterfs/ 下,排查问题时最有用的是 bricks/gv0.log 和客户端挂载时指定的日志。可以给卷关掉多余的访问日志,减少磁盘写入:

gluster volume set gv0 nfs.disable on

只要不用 NFS 方式挂载,就把内置的 NFS 服务关掉,能省内存也能少一个攻击面。

必须知道的五个坑

坑一:脑裂(split-brain)。这是复制卷最危险的状态。当三台机器之间的网络断开,客户端在两侧各自写入了同一个文件的不同版本,恢复网络后 GlusterFS 无法判断该保留哪一份,就会进入脑裂,文件变成 gfid 命名的怪异文件且读不出来。预防办法是至少三副本、保证网络稳定,出问题的修复命令是:

gluster volume heal gv0 info split-brain
# 选定保留某一份后,对具体文件执行
gluster volume heal gv0 split-brain source-brick gfs1:/data/brick1/gv0 /path/to/file

坑二:砖块目录必须为空。如果砖块目录里已经有文件,创建卷时要么被拒绝,要么带 force 后把这些旧文件当作已有数据挂进去,容易造成混乱。每次都从空目录开始。

坑三:时钟不同步。三台机器时间差太大,会导致自愈判断和日志混乱。上线前务必配好 NTP,用 timedatectl 检查同步状态。

坑四:把 GlusterFS 当数据库存储。GlusterFS 面向的是文件共享,不是低延迟的块设备。MySQL 的数据目录绝对不要放在 GlusterFS 卷上,共享文件、图片、代码才是它的主场。

坑五:单点挂载。如果所有客户端都只从 gfs1 挂载,gfs1 一挂全部客户端都断。正确做法是每个客户端用不同的节点作为挂载入口,或者直接写多台节点做负载,客户端会自动故障转移。

个人站的典型用法

对绝大多数个人站长来说,GlusterFS 最有价值的场景只有一个:让多台 Web 服务器共享同一份网站目录和上传附件。典型架构是:

  • 三台服务器组成三副本复制卷,每台都既做存储节点、又做 Web 节点;
  • Nginx + PHP 都从挂载好的 /mnt/webdata 目录读取网站文件;
  • 用户上传的附件写到同一个目录,无论请求被负载均衡分发到哪台机器,都能读到;
  • 任何一台机器宕机,另外两台照常提供完整服务,数据不丢。

这样一套架构,硬件成本就是三台普通 VPS,但可用性和扩展性直接上了一个台阶。GlusterFS 不需要你懂什么分布式理论,只要记住「砖块组成卷,复制保平安」这一句话,就能把个人站从「单机裸奔」升级成有冗余的小集群。真正的价值不在于技术多高级,而在于它把原本只有大厂工程师才敢碰的能力,拉到了每个草根站长都能动手实现的水平。

Last modification:October 4th, 2026 at 10:24 pm

Leave a Comment