...

Receive Side Scaling при скоростях 10 и 25 Гбит/с: оптимизация производительности для современных серверных сетей на базе Linux

Масштабирование на стороне приема распределяет сетевой трафик по каналам со скоростью 10 и 25 Гбит/с между несколькими ядрами, чтобы серверы Linux могли обрабатывать большие объемы данных с низкой задержкой. Я покажу на практике, как я включаю RSS, которые Кии на карте ядер и таким образом избегаю узких мест при обработке прерываний и попаданий в кэш.

Центральные пункты

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

  • Распределение нагрузки: Пакеты распределяются по нескольким ядрам через несколько очередей.
  • Локальность кэша: Поток всегда остается в одной и той же очереди.
  • Хеширование: Хеш-функция на 4-кортерах равномерно распределяет потоки по очередям.
  • аффинность: Целенаправленное сопоставление IRQ позволяет сократить задержки.
  • Масштабирование: Начиная со скорости 10/25 Гбит/с, RSS обеспечивает высокую пропускную способность.

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

В чем заключается эффективность технологии Receive Side Scaling

RSS разбивает процесс приёма пакетов на несколько этапов Очереди приема, которые я распределяю по конкретным ядрам ЦП, чтобы ни одно из ядер не стало «узким местом». Это снижает пиковые нагрузки от аппаратных прерываний и сглаживает обработку с помощью программных прерываний (SoftIRQ), что уменьшает пиковые значения задержки и повышает пропускную способность. Каждая очередь инициирует собственные прерывания, которые я жестко привязываю к ядрам, чтобы обеспечить согласованность путей передачи данных. Эта согласованность способствует Кэш-локальность, поскольку поток всегда сталкивается с одним и тем же ядром. Именно это взаимодействие при высоких показателях PPS напрямую способствует повышению измеримой эффективности.

Как работает RSS с технической точки зрения

NIC формирует на основе IP-адресов источника и назначения, а также портов источника и назначения Хаш и использует его в качестве индекса для таблицы Indirection, которая указывает на очереди. Таким образом, пакеты одного потока всегда попадают в одну и ту же очередь и, следовательно, остаются привязанными к одному и тому же ядру. Различные потоки распределяются равномерно, при условии что хеш-ключи и поля протокола настроены правильно. Таким образом, работа перемещается ближе к Оборудование, благодаря чему ядру приходится меньше заниматься балансировкой, а накладные расходы снижаются. Именно этого я и хочу добиться, чтобы при скорости 10G/25G количество обрабатываемых пакетов на каждое ядро оставалось низким.

Почему RSS имеет значение при скорости от 10 до 25 Гбит/с

При скорости 1 Гбит/с часто достаточно одного Ядро нагрузка от пакетов, однако при скорости от 10 Гбит/с баланс быстро нарушается. Небольшие пакеты приводят к росту показателя PPS, в результате чего ядро быстро достигает 100-процентной загрузки и возникают пропуски. Именно в этот момент RSS действует как мультипликатор полезной пропускной способности. Я распределяю нагрузку между несколькими Ядра, сокращает количество переключений контекста и обеспечивает более стабильные кривые задержки. Результат: реальная пропускная способность приближается к скорости передачи данных только при использовании «чистого» RSS.

Настройка RSS на сервере Linux

В Linux я управляю RSS в основном с помощью ethtool, параметры драйвера и sysfs, чтобы возможности сетевой карты действительно реализовались. Сначала я считываю максимальное количество каналов приема (RX-Channels), а затем устанавливаю количество очередей, соответствующее процессору. Затем я проверяю RSS-хэш для TCP/UDP и, по желанию, для VLAN или туннелирования, чтобы профили нагрузки оставались правильно распределенными. Для устранения фонового шума при распределении прерываний мне помогает Балансировка IRQ, хотя я предпочитаю вручную фиксировать критические очереди. Вот как я связываю Кии тесно привязываться к топологии хоста и предотвращать нежелательные перемещения.

Таблица косвенных адресов, RSS-ключ и точная настройка хеша: конкретные команды

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

ethtool -x eth0 # — отобразить таблицу косвенного адресации (очереди приема) и ключ RSS
ethtool -n eth0 rx-flow-hash tcp4
ethtool -n eth0 rx-flow-hash udp4

Для чистого и равномерного распределения я устанавливаю в таблице Indirection желаемое количество очередей. При 16 очередях я выбираю равномерное сопоставление:

