归档存储:冷数据也有脾气,聊聊底层那点事

做存储的是不是都有点那种……囤积癖?热数据当宝贝供着,冷数据就扔墙角。结果呢?成本炸了,合规还追着你要审计日志。归档存储,看着不起眼,其实是真正在跟物理世界较劲的东西。

一、磁带没死,它只是换个姿势当老大

别一听到磁带就想到老式录音机。LTO-9单盘容量18TB,传输速度300MB/s。这什么概念?一块企业级HDD也就这个水平。但磁带一盘的裸价不到200美元,每TB成本只有HDD的几分之一。功耗更是离谱——磁带库在静止时几乎不耗电,机械臂动起来才几十瓦。100PB的数据,如果全放HDD,按10W/盘、每盘20TB算,需要5000块盘,光待机功耗就50kW。磁带库呢?占地可能只有一个小房间,机械臂来回跑,能耗低一个数量级。

但代价是什么?随机访问。你想从磁带第500米的位置读数据?先让机械臂把磁带抽出来,卷带,寻址。典型时间几十秒。所以归档存储永远不会跟热数据抢饭碗,它赌的就是你十年八年不碰这一下。

类比一下,磁带库就像个图书馆,机械臂就是那个推着车找书的图书管理员。你问他要一本书,他要查索引、走到正确的架子、抽出书、再翻到某一页。HDD呢?相当于你把书摊在桌面上,随便翻。但桌面上摊得下10000本书吗?

磁带库机械臂调度与LTO磁带盒存储结构示意图
磁带库机械臂调度与LTO磁带盒存储结构示意图

二、文件系统?对象存储才是归档的根

二、文件系统?对象存储才是归档的根
二、文件系统?对象存储才是归档的根

归档数据需要无限扩展,POSIX文件系统在PB级面前就是灾难——inode爆炸、元数据锁竞争、文件数量上限。对象存储没有目录树,扁平化的桶(Bucket)+键(Key),元数据丢给数据库或专门的索引引擎。你可以把每个对象当成一个独立王国,数据流和元数据流彻底分离。

这里有一个设计精巧的点:对象存储的元数据节点通常用哈希环做一致性哈希。你写入一个对象,它的元数据落在哪个节点,由它的键哈希决定。这保证了负载均衡,但随之而来的是元数据跨节点操作。就像你把每本书的卡片扔进了上千个盒子,查书时要先算出它在哪个盒子。

有个真实案例:某在线归档服务,用Ceph RGW做对象存储,对接底层磁带库。他们遇到了一个尴尬:磁带库的顺序写性能很好,但对象存储的写入是随机的。多个客户端同时写,一个个小对象落到磁带库上,变成了在磁带上跳来跳去——机械臂来回疯跑,性能直接掉到十几MB/s。后来他们改成了聚合写入:在SSD缓冲层攒够几GB,再按顺序刷到磁带上。性能恢复到了接近线性。

这就是工程。你以为在玩逻辑,实际是在跟物理规律打太极。

三、纠删码:用数学换寿命,但也换来了坑

归档存储不需要实时访问,但数据不能丢。传统三副本冗余在冷数据上太奢侈——1TB数据要占3TB空间。纠删码(Erasure Coding)用计算换空间。最经典的RS(Reed-Solomon)编码,把数据分成k块,再生成m块校验块。比如8+4策略,12块里丢任意4块都能恢复到原始8块。存储开销是12/8=1.5,比三副本省一半。重建时只需要读取k块进行运算,比全量拷贝优雅。

但问题来了。纠删码的数学有多美,工程就有多痛。每个对象要分片,分布在不同节点或磁盘上。你写一个小对象,比如只有1KB,照样要切成8份,还要算出校验块。这导致小对象写入放大器严重。归档场景很多小文件,比如邮件归档,几十万个1KB小邮件——直接被打爆。解决办法是先合并成一个大容器,比如把几百万个小文件打包成一个大对象,再塞进纠删码。但这样又引入了索引问题:你读一个邮件,得先找到它在哪个容器里,再定位偏移量。

