数据的读取和写入,作为任何冯·诺依曼计算机最基本的方面之一,其微妙性和细微差别却令人惊讶。例如,考虑在具有多个处理器的系统中访问共享内存。虽然一种被称为强一致性的简单直观的方法最容易被程序员理解,14 但许多较弱的模型也被广泛使用(例如,x86 总存储顺序22);这些方法提高了系统性能,但代价是使对系统行为的推理更加复杂且容易出错。幸运的是,人们已经花费了大量时间和精力来思考此类内存模型,24 因此,大多数多处理器应用程序都不会在不知不觉中陷入困境。
本地文件系统也存在类似的微妙之处——这些系统管理存储在您的台式电脑或手机13 中的数据,或者作为 HDFS(Hadoop 分布式文件系统)等大型分布式系统的底层存储。23 具体而言,对于试图在本地文件系统上编写可移植应用程序的开发人员来说,一个紧迫的挑战是崩溃一致性(即,确保在突然断电或系统崩溃的情况下可以正确恢复应用程序数据)。
崩溃一致性非常重要。考虑一个典型的现代照片管理应用程序,例如 iPhoto,它不仅存储用户拍摄的照片,还存储与照片库相关的信息,包括标签、事件和其他照片元数据。没有用户希望系统仅仅因为照片管理应用程序尝试更新其内部数据库时发生崩溃而丢失照片或其他相关信息。
如今,确保崩溃一致性的很大一部分负担落在了应用程序开发人员身上,他们必须设计一个更新协议,以协调文件系统持久状态的修改。具体而言,开发人员创建了一个精心构建的系统调用序列(例如文件写入、重命名和其他文件系统调用),以可恢复的方式更新底层文件和目录。因此,应用程序的正确性本质上取决于这些系统调用在系统崩溃方面的语义(即文件系统的崩溃行为)。
不幸的是,虽然标准化的文件系统接口已经广泛使用了多年,但应用程序级别的崩溃一致性目前依赖于文件系统行为的复杂而微妙的细节。无论是有意设计还是偶然,许多现代应用程序都依赖于特定的文件系统实现细节,因此在不同的文件系统或不同的配置上运行时,很容易受到系统崩溃或断电时意外行为的影响。
最近的研究,包括我们在威斯康星大学麦迪逊分校的研究小组21 以及其他地方29 进行的工作,已经证实崩溃是有问题的:许多应用程序(包括一些广泛使用且由经验丰富的程序员开发的应用程序)在崩溃或断电时可能会丢失或损坏数据。这种现实的影响是广泛而痛苦的:用户必须准备好处理数据丢失或损坏,15 可能通过耗时且容易出错的备份和恢复;应用程序代码可能需要根据微妙的文件系统内部机制进行定制,这公然违反了分层和模块化原则;新文件系统的采用速度减慢,因为它们的实现与应用程序期望的崩溃行为不符。6 本质上,文件系统抽象,作为现代操作系统的基本和最古老的组件之一,已经损坏了。
本文总结了系统社区最近在识别这些崩溃一致性问题并为更美好的未来指明方向的研究。首先,一个详细的示例说明了该问题的微妙之处。然后,总结了最新的技术水平,表明我们和其他人发现的问题非常普遍。社区中一些有希望的研究旨在纠正这些问题,为改变最新技术水平带来了新的思路和新技术。
许多应用程序级别的崩溃一致性问题仅在不常见的时序条件下或特定的文件系统配置下才会暴露出来,但有些问题很容易重现。例如,在默认安装了 Fedora 或 Ubuntu 且带有 Git 存储库的情况下,执行 git-commit,等待五秒钟,然后拔掉电源插头;重启机器后,您可能会发现存储库已损坏。幸运的是,这个特定的漏洞并不具有破坏性:如果您有存储库的克隆,您可能可以通过少量工作从中恢复。(注意:除非您 (a) 真的好奇且 (b) 能够从您造成的任何问题中恢复,否则不要这样做。)
让我们看一个例子,演示崩溃一致性的复杂性:一个简单的 DBMS(数据库管理系统),它将其数据存储在单个文件中。为了在系统崩溃时保持事务原子性,DBMS 可以使用一种称为撤消日志的更新协议:在更新文件之前,DBMS 只需将文件中即将更新的部分记录在单独的日志文件中。11 图 1 显示了伪代码(offset
和 size
对应于应修改的 dbfile
的部分);每当 DBMS 启动时,如果日志文件存在且已完全写入(使用 size
字段确定),则 DBMS 会回滚事务。图 1 中的伪代码使用了 POSIX 系统调用(POSIX 是类 Unix 操作系统中使用的标准文件系统接口)。在理想的世界中,人们会期望伪代码在所有实现 POSIX 接口的文件系统上都能工作。不幸的是,伪代码在任何广泛使用的文件系统配置上都无法工作;事实上,它需要一套不同的措施才能使其在每种配置上工作。
由于文件系统在内存中缓冲写入,然后稍后将其发送到磁盘,因此从应用程序的角度来看,大多数文件系统可以重新排序系统调用的效果,然后再将其持久化到磁盘上。例如,在某些文件系统中(ext2、ext4、xfs 和 btrfs 的默认配置,但不包括 ext3),日志文件的删除可以在写入数据库文件之前重新排序。在这些文件系统中发生系统崩溃后,可能会发现日志文件已从磁盘中删除,而数据库已部分更新。其他文件系统可能会以看似荒谬的方式部分持久化系统调用。例如,在 ext2 以及 ext3 和 ext4 的非默认配置中,在写入(追加)到日志文件时,崩溃可能会在文件中新追加的部分留下垃圾数据;在这样的文件系统中,在恢复期间,人们无法区分日志文件是否包含垃圾或撤消信息。
图 2 显示了撤消日志在 Linux 文件系统配置上工作所需的措施(“./
”指的是当前目录);红色部分是所需的额外措施。图中的注释解释了不同文件系统所需的措施:我们考虑了 ext2、ext3、ext4、xfs 和 btrfs 的默认配置,以及 ext3/4 的数据写回配置(表示为 ext3-wb 和 ext4-wb)。几乎所有措施都只是求助于使用 fsync()
系统调用,该调用将给定文件(或目录)从缓冲区缓存刷新到磁盘,用于防止文件系统重新排序更新。 fsync()
调用可能会非常昂贵,具体取决于文件系统如何实现它们;因此,高效的应用程序会尝试在可能的情况下避免 fsync()
调用。然而,仅使用一部分 fsync()
调用,实现将仅在某些文件系统配置上保持一致。
请注意,在所有应用程序中使用经过验证的单个更新协议实现是不切实际的;在实际应用程序中找到的更新协议差异很大,并且可能比图 2 中所示的更复杂。选择可能取决于性能特征;某些应用程序可能以顺序磁盘 I/O 为目标,并且更喜欢不涉及寻道到文件不同部分的更新协议。选择也可能取决于可用性特征。例如,单独的日志文件的存在不必要地使常见工作流程复杂化,将恢复负担转移到包括用户参与。更新协议的选择也与应用程序的并发机制及其数据结构使用的格式内在相关。
应用程序可以依赖什么?文件系统开发人员似乎就两条规则达成一致,这两条规则规定了哪些信息在系统崩溃时会被保留。第一条规则很微妙:磁盘上已有的信息(文件数据、目录条目、文件属性等)在系统崩溃时会被保留,除非明确发出影响它的操作。
第二条规则涉及类 Unix 操作系统中的 fsync()
和类似构造(msync()
、O_SYNC
等)。对文件执行 fsync()
可保证当调用返回时,文件的数据和属性位于存储设备上,但存在一些微妙之处。 fsync()
的一个主要微妙之处在于存储设备的定义:在信息通过 fsync()
发送到磁盘后,它可以驻留在磁盘缓存中,因此可能会在系统崩溃期间丢失(除非在某些特殊磁盘中)。操作系统提供临时解决方案来尽其所能刷新磁盘缓存;由于您可能在伪硬盘8 之上运行,因此没有任何承诺。另一个微妙之处与目录广泛相关:文件的目录条目和文件本身是独立的实体,可以分别发送到磁盘;对其中一个执行 fsync()
并不意味着另一个的持久性。
鉴于在不同的文件系统之间实现崩溃一致性的复杂性,大多数开发人员编写的代码都不正确。某些应用程序(例如,Mercurial)甚至不尝试处理崩溃,而是假设用户将手动恢复因崩溃而丢失或损坏的任何数据。虽然应用程序的正确性取决于文件系统复杂的崩溃行为,但关于此主题的正式讨论却很少。
最近的两项研究调查了应用程序级别崩溃一致性的正确性:一项在威斯康星大学麦迪逊分校21 进行,另一项在俄亥俄州立大学和惠普实验室29 进行。分析的应用程序包括分布式系统、版本控制系统、数据库和虚拟化软件;许多是广泛使用的应用程序,由经验丰富的开发人员编写,例如 Google 的 LevelDB 和 Linus Torvalds 的 Git。我们在威斯康星大学麦迪逊分校的研究发现了在广泛使用的文件系统配置下暴露的 30 多个漏洞;在研究的 11 个应用程序中,7 个受到数据丢失的影响,而 2 个受到静默错误的影响。俄亥俄州立大学和惠普实验室的研究结果相似:他们研究了八个广泛使用的数据库,并在所有八个数据库中发现了错误行为。
例如,我们发现,如果文件系统决定在 HDFS 中重新排序两个 rename()
系统调用,则 HDFS namenode 无法启动2,并且重新排序会导致不可用。因此,为了实现可移植的崩溃一致性,需要在发生 rename()
调用的目录上调用 fsync()
。然而,据推测,由于广泛使用的文件系统配置很少重新排序 rename()
调用,并且 Java(HDFS 是用 Java 编写的)不允许直接在目录上调用 fsync()
,因此 HDFS 开发人员目前忽略了这个问题。
再举一个例子,考虑 LevelDB,这是一个键值存储,它将任何插入的键值对添加到日志文件的末尾。 LevelDB 定期切换到新的日志文件,并压缩之前的日志文件以加快记录检索速度。我们发现,在此切换期间,需要在即将压缩的日志文件上执行 fsync()
;19 否则,崩溃可能会导致某些插入的键值对消失。
许多漏洞的出现是因为应用程序开发人员依赖于一套关于崩溃一致性的流行信念。不幸的是,许多关于文件系统崩溃行为的信念是不真实的。考虑以下两个误解
• 误解 1:POSIX 定义了崩溃行为。 POSIX17 定义了类 Unix 操作系统导出的标准文件系统接口(open
、close
、read
和 write
),并且对于构建可移植应用程序至关重要。鉴于此,人们可能会认为 POSIX 要求文件系统对崩溃做出合理且明确定义的响应,例如要求目录操作按顺序发送到磁盘。18 不幸的是,关于 POSIX 究竟定义了什么关于崩溃的内容,几乎没有明确的说明,3,4 导致了许多争论,但几乎没有达成共识。
• 误解 2:现代文件系统需要并实现有序元数据更新。 日志记录是一种用于维护文件系统元数据一致性的常用技术,它将不同组的文件系统元数据更新(例如目录操作)作为原子事务提交。日志记录在现代文件系统中很流行,并且传统上按顺序提交元数据更新;12 因此,很容易假设现代文件系统保证有序元数据更新。然而,应用程序开发人员不应假设这种保证。日志记录是一种内部文件系统技术;一些现代文件系统,例如 btrfs,采用日志记录以外的技术,并且通常会重新排序目录操作。此外,即使是实际使用日志记录的文件系统,在保持内部一致性的同时,也逐渐重新排序了更多操作。考虑 ext3/4:ext3 仅重新排序文件数据覆盖,而 ext4 也重新排序文件追加。根据 ext4 的维护者 Theodore Ts'o 的说法,未来的日志文件系统可能会重新排序更多操作(尽管 ext4 不太可能这样做)。
文件系统开发人员是否应该因设计复杂的、不利于实现崩溃一致性的文件系统而受到责备?一些复杂的文件系统行为可以(并且应该)修复。然而,大多数使应用程序一致性变得困难的行为对于通用文件系统至关重要。
为了说明这一点,请考虑重新排序,这可以说是最不直观且导致最多崩溃一致性漏洞的行为。在我们的研究中,一个提供有序操作(和一些最小原子性)的文件系统仅暴露了 10 个漏洞,所有漏洞都只有轻微的后果;相比之下,btrfs 中暴露了 31 个漏洞,ext4 中暴露了 17 个漏洞。然而,在当前多个应用程序同时运行的环境中,文件系统需要重新排序才能获得良好的性能。如果没有重新排序,来自重要应用程序的 fsync()
调用将需要等待来自非必要任务的写入完成。实际上,ext3 在其默认配置中提供了(几乎)有序行为,但因其不可预测的慢速 fsync()
调用而受到批评。7
开发人员可以通过遵循以下建议的实践来缓解其应用程序中的崩溃一致性问题
使用库。 直接在文件系统接口之上实现一致性就像在法庭上辩称精神错乱:只有在别无选择时才这样做。在任何可能的情况下,更明智的策略是使用库,例如 SQLite,它在您的应用程序下方实现崩溃一致性。
记录保证和要求。 应用程序提供的保证一致性可能会令人困惑;一些开发人员可能不清楚他们自己的应用程序提供的保证。记录应用程序为保持一致性所需的文件系统行为更加复杂,因为应用程序开发人员和用户通常都不清楚文件系统行为。最好的文档是支持的文件系统配置列表。
测试您的应用程序。 由于文件系统表现出的令人困惑的崩溃行为,测试应用程序非常重要。在公开可用于查找应用程序崩溃漏洞的工具中,ALICE21 已成功用于测试 11 个应用程序;它还清楚地显示了哪些程序行导致了漏洞。然而,公共版本的 ALICE 不适用于 mmap()
内存和一些罕见的系统调用。还有另一个为测试文件系统9 而设计的工具,它可以与在 Linux 上运行的任何应用程序一起使用,但效果较差。
幸运的是,在崩溃一致性领域并非一片黯淡。最近的研究为本文概述的问题指出了许多有趣且合理的解决方案。一种方法是帮助开发人员构建正确的更新协议。至少有两个新的开源工具可公开用于一致性测试(尽管两者都不成熟):ALICE,20 这是为我们在威斯康星大学麦迪逊分校的研究而创建的工具,以及 Linux 内核开发人员9 设计的用于测试文件系统实现的工具。 ALICE 更有效地用于测试应用程序,因为它验证了给定应用程序测试用例在各种模拟系统崩溃下的正确性。相比之下,内核工具仅验证给定测试用例运行期间文件系统遍历的特定执行路径中发生的系统崩溃的正确性。
另外两个测试工具是最近研究的一部分,但尚未公开:来自我们研究的 BOB21,以及俄亥俄州立大学和惠普实验室的研究人员使用的框架。29 这两个工具都类似于内核工具。
实现更好的应用程序崩溃一致性的第二种方法是文件系统本身提供更好、更易于理解的抽象,从而为应用程序实现正确性和高性能。一种解决方案是扩展和改进当前的文件系统接口(在 Unix 世界或 Windows 中)。然而,该接口建立在多年的经验和标准化的基础上,因此很难改变。16 最好的解决方案是在当前文件系统接口下提供更好的崩溃行为。然而,如前所述,有序更新(即更好的崩溃行为)在具有多个应用程序的多任务环境中是不切实际的。在这些环境中没有重新排序的情况下,应用程序的性能在很大程度上取决于在后台运行的其他应用程序写入的数据,因此将是不可预测的。
有一个解决方案。我们的研究小组正在开发一种仅在应用程序内部维护顺序的文件系统。构建这样的文件系统并非易事;传统的文件系统在元数据更新10 之间强制执行某种顺序,因此也可能在不同的应用程序之间强制执行顺序(如果它们更新相关的元数据)。来自惠普实验室的另一种可能的方法26 是更改文件系统接口,但保持新接口简单,同时在生产就绪的文件系统上得到支持。
改进应用程序崩溃一致性的第三条途径超越了测试,并寻求一种正式建模文件系统的方法。我们的研究引入了一种建模文件系统的方法,该方法完全表达了它们的崩溃行为(抽象持久性模型)。我们建模了五个文件系统配置,并使用这些模型来发现每种建模文件系统中暴露的应用程序漏洞。来自麻省理工学院的研究人员5 更广泛地考虑了建模文件系统的不同形式方法,并发现 Hoare 逻辑是最好的。
除了本地文件系统之外,应用程序崩溃一致性在提议的存储堆栈中也是一个有趣的问题,这些堆栈将在运行时构建,混合和匹配不同的层,例如块重映射器、逻辑卷管理器和文件系统。27,28 需要一种富有表现力的语言来指定此类存储堆栈中不同层的复杂存储保证和要求。我们的研究小组还在开发这样一种语言,以及证明整个存储堆栈总体正确性的方法。1
本文旨在使读者确信应用程序级别的崩溃一致性是一个真实且重要的问题。在计算机系统的其他领域,在多处理器共享内存和分布式系统领域,以前也面临过类似的问题。这些问题已通过创建新的抽象、理解各种权衡,甚至通过棒球类比来思考问题而得到克服。25 类似的解决方案也可能适用于应用程序崩溃一致性,但这需要更广泛的系统社区的参与。
1. Alagappan, R., Chidambaram, V., Sankaranarayana Pillai, T., Arpaci-Dusseau, A. C., Arpaci-Dusseau, R. H. 2015. 超越存储 API:存储堆栈的可证明语义。在瑞士伊廷根卡尔特豪斯举行的第 15 届热点操作系统研讨会(5 月)。
2. Al-Kiswany, S. 2014. 如果文件系统重新排序重命名操作,Namenode 无法启动; http://issues.apache.org/jira/browse/HDFS-6820。
3. Aurora, V. 2009. POSIX v. 现实:关于 O_PONIES 的立场; http://lwn.net/Articles/351422/。
4. Austin Group 缺陷跟踪器。 2013. 0000672:在磁盘上同步文件名操作的必要步骤; http://austingroupbugs.net/view.php?id=672。
5. Chen, H., Ziegler, D., Chlipala, A., Kaashoek, M. F., Kohler, E., Zeldovich, N. 2015. 为存储系统指定崩溃安全性。在瑞士伊廷根卡尔特豪斯举行的第 15 届热点操作系统研讨会(5 月)。
6. Corbet, J. 2009. Ext4 和数据丢失; https://lwn.net/Articles/322823/。
7. Corbet, J. 2009. 那个庞大的文件系统线程; http://lwn.net/Articles/326471/。
8. Davies, C. 2011. 假硬盘具有短期记忆,而不是 500GB。 SlashGear; http://www.slashgear.com/fake-hard-drive-has-short-term-memory-not-500gb-08145144/。
9. Edge, J. 2015. 测试电源故障; https://lwn.net/Articles/637079/。
10. Ganger, G. R., Patt, Y. N. 1994. 文件系统中的元数据更新性能。在第一届操作系统设计与实现研讨会论文集中:49-60,加利福尼亚州蒙特雷(11 月)。
11. Garcia-Molina, H., Ullman, J. D., Widom, J. 2008. 数据库系统:完整书籍。 Prentice Hall Press。
12. Hagmann, R. 1987. 使用日志记录和组提交重新实现 Cedar 文件系统。在第 11 届 操作系统原理研讨会论文集中,德克萨斯州奥斯汀(11 月)。
13. Kim, H., Agrawal, N., Ungureanu, C. 2012. 重新审视智能手机的存储。在第 10 届 Usenix 文件和存储技术研讨会论文集中,加利福尼亚州圣何塞(2 月)。
14. Lamport, L. 1979. 如何制造一台能够正确执行多进程程序的多处理器计算机。 IEEE 计算机学报 28(9): 690-691。
15. Mercurial. 2014. 处理存储库和 dirstate 损坏; http://mercurial.selenic.com/wiki/RepositoryCorruption。
16. 微软。 使用事务性 NTFS 的替代方案; https://msdn.microsoft.com/en-us/library/windows/desktop/hh802690(v=vs.85).aspx。
17. Open Group 基础规范。 2013. POSIX.1-2008 IEEE Std 1003.1; http://pubs.opengroup.org/onlinepubs/9699919799/。
18. Sankaranarayana Pillai, T. 2013. 可能的错误:调用 rename() 后需要 fsync(); https://code.google.com/p/leveldb/issues/detail?id=189。
19. Sankaranarayana Pillai, T. 2013. 可能的错误:在压缩之前日志文件缺少 fsync(); https://code.google.com/p/leveldb/issues/detail?id=187。
20. Sankaranarayana Pillai, T., Chidambaram, V. Alagappan, R., Al-Kiswany, S., Arpaci-Dusseau, A. C., 和 Arpaci-Dusseau, R. H. ALICE:应用程序级别智能崩溃探索器; http://research.cs.wisc.edu/adsl/Software/alice/。
21. Sankaranarayana Pillai, T., Chidambaram, V., Alagappan, R., Al-Kiswany, S., Arpaci-Dusseau, A. C., Arpaci-Dusseau, R. H. 2014. 并非所有文件系统都是一样的:关于设计崩溃一致性应用程序的复杂性。在第 11 届操作系统设计与实现研讨会论文集中,科罗拉多州布鲁姆菲尔德(10 月)。
22. Sewell, P., Sarkar, S., Owens, S., Nardelli, F. Z., Myreen, M. O. 2010. x86-TSO:x86 多处理器的严格且可用的程序员模型。 通讯 53(7): 89-97。
23. Shvachko, K., Kuang, H., Radia, S., Chansler, R. 2010. Hadoop 分布式文件系统。在第 26 届 IEEE 大容量存储系统和技术研讨会论文集中,内华达州英克莱恩村(5 月)。
24. Sorin, D. J., Hill, M. D., Wood, D. A. 2011. 内存一致性和缓存一致性入门。 Morgan & Claypool Publishers。
25. Terry, D. 2011. 通过棒球解释复制数据一致性。 MSR 技术报告(10 月)。
26. Verma, R., Mendez, A. A., Park, S., Mannarswamy, S. S., Kelly, T. P., Morrey, C. B., III. 2015. Linux 文件系统中应用程序数据的故障原子更新。在第 13 届 Usenix 文件和存储技术研讨会论文集中,加利福尼亚州圣克拉拉(2 月)。
27. VMWare。 软件定义存储 (SDS) 和存储虚拟化; http://www.vmware.com/software-defined-datacenter/storage。
28. VMWare。 VMware 关于软件定义存储的观点; http://www.vmware.com/files/pdf/solutions/VMware-Perspective-on-software-defined-storage-white-paper.pdf。
29. Zheng, M., Tucek, J., Huang, D., Qin, F., Lillibridge, M., Yang, E. S., Zhao, B. W., Singh, S. 2014. 为了乐趣和利益而折磨数据库。在第 11 届操作系统设计与实现研讨会论文集中,科罗拉多州布鲁姆菲尔德(10 月)。
喜欢还是讨厌?请告诉我们
Thanumalayan Sankaranarayana Pillai ([email protected]), Vijay Chidambaram ([email protected]), 和 Ramnatthan Alagappan ([email protected]) 是威斯康星大学麦迪逊分校计算机科学系的博士候选人。 Chidambaram 即将加入德克萨斯大学奥斯汀分校的教职队伍。
Samer Al-Kiswany ([email protected]) 是威斯康星大学麦迪逊分校计算机科学系的博士后研究员。 他在加拿大不列颠哥伦比亚大学获得博士学位。
Andrea Arpaci-Dusseau ([email protected]) 和 Remzi Arpaci-Dusseau ([email protected]) 是威斯康星大学麦迪逊分校的计算机科学教授。
© 2015 1542-7730/15/0500 $10.00
最初发表于 Queue vol. 13, no. 7—
在 数字图书馆 中评论这篇文章
Pat Helland - 关注您的状态,了解您的心境
随着应用程序进入分布式和可扩展的世界,它们经历了有趣的演变。同样,存储及其表亲数据库也与应用程序并肩发展。很多时候,存储和应用程序的语义、性能和故障模型都在微妙地跳舞,以支持不断变化的业务需求和环境挑战。在混合中添加规模确实激化了事情。本文着眼于其中的一些问题及其对系统的影响。
Alex Petrov - 现代存储系统背后的算法
本文仔细研究了现代数据库中使用的两种存储系统设计方法(读取优化的 B 树和写入优化的 LSM(日志结构合并)树),并描述了它们的使用案例和权衡。
Mihir Nanavati, Malte Schwarzkopf, Jake Wires, Andrew Warfield - 非易失性存储
对于大多数执业计算机科学家的整个职业生涯而言,一个基本的观察结果始终成立:CPU 的性能和成本都远高于 I/O 设备。CPU 可以极高的速率处理数据,同时为多个 I/O 设备提供服务,这一事实对各种规模系统的硬件和软件设计产生了广泛的影响,几乎与我们构建它们的时间一样长。
Michael Cornwell - 固态硬盘剖析
在过去的几年中,一种新型存储设备已进入笔记本电脑和数据中心,从根本上改变了人们对存储的功耗、尺寸和性能动态的期望。SSD(固态硬盘)是一种已经存在了 30 多年的技术,但由于价格过于昂贵而未能得到广泛采用。