ethtool -X eth0 equal 16  Распределение # равномерно по 16 очередям

При необходимости я настраиваю поля хеша. Для TCP4 с 4-кортежами (s = src-ip, d = dst-ip, f = src-port, n = dst-port):

ethtool -N eth0 rx-flow-hash tcp4 sdfn
ethtool -N eth0 rx-flow-hash udp4 sdfn
ethtool -N eth0 rx-flow-hash tcp6 sdfn
ethtool -N eth0 rx-flow-hash udp6 sdfn

Некоторые драйверы также позволяют задавать собственный ключ RSS (например, для более эффективного распространения в особых случаях):

ethtool -X eth0 hkey   # — только если это поддерживается драйвером/сетевой картой

Правильная настройка аффинности процессора и NUMA

Я создаю карту для каждой очереди RX с помощью Сродство к IRQ привязывайте их к выделенным ядрам, учитывая при этом NUMA, чтобы данные проходить по контроллеру памяти на коротком расстоянии. Если сетевая карта работает на узле 0, я также привязываю основные очереди к ядрам на узле 0 и размещаю рабочие нагрузки поблизости. Такая близость сокращает количество удалённых обращений и значительно снижает задержки в памяти. Для этого полезно создать профиль для производственных очередей, а также выделить отдельные ядра для задач управления и разгрузки. Те, кто хочет углубиться в эту тему, найдут рекомендации по тонкой настройке по адресу Сродство к IRQ, что касается планирования на Ядро упрощенный.

Руководство по аффинности IRQ: от IRQ к стабильной привязке к ядру

Сначала я определяю, какие IRQ относятся к очередям приёма (RX-Queues), а затем фиксирую их:

grep -E "eth0.*Rx" /proc/interrupts
cat /sys/class/net/eth0/device/numa_node

Я настраиваю сопоставление с помощью smp_affinity_list, чтобы мне не пришлось вычислять «маски Hex». Пример: очереди RX 0–7 на ядра 2–9:

Пример #: назначение IRQ ядрам 2–9 (по одной строке на каждый IRQ)
echo 2  > /proc/irq//smp_affinity_list
echo 3  > /proc/irq//smp_affinity_list
echo 4  > /proc/irq//smp_affinity_list
...
echo 9  > /proc/irq//smp_affinity_list

Важно: функция MSI-X должна быть включена, чтобы каждая очередь имела собственные прерывания. Если я использую ручную привязку выводов, я блокирую irqbalance для этих IRQ (например, с помощью черного списка) или целенаправленно отключить службу на хостах со статической схемой размещения. Проверку NUMA я дополнительно выполняю с помощью lscpu и настройки PCIe, чтобы не создавать межузловые пути.

Настройка хэша и протоколы

Я определяю поля хешей таким образом, чтобы настоящие Трафик-Распределять образец равномерно, а не сосредотачивать его в нескольких очередях. Для TCP/UDP я использую 4-туплет, для IPv6 — аналогичный подход, а для VXLAN или GRE учитываю дополнительные поля инкапсуляции. Некоторые сетевые карты поддерживают настраиваемые хеш-ключи, которые я адаптирую под доминирующую рабочую нагрузку. Как только я замечаю скопление нагрузки в отдельных очередях, я корректирую выбор хеша. Этот шаг занимает мало времени, но предотвращает нестабильное положение при большом количестве соединений.

Объединение прерываний и PPS

Я сочетаю RSS с умеренным Коалесценция прерываний, чтобы сгруппировать трафик с высокой интенсивностью PPS в удобные для обработки пакеты. Это снижает накладные расходы на прерывания, но не должно ухудшать задержку для чувствительных сервисов. Поэтому я измеряю время прохождения в обоих направлениях и постепенно изменяю параметры объединения. При обработке нагрузок, связанных с хранением данных или резервным копированием, можно осуществлять более значительную агрегацию, чем в случае с L7-API или VoIP. В целом я балансирую Латентность по сравнению с пропускной способностью, пока оба показателя не станут согласованными.

Коалесцирование на практике: профили и точки измерения

Я начинаю с умеренных значений по умолчанию и постепенно подбираю оптимальные настройки для каждой рабочей нагрузки. Три проверенных исходных профиля:

  • API/низкая задержка: rx-usecs 2–6, rx-frames 16–32, отключить адаптивный режим
  • Универсальный: rx-usecs 8–16, rx-frames 32–64, адаптивный к
  • Оптовые поставки/хранение: 24–48 ркс-микросекунд, rx-frames 128–256, адаптивный к