更麻烦的是重建风暴。一个节点故障,纠删码需要读取k块来重建丢失的一块,每个被读取的块又关联其他对象,可能触发进一步的重建。在HDD上做随机读,那叫一个酸爽。有个压测案例:某公司用8+4纠删码,节点坏了,重建一个1TB节点,结果因为数据分布不均匀,引发了多个节点同时重建,网络和磁盘全部打满,服务正常响应时间从50ms涨到3秒。后来他们引入了重建限速和分优先级,才压住。

纠删码RS编码数据块与校验块分片布局示意图
纠删码RS编码数据块与校验块分片布局示意图

四、落坑指南:三个坑,每个都是真金白银换来的

四、落坑指南:三个坑,每个都是真金白银换来的
四、落坑指南:三个坑,每个都是真金白银换来的

我在好几个团队踩过同样的坑,写出来。谁用谁知道。

坑一:磁带库的机械臂调度——以为不用考虑,结果成了瓶颈

磁带库的机械臂是稀缺资源。一个库通常只有几个机械臂,但可能有几千盘磁带。如果你让每个小请求都去驱动机械臂,那机械臂排队时间比读写时间还长。我们曾经上线一个归档系统,刚开始所有客户端直接发请求到磁带库驱动,结果机械臂利用率到90%,但吞吐量却不到理论值的30%。

解决方案是分层缓冲。用一个SSD层吸收突发写,定期把大文件批量刷到磁带。读取也一样,把频繁访问的“温”数据缓存到磁盘。本质上就是多级缓存,但关键是要知道什么时候刷、刷多大。经验值:当缓冲区积压超过256MB时,触发一次顺序写,效果最好。

坑二:纠删码的“坏账”问题——元数据事务一致性

对象存储里,数据块和元数据是分开的。比如你用8+4纠删码,数据块分布在8个节点上,元数据记录每个块的地址。如果写入过程中某个节点失败,你可能会得到:有的块写了,有的没写,元数据却已经更新成“完成”。这就是撕裂状态。归档数据必须终生可访问,不允许这种半吊子。

我们当时用了一个笨办法:两阶段提交。写入时先写入元数据节点的一个“预写入”日志,所有数据块都写完后,再把日志标记为提交。读取时如果发现预写入未提交,就按日志回滚。这个方案在性能上有损失,但换来的是强一致性。对于归档,正确性远比性能重要。

坑三:数据生命周期管理——自动分层比你想的复杂

很多团队以为归档存储就是“把不用的数据挪走”。可“不用”怎么定义?30天没访问?90天?不同业务完全不一样。而且数据是有温度的:有些数据偶尔被读取,比如数据库备份,可能一年要看一次。如果你把它直接扔进磁带,那查询时等几十秒,用户会骂娘。

我们总结了一套规则:先按最后访问时间分三个温度级别。热(小于7天),温(7~180天),冷(超过180天)。热数据存SSD或NVMe,温数据存HDD,冷数据落到磁带或蓝光。迁移策略不是简单的时间触发,还要考虑数据大小、访问模式预测。比如一个段文件如果一直被追加写,那它实际上是热的,不能因为最后一次访问是昨天就降级。用机器学习?不用,规则就够了。但规则要细心。

另外一个坑:删除或过期策略。归档数据不能物理删除,尤其是合规要求。我们做的是标记删除+定期清理。但清理时要确保所有副本和校验块都删干净,不然会产生孤儿块,占空间。

最后说一句:归档存储不是屌丝技术,它是存储系统里最讲究“妥协”的艺术。你会发现所有性能问题都是容量问题,所有容量问题都是物理问题。理解物理,才能理解归档。愿工程师们少几个熬夜的夜晚。

免责声明:市场有风险,选择需谨慎!此文仅供参考,不作买卖依据。如有侵权请联系删除。
文章名称:归档存储:冷数据也有脾气,聊聊底层那点事
文章链接:https://lfdjt.com/info_23_8422.html