Learning Platform
Глоссарий Troubleshooting
Урок 16.03 · 20 мин
Начальный
/proc/sysLinuxKerneltuning

/proc и /sys — окно в kernel state

Если top, vmstat, iostat — это утилиты, которые показывают вам kernel state в красивом виде, то /proc и /sys — источник, откуда они эту информацию берут. Это виртуальные файловые системы: на диске их нет, kernel создаёт их inodes “на лету” и наполняет содержимым по запросу. Открыть файл из /proc — это спросить kernel “какое у тебя текущее состояние”.

В этом уроке: что такое pseudo-FS, как читать главные файлы (/proc/loadavg, /proc/meminfo, /proc/cpuinfo, /proc/[pid]/, /sys/class/net/), и как через echo в /proc/sys/ менять runtime kernel parameters без перекомпиляции.


Что это такое: virtual filesystem

/proc и /sys — не настоящие ФС. Они virtual: kernel создаёт inode и file_operations динамически. Когда вы делаете cat /proc/cpuinfo, происходит:

  1. open("/proc/cpuinfo") — VFS видит, что это /proc, делегирует procfs.
  2. procfs создаёт inode для файла.
  3. read() — procfs вызывает callback, который формирует строки на лету (читая kernel state).
  4. close() — inode уничтожается.

Поэтому ls -l /proc/cpuinfo показывает размер 0:

$ ls -l /proc/cpuinfo
-r--r--r-- 1 root root 0 May 18 09:12 /proc/cpuinfo

$ wc -l /proc/cpuinfo
145 /proc/cpuinfo

Файл якобы 0 байт, но в нём 145 строк! Это потому что kernel генерирует содержимое в момент read, а stat показывает stored size (которого нет).

/proc и /sys в архитектуре
Userspace toolstop, ps, free, ip, sysctl, sensors -- все читают /proc и /sys для информации. Это не magic, это просто открытие файла
open/read
/procПроцесс-ориентированные данные: PID директории, общие kernel-вверх. /proc/cpuinfo, /proc/meminfo, /proc/[pid]/, /proc/sys для tuning
/sysУстройство-ориентированные данные: /sys/class/, /sys/block/, /sys/devices/. Driver-attributes, hardware info, hotplug events
callbacks
Kernel stateIn-memory структуры kernel: task_struct, memory zones, scheduler runqueues, device drivers' attributes. Чтение файла -> чтение этих структур

/proc — что тут

Главные категории файлов:

Общие kernel info:

$ ls /proc/ | head -30
1                  # PID 1 -- systemd
123                # другие PID
...
buddyinfo          # buddy allocator
cgroups
cmdline            # kernel cmdline (как был загружен)
config.gz          # config с которым собрана kernel (если включено)
cpuinfo            # CPU info
crypto
devices            # registered char/block drivers (видели в уроке 12.1)
diskstats          # raw disk stats (iostat использует)
filesystems        # supported FS
fs/                # FS internals (inotify, etc.)
interrupts         # IRQ stats
iomem              # memory map (физические адреса устройств)
ioports            # ports map
kallsyms           # kernel symbols (нужны root для отладки)
kmsg               # kernel ring buffer (dmesg использует)
loadavg            # load average + tasks
mdstat             # md/RAID status
meminfo            # memory breakdown
modules            # loaded kernel modules (lsmod использует)
mounts             # active mounts
net/               # сетевая info
partitions
schedstat
self -> /proc/<current pid>   # symlink на свой PID
slabinfo           # kernel slab allocator stats
stat               # system stats (boot time, irq totals)
swaps              # swap usage
sys/               # tunable kernel parameters
sysrq-trigger      # сейчас не записал ли кто sysrq
sysvipc/           # SysV IPC (sem, msg, shm)
thread-self -> ...
tty/
uptime             # uptime in seconds (cf top)
version            # kernel version
vmstat             # vm stats (vmstat -s использует)
zoneinfo           # NUMA zones

