图书前言

市面上大多数的计算机书籍都是从某个技术入手,对于如何运用已经讲解得十分透彻,如果是有一定计算机基础的读者,学习起来并不困难,但如果想要进一步地了解技术出现的原因并探究其产生的过程,则需要学习更深的计算机底层知识。当读者对计算机底层有了一定的了解并形成了自己的思维体系,再来看许多上层框架就会豁然开朗,运用起来也会更加得心应手。

在整个计算机体系中,基础硬件一定是计算机运行的根本要素,为了能够控制机器的指令,汇编语言应运而生并将硬件的各种行为抽象成了语言模型,正因为汇编的存在,程序员不用再对着密密麻麻的0和1进行编程和校正。但极度简单且纯粹的汇编语言对于编程而言实在太过烦琐,同一条汇编指令需要在不同的地方反复使用,为了能够简化相同流程的调用,又诞生了C语言,在C语言的基础上衍生出了操作系统,诸如我们现在所熟知的 Linux 及其发行版、Mac OS 等都是在 UNIX 系统的基础上演变而来的,有了操作系统后,才能基于操作系统发展其他的上层语言和框架。

现在,绝大多数公司都会选择 Linux作为服务器进行上层开发,Linux相比于Mac OS和 Windows 系统而言,最大的好处就是开源,能够让阅读它的人深刻了解底层到底做了什么,开发人员最担心的事情是不可控的 inux,而可控的 Linux 给了我们足够的安全感和信心来搭建上层框架。这样一来探究底层的理由也非常明显了,任何事物知其因,才得其果,Linux 聚集了全世界计算机精英的智慧,更有其创始人Linus 为每一次的代码审核和版本迭代把关,我们不仅可以通过学习内核来了解优秀的上层框架如何利用底层函数解决问题,还可以获取到他人对于程序设计的思想和流程的把控,学习如何在精简的代码下完成庞大的项目,实属当今时代的最大宝藏。

为了能将上层应用和底层原理融会贯通,本书将通过概念与源码结合的方式带领读者探寻内核,从最简单的0.11版本走向2.6版本,从根本上了解内核的设计思想,把握内核各个模块的主流程,梳理内核脉络,让大家对内核有整体的认知。

学习内核是为了能够更好地理解上层框架是如何编写的,本书将以Redis作为例子探究其对底层的运用思路。Redis是一个小而美的缓存数据库,几乎各家互联网公司都会用到,我们同样以 2.6 版本的 Redis 向读者展示,中间过程肯定也少不了对源码的解读,毕竟 Linus 的名言:Talk is cheap.Show me the code.(大意为废话少说,放“码”过来)

为什么要写这本书

起初黄俊老师通过混沌学堂这门课,从计算机的发展史讲到了如今热门的各大框架,他深悟混沌之道,知道任何事物都有其发展的过程,探究原因和发掘历史是学习前辈思想的最佳路径,也是探索未来的唯一途径,他在课堂上将计算机从底层原理开始娓娓道来细心地为我们讲解着每一个重要的知识点。

开始探索的过程是艰难的,初探内核的我们是迷茫的,对于庞大的内核,我们无从下手。直到 0.11版本的内核讲解结束,我们从低版本的内核中看到了 Linux 的全貌,它足够简单,这让我们吸收到了很多初代设计的精华,此外,其中涉及的许多汇编代码通俗易懂,硬件设备的交互也容易理解,这为后续的学习打下了坚实的基础。

来到2.6版本后,我们发现内核的整体架构依然没有大的变化,块划分也在初期就定型了(因为Linux的前身是 UNIX操作系统,其诞生于 20 世纪 70年代初,距Linux 的诞生已有二十来年,UNIX系统为 Linux的诞生奠定了基础),但其难度在于扩展性有了极大的提升,由于高版本的内核是由多人协作完成的,代码风格相对初代有了巨大的变化,为了保证内核高可扩展,大量的函数指针会让初学者晕头转向。另外,高版本的内核功能也在不断迭代,虽然模块与模块、层与层之间划分明确,但每进入一层,就仿佛走入了无尽的深渊,几长的调用链同样让初学者措手不及,往往研究了许久才发现自己只是走向了某个支线场景,背离了主干道,不得已又要从头开始探索。

