惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

阮一峰的网络日志
阮一峰的网络日志
The GitHub Blog
The GitHub Blog
V
Visual Studio Blog
G
GRAHAM CLULEY
Spread Privacy
Spread Privacy
Last Week in AI
Last Week in AI
腾讯CDC
P
Privacy & Cybersecurity Law Blog
WordPress大学
WordPress大学
C
Cybersecurity and Infrastructure Security Agency CISA
Security Archives - TechRepublic
Security Archives - TechRepublic
博客园 - 司徒正美
爱范儿
爱范儿
雷峰网
雷峰网
The Hacker News
The Hacker News
S
SegmentFault 最新的问题
Cisco Talos Blog
Cisco Talos Blog
博客园 - 聂微东
T
Tor Project blog
I
Intezer
大猫的无限游戏
大猫的无限游戏
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Schneier on Security
Schneier on Security
T
Tenable Blog
Google Online Security Blog
Google Online Security Blog
S
Schneier on Security
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
AI
AI
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
宝玉的分享
宝玉的分享
Help Net Security
Help Net Security
O
OpenAI News
博客园 - 【当耐特】
博客园 - Franky
AWS News Blog
AWS News Blog
罗磊的独立博客
J
Java Code Geeks
Know Your Adversary
Know Your Adversary
A
Arctic Wolf
小众软件
小众软件
量子位
SecWiki News
SecWiki News
S
Security Affairs
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Hugging Face - Blog
Hugging Face - Blog
N
News and Events Feed by Topic
Apple Machine Learning Research
Apple Machine Learning Research
H
Heimdal Security Blog
Google DeepMind News
Google DeepMind News
IT之家
IT之家

暗无天日