Самые полезные /proc файлы

# Load average:
$ cat /proc/loadavg
1.42 1.05 0.87 1/287 12345
# Format: load1 load5 load15 runnable/total last-pid

# Память:
$ cat /proc/meminfo | head -15
MemTotal:       32985856 kB
MemFree:         3145728 kB
MemAvailable:   12345678 kB
Buffers:          124356 kB
Cached:          9821456 kB
...

# Uptime в секундах + idle time:
$ cat /proc/uptime
1234567.89 4521879.11
# uptime, sum of idle time per CPU

# Kernel cmdline:
$ cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-6.5.0-21 root=UUID=5d3e... ro quiet splash

# CPU info:
$ cat /proc/cpuinfo | grep 'model name' | head -1
model name      : Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz

# Active mounts:
$ cat /proc/mounts | head -5
sysfs /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0
proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
devtmpfs /dev devtmpfs rw,nosuid,relatime,size=4015868k,nr_inodes=1003967,mode=755 0 0
tmpfs /run tmpfs rw,nosuid,nodev,noexec,relatime,size=1607672k,mode=755 0 0
/dev/nvme0n1p2 / ext4 rw,relatime,errors=remount-ro 0 0

# Interrupts breakdown:
$ cat /proc/interrupts | head
            CPU0       CPU1       CPU2       CPU3
   0:         33          0          0          0   IO-APIC    2-edge      timer
   1:          9          0          0          0   IO-APIC    1-edge      i8042
   8:          0          0          0          0   IO-APIC    8-edge      rtc0
   9:    1234567        234        456        789   IO-APIC    9-fasteoi   acpi
  16:     345678     123456    234567     345678   IO-APIC   16-fasteoi   ehci_hcd:usb1
...

/proc/[pid] — per-process data

Каждый процесс имеет директорию в /proc по своему PID:

$ ls /proc/$$         # $$ -- PID текущей shell
attr/
auxv
cgroup
clear_refs
cmdline
comm
cwd -> /home/lev      # symlink на cwd
environ              # env vars
exe -> /usr/bin/bash # symlink на executable
fd/                  # open file descriptors
fdinfo/
io                   # IO stats
limits               # rlimits
maps                 # memory map
mountinfo
mounts
mountstats
net/
ns/                  # namespaces
oom_adj
oom_score
oom_score_adj
root -> /
stat                 # main stats (ps использует)
status               # human-readable status
syscall              # текущий syscall (если в нём)
task/                # threads
wchan                # waiting on what

Часто используемые:

# PID текущей shell:
echo $$
2345

# Command-line:
$ tr '\0' ' ' < /proc/2345/cmdline
bash

# Текущий cwd:
$ readlink /proc/2345/cwd
/home/lev

# Open fds:
$ ls -l /proc/2345/fd/
total 0
lrwx------ 1 lev lev 64 May 18 09:12 0 -> /dev/pts/0
lrwx------ 1 lev lev 64 May 18 09:12 1 -> /dev/pts/0
lrwx------ 1 lev lev 64 May 18 09:12 2 -> /dev/pts/0
lrwx------ 1 lev lev 64 May 18 09:12 255 -> /dev/pts/0

# Memory map:
$ cat /proc/2345/maps | head
55b234567000-55b234568000 r--p 00000000 fd:01 1234567 /usr/bin/bash
55b234568000-55b234678000 r-xp 00001000 fd:01 1234567 /usr/bin/bash
55b234678000-55b234712000 r--p 00111000 fd:01 1234567 /usr/bin/bash
...
7f8c12345000-7f8c12346000 r-xp 00000000 fd:01 7654321 /usr/lib/libc.so.6
[heap]                              ...
[stack]                             ...