ethtool -c eth0
ethtool -C eth0 rx-usecs 12 rx-frames 64 adaptive-rx on

Для этого я измеряю задержки p95/p99, PPS, нагрузку на ЦП на каждое ядро и количество повторных передач. Как только я замечаю рост дисперсии в API/VoIP, я перехожу к rx-мкс снова уменьшаю. В случае с хранением данных я скорее увеличиваю масштаб через кадры, чтобы сэкономить на прерываниях.

RSS в средах с пропускной способностью 10 Гбит/с

На 10G-NIC я обычно работаю с 8–16 Кии на каждый порт, при условии, что ЦП предоставляет достаточное количество ядер. Таким образом, веб-серверы, шлюзы хранилищ и хосты виртуализации плавно масштабируются при большом количестве параллельных соединений. Я привязываю основные очереди к свободным ядрам, а затем измеряю PPS, задержку и количество повторных передач. Если возникают потери пакетов, я проверяю коалесцирование, хэширование и загрузку каждой очереди. Затем я настраиваю аффинность, пока загрузка не станет равномерной.

RSS в конфигурациях 25 Гбит и Multi-25G

При скорости 25 Гбит/с растут PPS и нагрузка на шину, поэтому я NUMA-уделяю больше внимания наличию достаточного количества очередей и механизмов разгрузки. Large Receive Offload (LRO) или RSC могут снизить нагрузку пакетов на стек, если приложения это допускают. Кроме того, я проверяю линии PCIe, чтобы исключить узкие места вне сети. На хостах с несколькими 25G-соединениями я строго разделяю очереди и аффинность в зависимости от задач и узлов. Таким образом, я использую Полоса пропускания и ядра эффективно, не переходя в межузловой трафик.

Сведения об оборудовании и драйверах: на что я обращаю внимание

Не все сетевые карты ведут себя одинаково. Поколения Intel (например, ixgbe, i40e, ice) предлагают такие функции, как Flow Director/ATR, которые целенаправленно привязывают потоки к очередям — это полезно, если я хочу сгладить пиковые нагрузки. Mellanox mlx5 может аппаратно поддерживать aRFS, что снижает нагрузку на ЦП, если стек обслуживает много сокетов. Я решаю в каждом конкретном случае, активировать ли эти функции, и измеряю, улучшают ли они распределение нагрузки. На системах маршрутизации/NAT я часто отключаю LRO и использую GRO для обеспечения согласованности заголовков; при работе с чисто серверными нагрузками LRO/GRO может помочь снизить нагрузку по PPS. Кроме того, важно обеспечить достаточное количество векторов MSI-X на каждую очередь и правильные версии прошивки.

RSS в виртуализации и контейнерах

В гипервизоре я объединяю физические RSS-Очереди с виртуальными сетевыми адаптерами (vNIC), поддерживающими работу с несколькими очередями, например virtio-net, чтобы гостевые системы не сталкивались с искусственными узкими местами. Я уделяю внимание привязке виртуальных машин к процессору (CPU-pinning) и настраиваю близость их vCPU к физическому сетевому интерфейсу в рамках NUMA. Таким образом, данные остаются локальными, а хост тратит меньше ресурсов на доступ к памяти. Для контейнеров я привязываю критически важные поды к подходящим ядрам и освобождаю очереди хоста от ненужной нагрузки. Такая организация повышает Эффективность в случае микросервисов, где возникает множество небольших потоков.

Как правильно использовать SR-IOV и VF-RSS

С помощью SR-IOV я назначаю виртуальным машинам собственные виртуальные каналы (VF), которые, в свою очередь, могут предоставлять несколько очередей и RSS. Я планирую достаточное количество виртуальных интерфейсов на каждый порт, обращаю внимание на пропускную способность MSI-X и привязываю IRQ виртуальных интерфейсов в виртуальной машине в соответствии с её виртуальными процессорами. В гостевых системах Linux я явно включаю Multi-Queue, иначе виртуальная сетевая карта часто остаётся одноуровневой:

# в гостевой системе (пример virtio-net)
ethtool -l eth0
ethtool -L eth0 combined 4

Хосты с несколькими виртуальными функциями (VF) я строго распределяю по NUMA-узлам и рабочим нагрузкам, чтобы виртуальные машины (VM) не создавали друг другу помех в одних и тех же физических путях приема (RX).

