Быстрый анализ производительности Linux-сервера

Производительность — один из наиболее заметных параметров системы. Именно на её недостаток чаще всего жалуются пользователи. Ниже приведены некоторые элементарные способы по анализу производительности системы.

Часто ошибочно считает, что поднять скорость системы можно хорошо «оптимизировав» конфиги. Это редко бывает так. Оригинальные стоковые конфиги репозиторного софта подходят для решения многих задач. Их можно (и нужно) менять для достижения задач конкретного проекта. Естественно, все изменения следует сопровождать тестами производительности, а для этого должны быть соответствующие методики и инструменты.

Прежде чем что-то пытаться менять в конфигурации необходимо найти проблемные (узкие) места в системе. В общем случае методика исследования следующая:

  • Собирайте и анализируйте статистические данные о работе системы. На минимальном уровне это решается различными системами мониторинга, например, munin, Zabbix. В более продвинутом случае — свои плагины к этим системам мониторинга или собственные скрипты. Если пару дней назад всё работало отлично, а сейчас какие-то «тормоза» — мониторинг поможет установить их источник. Кроме этого, мониторинг позволяет обнаружить еще не проявившиеся проблемы, когда используемые ресурсы системы исчерпываются.
  • Журналируйте собственные изменения конфигурации. И сравнивайте динамику производительности (по собранным статистическим данным) до включения новой конфигурации и после нее. Это поможет узнать, какие изменения действительно эффективны, а какие бесполезны или даже вредны. Также, журналирование позволит оперативно обнаружить медленный код в бизнес-приложениях.
  • Не перегружайте систему. На небольших нагрузках кажется, что ресурсов системы очень и очень достаточно впрок. Однако, это не так. Когда загрузка какого-либо из ключевых параметов системы подходит к 100% (это может быть, например, загрузка ЦП, или ввода-вывода или даже наличие свободного места на дисках), «тормоза» системы возрастают нелинейно. В том числе это происходит из-за «накладных расходов», т.е. ресурсов системы не расходуемых на определённые процессы, а теряемые в процессе работы ОС и переключения задач.

Процессорное время (CPU)

Load average легко собираются любым мониторингом круглосуточно и его необходимо анализировать. Максимальное значение LA (в часы наибольшей нагрузки) не должно превосходить возможностей системы, т.е. количества её ядер CPU. В противном случае неизбежно замедление работы приложений, причем с увеличением LA выше возможностей системы будут возрастать потери на переключении контекста.

Когда LA достаточно высок имеет смысл посмотреть на что именно расходуются ресурсы процессора. Простейший способ это сделать — посмотреть процессы с наибольшим процессорным временем (TIME) в выводе утилит top, htop или ps aux. Далее уже пытаться снизить нагрузку именно на этом звене.

Часто считается, что процессорная мощность это основной показатель, влияющий на общую производительность системы. Это действительно так лишь в некоторых узких применениях, например в численных расчетах. Во многих других прикладных задачах это не так.

В тех же top и htop следует обратить внимание на процессы в состоянии D, которое обычно соответствует ожиданию ввода-вывода процесса, а также на заполнение свопа. Но об этом ниже.

Коротко (для скриптов мониторинга) значение LA можно взять из параметров системы:

cat /proc/loadavg

Вручную — легче в top и htop.

Характеристики использования процессорного времени отображается также командой vmstat:

$ vmstat
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0   7596 329216  13260 14506756    0    0  4625    26   42  145  4  1 81 13  0

vmstat принимает 2 аргумента: время в секундах, в течение которого необходимо наблюдать за системой, и количество генерируемых отчетов. Эту утилиту полезно запускать для наблюдения, например для формирования 10 отчетов по 1 минуте каждый:

vmstat 60 10

Колонки us (user) и sy (system) означают соответсвенно процессорное время затраченное на пользовательские процессы (демоны и прикладного ПО) и системное. Для большинства систем нормально, если время распределяется между ними поровну.

in (interrupts) и cs (context switches) это количества прерываний и переключений контекста, и оба эти параметра — накладные расходы системы и их не должно быть много.

Разбивку использования CPU по ядрам можно получить с помощью mpstat, например по всем ядрам

$ mpstat -P ALL
Linux 3.2.0-4-amd64 (sys01) 	01/05/15 	_x86_64_	(16 CPU)

