00 开篇词 为什么大厂面试必考操作系统?

你好,发现求知的乐趣,我是林䭽。

我在阿里巴巴做架构的多年时间里,每天都在和复杂的业务场景斗争着,比如如何应对高并发场景?如何解决系统间的数据一致性问题?如何带给用户更快更爽的体验?

在处理一个又一个业务架构、系统架构问题的过程中,我愈发地意识到有一块知识非常重要,也就是我们这门课的主题——操作系统。操作系统可以作为一个完整的知识框架,把复杂如高并发、数据一致性的问题,基础到编程语言、计算框架、业务框架的问题都串联起来。

为什么要学习操作系统?

操作系统(Operating System)作为一门计算机专业大学必修课,如今已经成为程序员跳槽、涨薪、过面试的必考内容。像面试中高频的考点,比如 Linux 指令、中断、多线程、并发、性能、内存管理、系统稳定性、文件系统、容器和虚拟化等,知识都来源于操作系统。学了操作系统:

  • 你不懂 Java 多线程,也可以回答好 Java 多线程的面试题;
  • 你不熟悉 Docker,也可以回答出容器化应该如何做。

2.png

操作系统已不仅仅是一门大学的必修课那么简单,更是计算机领域的本源知识,任何编程语言学下去都会碰到操作系统知识,比如 Java 的虚拟机、Go 语言的协程与通道、Node.js 的 I/O 模型等。任何研发工具学下去也都会碰到操作系统,比如:

  • MySQL 深入学下去会碰到 InnoDB 文件系统;
  • HBase 深入学下去会有 Hadoop 文件系统(HDFS);
  • Redis 深入学下去会碰到 Linux 的I/O模型;
  • Docker 深入学下去有 Linux 的命名空间等;
  • 甚至 Spring 框架,也需要用到线程池和调度算法。

因此,作为面试官,我们需要通过操作系统知识判断求职者的综合能力,你可以将这些语言、开发工具用到什么层次?是能够使用还是理解原理,甚至具备系统改造的能力?

为什么你要学习我这门操作系统课?

互联网领域有一个非常重要的分析方法,那就是一件事情如果可以成功,无非就是合适的人,在合适的时间,做合适的事情。接下来,我将结合课程设计思路和自己的人生经历来分析, 你为什么要学习我的这门操作系统课。

我们可以先从“事到人”的角度入手。从事情上说,我希望做一门学了就能用的课程,所以本课程学习目标有两个:一是帮助你顺利通过面试、跳槽涨薪;另一个是帮助你提升应对实际工作场景的能力,具体包括以下几点。

  • 提升学习和理解能力:比如学习 Redis 可以理解到日志文件系统层面;学习 Java/Python/Node 等语言可以理解到语言最底层。
  • 提升应用架构能力:比如可以将操作系统的微内核架构迁移到自己设计的系统中。
  • 提升系统稳定性架构能力:比如在多线程设计上更出色,可以帮助同事找到设计漏洞。
  • 提升运维能力:做到可以方便地管理集群和分析日志。

下面我再来结合我自身背景和互联网行业特点与你具体聊一聊。

首先,帮你面试涨薪这块我非常有底气,为什么我敢这样说?

我曾在 3 家互联网大厂任职架构师(技术专家),而且是技术委员会成员;另一方面,我做了 10 年的面试官,每年都会到拉勾网筛选简历,保守估计按每年面试 100 个人来算,我至少已经面试过上千人了;还有一方面,我有很多朋友在大厂做技术 Leader,也有很多学生在大厂工作,因此我有一个精准的面试圈子。

我们在面试题、面试技巧方面交流非常多,而且我已经出过几门技术类的在线课程,我的讲课风格也受到了很多学员的认可,他们很喜欢和我交流问题、探讨技术,所以我可以自信地说:我是一个非常懂面试和公司用人标准的老师。

再者,我有丰富的实际应用场景经历。

中国互联网系统最主要的设计约束:并发高、数据量大(毕竟中国互联网是以人口红利起家的)。比较巧的是,海量用户的 C 端场景和大数据商业分析场景,我刚好都负责过。而高并发、大数据中的很多知识,又需要从操作系统中获取,加上我本身操作系统方面的知识也比较扎实,所以在实际场景这块我也有丰富的经验。

