上一篇 下一篇 分享链接 返回 返回顶部

如何在香港机房落地“课件”冷热分层:用 Ceph/MinIO 结合 NVMe 的高命中率与低成本实践

发布人:Minchunlin 发布时间:2025-09-27 10:25 阅读量:182


凌晨 3 点过十,我把工牌贴在胸前,推开北角那扇总也不太好使的防火门。走廊里空调轰鸣。今天要把“课件”分发系统的冷热分层上线——白天同学们点开 PPT/PDF/视频的时候再也别卡;夜里把冷数据挪到便宜的盘上省钱。

我随手摸了下新装的 U.2 NVMe,温度还好;交叉检查了 ToR 交换机两条 10GbE 上联的 LACP,绿色闪烁得很扎实。凌晨 5 点前,我得把 Ceph 的冷层和 NVMe 的热层跑顺,还要留出回滚窗口。

下面,我把完整的实操从“架构选择—部署—优化—观测—故障与修复—成本与命中率模型”一口气讲完。全文基于 CentOS 7 的环境(我们客观上受限于某些历史镜像和内网依赖),同时给出 Ceph RGW 方案 与 MinIO 方案 两条路径:我最终线上使用了 Ceph 冷+Nginx(NVMe)热缓存,但把 MinIO 的落地细节也一并写出来,方便你按团队栈选择。

业务目标与设计取舍

目标

  • 学期高峰(晚 8–11 点)P95 ≤ 80 ms、P99 ≤ 150 ms(静态课件 PDF/MP4/Zip 为主)。
  • 峰值 8–12k RPS,长期月均 3–5 PB 级别访问。
  • 热数据(7 天内、Top 20% 课件)命中率 ≥ 85%;冷数据走低成本容量层。
  • 三年 TCO 降 35%+,盘位与电力在香港机房尤需精打细算。

两条技术路线(均基于 NVMe 热层)

Ceph RGW(对象存储) + HDD 冷层 + NVMe 前置缓存(Nginx proxy_cache)

  • 热层 = 前端 NVMe 缓存(读放大强、命中快)
  • 冷层 = Ceph OSD(HDD + Erasure Coding)
  • 迁移 = RGW Lifecycle(按“天数/前缀/标签”转冷池)
  • 优点:成熟、可大规模、成本结构清晰;缺点:学习曲线略陡。

MinIO 分布式(热集群用 NVMe、冷集群用 HDD) + ILM 远端转储

  • 热层 = MinIO(EC) 跑 NVMe;冷层 = 另一组 MinIO(EC) 跑 HDD
  • 迁移 = MinIO ILM Transition 到远端(冷集群)
  • 优点:部署快、S3 生态友好;缺点:两套集群与跨集群网络需设计好容灾。

为什么不用 Ceph 的缓存分层(cache tier)?

旧式 cache tier 已不推荐;我们采用“前端代理缓存 + 后端存储分层(生命周期)”的组合,简单、可控、可观测。

机房与硬件参数(香港实配)

机柜与网络

  • 机柜:42U,双市电,UPS,A/B 路供电。
  • ToR:2× 10/25GbE 交换机(我们实际跑 10GbE,日后可上 25GbE)。
  • 服务器对接:Bond(LACP) + VLAN,公有/集群网络分离。MTU 1500(后文有坑)。

服务器分层

  • 前端缓存/网关节点(3 台)
  • CPU:Xeon Silver 4310(或同级)
  • 内存:64–128 GB
  • NVMe:2× 3.84 TB U.2(RAID0 做缓存目录或独立挂载)
  • 网卡:2× 10GbE
  • 角色:Nginx(或 MinIO 热集群节点)

存储节点(6 台)

  • CPU:Gold 5220(或同级)
  • 内存:128–256 GB
  • HDD:8× 18 TB 7200RPM(SATA/SAS 混编避免同批次故障)
  • NVMe(小容量):1× 800 GB(BlueStore DB/WAL)
  • 网卡:2× 10GbE
  • 角色:Ceph OSD(或 MinIO 冷集群节点)

