Масштабирование на стороне приема распределяет сетевой трафик по каналам со скоростью 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, сохраняя Латентность в рамках этого и стабильно получает доход от сети.