接下来再从我的角度来看看“现在要不要学操作系统”,我觉得现在的时机刚刚好

首先,目前是一个在线教育的风口,我结合自身背景以及拉勾网在线招聘求职方向的优势,给你带来一门针对工作场景的就业提升类操作系统课程,符合平台调性。

3.png

再者,云原生架构出现之后,越来越强调“谁开发谁运维”,因此业内对操作系统的需求度在提升、要求也在提高,所以我设计这门针对工作场景的就业提升类操作系统课程符合市场需求。

操作系统的需求量也是急剧增长。 随着我国用户量和数据量的爆发式增长,也让互联网的运营成本变高。因此,公司很希望自己的员工熟悉操作系统,可以从系统底层去帮助公司节约成本。

此外,随着我国用户量和数据量的爆发式增长,也让互联网的运营成本变高,一个普普通通千万级用户量的网站,就需要每年上亿的运维成本去 Cover。在这种情况下,公司很希望自己的员工熟悉操作系统,可以从系统底层去帮助公司节约成本。所以市场对于操作系统的需求量也是急剧增长的。

课程介绍

接下来我们聊聊课程内容,这门课程对标的是架构师层级的基础能力,看个人的接受程度,学完之后大概会在阿里的 P7 及以上层级

课程共分为 8 个模块,合计 39 个课时。具体每个模块的介绍,我将在下一课时“课前必读”中详细讲解。在这里,我先跟你分享一下课程的整体设计思路。

这门操作系统课程将帮助你系统地解决面试中可能遇到的计算机原理和操作系统类问题,并以大厂面试题作为切入点,引出很多你在实际工作中会遇到的问题和技术难点。同时,每一个模块聚焦操作系统知识的一个方向,每节课的标题就是这个方向最需要掌握的,也是真实出现过的大厂面试题,同时它也代表着一类知识点。而且,我还将结合实战场景帮助你打牢基础知识,向架构师的方向努力。

说到工作场景,我认为有两个非常重要的问题需要解决。

第 1 个问题是提高大家在实际工作场景中的实战能力。 除了讲解操作系统的知识结构,还会结合以下 6 个场景深入分析:

  • 架构师必备的高并发、多线程编程技巧;
  • 团队 Leader 如何掌握必备的 Linux 运维技巧;
  • 程序语言(Java/Go/Node)的内存分配和回收;
  • 数据库底层(MySQL/Hadoop)的文件系统;
  • 计算机网络和操作系统 I/O 模型结合有哪些注意事项;
  • 如何从操作系统底层理看容器化技术:K8s 和 Docker。

这些都是目前国内大厂研发岗位最为关心的问题,也是大厂面试的热门问题,学会和理解这些问题背后的原理,将对你面试和晋升有很大的帮助。

第 2 个问题是解决面试难题,让你顺利拿到 Offer。我精选了 80 道左右的大厂面试题:

  • 其中 40 道题目会作为课程标题或者课前的提问,在课时中会带着大家分析,以此引出该问题背后的知识点,从点到面一步步把知识点和原理讲清楚。
  • 另外 40 道题目将作为课后练习题,帮助你巩固本课时的内容,检测自己的学习成果。此外,这部分问题还会作为精讲习题,在每个模块单独设置一个课时带你梳理解题思路、分析底层原理,结合实战场景帮你分析工作中可能遇到的瓶颈。

学完之后,希望你可以举一反三,这非常有利于提升你的面试成功率。

其实我在做课程设计之前,花了大量的时间进行市场调研,发现目前市场上专门针对互联网方向,帮助你提升系统架构能力、应对日常使用和高并发场景的操作系统课程是缺失的。

这也是我做这门课程的初衷:课程中没有大量的源代码,也没有特别的语言依赖。我会把面试要点和工作场景中的重难点内容都覆盖到,彻彻底底、由内而外地给你讲清楚,帮你应对面试、解决工作难题。

说到这里,我想你可能还有些疑问,比如课程的难度怎么样,适不适合新手学习?或者是课程深度能否满足进阶大厂架构师?

  • 第一个问题,适不适合新手学习?

我的答案是:适合。这门课程对大家的基础知识没做任何假设,比如操作系统唯一依赖的知识——计算机组成原理,我也把它们做成了前置课程,利用模块一的 4 个课时把这块内容讲清楚。