16:09:51     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
16:09:51     all    3.55   18.39    9.83    1.24    0.00    0.50    0.00    0.00   66.49
16:09:51       0    5.85   43.47   11.04    1.62    0.00    6.79    0.00    0.00   31.23
16:09:51       1    4.23   29.35   10.81    1.34    0.00    0.11    0.00    0.00   54.17
16:09:51       2    3.86   24.70   10.17    1.26    0.00    0.11    0.00    0.00   59.90
16:09:51       3    3.66   22.73    9.64    1.10    0.00    0.13    0.00    0.00   62.74
16:09:51       4    6.01   15.49    8.84    4.94    0.00    0.26    0.00    0.00   64.47
16:09:51       5    3.15   12.93    8.29    1.43    0.00    0.08    0.00    0.00   74.13
16:09:51       6    2.93   12.90    8.11    1.08    0.00    0.08    0.00    0.00   74.90
16:09:51       7    2.79   14.15    8.43    0.87    0.00    0.07    0.00    0.00   73.69
16:09:51       8    4.01   24.11    8.93    0.93    0.00    0.04    0.00    0.00   61.98
16:09:51       9    2.89   15.37   10.24    0.84    0.00    0.07    0.00    0.00   70.60
16:09:51      10    2.91   15.56   10.64    0.85    0.00    0.07    0.00    0.00   69.98
16:09:51      11    2.78   15.35   10.61    0.81    0.00    0.09    0.00    0.00   70.36
16:09:51      12    2.89   11.69    8.56    0.84    0.00    0.04    0.00    0.00   75.98
16:09:51      13    3.58   12.81   12.09    0.66    0.00    0.03    0.00    0.00   70.83
16:09:51      14    2.95   12.32   11.24    0.66    0.00    0.03    0.00    0.00   72.80
16:09:51      15    2.36   11.60    9.59    0.59    0.00    0.04    0.00    0.00   75.82

Выводимые параметры утилиты понимающему человеку там очевидны.

Оперативная память (RAM)

Использование оперативной памяти «на ходу» анализируется с помощью утилит htop, vmstat, free. Лучше — смотреть в динамике в мониторинге, том же мунине. Прежде всего необходимо обратить внимание на использование свопа, который в хорошей должен быть почти свободным и не увеличиваться/уменьшаться в определённое время суток.

В выводе

$ free -h
             total       used       free     shared    buffers     cached
Mem:           47G        44G       2.3G         0B       559M        26G
-/+ buffers/cache:        18G        29G
Swap:          15G       3.6G        12G

если окажется мало free-памяти, но много cached — это нормально. Память может быть занята страничным кэшем (cached), который многократно увеличивает скорость дисковых операций. Когда «свободной» (free) памяти действительно много это даже плохо и означает, что она не полностью используется. То же самое относится к выводу vmstat.

Ввод-вывод (IO, input-output)

Статистику по ввода-выводу системы лучше собирать пакетами мониторинга. Параметр системы, на который в первую очередь необходимо обратить внимание — iowait, т.е. ожидание ввода-вывода. Его подробные значения можно получить, например, с помощью mpstat:

mpstat -P ALL

Сводные значения есть также в top, vmstat.

Часто признаком наличия проблем с вводом-выводом является большое количество процессов в состоянии D (uninterruptible sleep), в которое процесс переходит при ожидании ввода-вывода. Это не обязательно означает, что дело именно в I/O, но такая ситуация в любом случае должна быть исследована.

Счетчики чтения-записи с дисковых устройств получаются по

$ vmstat -d
disk- ------------reads------------ ------------writes----------- -----IO------
       total merged sectors      ms  total merged sectors      ms    cur    sec
sda   90878564 7454833 2829423640 647949492 205895042 265140200 14858972810 2510368504      0 448274
sdb   455801809 14612605 57375867578 2021813576 434699644 365377967 109699014136 4291627964      0 2081456
sdd   94938371 343221533 57971885640 3782143884 34980046 34425685 8816083324 1994769084      0 449787
sdf   83996804 354254620 57971510608 1338153836 35203200 34649634 8822861163 2201253492      0 462982
sde   83274303 354838922 57968955195 1266856936 34793484 34477071 8818425628 2217294360      0 461751
sdc   112569402 325806501 57972989224 4284077532 35217039 34782607 8820518859 2068813212      0 446935
sr0        0      0       0       0      0      0       0       0      0      0
loop0      0      0       0       0      0      0       0       0      0      0
loop1      0      0       0       0      0      0       0       0      0      0
loop2      0      0       0       0      0      0       0       0      0      0
loop3      0      0       0       0      0      0       0       0      0      0
loop4      0      0       0       0      0      0       0       0      0      0
loop5      0      0       0       0      0      0       0       0      0      0
loop6      0      0       0       0      0      0       0       0      0      0
loop7      0      0       0       0      0      0       0       0      0      0
md0   289404098      0 44556083939       0 123718867      0 17627362527       0      0      0