# Status (более user-friendly):
$ cat /proc/2345/status | head -20
Name:   bash
Umask:  0022
State:  S (sleeping)
Tgid:   2345
Pid:    2345
PPid:   2344
TracerPid:      0
Uid:    1000    1000    1000    1000
Gid:    1000    1000    1000    1000
FDSize: 256
Groups: 4 24 27 30 46 116 1000
VmPeak:    14156 kB
VmSize:    14156 kB
VmRSS:      6789 kB    <-- resident memory
VmData:     2345 kB
VmStk:       132 kB
VmExe:       968 kB
VmLib:      2345 kB

# IO stats:
$ cat /proc/2345/io
rchar: 12345678
wchar: 234567
syscr: 4567
syscw: 234
read_bytes: 1234567
write_bytes: 89012
cancelled_write_bytes: 0

Это огромное окно в каждый процесс. Multiple tools (lsof, gdb, strace) под капотом используют /proc.


/sys — структурированный hierarchy

/sys (sysfs) появилась позже /proc и более структурированная. Делится на:

$ ls /sys/
block/        # block devices: sda, nvme0n1
bus/          # buses: pci, usb, scsi
class/        # классы устройств: net, block, tty, input
dev/          # major:minor lookup
devices/      # физическая иерархия устройств
firmware/     # firmware info (efi)
fs/           # FS-specific (ext4 attrs, etc.)
hypervisor/   # if running in VM
kernel/       # kernel parameters
module/       # loaded modules
power/        # power management

Главные категории:

# Все сетевые интерфейсы:
ls /sys/class/net/
eth0  lo  wlan0

# Информация про eth0:
ls /sys/class/net/eth0/
address          # MAC
speed            # текущая скорость в Mbps
duplex           # full/half
operstate        # up/down
mtu
rx_bytes         # total
tx_bytes
statistics/      # детальная статистика

# Конкретные значения:
cat /sys/class/net/eth0/address
e0:d5:5e:12:34:56

cat /sys/class/net/eth0/speed
1000

cat /sys/class/net/eth0/statistics/rx_bytes
12345678901

# Block devices:
ls /sys/block/
nvme0n1  sda  sdb

# Информация про nvme0n1:
cat /sys/block/nvme0n1/size
4000797360
# (число секторов 512 байт; * 512 = размер в байтах)

cat /sys/block/nvme0n1/queue/scheduler
[none] mq-deadline kyber bfq

# Текущий scheduler в [скобках]. Поменять:
echo mq-deadline > /sys/block/nvme0n1/queue/scheduler

# Per-CPU info:
ls /sys/devices/system/cpu/
cpu0  cpu1  cpu2  cpu3  cpufreq/ ...

cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
2600000   # текущая частота в кГц

/proc/sys — runtime kernel tuning через sysctl

/proc/sys — особенный subdir. В нём kernel parameters, которые можно менять записью:

# Текущее значение swappiness:
$ cat /proc/sys/vm/swappiness
60

# Поменять:
$ echo 10 | sudo tee /proc/sys/vm/swappiness
10

# Через sysctl:
$ sudo sysctl vm.swappiness=10
vm.swappiness = 10

# Все настройки сейчас:
$ sysctl -a | head -20
abi.vsyscall32 = 1
crypto.fips_enabled = 0
dev.cdrom.autoclose = 1
...

# Чтобы сохранить навсегда -- /etc/sysctl.d/:
$ sudo tee /etc/sysctl.d/99-myconf.conf <<EOF
vm.swappiness = 10
net.ipv4.tcp_keepalive_time = 600
kernel.sysrq = 1
EOF

# Применить:
$ sudo sysctl -p /etc/sysctl.d/99-myconf.conf

Полезные tunables:

# Memory:
vm.swappiness           # 0-100, как агрессивно swap-ить (default 60, server обычно 10)
vm.dirty_ratio          # % памяти для dirty pages until forced flush
vm.dirty_background_ratio  # % для async flush
vm.overcommit_memory    # 0/1/2 -- политика overcommit
vm.min_free_kbytes      # минимум, который kernel держит свободным

