读书笔记——《操作系统导论》


banner

很惭愧,虽然在互联网行业从事一线开发已有相当的经验了,但自己本身并不是计算机专业的科班出身,入门及后续的职业技能成长一直都是偏前端方向的软件开发,对计算机软硬件和操作系统如何配合着工作的缺乏体系化的思考和理解。这本由 Remzi 编写的《操作系统导论》(Operating System: Three Easy Pieces),几年前断断续续看过一小部分,最近一段时间翻出来读完,又有了一些新的理解和感悟。

重启是有用的

the it crowd

你可能没看过电视剧 The IT Crowd,但你一定见过这张出自该剧集的表情图。最近这几年作为桌面软件开发,我们也直接或间接的参与到了相当多的一线软件运维中,遇到了各种各样稀奇古怪的问题。当然,作为技术人员,肯定是希望一切表象上的异常最终都能有个合理的原因和解决方法;但受限于软件运行环境差异、调试难度、解决问题周期等等无法快速定位解决,这时“重启”往往成为了一种屡试不爽的策略。

“重启”是否是一种科学有效的解决问题策略?在操作系统导论一书中介绍 CPU 虚拟化的多任务协作式抢占时明确提到:重启是有用的

…虽然我们可能会嘲笑这种粗暴的做法,但研究表明:重启(或在通常意义上说,重新开始运行一些软件)可能是构建强大系统的一个非常有用的工具:

具体来说,重启很有用,因为它让软件回到已知的状态,很可能是经过更多测试的状态。重启还可以回收旧的或泄露的资源(例如内存),否则这些资源可能很难处理。最后,重启很容易自动化。由于所有这些原因,在大规模集群互联网服务中,系统软件管理定期重启一些机器,重置它们并因此获得以上好处,这并不少见。

因此,下次重启时,要相信自己不是在进行某种丑陋的粗暴攻击。实际上,你正在使用经过时间考验的方法来改善计算机系统的行为。干的漂亮!

具体到在桌面软件开发中(尤其是需要长期存活的 IM 软件中),在保障用户的数据不丢失的前提下,可以使用定时重启(或闲时重启)来做一些可能很棘手的资源回收、内存泄漏问题(例如 node.js 中的文件描述符泄漏);另外,可以将应用的进程拆分类似“守护进程”加“工作进程”模式,当工作进程处于最恶劣的情况下(例如进程未能响应或已崩溃)时,自动重启工作进程,尽可能的恢复工作状态——这些理念,与后端服务的“保活”、“高可用”等概念来说本质上并没有太多区别;从过去我们软件的稳定性指标上看,也颇为实际、有效。

间接的一层

操作系统中,内存是如何被系统分配给进程并使用的?早期的计算机中,程序直接运行在物理内存上,其实际访问的地址即真实的物理内存地址。这种不隔离的地址空间带来了安全和效率问题,于是,人们又在应用程序和物理内存之间,引入了一层“虚拟内存”。虚拟内存即操作系统给进程虚拟化出来的一个完整、专属的内存空间,它通过分段、分页的方式继续拆分管理,最终映射到了实际的物理内存中:

virtual mem

这一层间接的“虚拟内存”至关重要。程序在运行时,无论它们被分配到物理地址空间的哪一个区域,对于程序来说都是透明的,它们不需要关心物理地址的变化,它们只要按照从地址 0x00000000 处来编写程序、放置变量,不再需要重定位。

在《操作系统导论》的系统的设计和演进中,这样的间接的一层随处可见:程序和硬件设备之间通过抽象出“进程”的概念实现硬件资源的虚拟化;进程和物理内存之间通过抽象出一层“虚拟内存”实现内存安全;虚拟内存又通过抽象出一层“分页”的机制实现高效管理;在物理内存之上又可以通过抽象出一层基于磁盘读写的“交换空间”实现物理内存的超越。这正应了那句著名的话:

计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决。

回到我们自己的业务开发中来,其实很多时候实现是否合理,不是在于有没有用一些聪明的编程技巧或设计模式,而是在于是否有一个清晰合理的层级划分。为了所谓的功能复用而带来的依赖混乱、职责耦合带来的可维护性的损坏往往是最常见的。也许我们可以多思考功能背后的逻辑层级,思考如何提炼出这“间接的一层”,帮助更好的组织代码。

量纲分析

你也许曾好奇过,一些硬件设备的磁盘性能是如何定义和计算的。在《操作系统导论》中的持久化章节中,介绍了机械磁盘的构造和特点:

disk seek

如图所示为一个多磁道磁盘的结构示意图。假设现在要读取扇区 11 的数据。为了能响应这个读取请求,驱动器必须首先将磁盘臂移动到正确的磁道(在 这种情况下,是最外面的磁道),通过一个所谓的寻道(seek)过程。寻道以及旋转,是最昂贵的磁盘操作之一。

寻道有许多阶段:首先是磁盘臂移动时的加速阶段;然后随着磁盘臂全速移动而惯性滑动;然后随着磁盘臂减速而减速;最后,在磁头小心地放置在正确的磁道上时停下来——这也会有个不小的停放时间(settling time),因为驱动器必须确定找到正确的磁道。之后,磁盘臂将磁头定位在正确的磁道上。

在寻道过程中,磁盘臂已经移动到所需的磁道上,并且盘片当然已经开始旋转,大约旋转了 3 个扇区。因此,扇区 9 即将通过磁头下方,一定的转动延迟后,最终完成传输。当扇区 11 经过磁盘磁头时,I/O 的最后阶段将发生,称为传输(transfer),数据从表面读取或写入表面。因此,我们得到了完整的 I/O 时间图:首先寻道,然后等待转动延迟,最后传输,即:

T(I/O) = T(寻道) + T(旋转) + T(传输)

从上面例子我们得到了一个磁盘性能的度量方法。在《操作系统导论》中,特别介绍了这种系统分析方法,即“量纲分析”:

回忆一下在化学课上,你如何通过简单地选择单位,从而消掉这些单位,结果答案就跳出来了。这几乎能解决所有问题。这种化学魔法有一个高大上的名字,即量纲分析(dimensional analysis),事实证明,它在计算机系统分析中也很有用。

量纲分析使得一个简单而可重复的过程变得很明显。除了上面的 RPM 计 算之外,它也经常用于 I/O 分析。例如,经常会给你磁盘的传输速率,例如 100MB/s,然后问:传输 512KB 数据块需要多长时间(以 ms 为单位)?利用量纲分析,这很容易。

通过这种“量纲分析”,假设某磁盘 RPM = 7200,平均时间 9ms,最大传输速度 105MB/s, 可以计算得到磁盘的 T(I/O) ~= 13.2ms,进而得到其随机工作负载下的传输速率约为 0.31MB/s(但如果是顺序工作负载,则可能接近满速!)。

在《操作系统导论》中,从 CPU 的进程调度算法,到并发控制,到磁盘与文件系统的设计,量纲分析的思想一以贯之,足可见其系统研究论证之理性严谨。这带给我相当多的感触:当我们有一些朦胧的想法,是否可以从一片混乱嘈杂中提炼出一些“量纲”,并用来度量分析相关的效果?相信很多时候,非不能也,实不为也。

总结

计算机是一门理性的科学,它有自身的历史渊源传承、发展设计理念。限于篇幅,本文只零散的记录以上几点感想;实际阅读全书的过程中,一些零碎的概念得以整合,理论结合实践,温故同时知新,颇有乐趣,远非三言两语可道尽。

References