Я тут за последнюю неделю довёл до ума свой полусайд-проект: netutils-linux.

Его можно разделить на три части:

  • тулзы для мониторинга сетевого стека Linux
  • тулзы для тюнинга сетевого стека Linux
  • тулзы для оценки параметров используемого на сервере железа по шкале от 1 до 10 (чот типа индекса производительности Windows)

Почему я его начал разрабатывать

На самом деле причин много и все они сводятся к тому, что меня бесит человеческий фактор и люди которым надо что-то объяснять/обучать.

Так уж случилось, что по работе мне часто приходится выжимать из сетевого стека Linux все соки, так как это даёт результаты куда более эффективные чем оптимизация каких-либо алгоритмов, мною используемых. Вот взять этот самый сетевой стек - чтобы хорошо понять как это всё работает необходимо знать С и разбираться в архитектуре современных компьютеров, т.е. представлять что такое кольцевые буферы, выделение, чтение и запись памяти, кэши процессора, NUMA, DMA, DCA, прерывания всех сортов и это только первые полтора уровня модели OSI. Требовать это от ребят, которые не разработчики, а помогают клиентам и вообще специализируются на том, чтобы всякие штуки просто работали надёжно и не трахали им мозг было бы как-то странно. К тому же к нам в команду периодически попадают новые люди и разом забивать всё это в голову человека, который недавно вообще в промышленное программирование пришёл, а ему ещё и работу работать успевать надо - глупо вдвойне.

Короче - знания по тому, как и куда смотреть чтобы понять насколько всё хорошо работает на конкретной машинке в конкретный момент времени засунуть в человека довольно долго и дорого, а часто ему самому это ещё и не особо нужно. Есть много хороших источников для того чтобы просветиться - статьи в блоге packagecloud и доках red hat (во многом на эту штуку вдохновили меня именно они), но они на английском языке, а языковой барьер - распространённая беда в нашей любимой стране. Можно перевести их на русский - но для этого нужно довольно много времени.

Тут будет несколько непривычно звучать известная многим фраза: “Код - лучшая документация”. Но в данном случае, спрятав всю известную мне хрень в утилиты, которые наглядно показывают распределение нагрузки на всех уровнях сетевого стека и помогают понять устройство настраиваемого сервера, невероятно экономят время. Унифицированные тулзы для тюнинга сетевого стека вместо прописывания специфичных стартовых скриптов вручную для каждой машинки - экономят его ещё сильнее. А самое главное - люди больше почти не приходят ко мне с просьбой помочь и я могу спокойно заниматься разработкой. Ура!

Самый короткий экскурс в тюнинг сетевого стека

Основная задача - максимально равномерно размазать нагрузку по обработке пакетов между ядрами процессора, желательно с учётом cache-locality и принадлежности CPU и девайса к одной NUMA-ноде и всё это минимальными усилиями, чтобы не создавать лишнего оверхеда.

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

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

Что оно умеет?

Мониторинг

Здесь рассмотрим только одну тулзу, которая включает в себя все остальные - network-top. Это эдакий консольный dashboard, который на одном экране включает в себя всю информацию о текущей утилизации сетевого стека. Остальные рассматривать не будем, так как они были небольшими шагами по пути к созданию этого самого network-top. Все они появились из-за того, что меня бесило как коллеги стучали по клавиатуре запуская cat /proc/какой/нибудь/файл или ip -s -s link show eth1 снова и снова, наблюдая за изменением каких-нибудь счётчиков. Да и самому вместо этого писать watch -n 1 перед подобными командами и городить пайпы с грепами седами надоело довольно быстро.

Что оно показывает:

network-top

Есть проблема с компактностью на большом числе ядер. Я пробовал это исправить, вышло как-то так:

network-top

Прерывания

В самом верху отображаются основные источники прерываний (прерывания с слабо меняющимися или не меняющимися вовсе счётчиками скрываются, чтобы всё умещалось на 1 экран). Имена ядер процессоров с помощью подсветки делятся на группы с хитрой логикой: по принадлежности к NUMA-ноде, если их больше одной, в противном случае по принадлежности к сокету процессора (бывают системы с двумя процессорами и одной NUMA-нодой, хотя я слабо представляю насколько это хорошо работает и как вообще). Тут есть над чем поработать, потому что в случае 32+ядерных систем всё это дело с трудом влезает на экран. Кстати ещё две клёвые идеи: прерывания сетёвых карт тоже подсвечивать там, а

