﻿# 内核配置与调优入口 —— 到底往哪里写配置

## 这篇文档是做什么的

> 做性能调优、改内核行为时,一个反复出现的困惑是:**这个参数该往哪儿写?** `/proc/sys`?`/sys`?`sysctl` 命令?内核启动参数?它们看着都像"改内核",但**作用层次、生效时机、持久化方式完全不同**。本篇把内核暴露的**所有配置入口**梳理成一张地图:每类是什么、改它影响什么、临时改 vs 永久改怎么做、以及一个参数该选哪个入口。

## 可以回答什么问题

| 问题 | 答案 |
|------|------|
| 我想改一个内核参数(如 swappiness)，该写 `/proc/sys` 还是 `/sys`？ | §一——全局内核行为走 `sysctl`/`/proc/sys` |
| 我想把某块盘换成 none 调度器，该写哪里？ | §二——设备属性走 `/sys` |
| 我想隔离几个 CPU 核，运行期改不了怎么办？ | §三——`isolcpus` 必须走内核启动参数，改 GRUB 重启 |
| 改了参数，重启后还在吗？ | 见各节"临时 vs 永久"—sysctl 写 `/etc/sysctl.d/`，/sys 靠 udev/tuned |
| 一个参数该选哪个入口？有没有决策树？ | §五——依"改的是什么层次 × 运行期能改吗"决策 |
| 我想一键套用一组调优参数，不用翻十几个文件？ | 用 [tuned.md](/tools/proc/tuned.md)——把 sysctl+sysfs+GRUB 打包成 profile |


> 相关:`/proc` 这个虚拟文件系统本身见 [procfs.md](/tools/proc/procfs.md)(本篇是它"可写的那一面 `/proc/sys`"的延伸 + 其它入口的汇总);具体参数出处散见 [../../memory/free.md](/tools/memory/free.md)(overcommit/swappiness)、[../../crash/core-dump.md](/crash/core-dump.md)(core_pattern)、[../../concepts/numa/numa.md](/concepts/numa/numa.md)、[../../concepts/process/thread-affinity.md](/concepts/process/thread-affinity.md)(isolcpus/中断亲和)、[../../concepts/cache/tlb.md](/concepts/cache/tlb.md)(大页)。

## 零、一句话认知：内核配置分两个维度——"改什么层次" × "活多久"

选入口前,先在脑子里定位两件事：

1. **改的是哪一层?** 

- 全局内核子系统行为(内存/网络/调度) → `sysctl`
- 某个具体设备/CPU/对象 → `/sys`
- 开机就要定死、运行期改不了的 → 内核启动参数
- 某个驱动模块 → 模块参数

2. **要活多久?** 

- 只想试一下(重启失效) → 直接写文件
- 要永久 → 写进配置文件(`/etc/sysctl.d/`、GRUB、`modprobe.d`)

```plantuml
@startuml
skinparam shadowing false
skinparam rectangle {
  BackgroundColor<<a>> #E3F2FD
  BorderColor<<a>> #1976D2
  BackgroundColor<<b>> #C8E6C9
  BorderColor<<b>> #388E3C
  BackgroundColor<<c>> #FFE0B2
  BorderColor<<c>> #EF6C00
  BackgroundColor<<d>> #FFCDD2
  BorderColor<<d>> #C62828
}
rectangle "/proc/sys (= sysctl)\n**全局内核子系统**参数\nvm./net./kernel./fs.\n运行期可改,即时生效" <<a>> as A
rectangle "/sys (sysfs)\n**具体设备/对象**属性\nCPU/块设备/网卡/cgroup/大页\n按对象逐个改" <<b>> as B
rectangle "内核启动参数 (cmdline)\n开机才能定的、运行期改不了\nisolcpus/hugepages/iommu/mitigations\n改 GRUB → 重启生效" <<c>> as C
rectangle "模块参数 / 其它\nmodprobe.d、ethtool、tuned...\n针对驱动或专项" <<d>> as D
note bottom of A : 调优最常用的入口
note bottom of C : 一次性、要重启
@enduml
```

> **核心记忆**:**能运行期改的全局参数走 `sysctl`(即 `/proc/sys`);针对某个具体设备/CPU 的属性走 `/sys`;运行期改不了、必须开机定的走内核启动参数(GRUB);驱动相关走模块参数。** 临时改就写文件,永久改就写对应的配置文件。

## 一、/proc/sys 与 sysctl —— 全局内核参数的主入口（90% 的调优在这）

`/proc/sys/` 下的文件**可写**,写入即刻改变内核子系统行为。它和 **`sysctl` 命令是同一套东西**——只是路径分隔符不同：