另一方面,我会从设计者角度出发来给你讲问题。比如讲多线程算法的时候,我会先讲遇到了什么困难,再诱导大家思考如何解决这些困难,然后和你一起分析出几个解题方向,最后循序渐进地给出一个合理的方案。所以这门课程非常适合新手学习。

  • 第二个问题,课程内容的深度能否满足进阶大厂架构师?

我的答案依然是:满足,这门课程的深度足够培养一名架构师。课程内容会涉及多线程编程中 AQS 的原理;数据同步中的乐观锁;Java 新生代用了什么算法、老生代用了什么算法;还有比如高并发时有哪些提升性能的方法?这些都是架构师需要掌握的,也是课程的重点。

所以,操作系统这门课程既适合新手入门,也适合有经验的开发人员进阶学习,这并不受经验影响,不同的是你们的学习目标和学习收获。

寄语

最后,我还想和你说点关于职业发展相关的事情。

1.png

中国有超过 1000 万程序员,大部分人的年薪小于 30 万。我观察到一个这样的现象:一方面求职者们抱怨市场竞争激烈,大家争抢一两个岗位;另一方面很多优秀团队的高薪岗位招人难,闲置多个空位,求职者很多但是符合岗位要求的却很少。到底是什么原因造成企业招人难,求职者求职难的情况呢?

其实,拉开个人薪资和团队整体水平差异的分水岭,根本原因就是计算机基础知识的掌握程度。基础好的程序员,学习速度快,愿意花时间去积累知识,提高自身能力,因此涨薪快、跳槽更容易;而基础不好的,学习相对较慢,知识输入少,因此涨薪慢、跳槽难。个人能力的高低决定了收入的水平。

这个事情很现实,也很不公平。但是反过来想,为什么基础不好的同学,不把时间精力拿出来去填补自己的知识空缺呢?如果你的操作系统知识还是一盘散沙,那么请你现在就开始行动,跟着我一起重学操作系统,把这块知识捡起来。愿正在看这篇文章的你,能通过自己的努力去到更好的团队,拿更高的薪水,进而得到更广阔的发展空间。

00 课前必读 构建知识体系,可以这样做!

我认为,在学习中有一件非常重要的事情,那就是梳理知识体系,所以在进入操作系统课程的学习之前,我想先给你一份这门课程的知识体系(也是一份学习路径),然后再介绍一套我自己梳理知识体系的方法,帮助你更轻松地学好这门课。

课程内容&知识体系

我们先来看下这门课程的知识体系结构,分为 8 个模块,39 个课时,具体如下。

  • 模块一:(前置知识)计算机组成原理。 如果你对计算机的组成原理中涉及的比如内存、寄存器工作原理、CPU 指令、总线都是怎么工作的这些基本问题,没有搞清楚,大概率会影响你后续对操作系统的学习。因此,在课程开始前,我先来给你一份操作系统的前置知识,帮助你更好地理解后续内容。
  • 模块二:(初探)Linux 指令入门。 这个模块将介绍一些实用的知识,带你入门 Bash 编程,并通过日志分析、性能监控、集群管理等实战场景深入学习 Linux 指令。这些对于日常开发和运维人员来说,都会非常有帮助。
  • 模块三:(总纲)操作系统概述。 这部分帮助你了解操作系统的整体设计,介绍内核、用户空间等基本概念,还会介绍操作系统的分类,以及对比一下市面上的操作系统(如 Windows、Linux、Unix、Android 等),让你对整个操作系统生态能有一个整体的认识。

