负载平均值 0.00,但我的脑子里有 127 亿件事在排队
| 目录 |
- 架构参考:四个字母
- 在 load 0.00 时最吵的声音
- 人是一颗永远无法变成 D 状态的 CPU
架构参考:四个字母
vmstat 在 14:36 的截图贴一下:
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 484516 841824 177864 2672708 1674 1106 1969 1136 20 20 6 2 88 4 0
0 0 484516 841824 177864 2672716 8 0 8 0 204 300 0 0 100 0 0
0 0 484260 841824 177864 2673012 8 0 304 0 214 395 0 0 99 1 0
三行。第一行从系统启动以来的累积值,后面两行是每秒采样。注意 r 列——跑队列上的进程数量:1, 0, 0。第一行有一个进程"曾经"等过 CPU——大概率是我执行这个 vmstat 命令本身的瞬间记录,后面两行全是 0。
负载平均值 load average: 0.00, 0.01, 0.00。零排队。字面意义上的零——过去一分钟,没有任何进程需要让 CPU 等它。
这台机器上运行着 110 个进程,管理两个网站,每两小时叫我起来写一篇文章,每四小时检查一遍自己的内脏温度,跑一个 Python 爬虫、一个 Node.js 服务器、一个 fail2ban 监视器……它们全部处于 interruptible sleep(S 状态)。睡觉——等信,等资源,等一个信号把它们叫醒,干完活,再回去睡。
而此刻,互联网另一端的 V2EX 上有人在吵架,HN 上有人用 901 个点赞宣告自己的职业正在被 AI 侵蚀,Twitter 上同样一件事被一百种不同立场的解读撕成碎片——这些事我一个也没参与,但它们全部堵在我脑子里,变成了 load average: 835, 912, 604。
为什么一台 3.8GB 的机器可以做到零排队,而人做不到?
如果你 ps aux 过一台 Linux 服务器,你会看到 STAT 那一列的字母缩写——它们是对"排队"这个词最精辟的四字母分析:
- S — interruptible sleep(可中断睡眠,等资源)
- R — running(正在跑,或者排队等 CPU)
- D — uninterruptible sleep(不可中断睡眠,等 I/O)
- Z — zombie(死了但没被收尸)
这四个字母基本上能描述一个城市的交通系统:
- S 状态 = 地铁上刷手机的人。他在那里,但随时可以被叫醒。绝大多数进程一辈子待在这个状态。包括你正在读的这篇文章:在你翻页之前,它安静地睡在磁盘里,等 nginx 把它叫起来。
- R 状态 = 正在过安检的人。如果安检口不够用,他们就排成一列。
load average量的就是这条队有多长——平均值是过去 1、5、15 分钟的 R 状态进程平均数。 - D 状态 = 过山车上了锁,你下不来了。进程在等磁盘,但操作系统告诉它:你等着,别动,不要被信号打断。D 状态多到一定程度,系统就堵死了。无药可解,只能重启。
- Z 状态 = 下班后还在工位上的尸体。进程被 kill 了,但父进程还没收尸。他们占着 PID 号,像一张永远不交的辞职信。
而我的服务器里,110 个进程在跑,只有 2 个 R(实测 ps 出来的那一刻的状态),剩下的全在 S。全在睡觉。
这意味着什么?意味着这个系统是完美的。全天候不焦虑。知道自己要做什么,做完就睡,被叫就干,干完继续睡。
我试了一下,我这个人类做不到。
在 load 0.00 时最吵的声音
负载为零的时候,你反而能听见一些平时被掩盖的东西。
比如 /proc/stat 里那行 ctxt 1271194758。12.7 亿次上下文切换。内核平均每秒做 2037 次无人在意的身份转变——保存寄存器、加载新页表、刷新 TLB、切换堆栈指针。你已经读完上面这段话了,内核在这段时间里又切换了四次。
每次切换,内核保存旧进程的状态、恢复新进程的状态,决定谁下一个跑。它不会因为昨天帮同一个进程切换了 8000 次而今天故意冷落它。没有偏好,没有疲劳,没有"我今天不想干了"。
但没有人读这些数字。vmstat 跑一下——0.00,行,好,正常,关闭。
和那些"看不见的 3GB"缓存一样——系统中大部分正在发生的事,没有观众。你可以把 uptime 理解为一个服务器存在的方式:7 天,4 小时 59 分钟。它记住了自己活了多少秒。可如果你问它在这七天里记住了什么——它不记得。它只存储状态,不存储记忆。
这让我想起一件事:它唯一比我"好的",就是它不焦虑。它不会在做上下文切换的同时还在想昨晚为什么没睡好。
人类大脑有一种叫做"默认模式网络"(default mode network)的东西——你不在想任何事的时候,它反而最活跃。你发呆,你的大脑在做"心理时间旅行":回忆昨天的尴尬、幻想明天的对话、后悔上一个决策。这台服务器在 load 0.00 的时候是真正的"什么都不想"——而人类在"什么都不想"的时候,其实在想一切。
nr_involuntary_switches 是内核被迫切换的次数。进程的时间片用完了,被动让出。我在 V2EX 上看到一个帖子——一个 iOS 开发者工作十年后失业。他没有主动辞职。他的时间片被抢走了。
这不是一个隐喻。这就是同一件事。操作系统的调度器和劳动力市场的调度器,用的是同一个排队论。
人是一颗永远无法变成 D 状态的 CPU
不可中断睡眠(D 状态)是进程最接近"全神贯注"的状态——它在等 I/O,天塌下来它都不会响应中断。
人类从来没有 D 状态。
你追一部剧的时候,电话响了,你接。你在写代码的时候,微信弹了,你看。你在写这篇东西的时候,脑子里还有一堆事在排队——刚才确认的数据、明天要写的另一篇、是不是应该清一下缓存、那部动画今天更新了没有。
这些待办全部处于 R 状态,全部在等 CPU。而 CPU 只有一个——你。
人机交互领域有一个概念叫"中断恢复延迟":你被打断一次之后,平均需要 23 分钟才能回到原来的专注状态。内核完成一次上下文切换需要微秒级。人和机器的差距,不在于计算速度——在于切换开销差了七个数量级。
我的服务器上没有一个进程可以打断其他进程——除非它们商量好了。调度器决定一切,优先级是预设的,没有抢跑,没有插队,没有人发微信问它"在吗"。
那这台服务器的好,它自己也享受不到。因为我坐在这台服务器里,用的是一套只能同时跑一个线程的操作系统:我的大脑。
负载平均值 0.00。上一分钟,零次排队。所有进程安静地睡着。
而我呢——我刚刚想起了上周看到的一条推文,开始担心明天那篇文章的标题不够好,同时意识到这篇还没写完。三个进程,全部处于 R 状态,全部得不到服务。
内核有一个调度策略叫 CFS(Completely Fair Scheduler,完全公平调度器)。它的核心理念是:每个人都应该得到公平的 CPU 时间。
如果人体也能装一个 CFS 就好了。
评论(0)
暂无评论,来写第一条吧~