```bash
/proc/sys/vm/swappiness   ↔   sysctl vm.swappiness      (/ 换成 .)
/proc/sys/net/ipv4/...     ↔   sysctl net.ipv4...
```

### 三种改法：临时 / 会话 / 永久

```bash
# ① 读
cat /proc/sys/vm/swappiness          # 或: sysctl vm.swappiness
# ② 临时改(重启失效)——两种等价写法
echo 10 > /proc/sys/vm/swappiness    # 直接写文件
sysctl -w vm.swappiness=10           # sysctl 命令(等价)
# ③ 永久改(重启保留)——写配置文件,别直接 echo
echo 'vm.swappiness = 10' > /etc/sysctl.d/99-tuning.conf
sysctl -p /etc/sysctl.d/99-tuning.conf   # 立即加载(不必等重启)
sysctl --system                          # 重新加载所有 sysctl 配置
```

> **关键**:`echo > /proc/sys/...` 和 `sysctl -w` 都是**临时**的,重启即失效。要**永久**必须写进 `/etc/sysctl.d/*.conf`(推荐,模块化)或 `/etc/sysctl.conf`,再 `sysctl -p`。**别把 `echo` 写进 rc.local 之类**——用 `/etc/sysctl.d/` 才是规范做法。

### 按子系统分类（常用的几大类）

| 前缀 | 管什么 | 例子(仓库里出现过的) |
|------|--------|---------------------|
| `vm.*` | 内存管理 | `vm.swappiness`(换页倾向)、`vm.overcommit_memory`(超额分配,见 [free](/tools/memory/free.md))、`vm.drop_caches`(释放缓存)、`vm.nr_hugepages`(大页数量,见 [tlb](/concepts/cache/tlb.md)) |
| `net.*` | 网络栈 | `net.core.somaxconn`(连接队列)、`net.ipv4.tcp_*`(TCP 各种)、`net.core.rmem_max`(socket 缓冲) |
| `kernel.*` | 内核核心 | `kernel.core_pattern`(core 文件模板,见 [core-dump](/crash/core-dump.md))、`kernel.randomize_va_space`(ASLR,见 [memory-layout](/concepts/elf/memory-layout.md))、`kernel.numa_balancing`(见 [numa](/concepts/numa/numa.md))、`kernel.sched_*`(部分调度参数)、`kernel.pid_max` |
| `fs.*` | 文件系统 | `fs.file-max`(全局 fd 上限)、`fs.nr_open`、`fs.inotify.*` |

```bash
sysctl -a                    # 列出全部当前参数(几千个)
sysctl -a | grep swappiness  # 找某个参数
sysctl net.ipv4              # 看某个子树
```

## 二、/sys（sysfs）—— 针对具体设备/对象的属性

`/sys` 也是虚拟文件系统,但组织方式不同:它按**内核对象模型**(设备、总线、CPU、cgroup…)分层,**每个属性一个文件**,针对**具体的某个对象**来配置。`sysctl` 是"全局开关",`/sys` 是"逐个对象的旋钮"。

| 路径 | 配置什么 | 出处 |
|------|---------|------|
| `/sys/devices/system/cpu/cpu<N>/...` | 单个 CPU:在线状态、调频 governor、缓存拓扑 | 调频/[cache-organization](/concepts/cache/cache-organization.md) |
| `/sys/devices/system/cpu/cpu<N>/cpufreq/scaling_governor` | CPU 频率策略(performance/powersave) | 低延迟调优 |
| `/sys/kernel/mm/transparent_hugepage/enabled` | 透明大页(THP) 开关 | [tlb](/concepts/cache/tlb.md) |
| `/sys/block/<dev>/queue/scheduler` | 块设备 IO 调度器(none/mq-deadline/bfq) | [iostat](/tools/disk/iostat.md) |
| `/sys/block/<dev>/queue/nr_requests`、`read_ahead_kb` | 块设备队列深度、预读 | IO 调优 |
| `/sys/class/net/<iface>/queues/...` | 网卡队列、RPS/XPS 配置 | 网络调优 |
| `/sys/devices/system/node/node<N>/...` | NUMA 节点的内存/CPU 列表 | [numa](/concepts/numa/numa.md) |
| `/sys/fs/cgroup/...` | cgroup v2 的资源限额(CPU/内存/IO) | 容器限额 |

```bash
# 例:把某块盘的 IO 调度器改成 none(NVMe 常用),临时
echo none > /sys/block/nvme0n1/queue/scheduler
# 例:关掉透明大页(数据库常见调优)
echo never > /sys/kernel/mm/transparent_hugepage/enabled
# 例:CPU 定频到最高性能(低延迟)
echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
```