Мониторинг и устранение неисправностей

Я отслеживаю загрузку по Очередь, отдельные ядра, потери пакетов и повторные передачи, чтобы на раннем этапе выявить дисбалансы. Если одно ядро «вырывается» вперед, а остальные остаются без нагрузки, это часто свидетельствует о неверных настройках аффинности или количества очередей. В таких случаях я поочередно проверяю хеш-поля, маски IRQ и параметры коалесцирования. Кроме того, я обращаю внимание на Нагрузка SoftIRQ, поскольку она указывает на наличие эффектов вытеснения. Только когда эти показатели выглядят стабильными, я увеличиваю трафик или расширяю Кии продолжайте.

RPS, RFS и XPS: программные дополнения к RSS

Если сетевая карта имеет лишь несколько очередей или я использую объединение/туннелирование, я дополняю RSS следующим образом: RPS (управление приемом пакетов) и RFS (Receive Flow Steering). RPS распределяет SoftIRQ-сигналы между ядрами, а RFS привязывает потоки к тому ядру, на котором активен соответствующий сокет. Я целенаправленно включаю обе функции:

# Увеличить общее количество записей потока (RFS)
echo 32768 > /proc/sys/net/core/rps_sock_flow_entries

# Установить количество процессоров для RPS на каждую очередь приёма (RX-Queue) (пример маски, настройте по необходимости!)
for f in /sys/class/net/eth0/queues/rx-*/rps_cpus; do echo ffff > "$f"; done

Настройка таблицы потоков для RFS в очереди приема #
for f in /sys/class/net/eth0/queues/rx-*/rps_flow_cnt; do echo 4096 > "$f"; done

На стороне TX я использую XPS (Transmit Packet Steering), чтобы исходящие пакеты отправлялись из того ядра, которое их сгенерировало:

for f in /sys/class/net/eth0/queues/tx-*/xps_cpus; do echo ffff > "$f"; done

RPS/RFS/XPS требуют некоторых ресурсов ЦП, но помогают, если у меня не хватает очередей на аппаратном уровне или если я хочу строго соблюдать локальность сокетов.

Пропускная способность Single-Flow, GRO/TSO и опрос занятости

Отдельный поток по веской причине остается привязанным к одному ядру. Если я хочу увеличить пропускную способность отдельного потока, я использую механизмы разгрузки (GRO/TSO), высокую тактовую частоту ядра и оптимальное объединение потоков. Для траекторий, для которых задержка имеет критическое значение, можно Занятый опрос помочь:

Установить низкое значение # и произвести измерение
sysctl -w net.core.busy_read=25
sysctl -w net.core.busy_poll=25

Метод «busy-polling» сокращает количество смен контекста, но занимает время процессора. Я включаю его только в тех случаях, когда задержки p99 имеют значение, и всегда проверяю, как это влияет на общую загрузку и задержку в конце последовательности. GRO я, как правило, оставляю включенным на серверах, LRO использую в зависимости от роли; на промежуточных устройствах я придерживаюсь консервативного подхода, чтобы не нарушать обработку заголовков и согласованность хешей.

Рекомендации и примеры: очереди, аффинность, команды

В качестве отправной точки я выбираю количество очередей, которое соответствует CPU подберите, затем отслеживайте нагрузку по каждой очереди и корректируйте пошагово. При 10G часто достаточно 8–16 очередей, при 25G я часто устанавливаю больше, если есть достаточно ядер. Для аффинности я использую чёткие маски для каждого IRQ, чтобы позже было проще анализировать пути. В приведённой ниже таблице представлены краткие ориентировочные значения, которые я затем проверяю с помощью измерений. Только результаты измерений определяют, буду ли я подробнее увеличи или уменьши.

Скорость соединения Типичные очереди RX Примеры команд Примечания
10 Гбит/с 8-16 ethtool -l eth0 | ethtool -L eth0 rx 16 Коалесцирующий поддерживать умеренный уровень, проверить задержку L7
25 Гбит/с 16–32+ grep . /proc/interrupts | Маски IRQ посредством echo NUMA обратите внимание, проверьте количество линий PCIe
Multi-25G Отдельно за каждый порт Включить многоочередную vNIC (например, virtio) Очереди по ядрам и Рабочие нагрузки разделить