Еще более удобная утилита для этого — iostat. Как и vmstat, она принимает 2 параметра (время наблюдения и количество отчетов). Полезно снять несколько расширенных отчетов за некоторый промежуток времени, например, минуту:

$ iostat -x 60 5
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           7.83   47.27   21.99    1.52    0.00   21.39

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda               0.50    42.87    7.70   40.28    37.27  1732.40    73.76     5.40  112.63   13.26  131.62   2.05   9.83
sdb               9.52    56.27   85.38   60.47  1459.00  5955.80   101.68    14.10   96.69   13.17  214.63   2.46  35.85
sdd               0.08     0.27    0.08    1.47    11.27    40.27    66.49     0.01    5.59   24.80    4.50   4.90   0.76
sdf               0.22     0.50    0.15    2.35    30.27    53.75    67.21     0.02    6.43   31.11    4.85   4.83   1.21
sde               0.17     0.45    0.15    2.28    24.47    44.45    56.64     0.01    4.77   11.11    4.35   3.12   0.76
sdc               0.17     0.32    0.73    1.53    25.47    49.57    66.21     0.02    8.44   12.91    6.30   4.68   1.06
md0               0.00     0.00    1.75    3.25    91.47    93.52    73.99     0.00    0.00    0.00    0.00   0.00   0.00

и по результатам сделать выводы, на какие устройства идет запись или чтение, и как перераспределить содержимое файловой системы для более эффективного использования. Там же есть статистика по iowait.

Сеть (Network)

В первую очередь при определении характеристик сетевых интерфейсов необходимо посмотреть количество ошибок на них, что элементарно делается древней командой ifconfig. Если интерфейс показывает существенное количество ошибок, следует удостовериться в корректности работы сетевой карты и физической сети до маршрутизатора.

Обязательно необходимо убедиться, что настройки скорости и дуплексного режима верны для сетевой карты. Это можно сделать (и изменить) с помощью утилит ethtool и mii-tool:

ethtool eth0

Обычно сетевые карты автоматически узнают сеть, её скорость и дуплексность, но это не всегда так. Иногда встречаются системы, работающие медленно лишь потому, что сетевая карта работает в полудуплексном режиме, что очень сильно снижает производительность и задержку даже ненагруженных систем. В случае полудуплекса или низкой автоопределённой скорости интерфейса, её имеет смысл повысить

ethtool -s eth0 autoneg off speed 100 duplex full

Полезно посмотреть и другие параметры интерфейсов, грепнув их вывода ядра:

dmesg | grep -i eth

Пиковую загрузку сети лучше (как и многое остальное) мониторить постоянно и автоматически, например, тем же munin. Ориентироваться лучше на пиковую нагрузку — по ней должен быть определённый запас и в её время не должно быть больших значений iowait.

Хорошую статистику по сети и разбивку по типам траффика можно получать с помощью ntop.

Что делать

Многие убеждены, что производительность можно многократно поднять («оптимизировать») чисто софтовыми способами, т.е. изменением настроек операционной системы и прикладного софта. На деле это не всегда так.
Ядра современных дистрибутивов Linux уже хорошо настроены в плане производительности. Если задача типовая и «железо» устраивает — менять ничего не нужно. Изменение каких-либо параметров через sysctl на большинстве серверных задач не повысит скорость работы, а при плохом подгоне даже понизит. Тем более, следует скептически относиться ко всем интернет-советам по оптимизации (в том числе, описанным на этом сайте).

Какие-то параметры работы можно оптимизировать: настройками прикладного софта, перераспределением файловой системы. Но большинстве случаев наилучший способ повысить производительности системы — «железный», т.е. изменением аппаратных характеристик сервера или распределением и балансировкой нагрузки по разным серверам. При высокой нагрузке на I/O поможет использование RAID, программных (mdadm) или аппаратных.

На масштабирование «железа» и стоит в перспективе ориентироваться и не строить иллюзий по поводу софтовых оптимизаций.

Защита от DDoS при помощи geoip