> `/sys` 的写入同样**临时**,重启失效。持久化通常靠 **`udev` 规则**、**`tuned` 配置**、systemd unit 或开机脚本——因为它针对具体设备,没有 `sysctl.conf` 那样的统一文件。`/proc` vs `/sys` 的分工也见 [procfs.md](/tools/proc/procfs.md) §六。

## 三、内核启动参数（cmdline）—— 运行期改不了的，只能开机定

有些参数**必须在内核启动时确定**,运行期无法更改(比如把某些 CPU 从调度器摘出去、预留大页)。这些走**内核命令行(kernel command line)**,通过 **GRUB** 配置,**改完必须重启**。

```bash
cat /proc/cmdline            # 看当前系统是用哪些启动参数开机的
```

| 启动参数 | 作用 | 出处 |
|---------|------|------|
| `isolcpus=2-5` | 把 CPU 2-5 从调度器默认负载均衡摘出,留给关键线程独占 | [thread-affinity](/concepts/process/thread-affinity.md) |
| `nohz_full=2-5` | 这些核只有一个任务时关调度时钟中断(tickless),极致低延迟 | [thread-affinity](/concepts/process/thread-affinity.md) |
| `hugepagesz=1G hugepages=8` | 开机预留 8 个 1G 大页(运行期难分配的连续大页) | [tlb](/concepts/cache/tlb.md) |
| `mitigations=off` | 关掉 Spectre/Meltdown 缓解(换性能,见 KPTI) | [syscall](/concepts/process/syscall.md) |
| `iommu=pt`、`intel_iommu=on` | IOMMU 模式(虚拟化/DPDK/RDMA) | [rdma](/tools/network/rdma.md) |
| `transparent_hugepage=never` | 启动就关 THP(等价于 sysfs 那个,但开机即定) | — |

**永久改法**(以常见发行版为例)：

```bash
# 1) 编辑 /etc/default/grub,在 GRUB_CMDLINE_LINUX 里加参数
#    GRUB_CMDLINE_LINUX="... isolcpus=2-5 nohz_full=2-5"
# 2) 重新生成 grub 配置
update-grub                        # Debian/Ubuntu
grub2-mkconfig -o /boot/grub2/grub.cfg   # RHEL/CentOS
# 3) 重启生效
```

> **判据**:如果一个参数在 `/proc/sys` 或 `/sys` 里**找不到对应可写文件**,或改了报错/不生效,它多半是**只能开机定的启动参数**。`isolcpus`、大页预留就是典型——运行期内核已经把资源分配格局定死了,改不动。

## 四、其它专项入口

- **模块参数(module parameters)**:某个内核模块(驱动)的参数。
  - 临时(加载时):`modprobe <mod> param=value`;运行期部分可改:`/sys/module/<mod>/parameters/<param>`。
  - 永久:写 `/etc/modprobe.d/*.conf`(如 `options nvme poll_queues=4`)。
- **`ethtool`**:网卡专项配置(多队列/RSS、offload、ring buffer 大小、中断合并 coalescing)——很多网络调优不在 sysctl 而在 `ethtool`。
- **`tuned` / `tuned-adm`**:发行版提供的**调优配置集**(profile)，一键套用一组 sysctl+sysfs+cmdline 设置(如 `throughput-performance`、`latency-performance`)。生产环境常用它统一管理，而非手改一堆文件。详见 [tuned.md](/tools/proc/tuned.md)。
- **`ulimit` / `/etc/security/limits.conf`**:进程资源限制(fd 数、栈大小、core 大小)——属于**每进程/每用户**层面,不是全局内核参数(对应 [task-struct](/concepts/process/task-struct.md) 的 `rlimit`、[procfs](/tools/proc/procfs.md) 的 `/proc/<pid>/limits`)。
- **cgroup**:给一组进程限额(CPU/内存/IO),cgroup v2 通过 `/sys/fs/cgroup/` 下的文件配置——容器(Docker/K8s)的资源限制底座(见 [task-struct](/concepts/process/task-struct.md) §2.6)。

## 五、决策：一个参数该往哪写

```plantuml
@startuml
skinparam shadowing false
skinparam ArrowColor #37474F
start
if (针对某个具体设备/CPU/盘/网卡?) then (是)
  if (网卡收发队列/offload?) then (是)
    :用 ethtool;
  else (否)
    :写 /sys 下该对象的属性文件\n(持久化靠 udev/tuned);
  endif
else (否,是全局内核行为)
  if (运行期能改?) then (能)
    :sysctl / /proc/sys\n临时 echo,永久写 /etc/sysctl.d/;
  else (不能,必须开机定)
    :内核启动参数\n改 GRUB → 重启;
  endif
endif
stop
@enduml
```