读:AI Agent 安全日志——从可见性与隐私的两难说起 - 暗无天日 读:AI Agent 生产化——一份从原型到上线的速查清单 - 暗无天日 AI写作的语言指纹——如何让文字不那么像机器 - 暗无天日 读:50 条 Claude Code 技巧——一个工程经理的六个月使用心得 读:AI 辅助开发为什么让 E2E 测试更有价值 - 暗无天日 读:在Emacs中使用Claude Code(Spacemacs适配版) - 暗无天日 Claude Code 背后的工程哲学——读 Agent Harness Engineering 读:Agent Harness Engineering——AI 智能体不只是模型,还有套件 - 暗无天日 browser-harness:让 AI 直接接管你的浏览器 - 暗无天日 读:Security-First CI/CD —— DevSecOps 自动化实践指南 TIL: 数字小键盘的小数点陷阱与行内算术求值 - 暗无天日 读:Immutability 不是万能药,它是一种权衡 - 暗无天日 Conducty:给 Claude Code 加上项目记忆和并行执行能力 - 暗无天日 读 — GitHub Trending 里的 Claude Code 技能包 读 — Prompt Caching 省钱指南 TIL: Emacs 中那些跟鼠标配合的冷门快捷键 - 暗无天日 读:Anvil——把 Emacs 变成 AI 的工具服务器 读:Emacs 代码折叠终极指南 - 暗无天日 读:Clojure 搭车客指南 - 暗无天日 git推送失败后恢复仓库损坏的完整记录 - 暗无天日 多智能体系统的两个有效模式——以及对 Claude Code 用户的启示 - 暗无天日 用 Org Babel 写 Literate 博文:扩展执行 + 定制导出 proced:Emacs 内置的进程查看器 - 暗无天日 从 proced 定制中学到的 Elisp 模式 读:让 Emacs proced 在 macOS 上显示 CPU 和内存 异步编程的函数着色税 - 暗无天日 链式调用的代价:JavaScript 和 Clojure 的共同教训 - 暗无天日 hyperfine:命令行基准测试工具 - 暗无天日 管道中的变量去哪了?——子 shell 作用域陷阱 - 暗无天日 开源包装器的信任陷阱:四个危险信号 - 暗无天日 程序员愿意为 AI 写文档,却不愿为同事写 - 暗无天日 mktemp: Shell 脚本中临时文件的安全陷阱与最佳实践 - 暗无天日 WSL9x —— 在 Windows 9x 里跑 Linux 内核 6.19 用 ox.el 做你想做的事 —— org-export 高级编程指南 读:Hot-wiring the Lisp Machine —— 用纯 Elisp 构建零依赖的 Org 静态站点生成器 Elisp 性能优化的六个实战教训 - 暗无天日 fcitx5 下 Emacs 无法切换输入法的排查 - 暗无天日 ERT 测试交互命令的三种方式 - 暗无天日 SEM Assistant: 当 Elisp 守护进程遇上 LLM 用 dmsg 给 Elisp 加上结构化调试日志 用 org-habit 追踪非每日习惯 - 暗无天日 Clojure X-Men:当编程语言特性变成超能力 - 暗无天日 TIL: 用 diff-hl 在 fringe 中显示 git 变更 读:llm-test —— 用 LLM agent 驱动 Emacs 测试 TIL: AI 时代的橡皮鸭调试 - 暗无天日 fcitx 启动后键盘输入卡顿的排查 - 暗无天日 TIL: 早期网页的图片热区导航 - 暗无天日 读 Seeing the Whole System 用 Emacs 自动生成每周链接推荐 - 暗无天日 读:ASCII control characters in my terminal 读 What to learn - 暗无天日 Lisp 的括号之痛——一个愚人节玩笑揭开的老伤疤 - 暗无天日 一本书该"线性读"还是"并行读" - 暗无天日 读 How to Monetize a Blog:一篇伪装成变现指南的讽刺文 Python Mock 第三方依赖的四种策略 - 暗无天日 Emacs Lisp 热重载实用指南 - 暗无天日 Prot 的 Emacs 配置哲学 - 暗无天日 TIL: 从直播对谈中学到的三个 Emacs 技巧 - 暗无天日 TIL: 自动使用项目虚拟环境的 Python - 暗无天日 TIL: 让 Help buffer 自动获得焦点 一条命令让本地开发用上 HTTPS —— slim 工具介绍 用 fsck 检查和修复 Linux 文件系统 排查Linux进程"卡死"实战:从strace到gdb全流程 - 暗无天日 PostgreSQL 索引:从基础到你可能不知道的高级用法 - 暗无天日 用 .pdbrc 自定义 Python 调试器 ANSI 转义码的标准化现状 - 暗无天日 终端程序的潜规则 - 暗无天日 PARA Org-mode 测试配置 - 暗无天日 AI越强越辣鸡?控制论说这是必然的 - 暗无天日 AI 越强越需要你盯着——反馈循环实操指南 - 暗无天日 你的AI代理正在偷你的密钥——四种你没想到的泄露通道 - 暗无天日 LLM 在 DevOps 中的三种角色 - 暗无天日 写作风格的反建议 - 暗无天日 反驳本质复杂性——Dan Luu 论为什么《没有银弹》错了 - 暗无天日 文件充满了危险——Dan Luu 谈文件系统的可靠性陷阱 - 暗无天日 AI 时代的 PARA 方法:用 Org-mode 和 AI 打造个人知识管理系统 创建跨平台 ZIP 文件的隐藏陷阱:Extra Field - 暗无天日 X11 Forwarding 排障指南 - 暗无天日 IP欺骗端口扫描:当别人冒充你去扫描别人 - 暗无天日 Linux 输入栈全景解析:从硬件按键到屏幕响应 - 暗无天日 Unix 系统中那些被埋没的配置开关——以 FontConfig 为例 - 暗无天日 在Linux上限制儿童使用电脑 - 暗无天日 GIF不仅仅是一种图片格式——用GIF流做些奇怪的事 - 暗无天日 Leiningen 学习笔记:Clojure 项目构建与管理从入门到实战配置 - 暗无天日 Google SRE Book 读书笔记 - 暗无天日 yes 管道 head 发生了什么 - 暗无天日 为什么 nohup 在 crontab 中不起作用 Bash中的Indirection与Nameref - 暗无天日 Linux PAM 简介 - 暗无天日 从Linux ISO文件启动计算机 - 暗无天日 用 Bash 打造一个Screen Locker 用GitHub Actions自动构建EGO博客 - 暗无天日 blocking I/O 的作用 - 暗无天日 mobileog 手机端同步提示Error:2 No such file 的解决方法 回收 WSL2 VHDX 文件占用空间 使用 org-mode columnview 生成任务列表 - 暗无天日 Emacs 作为 MPD 客户端 - 暗无天日 移动文件路径却不破坏org file link的方法 - 暗无天日 如何合理的导出help link 成HTML - 暗无天日 笑话理解之Biology - 暗无天日
Linux 数据去重学习笔记 - 暗无天日
lujun9972 · 2026-04-15 · via 暗无天日

目录

  • 什么是数据去重
  • 去重的工作原理
    • 1. 分块(Chunking)
    • 2. 指纹(Fingerprinting)
    • 3. 索引(Indexing)
    • 4. 复用(Reuse)
    • Inline vs Post-process
  • Linux 上的去重方案
    • Btrfs:CoW 文件系统 + 用户空间工具
    • ZFS on Linux:原生 inline 块级去重
    • dm-vdo:文件系统之下的去重
  • 去重的利与弊
    • 收益场景
    • 风险与代价
  • 实践建议
    • 识别"低垂果实"
    • 选择合适的层级
    • 结合快照策略
    • 关注关键指标
  • 未来方向