# Network:
net.ipv4.tcp_keepalive_time
net.ipv4.tcp_max_syn_backlog
net.core.somaxconn       # макс backlog для listen()
net.ipv4.ip_local_port_range  # эфемерные порты

# Filesystem:
fs.file-max             # макс открытых файлов всего
fs.inotify.max_user_watches

# Process / IPC:
kernel.pid_max          # макс PID
kernel.sysrq            # включить SysRq key

# Security:
kernel.unprivileged_userns_clone
kernel.kptr_restrict
WARNING

sysctl tuning — мощный tool, но может разрушить систему. Test на dev-машине сначала. И знайте, что нужно: tuning vm.swappiness=0 на production иногда хорошо, иногда плохо — зависит от workload. Не копировать настройки слепо из stack overflow.

Troubleshooting OOMKilled, Pending, Evicted в Kubernetes

Live writing в /proc и /sys (примеры)

# Drop page cache (полезно для benchmark):
sudo sync                                          # сначала flush dirty
sudo bash -c "echo 3 > /proc/sys/vm/drop_caches"  # потом drop
# 1 = pagecache, 2 = dentries/inodes, 3 = both

# Force kernel panic (для тестирования high availability):
echo c | sudo tee /proc/sysrq-trigger    # CAREFUL!

# Поменять disk scheduler:
echo mq-deadline | sudo tee /sys/block/sda/queue/scheduler

# Включить hotplug rescan SCSI:
echo '- - -' | sudo tee /sys/class/scsi_host/host0/scan

# Поменять MTU сетевой:
echo 9000 | sudo tee /sys/class/net/eth0/mtu

# Force re-detect mouse:
echo 'mouse_event' | sudo tee /sys/class/input/input2/uevent

/proc/diskstats — raw data для iostat

iostat использует /proc/diskstats:

$ cat /proc/diskstats | head
   8       0 sda 1234567 23456 89012345 234567 234567 89012 78901234 567890 0 234567 802457
   8       1 sda1 234567 1234 1234567 23456 12345 567 1234567 23456 0 23456 46912
259       0 nvme0n1 1234567890 234567 12345678901 2345678 345678901 23456 89012345678 12345678 0 1234567 13991346

15 колонок per partition. Самые важные: 1-2: major, minor. 3: имя. 4: reads completed. 6: reads merged. 7: sectors read. 8: time spent reading (ms). 9-13: writes (то же самое). 14: IOs currently in progress. 15: time spent doing IOs (ms) — для %util.

iostat вычисляет дельты двух snapshot’ов /proc/diskstats и делит на интервал.


/proc/interrupts — IRQ activity

$ cat /proc/interrupts | head -10
            CPU0       CPU1       CPU2       CPU3
   0:         33          0          0          0   IO-APIC    2-edge      timer
   1:        654         12          5          7   IO-APIC    1-edge      i8042
   8:          0          0          0          0   IO-APIC    8-edge      rtc0
   9:    1234567        234        456        789   IO-APIC    9-fasteoi   acpi
  16:     345678     123456    234567     345678   IO-APIC   16-fasteoi   ehci_hcd:usb1
  17:    1234567    1345678   2345678    1234567   IO-APIC   17-fasteoi   nvme0q1, eth0

Колонки — per-CPU counts. Последний столбец — описание (источник IRQ).

Что искать:

  • IRQ концентрируется на одном CPU — IRQ affinity issue. Попробуйте irqbalance или вручную:
    echo 0xf | sudo tee /proc/irq/16/smp_affinity   # все 4 CPU могут принимать IRQ 16
  • Слишком много interrupts от network — может помочь polling mode (NAPI, RPS), interrupt coalescing.

Попробуй сам

# 1. Прочитать главное:
cat /proc/loadavg
cat /proc/uptime
cat /proc/version
cat /proc/cmdline

# 2. Per-process:
echo $$
cat /proc/$$/status | head -20
ls /proc/$$/fd/
cat /proc/$$/cmdline | tr '\0' ' '; echo

