Linux: ядро (kernel), процессы /proc в ОС и работа с ними (proc, ps, kill, top, lsof)

  • kernel parameters /proc/cmdline (можно редактировать конфигом GRUB)
  • kernel parameters modification /etc/sysctl.conf

В Linux все рассматривается как файлы, включая устройства (/dev) и процессы (/proc).

Процессы запускаются самой системой для функционирования системы, такие процессы называют background/daemon process. Разделение на application и background processes можно увидеть в Windows taskmanager.

Одна программа может инициировать множество процессов (chrome, mediaplayer). При запуске процесс получает Process ID (PID, уникальный идентификатор процесса). Так же каждый процесс запрашивает физические ресурсы у ядра системы – CPU, RAM, HDD/SDD (i/o), NIC. При завершении процесса (автоматически или вручную) ресурсы возвращаются обратно ядру. Особенно удобно потребление ресурсов просмотривать в Мониторинге ресурсов (Windows) или top (Linux).

Процессы в linux построены в древовидной структуре – почти каждый процесс имеет своего родителя, кроме init/kthreadd (см. ps -auxf или ps -ef). Справедливо и при использовании pipe – cat 1 | grep 2 – grep будет являться дочерним для cat.

A process is a program or command running on the system. Every process has a unique numeric identifier, known as the process identifier (PID), which is used by the kernel to manage and control the process through its lifecycle. The process with PID 0 is started first at system boot, followed by the process with PID 1, and so on. Processes are organized in a hierarchical fashion.

When a process completes its lifecycle or is terminated, this event is reported back to its parent process, and all the resources provisioned to it are then freed and the PID is removed.

В Linux дочерние процессы не могут работать независимо от родительских, в отличии от Windows (там дочерний процесс связан с родительским только в момент создания – заимствует environment:переменные/настройки). Видно это например при запуске из консоли приложения – если в Windows убить консоль, то с приложением ничего не будет, в отличии от Linux, который дропнет child процесс при отключении родительского (поэтому так полезны в Linux демоны/сервисы/screen).

Each process has a parent process (a.k.a. a calling process) that spawns it. Asingle parent process may have one or many child processes and passes many of its attributes to them at the time of their creation.

Процессам можно передавать сигналы Sig/Signals. Ctrl-c и в Windows и в Linux передает сигнал sigint (signal interrupt), который шлет прерывание процесса от системы процессу. В отличии от Linux, в Windows пользователю сложно отправить произвольный сигнал программе с командной строки (кроме прерывания ctrl-c). В Linux же таких сигналов очень много (смотрим через kill -l) и их можно отправить через kill, начинаются они по названию с приставки SIG (сокращенно от Signal, например sigint).

У процессов есть приоритет исполнения на CPU – задачи с повышенном приоритетом исполняются первыми. В случае с Linux это называется niceness (nice value), значения в range от -20 до +19. Большая часть процессов по умолчанию запускается с значением 0. Чем НИЖЕ значение nice у процесса, тем ВЫШЕ ее приоритет. Child процесс наследует nice значение у родительского. Посмотреть значение nice можно в top или по ps -efl.

A process is spawned at a certain priority, which is established at initiation based on a numeric value called niceness (or a nice value). There are 40 niceness values, with –20 being the highest and +19 the lowest. Most system-started processes use the default niceness of 0. A higher niceness lowers the execution priority of a process and a lower niceness increases it. In other words, a process running at a higher priority gets more CPU scheduler attention. A child process inherits the niceness of its calling process in calculating its priority. Though we normally run programs at the default niceness, we may choose to initiate them at a different niceness to adjust their priority based on urgency and system load.

We can view current process priorities and niceness values with the ps command, the top command, and the system monitor GUI.
Просмотр

ps (в Windows taskmanager ctrl-shift-esc, tasklist/get-process, process explorer) – позволяет посмотреть процессы, запущенные в системе.  По умолчанию, ps показывает только принадлежащие вам процессы (freebsd) или только принадлежащие текущему терминалу pts (Linux).