在此感谢黄俊老师的悉心教导,每次碰壁后都是他的引导将我拉回主干道重新出发,在经历了无数次的“折磨”后,我对内核的兴趣越发浓郁,对于某个技术点的探究,我始终坚信自己一定能够克服,在这种心理下,终于艰难地将大部分2.6版本内核梳理完毕。

当2.6版本的内核学习完成后,我再翻阅上层源码框架时,仿佛整个人都脱胎换骨般,很容易就能理解源码的开发者为什么要这样做,知道技术的优点和弊端是什么,什么场景下适用什么框架,原因无他,即使再优秀的开源框架也要基于内核进行开发,内核中的系统调用是上层框架实现函数的必经之路。虽然框架的目的是更加方便应用开发,但过于简单的接口调用和极为严密的高度封装,已让应用开发者在面对许多生产问题时措手不及。

既然内核是一道绕不开的坎,那么趟过去了,后面就是一条光明大道。随着框架源码的大量阅读,就会发现其中的很多思想都借鉴了内核,不管如何变化,总归还是逃离不了进程、内存、文件、设备、网络这几大模块,而其中面向上层的又是那些重要的系统调用函数,上层框架往往是针对内核里的某个特性进行了适配和拓展,达到针对某些场景简化代码编写和提升性能的目的。

至此,计算机混沌之道分别由黄俊老师的三名学生基于混沌学堂课程进行总结完成其中包含了黄俊老师在课堂上讲解的绝大部分精华,本书是计算机混沌之道系列的第篇,第一篇已经为读者分析了汇编相关知识,本篇将基于汇编进而分析内核的相关内容而第三篇将为读者分析计算机网络和JVM,愿读者能从中获益,找到属于自己的混沌之道。

背景知识

本书需要一些简单的汇编知识,但涉及的内容并不会特别复杂,如果阅读过计算机混沌之道第一篇或有一定汇编基础的读者会更加容易理解本书出现的一些系统调用实现和硬件交互过程。

本书使用大量的图片和生活中的例子来解释内核中某些重点函数设计的技巧,方便读者理解,此外,由于内核是一个很深很大的话题,作者无法全面解释所有内容,但所述之处,皆为重点,每一个知识点的出现都有其推理过程,请读者放心阅读。

如果您有一定的编程基础,但对于内核并不是特别熟悉,那么本书将为您打开内核的大门,通读完本书,您将会对内核有一定的认识和理解。

如果您的编程技术尚浅,语言基础薄弱,那么本书对于您而言,可能会显得稍有难度您可以自行斟酌阅读。

本书适合以下读者阅读。 

有一定语言的基础(如C、C++、Java 等),想学习内核,希望有一本简单易懂的入门内核书籍。

想通过学习内核,提升源码的阅读能力和设计思维能力。

有开发的工作经验,但底层原理总是吃不透,阅读优秀的开源代码十分吃力。

有运维的工作经验,但对于inux系统始终没有一个体系思维。

如何阅读这本书

设计程序的主要思想是为了在尽量少地消耗资源的情况下,提升更高的性能,因此理解进程,可以从资源分配上进行优化;理解内存,可以从空间存储上进行优化;理解 IO,可以从数据传输上进行优化;理解同步机制,可以从资源协调上进行优化;理解网络,可以从收发数据上进行优化。一旦对内核的每个模块都有了清晰的认知,那么读者可以很容易地根据合适的场景,选择合适的技术,做出最匹配项目的选择。此外,任何程序都不可能做到一劳永逸,一切事物都会更新迭代,这世上只有变才是唯一不变的,因此即使某种技术放在当下是最好的选择,也会因为时代的变更而被淘汰掉。读者通过学习内核,可以看到大师们对于各个模块里的难题的处理思路,如果能感同身受地代入思考问题并将难题想通后有种恍然大悟的感觉,那真是最让人兴奋的事情了。引用《桃花源记》里的一句古文:“初极狭,才通人。复行数十步,豁然开朗。”刚开始学习内核当然是痛苦的,这让我们进入了一个陌生的领域,一旦能够坚持下来,相信读者也会有所明悟。

