ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

零基础学Linux内核:从环境搭建到问题定位的完整学习路线

零基础学Linux内核:从环境搭建到问题定位的完整学习路线 “零基础能不能直接啃Linux内核”“学内核到底要从哪本书读起”“为什么内核出了问题我连日志都不知道去哪看”后台每隔几天就会收到类似的问题。我干脆把话撂在这儿Linux内核没有你想象中那么玄它就是一堆跑在CPU上的普通C代码但它又确实和你平时写的业务代码不一样——它不依赖任何库、不依赖任何进程一开机就得把自己撑起来然后给所有进程当管家。写这个《Linux 内核专栏》就是想把这条学习路线完整铺开从环境搭建、源码阅读、机制拆解一直讲到问题定位和面试实战让零基础和半路出家的人都能找到一条走得通的路。这篇先当总目录给你一张完整的地图。1. 内核没那么玄它就是一个带权限管理的超级常驻进程很多人一听到“Linux内核”四个字就发怵觉得那得懂汇编、懂计算机体系结构、懂微内核宏内核之争才有资格碰。我的观点恰恰相反学内核的第一课是先把它还原成一个“程序”。1.1 内核也是程序只不过它编完就常驻内存你平时写的程序跑起来是一个进程有虚拟内存、有代码段、有堆栈。其实Linux内核本身也是一个“程序”只不过它编译完之后不会像普通程序那样启动一下就跑完了事。系统上电后引导程序把内核镜像加载到内存内核把自己初始化一遍然后就是一个永不退出的“超级常驻进程”。它没有退出代码不会在某个时刻return因为只要它在系统就在它一panic整台机器就没了。理解这一点之后很多恐惧就消失了。你不需要从零开始发明操作系统你只需要学会“读一个大型C程序”。这个程序规模大一点几千万行但你真正需要精读的核心路径也就那么几条。学会跟着一条路径走到底比背一百个晦涩概念有用得多。1.2 系统调用就是内核给用户态开的服务窗口用户态程序想读文件、发网络包、申请内存都是走系统调用syscall这个“服务窗口”去请求内核。你可以把内核想象成一个高级别的“管家”用户态进程是“住客”住客不能自己随便动硬件因为那样会乱套你碰我的内存我碰你的文件系统早崩了。所以住客要什么就打一个申请单给管家管家检查权限、分配资源、把事情办完再把结果返回。这个“检查权限、分配资源、办事情”的过程就是内核的核心逻辑。比如你执行一条ls命令实际发生的事是shell进程fork出一个子进程子进程调用execve把ls的代码加载进来ls再调用open、read这些系统调用去目录里读文件名内核在VFS层找到对应文件系统从磁盘读数据放到page cache再把数据拷贝回用户态缓冲区最后printf把内容打到屏幕。这一整条链路就是内核源码的“主路交通”。1.3 内核缓冲到底是什么热词里有“内核缓冲”这个搜索词很多人其实是看到page cache、缓冲区这些概念被搞晕了。我这么说吧读一个磁盘文件如果每次读都直接访问磁盘机械盘随机读只有几毫秒你应该能感受到那卡顿。内核的做法是把读过的磁盘数据暂存在物理内存里这块缓存就是page cache也就是平常说的“内核缓冲”。下次再读同一个文件直接命中内存速度提升几个数量级。理解内核缓冲对排查问题非常关键。你free -h看到内存占用很高别急着找哪个进程在吃内存很可能就是page cache把内存“借用”了。它在内存紧张时会自动回收这就是内核的“先缓存、再淘汰”逻辑。专栏后面讲内存管理时会专门把page cache的分配、回收、脏页回写这条线完整讲一遍。2. 开工前先养实验田虚拟机、镜像与第一次内核编译看内核源码不能只看你必须亲手编译一个内核、亲手把它跑起来。这是整个专栏的第一个硬性门槛也是最容易被新手跳过的一步。我的建议很明确你不可能用公司的物理机也不建议一开始就搞双系统先在虚拟机里圈一块实验田把内核编译这件事彻底跑通。2.1 为什么必须用虚拟机原因很简单内核开发是高风险操作。你改一个调度参数、加载一个模块、开一个调试开关都可能让系统直接panic。在虚拟机里挂了就快照回滚整个流程零成本。另一个原因是虚拟机方便你串流程装系统、下镜像、编内核、引导新内核、打断点调试每一步都可以清晰拆开不会因为硬件兼容性问题分心。选虚拟化方案我用过三套给你一个对比方案优点缺点建议VMware Workstation / 个人版成熟稳定Windows下最顺闭源独占性较强Windows用户首选VirtualBox免费开源扩展包安装方便大版本更新偶发兼容问题预算有限时的备选QEMU/KVM和内核调试无缝结合能直接连GDB命令行操作门槛略高想深入调试的必学关于“虚拟机安装linux蓝屏”这个热词我见过的大多数情况是Hyper-V或VirtualBox的嵌套虚拟化开关没开或者ISO文件没校验下载的镜像不完整。装之前先检查两个事虚拟化是否在BIOS里开启镜像是否用官方SHA256校验过。2.2 发行版镜像怎么选“linux镜像”“linux镜像安装”这两个热词搜的人特别多。我直接给结论纯学习内核装一个Debian系或Ubuntu LTS就够了社区资源多遇到问题一搜就有答案。如果你未来想去国产化、信创方向openEuler、统信这些发行版的内核侧工作也基本是围绕上游内核做特性和加固用openEuler做实验环境也是一个不错的选择。镜像下载优先走国内源别去官网硬挤。你下载完Debian或Ubuntu的ISO在虚拟机上装好系统之后先别急着apt装一堆东西先做一件事把内核源码拿到手。2.3 第一次编译内核完整走一遍这是我建议每个学内核的人都必须经历的第一课。命令不难但意义很大——编译过程会把“内核不是一个app”这种感觉直接拽到你眼前。# 以 6.1 LTS 版本为例也可以去 kernel.org 选其他长期支持版 wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.1.100.tar.xz tar xf linux-6.1.100.tar.xz cd linux-6.1.100 # 先用发行版现有配置打底保证能编出一个能启动的内核 cp /boot/config-$(uname -r) .config make olddefconfig # 如果不想折腾配置直接 make menuconfig 进去浏览一圈也行 make menuconfig # 编译并用多核加速注意虚拟机内存留够 4G 以上 make -j$(nproc) bzImage modules # 安装模块和内核 sudo make modules_install sudo make install # 更新引导 sudo update-grub # 重启后就进新内核了 reboot uname -r第一次编译我强烈建议你盯着屏幕看它跑几分钟。你会看到那是一个“编一个完整操作系统”的过程不是编译几行代码。遇到报错不要慌九成是缺依赖比如flex、bison、libssl-dev、bc这些按提示补齐重编就行。2.4 “内核裁剪”不是八股是功能取舍热词里有一个很有意思的词叫“linux内核裁剪八股”。裁剪这个事在嵌入式领域是刚需一块开发板就128MB Flash你不可能把完整内核塞进去就得根据硬件砍掉不用的驱动、协议、文件系统留下能跑的最小集合。学了内核裁剪绝不是背几个menuconfig选项而是学会分析“这块板子上到底需要哪些子系统”。嵌入式方向的同学注意嵌入式linux项目和嵌入式内核源码这些热词背后是同一个诉求你想维护一款产品级嵌入式系统就得掌握内核配置、设备树、驱动模块、根文件系统构建这套完整链路。这个专栏后面会用专门章节讲最小系统裁剪和Buildroot的使用你在虚拟机里就能练不需要立刻买开发板。2.5 调试环境提前备好只编译还不够你还要学会“看内核内部”。我推荐的组合是QEMU GDB以及VSCode Remote SSH。QEMU可以把内核以客户机方式跑起来GDB在主机侧挂上去设断点这样内核执行到某个函数时就能停下让你看变量。网上有些教程让人直接在虚拟机里装kgdb配置繁琐桌面环境也容易干扰不如QEMU轻量化。# 用 QEMU 直接启动刚编译的内核调试端口开在 :1234 qemu-system-x86_64 \ -kernel arch/x86/boot/bzImage \ -hda disk.img \ -append consolettyS0 nokaslr \ -nographic \ -s -S # 另一个终端启动 gdb gdb vmlinux (gdb) target remote :1234 (gdb) break do_sys_open (gdb) continue需要提醒的是QEMU调试需要内核把CONFIG_DEBUG_INFO打开建议编译时在menuconfig里把Kernel debugging那组选项全开。nokaslr参数也必须要否则内核地址随机化会让断点打不上。这个过程以后会单独写一篇这里先把环境骨架立起来即可。3. 专栏总目录按主线而非知识点铺的学习地图既然这篇是总目录我就把整个专栏的结构完整列出来。市面上的书和课程大多是按章节罗列知识点进程管理、内存管理、文件系统一个个讲读者看完常常觉得“每个概念都知道串不起来”。我这套专栏的思路不一样按一条主线走那就是“从用户的一次请求出发追踪内核到底做了什么”。后面每个部分都会对应一条可追踪的路径。3.1 主线总目录部分对应章节核心内容你最终能解决什么问题第一部分环境与工具链虚拟机、内核编译、QEMU/GDB调试、VSCode远程开发容器能亲手编译并启动一个自研内核第二部分进程管理task_struct、fork/exec、调度器CFS、上下文切换能讲清楚“进程是怎么生、怎么死、怎么被调度”第三部分内存管理页表、malloc背后、page cache、缺页异常、OOM能定位“内存被谁吃了”以及OOM问题的根因第四部分文件系统与块层VFS、ext4/xfs、dentry、inode、bio能理解文件读写链路处理文件IO卡顿第五部分网络协议栈sk_buff、TCP/IP收包发包路径、netfilter能从内核侧理解网络延迟和丢包第六部分中断、时间与同步硬中断/软中断、上下文、自旋锁、RCU能理解系统卡死的底层机制读懂hung task第七部分驱动与内核模块模块编写、字符设备、platform总线、设备树能写一个自己的内核驱动并加载到系统第八部分虚拟化与容器KVM、cgroup、namespace、容器逃逸视角能理解容器和虚拟机的隔离边界在哪第九部分问题定位与调优dmesg/crash/systemtap/perf、vmcore分析能接手真实内核故障并独立排查第十部分面试题与源码方法论高频面试题拆解、阅读源码的路径方法能把内核知识转化为面试表达与工作产出这张表就是你未来几个月的路线图。你不需要从头到尾全读比如做业务开发的人重点把第二部分、第三部分、第五部分和第九部分过一遍就足够建立底层认知做嵌入式的人重点在第二部分、第七部分和内核裁剪专题做运维和SRE的人重点在第八部分、第九部分和常用命令链路。3.2 为什么按主线而不是按知识点我遇到过很多自学内核的人花三个月把《深入理解Linux内核》啃了一半最后发现自己还是不会干活——知识点太多优先级不知道在哪里。按主线走就不一样了你始终带着问题读源码“我执行一条命令进程怎么被创建”“我malloc一块内存内核怎么给物理页”“我打开一个文件哪个函数在做实际工作”带着问题读源码的效率是漫无目的刷知识点效率的三倍以上。每讲完一条主线我会给你留一个动手实验比如“写一个小模块统计你自己写的进程被调度了多少次”“用ftrace追踪一次read系统调用的完整路径”。这些实验做完知识才是你的。4. 先啃三块硬骨头进程、内存与文件系统的阅读顺序从总目录看内容很多但如果你坚持要我从一个地方开始我的答案永远是进程管理 → 内存管理 → 文件系统。这三块是内核的“任督二脉”摸清任意一条链路其他子系统你都会有打通的感觉。4.1 进程管理task_struct就是进程的“身份证”内核里描述一个进程靠的是一个巨大的结构体叫task_struct里面存放了进程的ID、状态、内存描述符、文件描述符表、信号处理函数、运行统计信息、调度实体等几十个字段。通俗点说只要系统里有一个进程内核就维护这么一张“身份证”卡片。阅读源码时你不需要把task_struct的每个字段都背下来但要养成一个习惯看到一个字段就问它是给谁用的。比如comm字段存的是进程名pid字段是进程号parent是父进程指针children挂着子进程链表。下次你ps aux看到的所有信息几乎都能在task_struct里找到对应字段。这种“用户态命令 → 内核字段”的对应感是读内核最有效的锚点。4.2 内存管理malloc背后是一场“挂账”交易你自己写个程序malloc(1MB)你以为内核立刻就给你1MB物理内存不是的。用户态malloc在glibc里通常会走brk或mmap系统调用内核只是在你进程的虚拟地址空间里画一块区域记到VMA链表里物理页一个都不给。真正的分配发生在你写这块内存的一瞬间——CPU访问这个地址发现页表里没有映射触发缺页异常内核才临时找一页物理内存填上然后更新页表。这个机制的官方名字叫惰性分配demand paging它的意义体现在你申请大内存并不一定真的占用物理内存只有真正读写的时候才占用。这也是为什么用top看物理内存占用常常和程序实际“申请”的内存对不上原因就在这。书里讲这么多内存管理的细节落到实操上就是为了让你理解“内存到底去哪了”这个经典运维问题的答案。4.3 文件系统一切皆文件的入口在VFS文件系统是个特别容易被绕晕的地方因为Linux支持ext4、xfs、btrfs、tmpfs等一堆文件系统每个实现都不同。好在内核在最上层设计了一个VFS虚拟文件系统层它对上层提供一个统一的接口open、read、write这些系统调用先经过VFS再由VFS调到具体文件系统的实现函数。这个设计的思想其实和“面向接口编程”很像内核上层不关心底下是ext4还是xfs你只要实现了VFS要求的那些接口——inode操作、文件操作、目录操作——你就能成为Linux支持的一个文件系统。这种“统一入口多种实现”的套路你在学网络协议栈、块设备层时还会反复看到。4.4 阅读顺序的具体建议我建议你按“进程创建流程、调度器核心、页表与缺页异常、VFS文件打开路径”这个顺序逐条读。遇到不懂的概念先不求甚解绕着主线再走一遍往往第二次读就通了。源码文件路径我也给你列好进程kernel/fork.c、kernel/sched/core.c内存mm/mmap.c、mm/page_alloc.c、mm/khugepaged.c文件系统fs/open.c、fs/read_write.c、fs/namei.c我当年第一次看fork.c时以为那么复杂的东西一定得提前学完编译原理才能懂后来发现完全不是。fork.c的核心就是复制父进程的task_struct和内存描述再加进调度器代码条理非常清楚。逼自己读三轮三轮之后你会有明显不一样的感觉。5. 学了一半就能用内核问题定位与常用运维链路学了内核不只为了面试更为了解决实际问题。很多做运维的同学搜“linux运维故障案例”“定位内核问题”说明真实的痛苦已经在工作里遇到了。我在这里先讲一套通用排查方法论细节在专栏第九部分展开。5.1 内核出错的第一现场日志普通程序崩了会打印个堆栈你能看到它死在哪儿。内核崩了panic就直接黑屏或者转圈圈除非你提前配置了串口控制台或kdump否则什么日志都留不下来。所以生产环境第一件事确认kdump和crash工具的配置是好的保证系统一崩能留下vmcore文件这是内核问题的“黑匣子”。平时排查问题日志优先级是这样的dmesg内核自己的环形缓冲区日志覆盖硬件识别、驱动加载、OOM、软死锁等信息journalctl -ksystemd环境下查内核日志更带时间戳/var/log/messages或/var/log/syslog部分发行版的内核日志也会落到这里我见过许多人的排查习惯是上来就先free、top折腾很久才想起来看dmesg结果一条“Memory cgroup out of memory”早就说清了原因。看完dmesg再动手永远是排查内核相关问题的第一步。5.2 典型案例内存明明够却被OOM Kill了有一次我们在测试环境压一个Java服务Java进程起来不到十分钟就被杀掉了。dmesg里直接看到“Out of memory: Killed process 1234 (java)”。但当时free看物理内存还有十几个G空闲为什么会OOM答案是“可回收内存不等于可无限回收”。内核在OOM判定时主要看一个指标当前内存是否处于“cgroup限额内耗尽”或“超量承诺”。那次是容器cgroup内存上限设置得比Java堆还小物理机内存再多也没用。这个问题的根因不在物理内存而在内存控制组配置。类似这种“表象在业务层、根因在内核层”的问题没有内核知识你是很难定位的。再来一个常见案例进程进入D状态不可中断睡眠怎么都kill不掉。D状态说明进程正在等待内核IO完成比如磁盘在硬错误重试、NFS挂载的网络断了。此时kill命令不生效因为进程根本不在可唤醒状态。正确做法是先用iostat -x 1看磁盘是否堵死再lsof查进程打开的IO路径解决底层IO问题进程才会活过来。强杀不掉就等等IO超时这是内核的自我保护机制不是bug。5.3 运维常备命令链路热词里有“linux常用命令”“linux删除文件夹命令”“linux 让后台运行指令 不因界面退出而退出”“linux查看系统时间同步时间”这些都是实际干活最常碰到的场景。我整理几条使用频率极高、又容易踩坑的删除文件夹和文件被占用有时候rm一个文件提示“Text file busy”或“Device or resource busy”说明有进程正在使用它。先lsof 文件名查谁在占用再决定是清空重定向还是重启进程释放。清理大日志我惯用 nohup.out而不是直接rm因为rm之后进程持有的文件句柄还在磁盘空间不会立刻释放。后台运行不随会话退出SSH登录后跑一个长任务一关终端任务就没了这是因为收到了SIGHUP信号。常用解决办法是nohup command 更推荐用tmux或screen把会话真正“托管”在系统里下次ssh还能接上。这是运维基本功按规律用的多了你自然就把进程会话和信号机制这几块内核知识串起来了。时间同步timedatectl查看系统时间和时区同步时间用chrony或ntpdate。时间不同步会导致很多诡异问题比如证书校验失败、日志时间对不上、分布式系统心跳超时。排查顺序date看时区 → timedatectl status看同步状态 → systemctl status chronyd看服务状态。5.4 常用热词背后还有一些实用工具搜“linux alternatives”的人多半是装了多个版本的Python或JDK后发现命令行指向不是自己想要的那个。这时用update-alternatives就能管理软链接优先级比如sudo update-alternatives --config python3。这个东西本身不复杂但它能培养你“命令也是文件链接”的意识和内核里/sbin路径解析是同一套逻辑。搜“linux 系统如何安装 hermes desktop”这类具体软件安装问题的我的建议是按官方文档走别信一键脚本。6. 面试与职业方向内核知识在哪几个岗位真正算加分项最后一个部分聊点现实的。学Linux内核的人很多不只是为了兴趣还为了面试和职业跃迁。热词“linux面试题”“linux面试题测试”搜的人多说明大家都盯着招聘要求里的“熟悉Linux内核”几个字发愁。这里我先按方向拆一拆后续专栏第十分部分再逐题展开。6.1 面试官真正想听到什么内核面试题和普通八股文面试最大的区别是面试官基本能分辨你是真读过源码还是在背概念。比如“进程和线程的区别”普通答案是共享地址空间、各有栈内核视角的答案是线程在task_struct层面是同一套进程结构Linux里线程是通过clone系统调用共享地址空间和文件表创建的调度器眼里它们都是task_struct节点。常见的切入点还有这几个系统调用从用户态到内核态经过哪几步需要答出陷入内核、栈切换、入口表OOM Killer如何选择进程下手需要答出oom_score的计算逻辑僵尸进程是什么怎么避免需要答出父进程没调用wait内核保留了task_struct自旋锁和互斥锁的区别是什么需要答出睡眠与否、持有时间、上下文约束写时复制COW是什么需要答出fork后父子进程共享物理页写时缺页异常复制这些题单看也很普通但每道题都要求你“再往下说一层”。读源码的人能随口补一句“这个逻辑在kernel/fork.c里其实是do_fork→copy_process”没读源码的人只能停在概念表面。面试的差距就是这么拉开的。6.2 那些岗位需要内核知识我做过的分工经验是这样的岗位方向内核知识重要度最常用到哪部分业务后端开发中进程模型、内存语义、网络IO模型SRE/运维高内核日志、IO栈、OOM、虚拟化嵌入式Linux开发极高内核裁剪、设备树、驱动、交叉编译驱动与内核开发极高模块、中断、锁、内存管理全栈云计算/虚拟化底层高KVM、cgroup、namespace、容器隔离数据库/存储中高文件系统、块层、NUMA、io_uring近些年“国产linux”相关岗位明显多了起来。很多人以为所谓国产操作系统就是把Ubuntu换个皮肤实际从内核视角看真正的活在于内核适配、安全加固、性能优化、软硬协同调优。懂内核原理的人在这些岗位上比只懂命令行的人值钱得多因为你面对的不再是“敲命令”而是“改内核”。6.3 学习节奏建议如果按专栏节奏走我建议第一阶段环境与编译控制在两周内别恋战第二阶段进程、内存、文件系统主线花六到八周第三阶段驱动与网络根据方向取舍第四阶段定位实战与面试放在找工作前一个月集中冲刺。每周必须保证至少一次“动手实验”哪怕只是重新编译一次内核、加载一个hello world模块都比多看两章书强。我最后再分享一个个人体会学内核最大门槛不是智力而是“看不懂的时候愿不愿意硬着头皮走下去”。我第一次编译内核的时候卡在依赖缺失上折腾了四个小时第一次在VMware里装Linux时蓝屏过两次第一次写内核模块因为没签模块签名被拒绝加载气得差点砸键盘。但这些东西都过去了之后再看任何软件系统都会有一种“我能猜到它底层大概干了什么”的底气。这种底气的价值远远超过面试时背下的那几道题。下一篇文章我会直接带你从环境搭建开始把“第一次编译内核”这个最容易被卡住的门槛彻底迈过去。
返回列表