Тюнинг сетевого стека Linux для ленивых

в 6:59, , рубрики: linux, linux networking stack, numa, мониторинг сервера, Настройка Linux, производительность, Серверная оптимизация, Серверное администрирование, сетевые карты, Сетевые технологии, сети, я всё-таки немного пиарюсь, метки:

Сетевой стек Linux по умолчанию замечательно работает на десктопах. На серверах с нагрузкой чуть выше средней уже приходится разбираться как всё нужно правильно настраивать. На моей текущей работе этим приходится заниматься едва ли не в промышленных масштабах, так что без автоматизации никуда – объяснять каждому коллеге что и как устроено долго, а заставлять людей читать ≈300 страниц английского текста, перемешанного с кодом на C… Можно и нужно, но результаты будут не через час и не через день. Поэтому я попробовал накидать набор утилит для тюнинга сетевого стека и руководство по их использованию, не уходящее в специфические детали определённых задач, которое при этом остаётся достаточно компактным для того, чтобы его можно было прочитать меньше чем за час и вынести из него хоть какую-то пользу.

Чего нужно добиться?

Главная задача при тюнинге сетевого стека (не важно, какую роль выполняет сервер — роутер, анализатор трафика, веб-сервер, принимающий большие объёмы трафика) – равномерно распределить нагрузку по обработке пакетов между ядрами процессора. Желательно с учётом принадлежности CPU и сетевой карты к одной NUMA-ноде, а также не создавая при этом лишних перекидываний пакета между ядрами.

Перед главной задачей, выполняется первостепенная задача — подбор аппаратной части, само собой с учётом того, какие задачи лежат на сервере, откуда и сколько приходит и уходит трафика и т.д.

Рекомендации по подбору железа

  • Двухпроцессорный сервер не будет полезен, если трафик приходит только на одну сетевую карту.
  • Отдельные NUMA-ноды не будут полезны, если трафик приходит в порты одной сетевой карты.
  • Нет смысла покупать сервер с числом ядер большим, чем суммарное число очередей сетевых карт.
  • В случае с сетевыми картами с одной очередью распределить нагрузку между ядрами можно с помощью RPS, но потери при копировании пакетов в память это не устранит.
  • Hyper-Threading не приносит пользы и выключается в BIOS (тем более в Skylake и Kaby Lake с ним проблемы)
  • Выбирайте процессор с частотой ядер не менее 2.5GHz и большим объёмом L3 и остальных кэшей.
  • Используйте DDR4-память.
  • Выбирайте сетевые карты, поддерживающие размер RX-буферов до 2048 и более.

Таким образом, если дано 2+ источника объёма трафика больше 2 Гбит/сек, то стоит задуматься о сервере с числом процессоров и NUMA-нод, а также числу сетевых карт (не портов), равных числу этих источников.

"Господи, я не хочу в этом разбираться!"

И не нужно. Я уже разобрался и, чтобы не тратить время на то, чтобы объяснять это коллегам, написал набор утилит — netutils-linux. Написаны на Python, проверены на версиях 2.6, 2.7, 3.4, 3.6.

network-top

network-top

Эта утилита нужна для оценки применённых настроек и отображает равномерность распределения нагрузки (прерывания, softirqs, число пакетов в секунду на ядро процессора) на ресурсы сервера, всевозможные ошибки обработки пакетов. Значения, превышающие пороговые подсвечиваются.

rss-ladder

# rss-ladder eth1 0
- distributing interrupts of eth1 (-TxRx) on socket 0:"
  - eth1: irq 67 eth1-TxRx-0 -> 0
  - eth1: irq 68 eth1-TxRx-1 -> 1
  - eth1: irq 69 eth1-TxRx-2 -> 2
  - eth1: irq 70 eth1-TxRx-3 -> 3
  - eth1: irq 71 eth1-TxRx-4 -> 8
  - eth1: irq 72 eth1-TxRx-5 -> 9
  - eth1: irq 73 eth1-TxRx-6 -> 10
  - eth1: irq 74 eth1-TxRx-7 -> 11

Эта утилита распределяет прерывания сетевой карты на ядра выбранного физического процессора (по умолчанию на нулевой).

server-info

# server-info rate
cpu:
  BogoMIPS: 7
  CPU MHz: 7
  CPU(s): 1
  Core(s) per socket: 1
  L3 cache: 1
  Socket(s): 10
  Thread(s) per core: 10
  Vendor ID: 10
 disk:
   vda:
     size: 1
     type: 1
 memory:
   MemTotal: 1
   SwapTotal: 10
 net:
   eth1:
     buffers:
       cur: 5
       max: 10
     driver: 1
     queues: 1
 system:
   Hypervisor vendor: 1
   Virtualization type: 1