本书以 Redis 的基本结构为开篇,带入C语言一些重要的特性,第1章阅读起来并不困难,对于熟知C语言的开发者甚至会觉得是小菜一碟,但“开胃菜”总是要有的,这也是为了不让后续的“大菜”显得突兀且不易消化。

从第2章开始,将进入Linux操作系统的世界,本章会详细讲述inux的相关背景和一些内核的基础知识,该部分内容多半来自Intel白皮书,毕竟操作系统的编写需要依赖硬件的指导,其中列出的许多内容都是高度关联的,有极高的参考价值,在此作者也建议有兴趣的读者能够在网上搜索Intel白皮书并下载阅读。

第3章讲述了进程的相关知识,进程是资源调度的发起者,一切动作的执行都需要由进程来完成,了解进程的创建过程、调度过程可以在很大程度上帮助我们理解进程的执行原理,对于后续探索多进程协作和高并发也有益处。此外,程序的执行是由中断驱动的,本章概述了中断的相关概念,也展示了信号的处理过程。

第4章讲述了内存的相关知识,如果说进程执行的程序是资源的处理过程,那么内存就是在某个阶段所存储的结果,其中最重要的概念就是以页为单位进行数据的存取过程,分页对于整个IO过程来说都是绕不开的一道坎,读者将在后续的章节中看到大量分页的存在。

第5章讲述了 I/0的原理,通俗易懂的说法就是读和写的过程,这是一切IO运行的本质。由于磁盘的存取速度远不及内存,为了匹配处理器的处理速度和数据的存取速度,处理器只执行内存上的数据,而不是磁盘数据。如此以来,内存的目标就被明确地划分出了两个方向:上对应用程序,下对磁盘存储。此外,磁盘读取速度相对较慢,对于经常会被修改的数据不便于在内存与磁盘间反复读写,由此高速缓冲区就随之出现了,因此,理解高速缓冲区的存在、内存与高速缓冲区之间如何读写、高速缓冲区到磁盘之间如何读写就是本章的重点内容了。

第6章讲述了数据的同步机制,高速缓冲区的作用是在内存与磁盘之间缓存数据,避免重复调度磁盘存取,达到优化性能、减少资源浪费的目的,但高速缓冲区带来的弊端也很明显,原本内存可以直达磁盘,现在却多了一层高速缓冲区,此外,高速缓冲区是共享的,还要为它考虑脏数据的问题。那么,什么时候刷新高速缓冲区和怎样刷新高速缓冲区就是本章探索的主要内容。

第7章讲述了 TCP/IP 网络编程的相关内容,网络一直以来都是计算机行业的热门话题,互联网行业能发展得如此辉煌,计算机网络功不可没。TCP协议如何保证数据的可靠是每个开发者需要了解的基础知识,本章从TCP的编程流程、连接过程、三次握手、四次挥手等重点知识来解读相关源码。

相信学习完前7章内容的读者,已经有了一定的阅读源码的能力,此时我们再回到 2.6 版本的 Redis 中,从主流程开始分析,将Redis 大体脉络梳理一遍,此时的你应该能够深刻地感受到,阅读优秀的开源框架是如此轻松的一件事!

勘误和支持

由于作者水平有限,且编写的时间也较为紧促,书中难免存在疏漏之处,恳请读者批评指正。读者可以通过账号bxiava,添加作者微信,提出您宝贵的意见。此外,书中许多内容由于篇幅原因无法展开描述,仅涉及某些技术的主体内容但并非详尽内容,作者会在个人的博客中更新优质的文章为读者分析更多的技术要点。同时,如果您遇到任何问题,也可以与作者交流探讨,作者将尽量在线上为读者提供满意的解答。