Основная задача любой оптимизации состоит в минимизации частоты исполнения медленного кода. Применительно к администрированию web-серверов, медленно генерируемые страницы должны запрашиваться нечасто, или такие страницы необходимо сделать быстро генерируемыми. Для многих «простых» сайтов на известных CMS и обвешанными плагинами любая страница генерируется с использованием значительных ресурсов. Это играет злую шутку на большой мусорной нагрузке, например при умном, но узким DDoS: даже такой сможет обвалить сайт.
В случае, если DDoS идёт из определённых стран, например из Китая и Индии (что происходит в большинстве случаев), то появляется быстрое и эффективное решение для защиты региональных сайтов — фильтр входящих запросов по географии и ответ только на запросы с нужных стран. Тогда, «вредные» запросы не доходят до backend, медленный код не исполняется и ресурсы серверы не тратятся, в результате чего сервер для локальных запросов сервер не падает и обычно даже работает с незаметным замедлением.

Делается это правилом вроде

$IPTABLES -A HTTP -m geoip ! --src-cc RU -j DROP

Перед этим правилом определяется стандартным образом цепочка HTTP (-p tcp --dport 80).

Способ, естественно, не годится на случай широких DDoS, нацеленных на заполнение канала (особенно udp-траффиком). Но для слабых, основанных на генерировании нагрузки, DDoS, он вполне годится.

PS: Естественно geiop модули к iptables должны быть поставлены заранее. Тогда этот способ будет действительно быстрым.

Полезные твики bash

В этой статье наиболее полезные способы быстрой и продуктивной работы с коммандной строкой bash. Предполагается, что читатель уже несколько знаком с коммандной строкой, поэтому совсем тривиальных вещей, вроде использования Tab для автодополнения, здесь нет. В комментарии приветствуются другие полезные «твики» bash.

Алиасы

Листинги

alias ll='ls -l'
alias l='ls -lA'

Часто эти опции уже включены в .bashrc, но закомментированы. В Debian, например, в конфиге это реализовано так

# export LS_OPTIONS='--color=auto'
# eval "`dircolors`"
# alias ls='ls $LS_OPTIONS'
# alias ll='ls $LS_OPTIONS -l'
# alias l='ls $LS_OPTIONS -lA'

Остается раскомментировать нужные строчки. При этом в нагрузку получаем цветовую подсветку директорий.

Часто используемая команда по поиску процесса с определенным именем:

alias pg='ps aux | grep '

Просмотр наибольших файлов/директорий в гигабайтах и мегабайтах соответственно:

alias dug='du -h | grep ^[0-9.]*G | sort -rn'
alias dum='du -h | grep ^[0-9.]*M | sort -rn'

Полезности для скриптов

Иногда бывает полезным поймать сигналы, посылаемые ОС скрипту. Например, при нажатии Ctrl-C.

trap control_c SIGINT
trap control_c SIGTERM

Часто используемые команды

Часто бывает необходимо найти файл, в котором имеется определённая подстрока. Сделать это можно с помощью стандарной утилиты grep командой:

grep -rl

Горячие клавиши bash

  • Ctrl+w — удаляет слово перед курсором в строке,
  • Ctrl+u — удаляет все символы до начала строки,
  • Ctrl+k — удаляет все символы до конца строки,
  • Ctrl+y — вставляет удалённые вышеуказанными сочетаниями символы,
  • Ctrl+r — производит обратный поиск по истории команд,
  • Ctrl+l — очищает экран,
  • Ctrl+z — останавливает исполнение текущей команды (продолжить можно с помощью bg или fg),
  • Ctrl+d — выход из сессии.

История команд bash

В администрировании Linux (да и UNIX тоже) очень удобно пользоваться командами из истории. Содержание истории просматривается с помощью вызова history. Команду из истории можно выполнить по её номеру в списке например так:

history | less
!45

При этом последняя команда вызывается более просто, без указания номера выполнением !!.

Обратный поиск по истории команд вызывается с помощью Ctrl+R, например:

(reverse-i-search)`smart': smartctl -x /dev/sdd | less

Взять аргументы из одной из предыдущих команд можно сочетанием Alt+..

По умолчанию длина истории небольшая и если нет повышенных требований к безопасности её можно несколько увеличить добавлением в .bashrc строки:

export HISTFILESIZE=5000

Длинная история несколько понижает безопасность системы, особенно если в неё попадают всякие «интересные» команды. Поэтому, на критичных системах размер истории большой делать не стоит. Сбросить историю можно

history -c

Избежать добавления команды в историю можно начав её с пробела. Тогда исполненная инструкция в историю не попадает.