电力与散热

  • NVMe 温控目标:< 60°C;HDD 扇区错误/坏道监控;
  • U.2 托架风道要关注(后文“坑”内有细节)。

架构总览(ASCII 示意)

[Users/Clients]
      |
   [CDN/或直连]
      |
  [Nginx proxy_cache on NVMe]  <-- 热层(命中 ≥85% 目标)
      |             \
      |              \ (可选:MinIO 热集群 on NVMe)
      |
 [Ceph RGW S3 Endpoints]  <-- 统一对象访问
      |
 [Ceph Pools]
    ├─ hot-placement (replicated on NVMe OSD)     [可选/小规模]
    └─ cold-placement (EC k=6 m=3 on HDD OSD)     [主容量层]
      ^
      | (RGW Lifecycle Transition by prefix/tags/days)

实际线上:热缓存在 Nginx,后端只用 冷池(EC on HDD);极少量高频对象可单独放在 NVMe 小池(非必须)。

系统与网络基础调优(CentOS 7)

内核 & 系统

# 文件句柄与连接
echo "* soft nofile 1048576" >> /etc/security/limits.conf
echo "* hard nofile 1048576" >> /etc/security/limits.conf

# sysctl(网络与队列)
cat >> /etc/sysctl.d/99-tuning.conf <<'EOF'
net.core.rmem_max=268435456
net.core.wmem_max=268435456
net.ipv4.tcp_rmem=4096 87380 268435456
net.ipv4.tcp_wmem=4096 65536 268435456
net.core.somaxconn=65535
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_fin_timeout=10
vm.swappiness=1
EOF
sysctl -p /etc/sysctl.d/99-tuning.conf

Bond + VLAN(示意)

# ifcfg-bond0
BONDING_OPTS="mode=802.3ad miimon=100 lacp_rate=1 xmit_hash_policy=layer3+4"
# 分别为公有/集群 VLAN 配置 ifcfg-bond0.<vid>,保持 MTU=1500(后文讲为什么别盲目开 9000)

NVMe 挂载(ext4/xfs 皆可)

mkfs.xfs /dev/nvme0n1
mkdir -p /var/cache/nginx
echo "/dev/nvme0n1  /var/cache/nginx xfs defaults,noatime,nodiratime 0 0" >> /etc/fstab
mount -a

方案 A:Ceph RGW 冷层 + Nginx(NVMe) 热缓存

1) Ceph 集群部署(CentOS 7,Nautilus,ceph-deploy)

注:CentOS 7 环境更稳的是 Nautilus(v14)。需要所有节点 NTP 同步,禁用防火墙/SELinux(或放行)。

# 在一个部署节点(含免密 SSH):
yum install -y python2 python-pip
pip install ceph-deploy==2.0.1   # 与 Nautilus 匹配

# 预装 Ceph 仓库
cat > /etc/yum.repos.d/ceph.repo <<'EOF'
[ceph-noarch]
name=Ceph noarch
baseurl=https://download.ceph.com/rpm-nautilus/el7/noarch
enabled=1
gpgcheck=0
EOF

# 创建集群
mkdir ~/ceph-cluster && cd ~/ceph-cluster
ceph-deploy new mon1 mon2 mon3
# ceph.conf 基本项
cat >> ceph.conf <<'EOF'
osd_pool_default_size = 3
osd_pool_default_min_size = 2
mon_allow_pool_delete = true
osd_memory_target = 4294967296  # 4G
bluestore_cache_size_hdd = 1073741824  # 1G
public_network = 10.0.10.0/24
cluster_network = 10.0.20.0/24
EOF

ceph-deploy install --release nautilus mon1 mon2 mon3 osd[1-6]
ceph-deploy mon create-initial

# 准备 OSD(示例:HDD 作为 data,NVMe 作为 db/wal)
ceph-deploy osd create --bluestore --data /dev/sdb --block-db /dev/nvme0n1 osd1
# 其余节点类推……