Альтернатива – просмотр папок для PID в /proc/<PID>. Оттуда ps (так же как и другие команды, например top), берет информацию о процессах. В этой папке можно найти всю-всю-всю информацию о конкретном процессе. 

The data located under /proc is referenced by a number of system utilities, including top, ps, uname, and vmstat, for display purposes.

Популярные наборы опций:

~$ ps -ef
~$ ps -auxf
~$ ps -fU redkin_p
~$ ps -fG sudo
~$ ps -efl

Популярные опции:

-a - показывается все пользовательские процессы
-e - показывает все процессы, включая системные
-f/F/l - добавляются разные колонки к стандартному выводу. l добавляет pri/ni колонкие с значением niceness (приоритета процесса)
-U - фильтрация по пользователю
-G - фильтрация по группе
lsof – показывает какие файлы используются какими процессами. А т.к. в linux все есть файлы – это зачастую очень полезная утилита, полезна, например, для размонтирования флешек.
 

init – первый процесс стартуемый в системе linux. Имеет pid 1. Стартует другие процессы необходимые для работы системы. 

~$ ps -aux | grep init
root 1 0.0 0.0 33700 1960 ? Ss янв.11 0:04 /sbin/init

Поля:

  • USER – какой пользователь запустил процесс
  • %CPU/%MEM – сколько CPU/MEM потребляет процесс
  • PID – ID процесса
  • PPID – ID родительского процесса (ps -ef)
  • С – ID child процесса (ps -ef)
  • TTY – терминал, связанный с процессом
  • STAT – статус процесса, в один конкретным момент может быть только один статус
    • R:Running – работает (исполняется CPU прямо сейчас),
    • T:Stopped/Suspended – приостановлен (например через kill -20) и не будет исполнен, пока процесс не получит сигнал,
    • S:Sleeping – interruptible sleep – ждет события (пользовательского ввода, другого процесса) для продолжения
    • Waiting – sleeping процесс, который получил нужные данные для продолжения, но ждет очереди
    • Zombie – мертвый процесс, который есть в таблице с процессами, но ресурсы он не потребляет. Существует пока родитель не скажет ему умереть (или не умрет сам).
Each process is in one state at any given time. These states are running, sleeping, waiting, stopped, and zombie, and are explained below:
Running
: the process is being executed by the system CPU.
Stopped: the process is currently halted and will not run even when its turn comes, unless a signal is sent to it to change its behavior.
Sleeping: the process is waiting for input from a user or another process.
Waiting: the process has received the input it was waiting for and is now ready to run as soon as its turn arrives.
Zombie: the process is dead. A zombie process exists in the process table alongside other process entries, but it takes up no resources!!!!. Its entry is retained until the parent process permits it to die. Azombie process is also called a defunct process
  • STIME/START – когда запущен процесс
  • TIME – время которое CPU обрабатывает процесс (совокупное)
TIME - Aggregated execution time for the process, including time spent in both userland and kernel space.
  • COMMAND – исполняемая команда/процесс. При использовании флага -f совместно с -aux (-auxf) показывается дерево зависимостей процесса. Это может быть полезно для отслеживания приложения-источника, например zombie/defunct процессов (можно отследить и по ps -ef).
~$ ps -auxf
redkin_p 11293 0.0 0.0 27560 1928 ? Ss февр.02 0:00 SCREEN -S tp_daemon
redkin_p 11294 0.0 0.1 23664 2468 pts/2 Ss+ февр.02 0:00 \_ /bin/bash
redkin_p 6511 0.0 0.1 23692 2912 pts/4 Ss марта11 0:00 \_ /bin/bash
redkin_p 4098 0.0 0.1 107076 2304 pts/4 S+ марта11 0:00 \_ python3 bin/tp_snmp_proxy.py
root 9507 0.0 0.2 392396 4880 ? Ss февр.19 1:10 /usr/sbin/apache2 -k graceful
www-data 19494 0.0 0.2 392964 4692 ? S марта10 0:00 \_ /usr/sbin/apache2 -k graceful
www-data 19495 0.0 0.2 393208 4668 ? S марта10 0:00 \_ /usr/sbin/apache2 -k graceful
www-data 19496 0.0 0.2 393208 4840 ? S марта10 0:00 \_ /usr/sbin/apache2 -k graceful
redkin_p 29897 1.5 3.9 1171484 81616 ? Sl 03:00 9:54 ruby /home/redkin_p/bin/sms.rb
redkin_p 31681 0.0 0.0 0 0 ? Z 10:49 0:00 \_ [sh] <defunct>
redkin_p 936 0.0 0.0 0 0 ? Z 10:49 0:00 \_ [sh] <defunct>
redkin_p 9125 0.0 0.0 0 0 ? Z 10:50 0:00 \_ [sh] <defunct>
redkin_p 9446 0.0 0.0 0 0 ? Z 10:50 0:00 \_ [sh] <defunct>