记录 Linux 上数据去重(Data Deduplication)的原理、主流方案和实践要点。 参考文章:Data Deduplication Done The Right Way

什么是数据去重

数据去重(Data Deduplication)的核心思想很简单: 每个唯一的数据块只存一份,在需要重复使用时通过引用来共享

一个典型的场景:如果你每天对同一台虚拟机做快照,连续做 30 天,你并不是真的存了 30 份完全不同的数据——绝大多数数据块都是重复的。去重就是把这些重复的部分消除掉。

在 Linux 上,通过现代文件系统(如 Btrfs、ZFS)、块设备层方案(如 dm-vdo)以及用户空间工具,可以实现不同层级的数据去重。

去重的工作原理

去重分为两个大步骤:先决定如何切割数据,再判断哪些数据已经存在。

1. 分块(Chunking)

数据首先被切成小块。有两种主要策略:

  • 固定大小分块(Fixed-size) :按固定字节数切分,简单高效,但当文件中间插入或删除字节时,后续所有块的边界都会偏移。
  • 内容定义分块(Content-Defined Chunking, CDC) :根据数据流中的模式来选择块的边界,这样即使文件中间有增删,也只有受影响的少量块发生变化,其余块的边界保持不变。CDC 的去重效率通常更高。

2. 指纹(Fingerprinting)

每个数据块计算一个指纹(通常使用加密哈希,如 SHA-256),这个指纹相当于数据块的"身份证"。

3. 索引(Indexing)

所有指纹存储在一个索引中。当新数据块到来时,系统检查其指纹是否已存在于索引中。

4. 复用(Reuse)

如果发现重复,系统不会再次写入该数据块,而是创建或更新引用计数。

Inline vs Post-process

  • Inline 去重 :在写入路径上实时进行,数据在落盘前就被检查。优点是即时节省空间,缺点是增加了 CPU、内存和 I/O 开销。
  • Post-process 去重 :写入时不干预,等系统空闲时再由扫描器处理。优点是写入速度快,代价是延迟的去重效果。

Linux 上的去重方案

Linux 没有一个统一的"去重开关",而是需要根据你的场景选择合适的层级。

Btrfs:CoW 文件系统 + 用户空间工具

Btrfs 是一个现代化的 Copy-on-Write(CoW)文件系统,在克隆和快照时天然不会重复存储相同的数据块。通过 reflink(=cp --reflink=)可以创建即时逻辑副本,共享数据块直到被修改。

但 Btrfs 不会自动进行 inline 去重 ,需要借助用户空间工具:

  • duperemove :批量扫描工具,计算 extent 或 block 的哈希,在数据库中查找重复项,然后请求 Btrfs 将它们合并为共享 extent。适合在备份卷上定期运行。

    duperemove -r /path/to/backup
    
    duperemove -r -d /path/to/backup
    
  • bees :一个长期运行的守护进程,增量遍历文件系统树并在后台持续去重。适合需要持续去重的场景。

管理员在 VM 集合、容器层和 ISO 库上报告了很高的空间节省率。但需要注意: 过于激进的去重加上碎片化可能会降低繁忙卷上的随机读取性能

ZFS on Linux:原生 inline 块级去重

OpenZFS 提供了原生的 inline 块级去重。每个写入操作都经过以下流程:

  1. 对数据块计算哈希
  2. 在去重表(Dedup Table, DDT)中查找
  3. 如果已存在,增加引用计数而非写入新数据

    zfs set dedup=on poolname/dataset
    
    zfs get dedup poolname/dataset
    
    NAME      PROPERTY  VALUE          SOURCE
    poolname  dedup     on             local
    
    pool: poolname
     state: ONLINE
    config:
    
            NAME                 STATE     READ WRITE CKSUM
            poolname             ONLINE       0     0     0
              /dev/sdb1          ONLINE       0     0     0
    
    errors: No known data errors
    
     dedup: no DDT entries
    

ZFS 去重的优势是不需要运行外部扫描器。风险在于 DDT 主要驻留在 RAM 中,其大小随唯一块数量增长(而非逻辑容量)。

一个经验法则: 在 VM 启动盘场景下常见 3:1 到 5:1 的去重率,但需要精心规划内存——根据块大小和工作负载,每几 TB 唯一数据可能需要几 GB 的 RAM

近期 ZFS 社区的改进包括:基于时间的旧条目修剪(Age-based pruning)、以及尝试利用空闲资源的"机会性"去重模式。

