三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

南京大学 操作系统 (JYY) 学习笔记:从虚拟机、容器到 Serverless 的云端演进

南京大学 操作系统 (JYY) 学习笔记:从虚拟机、容器到 Serverless 的云端演进

写在前面:这是本系列的第二十七篇。

进程(运行的程序),一直以来都是操作系统中的核心抽象。作为应用程序的主体,运行它的方式却在多年的发展中历经了翻天覆地的变化。

本讲内容:我们将跳出单台计算机的视角,看看应用程序是如何打破物理机器的枷锁,最终在海量数据中心里实现极致的虚拟化与云原生调度的。

虚拟机和容器:虚拟化与隔离

Full System Emulation (全系统模拟)

  • 这个概念其实很简单,就是我们在实验里做的NEMU啊:取指令、译码、执行。
  • 致命的缺陷是性能: 纯软件模拟的性能通常不及 native 原生运行的 10%。

NEMU:一个虚拟的计算机?
在电脑上用纯软件模拟出其他设备或系统的运行环境。
让一些程序或系统以为自己是在真实的硬件上运行,但实际上它们是在电脑上通过 NEMU 模拟出来的环境中运行的。

Full System Emulation 的黄金时代

背景科普:httpd 的 CGI(通用网关接口)是一种早期的 Web 开发技术,允许 Web 服务器运行外部程序,并将用户请求传递给这些程序,然后将程序的输出返回给用户。

黄金时代的起点:

  • Disco (1997): “brings back an idea popular in the 1970s: virtual machine monitors” (让 1970 年代极其流行的虚拟机监视器技术重回大众视野)。
  • VMWare (1998): 我们能把这个硬核技术直接做成商业产品!

Hack 原理:Guest Ring 3 直接运行在 Host Ring 3

  • 虚拟机里的应用程序依然在真实的 CPU 上全速执行,但一旦触发 System call,就会 trap(陷入)到宿主机的 VMM(虚拟机监视器)中去拦截处理。
  • 类似的实现:Windows Subsystem for Linux (WSL 1.0, 2016)。
  • Xen and the art of virtualization (2003): 可以把操作系统内核改一改(半虚拟化)来配合 VMM 提升性能。
  • 最终硬件厂商下场:Intel 提供了 VT-x (2005) $ \rightarrow $ VT-d (2006) $ \rightarrow $ EPT (2008) 等强大的硬件虚拟化支持。
  • (我们之前讲过的/dev/kvm就是利用了这些硬件特性)。

/dev/kvm是 Linux 系统中的一个设备文件,用于支持硬件加速的虚拟化。它是 Kernel-based Virtual Machine 的缩写,允许用户空间程序利用 CPU 的硬件虚拟化特性来全速运行虚拟机。

虚拟化完全体:EPT 2008 (扩展页表)

八级页表:四级页表在物理机,另外四级页表在虚拟机上。硬件 MMU 会直接在虚拟机里构建这套极其复杂的地址翻译。

为什么会有黄金时代?

Dot-com bubble 互联网泡沫时代 (2000 纳斯达克泡沫)

  • 以前的 ISP (Internet Service Provider) 提供的是真实的物理机
  • 虚拟机的出现改变了游戏规则:它和物理机用起来完全一样,但一台高配物理机能当 $ n $ 台虚拟机卖!
  • 黑心商人的玩法:Oversubscribe (超分/超卖)
    • 通过超量分配,服务提供商可以将一台物理机当作几十台虚拟机出售,大幅减少闲置资源,利润起飞(当然如果大家同时占用资源,就会严重破坏用户体验)。

Everything is a State Machine…

NEMU 本质上也就是一个进程。想要保存虚拟机的状态?做一个 core dump 即可!
核心转储是程序运行时的内存快照,如果你怀疑运行出了问题,可以直接捕获其运行时状态,然后用 GDB 回溯分析。

虚拟机:更容易管理状态了!

  • 时间转移 (Replay):记录下虚拟机所有的非确定性输入,就可以“instruction-by-instruction”完美重放整个系统的执行过程(OSDI’02 ReVirt)。
  • 空间转移 (Migration):可以把一台正在运行的虚拟机内存状态,通过网络热迁移到另一台物理机上,几分钟内无缝切换,服务甚至不会中断(OSDI’02)。