~$ ps -ef | head
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 янв.11 ? 00:00:04 /sbin/init
root 2 0 0 янв.11 ? 00:00:00 [kthreadd]
root 3 2 0 янв.11 ? 00:22:33 [ksoftirqd/0]
root 5 2 0 янв.11 ? 00:00:00 [kworker/0:0H]
root 7 2 0 янв.11 ? 01:04:51 [rcu_sched]

~$ ls -l /proc/ | head
total 0
dr-xr-xr-x 9 root root 0 янв. 30 00:30 1
dr-xr-xr-x 9 root root 0 янв. 30 00:30 10
dr-xr-xr-x 9 redkin_p redkin_p 0 марта 12 10:51 10700
dr-xr-xr-x 9 root root 0 янв. 30 00:30 1089
dr-xr-xr-x 9 root root 0 янв. 30 00:30 11
dr-xr-xr-x 9 root root 0 янв. 30 00:30 1114
dr-xr-xr-x 9 root root 0 янв. 30 00:30 1118
dr-xr-xr-x 9 root root 0 янв. 30 00:30 1124
dr-xr-xr-x 9 root root 0 янв. 30 00:30 1126


~$ ls -l /proc/10700/ | head
dr-xr-xr-x 2 redkin_p redkin_p 0 марта 12 14:07 attr
-rw-r--r-- 1 root root 0 марта 12 14:07 autogroup
-r-------- 1 root root 0 марта 12 14:07 auxv
-r--r--r-- 1 root root 0 марта 12 14:07 cgroup
--w------- 1 root root 0 марта 12 14:07 clear_refs
-r--r--r-- 1 root root 0 марта 12 10:51 cmdline
-rw-r--r-- 1 root root 0 марта 12 14:07 comm
-rw-r--r-- 1 root root 0 марта 12 14:07 coredump_filter
-r--r--r-- 1 root root 0 марта 12 14:07 cpuset

~$ cat /proc/10700/status
Name: sh
State: Z (zombie)
Tgid: 10700
Ngid: 0
Pid: 10700
PPid: 29897
TracerPid: 0
Uid: 1000 1000 1000 1000
Gid: 1000 1000 1000 1000
FDSize: 0
Groups: 4 24 27 30 46 110 111 1000 1003
NStgid: 10700
NSpid: 10700
NSpgid: 29896
NSsid: 29896
Threads: 1
SigQ: 0/7891
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000000
SigCgt: 0000000000010002
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
Seccomp: 0
Speculation_Store_Bypass: vulnerable
Cpus_allowed: 3
Cpus_allowed_list: 0-1
Mems_allowed: 00000000,00000001
Mems_allowed_list: 0
voluntary_ctxt_switches: 2
nonvoluntary_ctxt_switches: 1
# Показать PID процесса и дочерних процессов
# pidof показывает в одну строку

~$ pidof systemd
1
~$ pidof crond
441

# pgrep показывает в разные строки (+ поддерживает разные опции и regexp)
~$ pgrep systemd
1
327
337
427
~$ pgrep crond
441
~$ pgrep --oldest postgres # показать только родительский postgres
8434

Аналог ps из мира Windows Powershell – довольно удобно с pipe:sort, select на основе столбцов в выводе.

PS C:\WINDOWS\system32> Get-Process| Sort CPU -descending | Select -first 3 -property ID, ProcessName, CPU