创建冷层 EC 池与 RGW

# EC 配置:k=6, m=3 适合 6~9 台/盘宽,按实际盘宽调整
ceph osd erasure-code-profile set ec63 k=6 m=3 crush-failure-domain=host
ceph osd pool create cold.ec 128 128 erasure ec63
ceph osd pool application enable cold.ec rgw

# 安装 RGW(3 节点)
ceph-deploy rgw create rgw1 rgw2 rgw3

# RGW placement:将默认 bucket 指向 cold.ec
radosgw-admin zonegroup get > zg.json
radosgw-admin zone get > zone.json
# 在 zone.json 的 placement_targets 中新增 cold-placement,指向 cold.ec
# 并将 default_placement 改为 cold-placement
radosgw-admin zone set --infile zone.json
radosgw-admin period update --commit

要不要 NVMe 热池?

可选:为极少量超热对象建 replicated NVMe 池(size=2),另建 placement hot-placement,配合对象标签(如 hot=true)或专用前缀,以 Lifecycle 不转冷;但我们线上依赖 Nginx 缓存 即可达到 85%+ 命中,不再复杂化后端。

2) RGW Lifecycle(N 天后转冷、或按前缀/标签)

{
  "Rules": [
    {
      "ID": "cold-after-7d",
      "Filter": { "Prefix": "courseware/" },
      "Status": "Enabled",
      "Transitions": [
        { "Days": 7, "StorageClass": "cold-placement" }
      ]
    }
  ]
}

上传方式(S3 兼容):

aws --endpoint-url http://rgw1:80 s3api put-bucket-lifecycle-configuration \
  --bucket cw-bucket --lifecycle-configuration file://lifecycle.json

3) 前端 Nginx 基于 NVMe 的热缓存

# /etc/nginx/conf.d/cw.conf
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=cwcache:200m
                 max_size=2500g inactive=7d use_temp_path=off;

map $request_method $purgeable { "PURGE" 1; default 0; }

server {
  listen 80 reuseport;
  server_name cw.example.com;

  location / {
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    proxy_cache cwcache;
    proxy_cache_key "$scheme://$host$request_uri";
    proxy_cache_valid 200 302 7d;
    proxy_cache_valid 206 1d;     # 断点续传
    proxy_ignore_headers Set-Cookie;
    add_header X-Cache $upstream_cache_status;

    proxy_pass http://rgw-upstream; # 指向 RGW VIP/Upstream
  }

  # 手动清理(灰度期有用)
  if ($purgeable) { proxy_cache_purge cwcache "$scheme://$host$request_uri"; }
}

upstream rgw-upstream {
  server rgw1:80 max_fails=3 fail_timeout=10s;
  server rgw2:80 max_fails=3 fail_timeout=10s;
  server rgw3:80 max_fails=3 fail_timeout=10s;
  keepalive 100;
}

缓存预热(开学周)

# 预热 Top N 清单
cat hotlist.txt | xargs -n1 -P16 -I{} curl -s -o /dev/null "http://cw.example.com/{}"

4) Ceph/网络关键优化

  • OSD:osd_memory_target=4G(HDD),NVMe 小池则 2–3G;bluestore_cache_* 按介质区分;
  • CRUSH:failure-domain=host,不同机位/机柜打散;
  • 网络:LACP xmit_hash_policy=layer3+4,RGW keepalive=100,somaxconn 提升;
  • 对象并发:RGW rgw_thread_pool_size=2048(视 CPU/内存),限制单连接带宽防止缓存雪崩。

方案 B:MinIO 热冷双集群 + ILM 迁移(可选)

1) 分布式 MinIO(热集群 on NVMe)

四节点示例,每节点 2× NVMe:

useradd -r minio
wget https://dl.min.io/server/minio/release/linux-amd64/minio
chmod +x minio && mv minio /usr/local/bin/

cat >/etc/systemd/system/minio.service <<'EOF'
[Unit]
Description=MinIO
After=network.target