总的来说,模块四 ~ 模块七是我们这门课程的核心内容,也是面试的重点考区。设置这块内容的目的是借助操作系统的知识,帮你思考如何解决实战问题,比如我们反复提及的高并发、数据一致性、大数据存储和网络问题等。

  • 模块四:(面试重点)进程和线程。 我会针对大家在面试和工作中最常见的并发和数据同步问题,从进程原理、多线程编程、互斥和乐观锁、死锁和饥饿、调度算法、进程通信等多个方面,同时结合一些语言特性(比如 Java 的语言特性)讲解原理、思考方案及对策。
  • 模块五:(面试重点)内存管理。 这部分我们是从页表和 MMU、虚拟化、内存的分配和回收、缓存置换、逃逸分析、三色算法、生代算法等方面入手,帮助你了解内存的工作原理,应对高并发带来的内存使用问题。
  • 模块六:(面试重点)文件系统。 这部分内容我们将从两个方面入手,一方面是通过学习 Linux 的文件目录结构,了解 Linux 下不同的文件目录的功能和作用,帮助你把 Linux 用好;另一个方面,从文件系统的底层设计入手,帮助你了解文件系统的设计思路和原理,并且通过讲解数据库的文件系统,比如 MySQL 的 InnoDb、B+Tree 以及 Hadoop 的 HDFS,帮你把文件系统的知识应用到处理海量数据的领域。
  • 模块七:(面试重点)网络与安全。 这部分讲解面试中常见的互联网协议群、TCP 和 UDP 协议、Linux 的 I/O 模型、公私钥加密体系,以及一些最基本的计算机网络安全知识,帮助你理解操作系统和网络之间的交互,从而更好地利用操作系统知识设计业务系统的网络架构。
  • 模块八:(知识拓展)虚拟化和其他。 最后这部分,我们将从操作系统的角度学习容器化应用(比如 Kubernetes 和 Docker),还会深入讨论 Linux 架构及商业操作系统。这些知识一方面能够帮你和面试官产生更多的共鸣,另一方面还能帮你开拓视野、打开思路,看到未来的发展趋势。

接下来,我给大家梳理一下操作系统整体的知识框架,帮你扫除知识盲区。

从知识结构上来看,操作系统最核心的部分是进程,因为操作系统自己不能提供服务,它要想实现价值,就必须通过安装在系统中的应用程序。而安装好的应用程序,启动后就成了进程,所以说进程处在操作系统知识体系的核心。

了解了以上内容后,我们围绕进程继续梳理,可以发现:

  • 进程往往要同时做很多事情,比如浏览器同时要处理网络、又要处理鼠标、还要展示内容,因此有了多线程的概念。
  • 进程需要执行用的存储空间,比如需要存程序指令、需要堆栈存执行数据,因此需要内存。
  • 进程需要将一部分数据持久的存储下来,因此需要文件系统。
  • 进程需要和外界通信,其中一种途径就是网络。
  • 开发过程中我们希望进程可以单独部署,于是需要容器。
  • 操作系统内核本身也是一个程序,可以理解成一个进程,它同样是需要单独研究的。

所以,进程是核心,内核、多线程、内存、文件系统、网络、容器和虚拟是配套的能力。我们要想展开操作系统知识的学习,就要先从它的核心——进程入手,通过进程将操作系统的知识串联起来,然后逐一击破。

到这里,请你思考一个问题:进程本身是做什么的?

给你一些提示,进程是程序的执行副本,操作系统用进程来分配资源。这里说的资源,就是 CPU 的计算资源、内存和磁盘的存储资源、I/O 设备的使用权等等。所以我们为了更好地学习操作系统,就需要知道计算机是怎么工作的,因此就需要一门前置课——计算机组成原理,我将在模块一把这部分内容给你讲解清楚。

最后,操作系统通常提供 3 类用户接口:

  • 给程序员用的 API,比如用 C 语言去调用;
  • 给运维人员和管理员用的 Shell;
  • 给大众用户的图形界面。

通常用 API 是为了定制操作系统的能力,如果你从事云计算、运维开发、嵌入式方向,那么一定会用到 API 。因为用户界面制作成本最高,能力也最少,所以大部分运维人员和管理人员都用 Shell。从这个角度分析,认真学习 Shell 有助于你快速掌握操作系统的基本功能,而且又不会太难。

以上就是操作系统课程的知识体系结构,你也可以通过目录,快速了解这个课程的内容设置。

目录.png

我是如何梳理知识体系的?

介绍完操作系统的知识体系,我还想借此再和你聊一聊我梳理知识体系的方法。

这是一套我运用多年的学习方法,它可以帮你节省时间成本,快速精准地查询到你需要的资料。这个学习方法有点像顺藤摸瓜,我自己称之为:“追溯源头、回归本质”。经过这样的思考,可以帮助你把知识学扎实,从而逐渐形成自己的知识体系。

我记得有一个技术大牛曾经说过,程序员最重要的是搜索知识的能力,我非常赞同这个说法,此外,我认为如果你想要长远发展,还应同时具备用结构化的思维去构建知识体系的能力。因为知识成体系后,会形成关联记忆和整体的理解,这种经过深度思考和梳理过的知识才能转化为自己的储备。