Распределение обработки пакетов по CPU

Посередине находится самое важное - статистика обработки пакетов с распределением по CPU. Здесь собраны:

  1. Interrupts. Суммарное число прерываний на это ядро. Верхний потолок для хорошей работы - 10к прерываний на 1GHz частоты ядра, в случае если все ядра физические. В случае с hyperthreading - 5к.
  2. NET_RX. Число softirq на приём пакетов. Приблизительно те же цифры, что и выше.
  3. NET_TX. Число softirq на отправку пакетов. С этим я особо не занимаюсь, ничего сказать не могу. Это поле добавил просто чтобы видеть, например, скопившиеся на одном ядре прерывания на отправку пакетов.
  4. Total. Число обработанных данным ядром пакетов (хихи, время меряться pps!)
  5. Dropped. Число дропнутых в процессе обработки пакетов. Это уже тоска и приводит к тому что ваша сеть работает медленнее, юзеры повторно отправляют пакеты, у них задержки, потери, жалуются в техподдержку например.
  6. Time squuezed. Число пакетов, которым не хватило времени для обработки (но их обычно успевают обработать в следующем). Ещё чуть чуть и начнут дропаться! Повод задуматься о дополнительном тюнинге.
  7. CPU Collision. times that two cpus collided trying to get the device queue lock. (почти ни разу не видел, мб стоит удалить это).
  8. Received RPS. Нужно чтобы убедиться, что настроенный RPS (спасает в случае сетёвок с одной очередью) реально работает и пакеты распределяются между ядрами для обработки.

Статистика по сетевым девайсам

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

Задать список интересующих девайсов

network-top --devices=eth1,eth2,eth3

Отсеять девайсы регуляркой:

network-top --device-regex='^eth'

Её можно сделать менее подробной, спрятав все специфичные ошибки командой --simple или убрав данные об отправке пакетов командой --rx-only.

Представление данных об объёме трафика можно менять ключами –bits, –bytes, –kbits, –mbits.

В принципе всей этой информации должно быть достаточно, чтобы сформировать представление о том, откуда идёт нагрузка, что и на каком уровне надо подтюнить, на что можно забить, а также увидеть косяки текущих настроек (очереди сетёвки раскиданы в remote NUMA node например).

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

Тюнинг

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

RSS

Эта возможность - must have для сетевых карт с несколькими очредями. Её реализация лежит на сетевой карте и её драйвере. Прописывать affinity ручками - дело тяжелое, поэтому я сделал утилиту rss-ladder, которая распределяет обработку прерываний (а следовательно и пакетов) между ядрами процессора “лесенкой”. На текущий момент она умеет распределять прерывания очередей сетёвки по указанному физическому процессору, хотя наверное по хорошему стоит делить только по NUMA-нодам.

Опций у неё немного, usage проще некуда:

rss-ladder <device> [CPU Socket, по умолчанию 0]

RPS

По сути программная реализация RSS. Теоретически может использоваться одновременно с RSS, теоретически при этом спасая от потерь при пиковых нагрузках, но в целом повышая нагрузку на CPU (оверхед же).

На мой взгляд она имеет смысл только в случае если у сетевой карты одна очередь, либо глючит RSS.

Для того, чтобы не заморачиваться с вычислением масок CPU можно воспользоваться утилитой autorps.

Размер RX-буферов сетевой карты.

Чем больше буфер - тем больше пакетов сетевая карта сможет накопировать с помощью DMA в кольцевой буфер в RAM, который уже будет обрабатываться процессором.

Обычно это выгодно, так что можно выкрутить их на максимум с помощью rx-buffers-increase.

Частота процессора

Нельзя давать процессору уходить в экономный режим, если мы хотим чтобы он отлично обрабатывал пакеты!

В случае, если процессор имеет плавающую частоту можно установить для каждого ядра минимальной частотой максимальную и радоваться жизни.

Сделать это можно с помощью maximize-cpu-freq.