> For the complete documentation index, see [llms.txt](https://freebsd-journal-cn.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://freebsd-journal-cn.bsdcn.org/20180102-cun-chu/tapes-not-dead.md).

# 磁带未死

作者：**KEN MERRY**

对许多评估存储方案、考察 NAS、SAN、对象存储、云存储、磁盘和闪存存储的人来说，磁带或许成了过时之物。磁带从计算诞生之初就存在，但它现在还有一席之地吗？我相信有。我职业生涯中有十多年在两家初创公司工作，它们明确致力于用磁盘（多数情况下基于 FreeBSD）取代磁带。如今我就职于一家既销售大量磁带产品，也销售（基于 FreeBSD 的）连接磁盘和磁带产品的公司。因此，这场辩论的两面我都见过。

## 磁带适合何处？

磁带在某些场景下非常合适，在另一些场景下则不然。20 世纪 80 和 90 年代，QIC 和 DAT 技术面向家庭和小型企业用户，作为终端用户备份表现得相当不错。如今没有等效的小型终端用户磁带技术。如果你是家庭用户，需要备份几 GB 甚至几 TB 的数据，磁带通常不是你应该寻找的方案。

在讨论磁带适合何处之前，先回顾一些近期的磁带机和磁带盒及其能力会有所帮助：

| 驱动器            | 介质类型   | 原始容量  | 压缩容量    | 原始速度       | 压缩速度       |
| -------------- | ------ | ----- | ------- | ---------- | ---------- |
| IBM TS1155     | JD     | 15TB  | 37.5TB  | 360MiB/sec | 750MiB/sec |
| IBM TS1150     | JD     | 10TB  | 25TB    | 360MiB/sec | 750MiB/sec |
| LTO-8          | LTO-8  | 12TB  | 30TB    | 360MiB/sec | 750MiB/sec |
| LTO-8          | LTO-M8 | 9TB   | 22.5TB  | 300MiB/sec | 700MiB/sec |
| LTO-7          | LTO-7  | 6TB   | 15TB    | 300MiB/sec | 700MiB/sec |
| Oracle T10000D | T2     | 8.5TB | 21.25TB | 252MiB/sec | 800MiB/sec |

上述驱动器和介质的成本差异很大，尤其是考虑到大多数驱动器会装在磁带库中，而磁带库通常有多个驱动器。数据量越大，磁带越有意义。大规模时，介质的成本通常高于磁带库和驱动器。

磁带相比磁盘和闪存用于存储有诸多优势：

* 磁带每 GB 的成本极低，通常低于最便宜的基于磁盘的备份。
* 磁带是极佳的归档存储介质。如果你有不常用的数据，可以存到磁带上，把昂贵的磁盘或闪存阵列留给常用数据。
* 吞吐量高于大多数机械磁盘驱动器。（尽管在任何规模下，你都必须考虑磁带或磁盘驱动器的总数以及互连特性来评估整体系统吞吐量。）
* 磁带设计为可移动和存储。磁盘通常不是为此设计的。（尽管可以这样使用。）这使其非常适合异地备份。
* 磁带通常有 30 年的保质期。磁盘制造商不会做出这样的承诺。
* 磁带适合气隙隔离存储。你是否担心软件 bug、恶意人员或勒索软件会毁掉你的数据？把它备份到磁带上并放到异地存储。那些威胁只能破坏它们能访问的数据。磁带在存储中提供了一定程度的遗传多样性。如果你的磁盘或闪存驱动器固件 bug 损坏了所有驱动器上的数据怎么办？如果文件系统 bug 损坏了所有数据怎么办？用磁带的话，你有不同的固件、不同的介质和不同的软件存储数据。只要花时间备份，你就能从驱动器固件 bug 或文件系统/OS bug 中恢复。

磁带不适合需要快速访问（例如 10 秒以内）或随机访问的数据。对于这类数据，磁盘和闪存是更好的选择。

## FreeBSD 中的磁带

FreeBSD 自 386BSD patchkit 起就支持磁带。最初的 FreeBSD SCSI 层由 Julian Elischer 编写，他还编写了 **st(4)** 磁带驱动。Justin Gibbs 和我编写了 FreeBSD 的 CAM（Common Access Method）SCSI 层，于 1998 年进入 FreeBSD 树，其中包含 **sa(4)**（Sequential Access）磁带驱动。（Justin 编写了 **sa(4)** 驱动的大部分。）Matt Jacob 从 1998 年底开始大幅改写 **sa(4)** 驱动，它现在的样子很大程度上归功于他的工作。Matt 多年来是该驱动的维护者。如今我是事实上的维护者。

**sa(4)** 驱动支持从旧式 SCSI-1 9-track 磁带机到最新的 Fibre Channel 连接 IBM TS1155 磁带机等各类磁带机。它包含现代密度支持，使用 **mt(1)** 的 `getdensity` 子命令。你可以用该命令询问现代磁带机它支持哪些磁带盒及哪些格式。这对于 IBM TS（以及现在的 LTO）磁带机非常有用，因为一盒磁带可以有多种不同容量的可用格式。

**sa(4)** 驱动还支持 unmapped I/O。Unmapped I/O 缓冲区是用户态缓冲区，不映射到内核的虚拟地址空间，而是直接翻译为物理页，再传输到 FC/SAS/SCSI 控制器固件进行 DMA。将用户缓冲区映射到内核虚拟地址空间在现代多核机器上会因 TLB（Translation Lookaside Buffer）shootdown 而变慢——更新每个核心的缓存需要 shootdown。Unmapped I/O 允许内核不需要触碰的数据不经映射穿过内核，避免 TLB shootdown。大量 I/O 活动下，避免 TLB shootdown 能显著提升性能。

## 处理磁带库

FreeBSD 自 1998 年从原始 SCSI 层过渡到 CAM 起就通过 **ch(4)** 驱动和 **chio(1)** 工具内置支持磁带库。我将 **ch(4)** 驱动和 **chio(1)**（由 Jason Thorpe 编写）从 NetBSD 移植到 FreeBSD/CAM。**ch(4)** 驱动支持从非常旧的磁带库到最新磁带库的一切设备。

**mtx(1)** 工具（位于 **Ports/misc**）也可控制磁带库，通过 SCSI passthrough 操作。

虽然 **chio(1)** 和 **mtx(1)** 适合命令行控制磁带库，但具有磁带库级支持的备份应用（如 Bacula 或 Amanda）会使用 **chio(1)** 或 **mtx(1)** 在磁带库的槽位和磁带机之间移动磁带。

## 数据完整性

如果数据被损坏，备份就没有多大价值；数据完整性至关重要。你要确保备份可用，所有位都按正确顺序到达磁带。

磁带 API 对 SCSI 等存储协议提出了独特挑战。当 OS 通过 SCSI 与硬盘通信时，硬件、软件或固件故障有时会导致命令或数据丢失。发生这种情况时，驱动会超时未完成的命令，中止它，并向 CAM 中间层发送状态，以便在用户请求重试时重试该命令。写入超时的情况下，命令和数据可能到达也可能未到达驱动器，但重发命令无害。硬盘只需重写数据并继续。

但磁带是顺序介质。写入发送到磁带时没有显式的逻辑块地址，地址是隐含的。每次写入（或读取）沿磁带推进块号。如果发送到磁带机的写入超时，OS 面临两难：什么到达了驱动器？整个块都到了，只是我们没收到状态？驱动器收到了部分数据？驱动器一点数据都没收到？在不知道什么到达驱动器的情况下重试可能导致数据损坏。替代方案似乎是中止整个备份作业并报错。

ANSI T10（t10.org）和 T11（t11.org）委员会分别编写 SCSI 和 Fibre Channel 规范，他们想出了解决方案。它最初叫 FC-Tape，现包含在 T10 的 FCP-4（Fibre Channel Protocol）规范中。规范第 4.4 至 4.7 节概述了为磁带机确保数据完整性所需的 Fibre Channel 特性。它们是：

### 命令的精确交付

此特性允许发起方（服务器）为每条命令指定 CRN（Command Reference Number）。CRN 是 1 到 255 的循环数字。如果目标方（此处为磁带机）收到一条命令，其与前一条命令的 CRN 不连续且 CRN 已启用，它将拒绝该命令。这确保磁带 I/O 请求按顺序执行。

### FCP I/O 操作的确认完成

确认完成是 Fibre Channel 的一项选项，允许目标方（此处为磁带机）请求发起方（服务器）告知目标方它收到了状态响应。这让目标方知道它不需要向发起方重发状态。

普通 SCSI 写命令序列如下：

```sh
发起方 -> 目标方：我要写 512KiB。
目标方 -> 发起方：请传输数据。
发起方 -> 目标方：传输 512KiB 数据。
目标方 -> 发起方：数据成功接收至缓存。
```

此时，发起方知道目标方完成了写入。目标方知道它完成了写入，但不知道发起方是否收到了消息。确认完成增加了另一条消息：

```sh
发起方 -> 目标方：我收到了你的完成消息。
```

### 任务重试标识

任务重试标识是标识重试序列的机制。由于 Fibre Channel 中命令标识方式的原因，这是必要的补充。

在 Fibre Channel 中，发起方（服务器）为发送给目标方（磁带机）的每条 SCSI（或其他）命令分配一个 OX\_ID（Originator Exchange ID）。目标方响应初始命令时，回复相同的 OX\_ID 并加上自己的 RX\_ID（Receiver Exchange ID）。OX\_ID 和 RX\_ID 是此后标识特定命令的方式。数据传输到目标方时，发起方指定 OX\_ID 和 RX\_ID，使目标方知道数据属于哪条命令。

OX\_ID 和 RX\_ID 是 16 位值，会快速回绕。因此，任务重试标识符随 Fibre Channel 命令（FCP\_CMND）、REC 和 SRR 一起指定，将错误恢复操作关联起来，明确它们指向哪条命令。

### 未成功传输 IU 的重传

如果到 Fibre Channel 设备的读或写命令耗时过长，此特性为 Fibre Channel 驱动和/或固件提供了一种机制，在不使用超时、中止和重试（或磁带情况下失败）这种大锤的情况下进行链路级错误恢复。

如果目标方（磁带机）响应命令或数据传输超过 3 或 4 秒，发起方（服务器）可向目标方发送 REC（Read Exchange Concise）ELS（Extended Link Services）Fibre Channel 命令查询命令状态。

如果目标方从未收到命令，发起方现在知道这一点（而非不知道什么被丢弃），可以重传。如果目标方只收到一半数据，发起方现在知道这一点，可在目标方支持 SRR 的情况下使用 SRR（Sequence Retransmission Request）ELS 命令重传数据。

这允许在比典型磁带超时短得多的时间范围内进行链路级错误恢复。**sa(4)** 驱动对读写命令使用 32 分钟超时。这是 IBM LTO-5 推荐的超时值。其他驱动器类似。查看你的磁带机超时值，试试这个：

```sh
# camcontrol opcodes sa0 -T
```

因此，如果链路上出现问题，没有 FC-Tape 时，FC 驱动会等待 32 分钟，中止 I/O，然后向 **sa(4)** 驱动回送失败通知。没有重试，因为我们所述的原因，无法安全重试磁带 I/O 操作。

但有了 FC-Tape，FC 驱动或固件会发送 REC 查询命令状态，假设驱动器仍有响应，发起方和目标方可在几秒内（而非几分钟）恢复传输。

此能力还可帮助确保在存在可靠性问题的 Fibre Channel 环境中可靠访问磁带。网络世界的类比是在可能丢包的网络上使用 TCP（Transmission Control Protocol）叠加 IP（Internet Protocol）确保可靠传输。

## FreeBSD FC-Tape 支持

FreeBSD 有三个 Fibre Channel 驱动，其中两个在树中，一个即将入树。

**isp(4)** 驱动由 Matt Jacob 编写，覆盖从 Parallel SCSI 到 16Gb Fibre Channel 的 Qlogic 控制器。Matt 在 2012 年得益于 Spectra Logic Corporation 的合同添加了 FC-Tape 支持。

**mpt(4)** 驱动支持较旧的 LSI FC 控制器（最高 4Gb），但不支持 FC-Tape。

**ocs\_fc(4)** 驱动由 Broadcom（前 Emulex）编写，应很快提交到 FreeBSD。它支持 Broadcom 的 16Gb 和 32Gb Fibre Channel 卡，并支持 FC-Tape。

SAS 包含一项名为 TLR（Transport Layer Retries）的特性，类似于 FC-Tape 特性。它可根据需要重传命令和数据。有关其工作原理的更多细节，可从 t10.org 获取 SPL-4r12（SAS Protocol Layer 4, revision 12）规范并查看第 8.2.1 节。

FreeBSD 中的 **mps(4)**（LSI/Broadcom 6Gb SAS）和 **mpr(4)**（LSI/Broadcom 12Gb SAS）驱动支持 TLR 并对磁带机默认开启。

## 位错误率与校验和

谈到硬盘和磁带机时另一个话题是位错误率。位错误率是磁带或磁盘驱动器向主机返回错误字节的可能性。你也可以将其视为静默数据损坏的可能性。

如果你的数据在磁盘或磁带上损坏了，你希望驱动器告诉你，而不是传回坏数据。

磁盘和磁带机使用各种算法降低静默数据损坏的可能性，默认情况下磁带的算法更好。但你可以在磁盘和磁带存储上添加校验和，显著降低静默数据损坏的可能性。（使用 ZFS 是减少磁盘静默数据损坏的极佳方式。）

仅位错误率这个话题就能写满一篇相当长的文章，因此这里不展开，以下文章对磁盘和磁盘通道的位错误率覆盖得相当全面：

<http://www.enterprisestorageforum.com/storage-technology/sas-vs.-sata-1.html>

LTO 联盟的这份白皮书简要说明了磁带机有更好的错误检测和纠正算法，因此远不如磁盘容易发生静默数据损坏：

<https://www.lto.org/wp-content/uploads/2014/06/LTO16_0026_ValueProp_Reliability_01_2016_FINAL.pdf>

现代磁带机还支持保护信息，这是一种额外的 CRC（CRC32 或 Reed-Solomon CRC），可随每个磁带块写入，并由磁带机在读写时检查。FreeBSD **sa(4)** 驱动支持保护信息。我所知唯一在 FreeBSD 上支持向每个块添加 CRC 的应用是 IBM 的 LTFS。（见下文。）详见 **mt(1)** 手册页的 `protect` 子命令部分和 **sa(4)** 手册页。

用户和应用也可自由地向磁带写入自己的校验和并读回。即使磁带的位错误率远优于磁盘，如果数据在到达磁带之前或从磁带读出之后被损坏，这也无济于事。（上文的保护信息可在此情况下提供帮助，尤其是当它在应用中生成时。）

## 应用支持

有许多应用与磁带交互，但有两个主要的开源备份应用在 FreeBSD 上运行并与磁带交互：Amanda 和 Bacula。此外还有其他内置工具可与磁带交互。最后还有 LTFS。

## Amanda

Amanda 全称 Advanced Maryland Automatic Network Disk Archiver。Amanda 主页在 <http://amanda.org>。Amanda 服务器在 Ports 树的 **misc/amanda-server**。

Amanda 提供众多功能。我喜欢 Amanda 的一点是它能与 ZFS 快照配合。做完整备份时，它创建 ZFS 文件系统的新快照，用 `zfs send` 将快照发送到磁带。做增量备份时，它创建另一个快照并做增量 `zfs send` 捕获自上次 Amanda 快照以来的变化。

备份 ZFS 快照的缺点是，如果你需要恢复单个文件，你将不得不从磁带拉取该文件所在文件系统的整个快照才能恢复文件。如果文件在增量备份上，你还得从磁带恢复增量和完整快照才能恢复文件。

你可以通过定期创建 ZFS 快照来降低需要恢复单个文件的可能性。如果你有每小时、每天、每周和每月快照（适当修剪以免保留太多历史），用户可以自行恢复误删的文件。这比从磁带拉取文件快得多，且除了指引用户外，希望不需要管理员介入。

## Bacula

Bacula 是 FreeBSD 上可用的另一个主要开源备份软件包。它同样提供众多功能。在 Ports 树的 **sysutils/bacula-server** 可用。

Bacula 的一大特性是支持基于文件的备份。如果你确实需要从磁带恢复单个文件，又不想拉取整个文件系统，Bacula 是出色的解决方案。它将文件列表存储在 Postgres 或 MySQL 等数据库中。

## 内置工具

FreeBSD 自带几个原生与磁带交互的工具：

* **tar(1)** 不仅是分发源代码的工具。它代表 Tape ARchive，tar 变体从 UNIX Version 7 起就存在。如果你需要快速将一组文件发送到磁带，**tar(1)** 能做到，且磁带应可在几乎任何 Unix 系统上读取。
* **dump(8)** 是备份 UFS 文件系统的系统工具，它也与磁带交互。Dump 会保留文件系统的完整元数据，是完整备份的绝佳工具。你也可以用 **dump(8)** 做增量备份。
* **dd(1)** 也知道如何与磁带交互。如果你只想从磁带复制块，可以用 **dd(1)**。例如：`dd if=/dev/nsa0 of=my_tape_image bs=128k`。dd 会读取直到遇到文件标记。遇到文件标记后，可再次运行 dd 从磁带拉取块。
* **camdd(8)** 知道如何与磁带交互。我编写它作为 dd 的更快、多线程版本，并作为使用异步 **pass(4)** 驱动接口的示例。它的特性之一是可以与磁带交互。例如：`camdd -i pass=da5,bs=128k,depth=8 -o file=/dev/nsa0,bs=128k`。这会通过 **pass(4)** 驱动一次向磁盘 da(5) 发出 8 个 128KiB 读取，然后（非常重要！）按顺序将这些块逐一写入磁带。

## LTFS

LTFS 全称 Linear Tape File System。它名副其实——磁带上的文件系统。它既可用作读写单个文件的文件系统，也可用作标准交换格式。

LTFS 在磁带上使用两个分区：Index 分区和 Data 分区。所有文件系统元数据（包括每个文件在磁带上的块位置）存储在 index 分区上的 XML 文件中，并包含在 data 分区中。向文件系统添加文件时，会生成新版本的索引并写入磁带。

IBM 最初编写 LTFS，并将标准转交 SNIA（<https://www.snia.org/tech_activities/standards/curr_standards/ltfs>）。LTO 联盟（<http://lto.org>）提供 LTFS 实现的合规性测试和认证，使不同厂商能确保其实现可与其他厂商互操作。

IBM 提供其 LTFS 版本（又称 Spectrum Archive Single Drive Edition）的源代码，与 IBM 磁带机交互已有数年。IBM 于 2017 年 10 月以 BSD 许可发布其 LTFS 版本（此前为 LGPL 许可），可在此获取：

<https://github.com/LinearTapeFileSystem/ltfs>

我于 2013 年将 IBM 的 LTFS 移植到 FreeBSD（由 Spectra Logic 赞助），目前正在准备将其作为 pull request 提交到 IBM 的代码树。

LTFS 适用于 LTO-5 及更高版本的驱动器。它需要磁带分区支持和磁带上足够大的闪存芯片（称为 MAM—Media Auxiliary Memory）。

IBM 的 LTFS 使用 FUSE（Filesystem in Userspace）呈现文件接口。LTFS 本身作为用户态进程运行，FUSE 将 VFS 请求转发给 LTFS 进程。

LTFS 不能替代 Amanda 或 Bacula 之类的备份程序，因为它只与单盘磁带交互。用户（或厂商）需要围绕它构建更大的应用来管理磁带库中的磁带并移动数据进出磁带。

FreeBSD 上的 LTFS 文件系统主要用作磁带交换格式。（许多媒体公司使用它。）如果你有大量数据，你真正需要的是能将 LTFS 用作其磁带格式的更大应用。

## 结论

磁带仍然活着，并得到积极开发和使用，用于存储海量数据。即使你的数据存在云端，它很可能也备份在磁带上。如果你有大量数据需要备份、需要气隙或异地存储，或者只是想在存储中获得一些遗传多样性，磁带可能是不错的解决方案。

***

**KEN MERRY** 自 1998 年起为 FreeBSD 提交者，自 1994 年起使用 FreeBSD。他是 FreeBSD CAM I/O 子系统的合著者，也是 CTL（CAM Target Layer）的作者。他与妻子和两个儿子住在亚特兰大附近。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://freebsd-journal-cn.bsdcn.org/20180102-cun-chu/tapes-not-dead.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