Данная утилита позволяет сделать две вещи:

  1. server-info show: посмотреть, что за железо вообще установлено на сервере. В целом похоже на велосипед, повторяющий lshw, но с акцентом на интересующие нас параметры.
  2. server-info rate: найти узкие места в аппаратном обеспечении сервера. В целом похоже на индекс производительности Windows, но опять же с акцентом на интересующие нас параметры. Оценка производится по шкале от 1 до 10.

Прочие утилиты

  • rx-buffers-increase автоматически увеличивает буфер выбранной сетевой карты до оптимального значения.
  • maximize-cpu-freq отключает плавающую частоту процессора. Энергопотребление будет повышенным, но это не ноутбук без зарядного устройства, а сервер, который обрабатывает гигабиты трафика.

Господи, я хочу в этом разбираться!

Прочитайте статьи про:

Эти статьи вдохновили меня на написание этих утилит .

Также хорошую статью написали в блоге одноклассников 2 года назад.

Обычные кейсы

Но руководство по запуску утилит само по себе мало что говорит о том, как именно их нужно применять в зависимости от ситуации. Приведём несколько примеров.

Пример 1. Максимально простой.

Дано:

  • один процессор с 4 ядрами
  • одна 1 Гбит/сек сетевая карта (eth0) с 4 combined очередями
  • входящий объём трафика 600 Мбит/сек, исходящего нет.
  • все очереди висят на CPU0, суммарно на нём ≈55000 прерываний и 350000 пакетов в секунду, из них около 200 пакетов/сек теряются сетевой картой. Остальные 3 ядра простаивают

Решение:

  • распределяем очереди между ядрами командой rss-ladder eth0
  • увеличиваем ей буфер командой rx-buffers-increase eth0

Пример 2. Чуть сложнее.

Дано:

  • два процессора с 8 ядрами
  • две NUMA-ноды
  • Две двухпортовые 10 Гбит/сек сетевые карты (eth0, eth1, eth2, eth3), у каждого порта 16 очередей, все привязаны к node0, входящий объём трафика: 3 Гбит/сек на каждую
  • 1 х 1 Гбит/сек сетевая карта, 4 очереди, привязана к node0, исходящий объём трафика: 100 Мбит/сек.

Решение:

1 Переткнуть одну из 10 Гбит/сек сетевых карт в другой PCI-слот, привязанный к NUMA node1.

2 Уменьшить число combined очередей для 10гбитных портов до числа ядер одного физического процессора:

for dev in eth0 eth1 eth2 eth3; do
  ethtool -L $dev combined 8
done

3 Распределить прерывания портов eth0, eth1 на ядра процессора, попадающие в NUMA node0, а портов eth2, eth3 на ядра процессора, попадающие в NUMA node1:

rss-ladder eth0 0
rss-ladder eth1 0
rss-ladder eth2 1
rss-ladder eth3 1

4 Увеличить eth0, eth1, eth2, eth3 RX-буферы:

for dev in eth0 eth1 eth2 eth3; do
  rx-buffers-increase $dev
done

Необычные кейсы

Не всегда всё идёт идеально:

  • Встречались сетевые карты, теряющие пакеты (missed) в случае использования RSS на несколько ядер в одной NUMA-ноде. Решение странное, но рабочее — 6 RX-очередей привязаны к CPU0, в rps_cpus каждой очереди записана маска процессоров 111110, потери пропали.
  • Встречались сетевые карты mellanox и intel (X710) продолжающие работать при прекратившемся росте счётчиков прерываний. Трафик в tcpdump имелся, нагрузка, создаваемая сетевыми картами висела на CPU0. Нормальная работа восстановилась после включения и выключения RPS. Почему — неизвестно.
  • Некоторые SFP-модули для Intel 82599ES при обновлении драйвера (сборка ixgbe из исходников с sourceforge) "пропадают" из списка сетевых карт и даже флаг unsupported_sfp=1 не помогает. При этом в lspci этот порт отображается, второй аналогичный порт работает, а в dmesg на оба порта одинаковые warning'и.
  • Некоторые драйверы сетевых карт подстраивают число очередей только под кратные двум значения (что обидно на 6-ядерных процессорах).

Автор: weirded

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js