[Service]
User=minio
Group=minio
Environment="MINIO_VOLUMES=http://node1/export{1...2} http://node2/export{1...2} http://node3/export{1...2} http://node4/export{1...2}"
Environment="MINIO_OPTS=--address :9000 --console-address :9001 --quiet"
ExecStart=/usr/local/bin/minio server $MINIO_VOLUMES $MINIO_OPTS
LimitNOFILE=1048576
Restart=always

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now minio

2) 冷集群(HDD)与远端目标

# 在热集群上配置远端(指向冷集群)
mc alias set hot http://hot:9000 ACCESSKEY SECRETKEY
mc alias set cold http://cold:9000 ACCESSKEY SECRETKEY
mc admin bucket remote add hot/cw-bucket http://cold:9000/cw-bucket \
     --service replication --replicate "delete,delete-marker,metadata"
# ILM:7 天转储
mc ilm add hot/cw-bucket --transition-days 7 --transition-tier "cold-tier"

MinIO 新版中“tier/remote”命名可能有差异,基本思路是 把冷集群作为远端,按 ILM 迁移。

前端依旧可使用 Nginx proxy_cache 在 NVMe 上做热读,MinIO 本身也可直接顶流量,但我们在高峰时更偏爱“前端统一缓存 + 后端存储聚合”的模式。

观测:命中率、延迟与吞吐(上线一周数据)

指标 上线前(直读存储) 上线后(Nginx+NVMe 缓存)
峰值总 RPS 8.4k 11.6k
缓存命中率(整体) - 87.3%
P95(静态 PDF 2–10MB) 180 ms 62 ms
P99(静态 PDF 2–10MB) 410 ms 136 ms
后端 RGW 请求量(峰值) 8.4k 1.9k
Ceph OSD 后端读吞吐(峰值) 5.2 GB/s 1.1 GB/s
NVMe 写放大(缓存段) - 1.4×(按小时均值)

采集来源:Nginx log → Prometheus(exporter) → Grafana;RGW/OSD 指标用 ceph mgr/prometheus;命中率按 $upstream_cache_status 汇总。

成本与容量规划(三年 TCO 粗算)

假设

  • NVMe 3.84TB/U.2 单价 X(USD),功耗 ~8–12W;
  • HDD 18TB 单价 Y(USD),功耗 ~6–9W;
  • 香港电价按 0.2 USD/kWh 粗估;
  • 机柜与带宽成本略。

结果(以 6 存储节点、48 盘 HDD、冷层 EC k=6 m=3)

  • 有效冷容量 ≈ 18TB×48×(6/9)= 576 TB(扣除校验和 CRUSH 打散)
  • NVMe 热缓存 3 台×(2×3.84TB) ≈ 23 TB(可命中 Top 20% 对象)
  • 按 85% 命中,后端读压力降至 ~15%,电力与盘磨损显著下降。
  • 三年摊销:在同样的服务质量下,TCO 下降 ~35–42%(取决于 NVMe 比例与机柜/电价)。

关键不是 NVMe 多,而是 命中率曲线:课件访问非常“尖峰 + 长尾”,Top 10–20% 对象贡献 80%+ 的请求。把它们留在前端 NVMe,就赢了。

踩过的坑与现场解法

MTU 9000 带来的“偶发性超时”

现象:跨交换机链路特定目的网段偶发 200–300ms 抖动。

根因:上游运营商与某跳点不支持巨帧,路径 MTU 不一致。

解法:全链路回退 MTU=1500,吞吐受损很小,抖动彻底消失。

U.2 NVMe 温度触发降频

现象:晚高峰写入穿透上升,缓存写尾延迟跳高。

根因:风道被理线带半遮,盘托架局部回风不畅。

解法:改理线、换高压风扇、增一组导风罩;温度由 68°C 降至 56°C。

Ceph OSD 内存顶满 OOM

现象:HDD OSD 偶发 OOM。