最佳实践: 将去重限定在特定用途的 pool 上 (如专门存放 VM 镜像的 pool),而非对所有 dataset 一刀切地开启。

dm-vdo:文件系统之下的去重

dm-vdo(Virtual Data Optimizer)是一个 device-mapper 目标,位于文件系统之下,提供 inline 块级去重、压缩、零块消除和精简配置。

sudo pacman -S vdo  sudo apt install vdo  
sudo vdo create --name=myvdo --device=/dev/sdb1 --vdoLogicalSize=100G

sudo mkfs.xfs /dev/mapper/myvdo

sudo mount /dev/mapper/myvdo /mnt/vdo

sudo vdostats --human-readable myvdo

VDO 的设计将职责分离为:

  • UDS(去重索引):快速识别重复块
  • 引用计数的数据存储:映射逻辑块到物理块

因为 VDO 工作在块设备层,所以它是 文件系统无关的 —— 你可以在上面运行 XFS、ext4 或 Btrfs。这对于不方便更换文件系统但又急需节省存储空间的场景特别有用。

去重的利与弊

收益场景

  • 备份 :研究和厂商报告显示,备份工作负载通常能获得 60-80% 的逻辑空间缩减,因为日备份或周备份之间共享大量相同区域。
  • VDI 和虚拟机 :一组相似的虚拟机共享内核、库和基础镜像,去重率通常可达 3:1 或更高。
  • 网络与云 :客户端去重可以避免发送重复数据,减少 WAN 使用量。

风险与代价

  • 碎片化 :当多个逻辑块映射到共享物理块的拼图时,顺序读取可能退化为随机 I/O。这对基于 HDD 的阵列和冷存储影响尤其严重。
  • 元数据和内存 :去重索引随唯一块数量增长。如果索引超出 RAM 容量,查找会溢出到磁盘,性能急剧下降。
  • 加密冲突 :应用层加密(写入前加密)会有效破坏去重,因为相同的明文会产生不同的密文。加密去重需要特殊方案才能使密文保持可比较。

一个实用的经验法则: 去重非常适合备份和镜像类数据,对延迟敏感的主数据库有风险,对已经压缩或重度加密的数据则几乎无用

实践建议

识别"低垂果实"

优先寻找以下工作负载:

  • 包含大量相似完整备份的大型备份仓库
  • VM 镜像库、黄金镜像和实验快照
  • ISO 镜像源、容器基础层、多分支代码仓库

这些工作负载天然包含大量重复块,且通常不像事务数据库那样对延迟敏感。

选择合适的层级

  • 如果已经在 Btrfs 上做备份盘,可以用 duperemove 每周运行或 bees 持续运行。先在测试目录上测量空间节省率和运行时间。
  • 如果想在 SAN 或本地 RAID 上实现文件系统无关的去重,可以在测试 LUN 上评估 =dm-vdo=,在上面叠加 XFS 或 ext4,然后重放典型备份工作负载对比逻辑使用量与物理使用量。
  • 如果用 ZFS 做 VM 池,只在包含高度相似数据的 dataset 上启用去重,并持续监控 DDT 大小、RAM 使用量和读取延迟。

结合快照策略

CoW 文件系统(Btrfs/ZFS)上的混合策略:

  1. 定期在 CoW 文件系统上做快照
  2. 对较老的快照进行更激进的去重,保持最新一代相对无碎片
  3. 清理快照时优先删除碎片化严重的较老世代

这样把碎片化的代价推向很少被读取的旧数据,保持最近备份的快速可读性。

关注关键指标

  • 逻辑使用量 vs 物理使用量(有效去重 + 压缩率)
  • 备份和恢复任务的平均延迟和尾部延迟
  • 去重索引大小和内存占用(ZFS 的 DDT 大小、VDO 的索引大小、duperemove 的数据库大小)

如果去重率低于约 1.2:1,而你在付出显著的性能或复杂度代价,那么这个工作负载可能不值得做去重。

未来方向

Linux 存储去重的发展趋势:

  • 更快的 CDC 算法 (如 RapidCDC 及更新的变体),在保持高去重率的同时大幅降低 CPU 开销
  • 面向 NVM 和 SSD 优化的 inline 去重 ,随机 I/O 惩罚更小,元数据可以驻留在持久内存中
  • 容器感知的去重引擎 ,理解 Docker/OCI 层语义,在数千个镜像间避免冗余副本而不影响 pull 性能

去重将越来越不像一个昂贵的实验,而更像一个可预测的基础构建块——尤其在备份、VM 和容器镜像平台中。