Hackers 的时代

  • 图中是华为操作系统首席科学家;上海交通大学 IPADS 所长(陈海波教授)。
  • 他的经典论文:Live updating operating systems using virtualization (VEE’06),利用虚拟化技术给操作系统内核打在线热补丁。

浪潮过后:容器化的崛起

操作系统:我自己就能虚拟化自己啊!

  • 应用程序其实只能看到“系统调用 API”。
  • 操作系统如果“假装”在虚拟机里为你执行系统调用,不就行了吗?
  • 例子:虚拟的 pstree
    • 在你的环境里,你看到的pid = 1是属于你的init进程。

这就是容器化技术:

  • 在同一个操作系统内核上,运行多个隔离的用户态环境。
  • 每个环境有自己独立的文件系统、网络接口和进程空间。
  • 容器化技术底层利用了Linux 的命名空间 (Namespaces) 和控制组 (cgroups)来实现资源的绝对隔离。

祝贺,你发明了 Linux Namespaces!

pid没必要是整个操作系统唯一的。

  • 给每个进程增加一个“osid”,然后增加一个系统调用vos(fs_root)
  • 创建一个新的 osid 后,这个环境里的pid就可以重新从 1 开始分配。fork()出的子进程自然继承父进程的 osid。

只要顺着想:“操作系统里还有什么对象需要隔离?”

  • 需要为不同 osid 隔离实现的对象包括:
    • pid: 进程编号。
    • user: 用户和组 (隔离 uid 权限极其重要)。
    • mnt: 文件系统和挂载点。
    • ipc: 信号量、消息队列、共享内存。
    • net: 网络设备、协议栈、端口 (让你可以在每个容器里都监听localhost:5000)。
    • time: 系统时间和时区。
    • uts: 主机名和域名。
  • Linux namespaces 底层全在/proc/[pid]/ns/目录下。
  • 你甚至可以用lsnsstrace去窥探这些隔离魔法。

Namespaces 核心 API

Linux 命名空间是一种内核特性,使得每个命名空间中的进程看起来像是在一台独立的机器中运行。

  • clone: 创建进程时带上CLONE_NEW_xxx(PID, IPC…) 选项,直接生在一个新空间里。
  • setns,unshare: 强行改变当前进程的“osid”,把它丢进隔离区。
  • Windows Subsystem for Linux (WSL 1) 听完后直呼放弃:要我在 Windows 内核里翻译实现这一整套 Linux 容器的 ioctl 和 namespaces,我选择死亡(所以 WSL 2 干脆切成了真正的轻量级虚拟机)。

在今天,由于这些系统调用的语义已经被容器极度依赖,你想要再修改 Linux 内核相关特性,变得极为困难。

再进一步:资源调度与 Cgroups

实现了环境隔离还不够,还得实现资源的控制

  • “圈一批进程”,硬性设定它们最多能用多少 CPU 和内存。
  • 祝贺,你发明了 cgroups (Control Groups)!
    • cgroups 是 Linux 内核特性,用于对进程组进行物理资源分配和限制(CPU 时间、内存使用量、磁盘 I/O 等)。
    • 配置全在/sys/fs/cgroup目录里,修改文本文件就能限制算力。

这是一个和 Namespaces 完美正交的机制!

  • 将 Namespaces (环境隔离) + Cgroups (资源限制) 共同使用,你就得到了现代的容器 (Container)
  • 例子:搞一个只有busybox的“系统中的系统”。
  • 祝贺,你发明了 Docker!

云时代的虚拟机 vs 容器

  • 如果只需要运行 Linux 环境:
    • 容器在体验上和虚拟机完全一样
    • 但它的开销比虚拟机低非常多(没有冗余的 Guest 内核,直接复用宿主机内核),虽然安全性略低。
    • 这样一台物理机上就能部署数量恐怖的服务。黑心商人的赚钱机器再一次升级!
  • Kubernetes (K8s): “容器编排”
    • 单机搞定了,跨主机的海量容器怎么办?
    • K8s 提供了极其强大的跨主机弹性自动编排。
    • 自动容错:检测到某个节点上的容器挂了,光速在另一个健康节点重新拉起。这是云厂商最爱看到的全自动化运维。