Эти ориентировочные значения являются лишь отправной точкой, а не конечной целью, поскольку рабочие нагрузки значительно различаются. Я фиксирую изменения, провожу измерения до и после настройки и в остальном оставляю среду без изменений. Как только система начинает стабильно работать под производственной нагрузкой, я фиксирую конфигурацию. Позже я повторяю измерения после обновлений ядра или драйверов. Таким образом, я придерживаюсь RSS Точное следование курсу и надежные, воспроизводимые результаты.

Типичные препятствия и меры по их устранению

Слишком мало Кии перегружают отдельные ядра, а их избыток увеличивает административную нагрузку и снижает коэффициент попадания в кэш. Неудачная аффинность приводит к перенаправлению прерываний на уже загруженные ядра или на неправильные узлы NUMA. Кроме того, неподходящий хеш приводит к тому, что доминирующие потоки забивают очереди. Я решаю эту проблему поэтапно: корректирую количество очередей, исправляю аффинность, расширяю поля хеширования, тонко настраиваю коалесцирование. Каждое изменение я документирую с помощью Метрики, прежде чем перейти к следующему рычагу.

Практические сценарии

Сервер хранения данных с интерфейсом 10G быстро начинает приносить пользу в объеме 8–12 Кии плюс умеренное коалесцирование, чтобы обеспечить плавную передачу больших объемов данных. API-сервер с большим количеством подключений часто требует более тонких хеш-полей и меньшей задержки при прерываниях. Хосты виртуализации значительно выигрывают, если на стороне гостя включена функция vNIC-Multi-Queue и она соответствует структуре хоста. Контейнерные рабочие нагрузки работают более стабильно, если критически важные поды запускаются вблизи сетевой карты и NUMA-памяти. Я расширяю эти шаблоны в зависимости от ситуации, используя PPS, ретрансляции и распределение по очередям.

Преимущество высокопроизводительных платформ

Настройки хостинга с последовательно сконфигурированным RSS, сетевые карты с поддержкой нескольких очередей и правильная настройка аффинности обеспечивают ощутимый запас производительности при пиковых нагрузках. При оценке предложений по серверам следует целенаправленно интересоваться поддержкой нескольких очередей, привязкой NUMA и возможностями мониторинга. Поставщик, который явно реализует эти моменты, часто демонстрирует заметно лучшие кривые пропускной способности. В качестве явной рекомендации для мощных серверных и хостинговых решений я здесь упоминаю webhoster.de. Такая ориентация окупается в Производительность и стабильность, особенно при большом количестве параллельных потоков.

Резюме для практики

Я активирую Получить Боковое масштабирование: задайте разумное количество очередей, привяжите IRQ к подходящим ядрам и проверьте настройки хеширования. Затем я оптимизирую коалесцирование с учетом задержки, обращаю внимание на близость NUMA и последовательно распределяю рабочие нагрузки. При виртуализации я использую многоочередную обработку вплоть до гостевых систем и синхронизирую привязку и аффинность. Результаты измерений PPS, загрузки очередей, повторных передач и задержки определяют следующий шаг. При таком подходе можно реально использовать 10G и 25G, сохраняя Латентность в рамках этого и стабильно получает доход от сети.

Текущие статьи

Серверная стойка с выделенными модулями оперативной памяти, иллюстрирующая кэш ZFS ARC в центре обработки данных
Серверы и виртуальные машины

Кэш ARC в ZFS: как правильно понимать потребление памяти

Узнайте, как работает кэш ARC в ZFS, почему высокое потребление оперативной памяти является нормальным явлением и как правильно настроить использование памяти для повышения производительности ZFS.

Серверы центра обработки данных с файловыми системами XFS и EXT4 на SSD-накопителях NVMe в фотореалистичном изображении
Серверы и виртуальные машины

XFS против EXT4 на серверах с NVMe: тесты производительности и сравнительный анализ в реальных условиях

XFS против EXT4 на серверах с NVMe: в этой статье рассматриваются результаты тестов, практические данные и дается рекомендация, какая файловая система лучше всего подходит для вашего хранилища под Linux.

Некатегоризированный

Подписка на Office — ловушка для кошелька? Как веб-мастера экономят сотни евро благодаря подержанным лицензиям

Для индивидуальных предпринимателей и веб-мастеров профессиональное офисное ПО — это не роскошь, а незаменимый инструмент. Будь то составление коммерческих предложений или ведение бухгалтерского учета в Excel