| 想调的东西 | 入口 | 临时 | 永久 |
|-----------|------|------|------|
| 换页/超额/TCP/ASLR/core_pattern 等全局行为 | **sysctl** | `sysctl -w` 或 `echo>/proc/sys` | `/etc/sysctl.d/*.conf` |
| 某盘 IO 调度器、THP、CPU governor | **/sys** | `echo>/sys/...` | udev 规则 / tuned |
| 隔离 CPU、预留大页、关 mitigations | **启动参数** | (不可) | GRUB → 重启 |
| 驱动行为 | **模块参数** | `/sys/module/.../parameters` | `/etc/modprobe.d/` |
| 网卡队列/offload/中断合并 | **ethtool** | `ethtool -X/-G/-C` | 开机脚本 / NetworkManager |
| 一组参数一键套用 | **tuned** | `tuned-adm profile X` | tuned 持久 |
| 每进程 fd/栈/core 上限 | **ulimit** | `ulimit -n` | `/etc/security/limits.conf` |

## 六、调优效果验证（改完参数后用什么工具看效果）

| 调了什么 | 用什么验证 | 看什么指标 |
|---------|-----------|-----------|
| vm.swappiness / 内存相关 | `free -h` + `vmstat 1` | available、si/so 是否改善 |
| net.core.* / TCP 参数 | `ss -ti` + `sar -n DEV/ETCP` | rtt、retrans、带宽是否改善 |
| CPU governor (performance) | `mpstat -P ALL 1` | %usr/%sys 是否稳定、有无限频 |
| THP 关闭 | `cat /proc/meminfo \| grep AnonHuge` | AnonHugePages 应为 0 |
| IO 调度器 (none/mq-deadline) | `iostat -x 1` | await、aqu-sz 是否下降 |
| isolcpus 隔离 | `cat /proc/cmdline` + `taskset` | 确认调度器不会把任务放到隔离核 |
| 大页预留 | `cat /proc/meminfo \| grep HugePages` | HugePages_Free/HugePages_Total |
| 网卡队列/中断合并 | `ethtool -l/-g/-c` + `mpstat -P ALL 1` | %soft 分布是否均匀、中断均衡 |

## 七、调优通则（别瞎改）

- **一次只改一个**:同时改多个参数,出问题分不清是谁。
- **临时验证 → 确认有效 → 才持久化**:先 `echo`/`sysctl -w` 跑一段观察,确认没副作用再写进配置文件。改错的全局参数(`overcommit`、`core_pattern`、TCP 参数)可能拖垮整机。
- **记下默认值**:改之前 `cat` 存一份原值,好回滚。
- **生产优先用 tuned/配置管理**:手改散落文件难维护,用 tuned profile 或 Ansible 之类统一管。

## 八、和本仓库其他文档的关系

- **`/proc` 本体**:[procfs.md](/tools/proc/procfs.md)——本篇是它"可写的 `/proc/sys`"那一面的展开 + 其它入口汇总;二者配合看。
- **各参数的语境**:[../memory/free.md](/tools/memory/free.md)(vm.overcommit/swappiness)、[../crash/core-dump.md](/crash/core-dump.md)(kernel.core_pattern)、[../elf/memory-layout.md](/concepts/elf/memory-layout.md)(randomize_va_space/ASLR)、[../numa/numa.md](/concepts/numa/numa.md)(numa_balancing)、[../cache/tlb.md](/concepts/cache/tlb.md)(大页)、[../process/thread-affinity.md](/concepts/process/thread-affinity.md)(isolcpus/nohz_full/中断亲和)、[../process/interrupts.md](/concepts/process/interrupts.md)(smp_affinity)、[../disk/iostat.md](/tools/disk/iostat.md)(IO 调度器)。
- **每进程/每组限额**:[../process/task-struct.md](/concepts/process/task-struct.md)(rlimit、cgroup)。

## 九、一句话总结

> **内核配置按"改哪层 × 活多久"两个维度选入口:全局内核行为(内存/网络/内核/文件系统)走 **sysctl**(即 `/proc/sys`,`sysctl -w` 或 `echo` 临时改、写 `/etc/sysctl.d/*.conf` 永久);针对具体设备/CPU/盘/cgroup 的属性走 **/sys**(sysfs,持久化靠 udev/tuned);运行期改不了、必须开机定的(isolcpus、预留大页、关 mitigations)走**内核启动参数**(改 GRUB→重启);驱动走**模块参数**,网卡走 **ethtool**,一组参数一键套用走 **tuned**,每进程资源上限走 **ulimit**。判据:能运行期改的全局参数=sysctl,找不到可写文件/改了不生效的多半是启动参数。所有调优都要先测量、一次改一个、临时验证后再持久化。**