Id ProcessName CPU
-- ----------- ---
8392 start 1231,53125
11484 chrome 749,71875
3912 avp 676,078125
Мониторинг всей системы

top/htop – мониторинг системных ресурсов и процессов в Linux. Показывает сводку по всей системе (сводка из команды uptime:uptime, user count, load average; tasks, CPU usage, Mem usage) и те процессы, которые потребляют больше всего ресурсов. Для начала в общем случае смотрится загрузка CPU/MEM, затем остальное.

load average – безразмерная метрика, показывает среднюю загрузку системы за период времени (100% значения = ~60% загрузка за 1/5/15 минутный интервалы + ~40% загрузка со старта системы – подробнее ниже). По умолчанию загрузка считается нулевой, каждый процесс, который ждет своей очереди для обработки CPU или Drive (HDD/SSD) добавляет значение в 1 к load average, каждый процесс, который прерывается, наоборот, уменьшает значение на 1. Сама метрика получается из файла /proc/loadavg.

In UNIX computing, the system load is a measure of the amount of computational work that a computer system performs. The load average represents the average system load over a period of time. It conventionally appears in the form of three numbers which represent the system load during the last one-, five-, and fifteen-minute periods.

An idle computer has a load number of 0 (the idle process isn't counted). Each process using or waiting for CPU (the ready queue or run queue) increments the load number by 1. Each process that terminates decrements it by 1. Most UNIX systems count only processes in the running (on CPU) or runnable (waiting for CPU) states. However, Linux also includes processes in uninterruptible sleep states (usually waiting for disk activity), which can lead to markedly different results if many processes remain blocked in I/O due to a busy or stalled I/O system.[1] This, for example, includes processes blocking due to an NFS server failure or too slow media (e.g., USB 1.x storage devices). Such circumstances can result in an elevated load average which does not reflect an actual increase in CPU use (but still gives an idea of how long users have to wait).

~$ uptime
18:00:38 up 59 days, 18:18, 4 users, load average: 3,74, 4,29, 3,94

~$ cat /proc/loadavg
3.74 4.29 3.94 3/287 14030

Чтобы получить понимание загружена ли система по load average, значение load average нужно поделить на количество CPU (ядер CPU). Конечно это далеко не всегда справедливо, потому что только в идеальных условиях, процессоры/ядра загружаются равномерно.

В результате Load average в значении 1.73 говорит о разном:

  • на системе c 8 CPU – система “отдыхает”
  • на в системе с 2 CPU – система недозагружена на 0.27%
  • на в системе с 1 CPU – система в полке на 0.73%

В примере ниже с реальных серверов – сервер с 2 CPU очень нагружен (6.43/2), а сервера с 8 (3.65/8) и 16 (0.03/16) недозагружены.

~$ cat /proc/cpuinfo | grep processor | wc -l
2
~$ cat /proc/loadavg
6.43 5.56 5.04 3/379 347

$ cat /proc/cpuinfo | grep processor | wc -l
8
$ cat /proc/loadavg
3.65 4.73 4.96 3/248 30671

$ cat /proc/cpuinfo | grep processor | wc -l
16
$ cat /proc/loadavg
0.03 0.05 0.05 1/782 27791
For example, one can interpret a load average of "1.73 0.60 7.98" on a single-CPU system as:
- during the last minute, the system was overloaded by 73% on average (1.73 runnable processes, so that 0.73 processes had to wait for a turn for a single CPU system on average).
- during the last 5 minutes, the CPU was idling 40% of the time on average.
- during the last 15 minutes, the system was overloaded 698% on average (7.98 runnable processes, so that 6.98 processes had to wait for a turn for a single CPU system on average).
This means that this system (CPU, disk, memory, etc.) could have handled all of the work scheduled for the last minute if it were 1.73 times as fast.

In a system with four CPUs, a load average of 3.73 would indicate that there were, on average, 3.73 processes ready to run, and each one could be scheduled into a CPU.

С точки зрения математики значение load average состоит из:

  • 63% от значения берется из предыдущего минуты/5минут/15 минут
  • 37% берется от загрузки с начала старта системы
Mathematically speaking, all three values always average all the system load since the system started up. They all decay exponentially, but they decay at different speeds: they decay exponentially by e after 1, 5, and 15 minutes respectively. Hence, the 1-minute load average consists of 63% (more precisely: 1 - 1/e) of the load from the last minute and 37% (1/e) of the average load since start up, excluding the last minute. For the 5- and 15-minute load averages, the same 63%/37% ratio is computed over 5 minutes and 15 minutes respectively. Therefore, it is not technically accurate that the 1-minute load average only includes the last 60 seconds of activity, as it includes 37% of the activity from the past, but it is correct to state that it includes mostly the last minute.

На практике сталкивался с высоким load average на gentoo после нагрузки на cpu/HDD (сжатие/архивирование файлов, системное обновление), причем load average уже после самой причины загрузки “не уходил” в течении ~часа – видимо это шлейф 37%. 

lsof – показать открытые процессами файлами. Сопоставление какой файл открыт каким процессом. Может быть полезно при размонтировке носителей (напр. ошибка “device or resource busy” при попытке eject USB). Чтобы посмотреть все процессы нужно запускать из под sudo.

~$ sudo lsof | wc
6175 58986 749350
~$ lsof | wc
2163 20393 250710
Изменение

kill (в Windows taskmanager ctrl-shift-esc, taskkill, process explorer can restart/pause processes) – позволяет остановить (частный случай для Linux kill) процесс/процессы по ID процесса (PID), процессы определенного пользователя и проч.

kill -9 # принудительная остановка процесса (SIGKILL)
kill -9 -1 # принудительная остановка всех процессов пользователя (SIGKILL)
kill -1 # сигнализируем процессу, что ему нужно перечитать свою конфигурацию (SIGHUP)
kill -2 или ctrl-c # сигнализируем процессу, что ему нужно прерывать исполнение (SIGINT)
kill -15 # софт-остановка процесса (может быть проигнорирована приложением) (SIGTERM)
kill -20 или ctrl-z # приостановить процесс (suspended state, SIGTSTP)
kill -18 или ctrl-z # возобновить процесс (SIGCONT)

kill позволяет отсылать большое количество сигналов процессам. По умолчанию используется непринудительная остановка процесса kill -15 (sigterm), которая позволяет приложению высвободить ресурсы и приостановить отключение, в случае если оно считает что оно опасно (например, для сохранения файлов или просто прописан exception не умирать никогда). kill -l позволяет показать все возможные сигналы, которые можно отослать процессу (64 штуки!).

Наиболее часто используемые:
1 SIGHUP Hang up signal causes a process to disconnect itself from a closed terminal that it was tied to. Also used to instruct a running daemon to re-read its configuration.
2 SIGINT The ^c signal issued on the controlling terminal to interrupt the execution of a process.
9 SIGKILL Kills a process abruptly. Some processes ignore signal 15 as they might be waiting for an input to continue processing. Such processes may be terminated forcefully using signal 9.
15 SIGTERM Sends a soft termination signal to stop a process in an orderly fashion. This signal may be ignored by a process. This is the default signal.

~$ kill -l
 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
# Дочерние
pkill <name>
- оперирует названием процесса (по сути kill`pidof <process_name`)
killall <name> - убить все процессы (если больше одного)
killall -9 python - убиваем принудительно все процессы python

nice – позволяет запускать приложения с измененным приоритетом nice value. Например, долгие неважные процессы (backup, обновление системы/приложений, скан сети) можно сделать с nice 15-20, а важные с -15 – -20.

sudo nice -n -20 <command> или nice --20 - запускаем команду с приоритетом -20
sudo renice -n 7 18153 - выставляем активному процессу 18153 приоритет 7
sudo renice -n -20 -u admin - делаем приоритет -20 для всех процессов пользователя admin
sudo renice -n 20 -g customers - делаем приоритет 20 для всех процессов группы customers

~$ sudo renice -n -18 29897
29897 (process ID) old priority 0, new priority -18

Leave a Reply