下面请你跟我一起进入到场景中,跟着我的思路把你的大脑运转起来。假设,在工作的过程中,我遇到了一块不懂的知识,其中有一个技术名词我不了解它的作用,比如 ReentrantLockLock,那么我该如何解决自己的问题呢?

注意: 你也可以把它替换成任意一个陌生的或者你不理解的技术名词。

首先我会去查阅它的官方文档,然后发现了以下这些线索:

  • 构造函数上有个参数在配置锁的公平性;
  • ReentrantLockLock 是可重入的;
  • 功能类似 synchronized 关键字,但是更灵活;
  • 支持 lock、unlock、tryLock 等方法;
  • 底层是 AbstractQueuedSynchronizer。

接着,根据我获得的知识,追溯 synchronized 关键字,发现 ReentrantLockLock 都说自己的底层是 AbstractQueuedSynchronizer(AQS),我感觉到 AQS 应该是一个重要的东西。

然后我会去查资料验证我的猜测。这时候,我又得到了一个新的信息:发现AQS是用来实现信号量、条件变量以及其他锁的一个编程框架。

假设我还不知道信号量、条件变量和锁是什么,于是我通过搜索资料,发现这些名词通通指向一门科学,也就是操作系统。

接下来,我会去挑选一门讲操作系统的在线课程或者买一本书来查阅,经过查阅发现这些名词出现在进程和多线程这个部分。然后我翻阅了这两个章节的内容,发现了更多我不知道的知识,比如死锁和饥饿、信号量、竞争条件和临界区、互斥的实现,以及最底层的 CPU 指令。

经过以上过程的推导,我开始在脑海中梳理这些知识点,然后动笔画出了一幅基于思考过程的思维导图,将这些知识点串联起来,如下图所示:

7.png

注意,上图梳理出来的知识关系不一定对,但是你一定要敢于去画,这个梳理和探索的过程能够带动你主动思考,锻炼主动解决问题的能力。

输出思维导图后,我将开始学习上面那些超出我现阶段知识储备的内容,然后进行归类和整理。

这时候,我发现公平锁、可重入锁其实都是锁的一种实现,而 Java 中实现锁这个机制用的是 AQS,而 AQS 最基本的问题是要解决资源竞争的问题。

通过学习,我发现资源竞争的问题在操作系统里叫作竞争条件,解决方案是让临界区互斥。让临界区互斥可以用算法的实现,但是为了执行效率,更多的情况是利用 CPU 指令。Java 里用于实现互斥的原子操作 CAS,也是基于 CPU 指令的。

操作系统在解决了互斥问题的基础上,还提供了解决更复杂问题的数据结构,比如说信号量、竞争条件等;而程序语言也提供了数据结构,比如说可重入锁、公平锁。

经过一番探索,我终于弄明白了,原来实际应用场景中对锁有各种各样的需求,因此不仅仅需要信号量等数据结构,甚至还需要一个快速实现这种数据结构的框架,这个框架就是 AQS。我们可以用 AQS 实现 ReentrantLockLock 的功能。

Lark20200907-165512.png

通过上面的方法,我不仅仅可以把 ReentrantLockLockt 学透,而且顺藤摸瓜找到了所有关联的知识点,比如 AQS 和 CAS。比起理解最初的知识点,更重要的是我通过这种方法形成了自己的一个知识体系;而且,我会发现在这个知识体系中,操作系统是起到支撑作用的骨架

与此同时,我还认识到了计算机语言和操作系统之间的联系非常紧密,操作系统知识是学习计算机语言的根基。于是我开始制定学习计划,投入时间学习操作系统。我更偏爱做一次性的时间投入,以防止日后碎片化学习做多次投入,陷入时间黑洞,而这个嗜好让我受益良多。

寄语

最后,希望今天的课程和学习方法可以帮助到你;也希望你平时遇到未知的问题,尝试使用我今天介绍的方法,学会构建自己的知识体系,提高自己的学商。你可以在留言区给自己立下 Flag,比如给自己定一个具体的目标,或者是打卡你的学习天数,总之希望你不要一看而过,留下你的思考。经过长期的积累,相信你会得到意想不到的收获