根因:osd_memory_target 未生效 + 监控刷新峰值。

解法:固定 osd_memory_target=4G,限制 mgr 模块抓取频率,问题消失。

Nginx 缓存目录 inode 打满

现象:max_size 还剩很多,写入失败。

解法:levels=1:2 + 预估对象数量增大 inode(ext4 时 mkfs -N);我们最后统一 XFS。

RGW Lifecycle 没触发

现象:对象未转冷。

根因:规则里 Prefix 少了末尾 /;

解法:加 / 并 period update --commit,次日凌晨生效。

LACP 单流瓶颈

现象:单连接速率卡在单链路上限。

解法:xmit_hash_policy=layer3+4,并行连接足够多即可;关键路径用多连接(Range/多段)。

回滚与演练

灰度开关:Nginx 里保留直连后端的 upstream 并加 map 做分流,命中低于 70% 或后端 5xx 提升即刻切回。

数据一致性:对象写入路径始终直达 RGW;缓存只做 GET,不缓存非 200/206。

灾备:Ceph 三监视器多故障域;MinIO 冷集群(若选)在另一机柜;每日做 radosgw-admin bucket check/mc admin heal。

日常运维要点(Checklist)

  • 每日查看:缓存命中、RGW 5xx、Ceph pg 状态、OSD 使用率均衡、NVMe 温度与 SMART。
  • 每周维护:清理僵尸对象、校验 Lifecycle 统计与冷层增长速率。
  • 每学期开学周:提前一周预热 Top 清单;上线值守延长到凌晨 1 点。

完整命令清单(汇总摘录)

Nginx 缓存清理

# 清理超过 14 天未访问缓存(按 mtime)
find /var/cache/nginx -type f -mtime +14 -delete

Ceph 常用

ceph -s
ceph osd df tree
ceph df
radosgw-admin buckets stats

压力与回放(小心生产)

wrk -t12 -c120 -d60s --latency http://cw.example.com/courseware/xxx.pdf

我会怎么在你那边落地(行动指南)

  • 先上 Nginx(NVMe) 缓存,两天之内你就能看到命中率与延迟的立竿见影。
  • 后端上 Ceph RGW 冷层(HDD + EC),一步到位把容量成本打下来。
  • 如果团队熟悉 Go/MinIO:用 MinIO 热冷双集群 + ILM 也很稳,但要把跨集群网络和容灾设计好。
  • 观测优先:Prometheus + Grafana、日志保留 30 天、构建“热点 TopN”自动榜单用于预热。

走出机房,维多利亚港的风

当早上 6 点我走出机房,海风带着一点咸味。手机上 Grafana 的曲线把夜里每一次命中、每一次降延迟都画得清清楚楚。
这套冷热分层不是“绝对的对或错”,它只是用成本与命中率讲了一个朴素的故事:把最热门的东西放在最近的地方。如果哪天你也在凌晨的机房里听见风声,看到那条 P99 曲线被稳稳按住,你会明白——这活儿,值。

附录:表格参数与样例

A. Ceph 关键参数建议(HDD 冷池)

参数 建议值/说明
osd_memory_target 4G(HDD)
osd_pool_default_size 3(Mon/OSD 足够时)
EC Profile k=6 m=3(按盘/节点数调整)
crush-failure-domain host
RGW rgw_thread_pool_size 1024–2048(视 CPU)
mon_allow_pool_delete 生产建议关闭(临时开以便管理)

B. Nginx 缓存策略

项目 设置
proxy_cache_key $scheme://$host$request_uri
命中有效期 200/302 → 7d;206 → 1d
目录层级 levels=1:2
最大容量 max_size=2.5T(按 NVMe 调整)
预热 TopN 列表并行 curl

C. 命中率与带宽粗估(示例)

热比例 命中率 后端带宽衰减
10% 75% ×0.25
20% 85% ×0.15
30% 90% ×0.10

这张表来自我们对“课件访问”Zipf 分布的经验值;实际以你站点流量特征校准。

目录结构
全文