云原生与微服务:Serverless 的终局

舞台已经搭好了

有了极度轻量的容器,软件的开发和部署模式随之发生巨变:

  • 以前我们把整个庞大的 Web Server 塞进一个沉重的虚拟机里。
  • 现在有了秒级启动的容器,干脆把庞大的单体程序拆成成百上千个微小的Microservices (微服务)
  • Cloud Native (云原生):云厂商会帮你把容器管理、API 网关、服务发现、负载均衡……全套搞定。

Serverless (无服务器计算):连“容器”的概念都可以不要了

  • 你根本不需要去管什么操作系统、端口监听和容器镜像。
  • 你只需要实现一个简单的函数int foo() {}
  • 剩下的网络监听、并发扩容,全交给云厂商。
  • 厂商也极其开心:连 oversubscribe 都不需要了,直接按调用次数和毫秒时长计费!最小化颗粒度,最大程度榨干物理机器的每一丝性能。

Function-as-a-Service(FaaS,函数即服务)

FaaS 是 Serverless 的核心实现形式:

  1. 编写/部署函数:开发者写好代码片段丢到云端。
  2. 事件触发:当 HTTP 请求或数据库更新发生时,平台光速拉起一个环境执行这个函数。
  3. 释放资源:跑完立刻销毁,绝不占用 1 KB 多余内存。

极简的资源单位,换来的是极致的商业利益!

利用 RPC (Remote Procedure Call) 远程调度能力:

RPC 允许一个程序像调用本地函数一样,跨网络去调用另一个云端函数,而无需关心底层的 TCP/IP 通信细节。

比如调用阿里云的云函数去跑笨重的ffmpeg处理音视频:

defget_media_data(object_key):client=fc2.Client(endpoint="https://<id>.cn-hangzhou.fc.aliyuncs.com",accessKeyID="xxxxxxxx",accessKeySecret="yyyyyy")# 发起跨越物理机器的 RPC 调用!returnclient.invoke_function("FcOssFFmpeg","GetMediaMeta",payload=json.dumps({"bucket_name":"test-bucket","object_key":object_key})).data get_media_data('/object/key/to/a.mp4')

再加上 CI/CD (持续集成/持续交付) 自动化

  • 开发者只需要git push,剩下的一切(打包、灰度测试、部署)全自动流水线完成。
  • 例子:我们课程的官网ics.nju.edu.cngit push会触发 Webhook HTTP 请求,带着鉴权 Token 呼叫服务器,服务器瞬间完成静态网站的重新编译和无缝发布。

未来:“计算机”会消失吗?

当算力全部集中在云端,我们真的只需要一块屏幕(终端)吗?

# 未来的编程可能长这样:直接向 AI 索要结果response=OpenAI().responses.create(model="gpt-4.1-mini",input="Generate an image of a cat and an otter...",tools=[{"type":"image_generation"}],)
  • 随着大语言模型的爆发,“AI Inference (推理)” 占程序运行总时长的比例正在疯狂飙升。未来的操作系统,会不会演变成专门用来调度和分发 AI 算力的底座?

总结

Take-away messages:

透过虚拟化几十年的发展浪潮,我们看到了从笨重的全系统虚拟机,到轻量的 Docker 容器,再到今天大道至简的 Serverless 云函数。

“计算机系统”作为最核心的支撑性技术,一次次给应用世界带来了彻底的降维变革。有趣的是,那些最终改变世界的技术,最初往往只建立在一些极简的极客动机上——例如“如果全系统模拟真的可以运行得很快会怎样?”,或是“如果我们给每个操作系统对象加上一个隐形的 osid 标签会怎样?”。

就是这些看似微小的奇思妙想,最终坚持到底,彻底重塑了今天庞大的数字世界。

← 返回列表