# 3. Memory deep dive:
cat /proc/meminfo | grep -i 'swap\|anon\|file\|slab' | head -10

# 4. CPU info:
grep 'model name' /proc/cpuinfo | head -1
grep -c '^processor' /proc/cpuinfo

# 5. Сетевые интерфейсы через /sys:
for iface in /sys/class/net/*/; do
    name=$(basename $iface)
    state=$(cat $iface/operstate 2>/dev/null)
    mac=$(cat $iface/address 2>/dev/null)
    echo "$name: $state, $mac"
done

# 6. Поменять swappiness (требует root):
sudo sysctl vm.swappiness
sudo sysctl vm.swappiness=10  # временно

# 7. Drop page cache и наблюдать:
free -h         # перед
sync; echo 3 | sudo tee /proc/sys/vm/drop_caches  # drop
free -h         # после: cache меньше

# 8. Конкретные kernel params:
sudo sysctl -a | grep tcp_keepalive

# 9. IRQ topology:
cat /proc/interrupts | head -10

Проверка знанийKnowledge check
Я хочу узнать, какие файлы открыты процессом 1234 (это postgres, и я подозреваю что он держит удалённый, но ещё не закрытый файл). Как через /proc это сделать?
ОтветAnswer
Через /proc/<pid>/fd/. Это директория с symlinks для каждого open file descriptor. ls -l /proc/1234/fd/ Вывод: lr-x------ 1 postgres postgres 64 May 18 09:12 0 -> /dev/null lrwx------ 1 postgres postgres 64 May 18 09:12 1 -> /var/log/postgresql/... lrwx------ 1 postgres postgres 64 May 18 09:12 3 -> /var/lib/postgresql/data/pg_wal/000000010000... lrwx------ 1 postgres postgres 64 May 18 09:12 7 -> /tmp/pgsql_tmp_5234 (deleted) ... Ключ -- '(deleted)' маркер. Это означает: файл удалён через rm/unlink, но процесс ещё держит fd. Inode и data на диске сохраняются пока fd не закроется -- так работает Unix file model. Зачем процесс может держать удалённый файл: 1. Open file -> unlink (другой процесс) -> ещё работает с ним. Postgres использует эту технику для tmp-файлов: создаёт, сразу unlink'ит, работает -- никто не удалит случайно, и когда процесс завершится -- автоматически освободится. 2. Лог-rotation: rsyslog был запущен с открытым /var/log/syslog, kто-то сделал mv syslog.1 syslog.2 + rm syslog. rsyslog держит fd, но пишет в то же место -- которое теперь '(deleted)'. Это часто причина 'disk full but where' -- пространство не освобождается до restart процесса. 3. Memory-mapped files: процесс mmap'нул shared library, файл удалили (например, apt upgrade libname). mmap-binding продолжает работать (страницы в RAM), но libname -- '(deleted)'. Дополнительные commands: # Размер удержанного файла: stat -L /proc/1234/fd/7 # -L follow symlink даже если target deleted # Содержимое удалённого файла (можно восстановить!): cat /proc/1234/fd/7 > /tmp/recovered_file # Это работает потому что fd is still valid, data on disk # Удобный инструмент lsof: sudo lsof -p 1234 # или специально на deleted: sudo lsof +L1 -p 1234 sudo lsof +L1 | head # все deleted-but-held в системе Если видим (deleted) на больших файлах, при том что disk full -- источник проблемы. Решение: restart процесса (тогда fd закроется, space освободится). Или, если процесс важен и нельзя рестартить -- сообщить разработчикам что в коде утечка fd на удалённые файлы. Это всё работает через /proc -- одна из самых полезных и элегантных features Linux. Любая утилита наблюдения (lsof, ss, ps) под капотом читает /proc. Зная это, вы можете дебажить без специальных тулзов, имея только cat и ls.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 6. Почему ls -l /proc/cpuinfo показывает размер 0, но cat выводит 145 строк?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5