Pull to refresh

Comments 45

Пользуясь внезапно подвернувшимся случаем, хочу ещё раз поблагодарить вас за ваши продукты :)

Как расшифровывается RPS в данном конткесте, если не секрет?

RPS: Receive Packet Steering, программный аналог аппаратного Receive-Side Scaling (RSS). Обе технологии позволяют распределять входящие пакеты по очередям в зависимости от хеша нескольких байтов заголовка (фильтра).


https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Performance_Tuning_Guide/network-rps.html
https://www.kernel.org/doc/Documentation/networking/scaling.txt


RSS: Receive Side Scaling

Contemporary NICs support multiple receive and transmit descriptor queues (multi-queue). On reception, a NIC can send different packets to different queues to distribute processing among CPUs. The NIC distributes packets by
applying a filter to each packet that assigns it to one of a small number of logical flows. Packets for each flow are steered to a separate receive queue, which in turn can be processed by separate CPUs. This mechanism is
generally known as “Receive-side Scaling” (RSS). The goal of RSS and the other scaling techniques is to increase performance uniformly.


Receive Packet Steering (RPS) is logically a software implementation of RSS. Being in software, it is necessarily called later in the datapath. Whereas RSS selects the queue and hence CPU that will run the hardware
interrupt handler, RPS selects the CPU to perform protocol processing above the interrupt handler. This is accomplished by placing the packet on the desired CPU’s backlog queue and waking up the CPU for processing.
RPS has some advantages over RSS:
1) it can be used with any NIC,
2) software filters can easily be added to hash over new protocols,
3) it does not increase hardware device interrupt rate (although it does introduce inter-processor interrupts (IPIs)).

RPS is called during bottom half of the receive interrupt handler, when a driver sends a packet up the network stack with netif_rx() or netif_receive_skb(). These call the get_rps_cpu() function, which selects the queue that should process a packet.
При запуске выдает следующее:
/usr/local/bin/network-top
Traceback (most recent call last):
  File "/usr/local/bin/network-top", line 3, in <module>
    from netutils_linux_monitoring import NetworkTop
  File "/usr/local/lib/python2.7/dist-packages/netutils_linux_monitoring/__init__.py", line 1, in <module>
    from netutils_linux_monitoring.irqtop import IrqTop
  File "/usr/local/lib/python2.7/dist-packages/netutils_linux_monitoring/irqtop.py", line 7, in <module>
    from netutils_linux_monitoring.base_top import BaseTop
  File "/usr/local/lib/python2.7/dist-packages/netutils_linux_monitoring/base_top.py", line 7, in <module>
    from netutils_linux_monitoring.colors import wrap
  File "/usr/local/lib/python2.7/dist-packages/netutils_linux_monitoring/colors.py", line 7, in <module>
    2: Fore.LIGHTYELLOW_EX,
AttributeError: 'AnsiCodes' object has no attribute 'LIGHTYELLOW_EX'


Подскажите пожалуйста:


  1. какой дистрибутив linux вы используете.
  2. что выдаёт set | egrep '^(TERM|LC|LANG).*='
Мне помогло: pip install --upgrade colorama

Развернул на digitalocean виртуалку:


Ubuntu 14.04.5
LANG=en_US.UTF-8
LANGUAGE=en_US:en
TERM=xterm

Работает прекрасно. На всякий случай посмотрел исходники colorama, про все эти LIGHT..._EX:


These are fairly well supported, but not part of the standard.

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


Обновиться можно с помощью pip install --upgrade netutils-linux, билд в котором это поправлено: 2.0.4

выглядит интересно. А измения перманетны или после перезагрузки нужно повторять процедуру?

Нет, эти изменения действуют до перезагрузки.
Как вариант запихать их в /etc/rc.local или куда сейчас там модно :)

weirded
Ubuntu 12.04
TERM=screen-bce
LANG=en_US.UTF-8
LANGUAGE=en_US:en


# rss-ladder eth1 0
- distribute interrupts of eth1 (-rx-) on socket 0
lscpu: unrecognized option '--extended=CPU,SOCKET'

Ubuntu 16.04.2
TERM=xterm (xfce-terminal)
LANG=ru_RU.UTF-8
LANGUAGE=ru_RU:ru:en


# rss-ladder eth1 0
- distribute interrupts of eth1 (-rx-) on socket 0
  - eth1: irq 128 1572865-edge -> eth1-rx-0
/usr/local/bin/rss-ladder: строка 80: echo: ошибка записи: Недопустимый аргумент

С 12.04 все в порядке в 2.0.5?

Не совсем, оно как-будто 2-х ядер не видит. Всё на первое вешает.
Написал в issue.

А, понял. Там логика для раздельных RX и TX очередей следующая:


  1. Размазываем лесенкой все RX очереди по ядрам.
  2. Размазываем лесенкой все TX очереди по ядрам.

Собственно это он и делает, а поскольку RX очередь одна и TX очередь одна — обе очереди падают на 0 ядро.


В феврале ещё думал как лучше поступать в этом кейсе:


https://github.com/strizhechenko/netutils-linux/issues/8


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

В debian и производных нет /etc/sysconfig/network-scripts/
Поэтому
rx-buffers-increase eth0
Traceback (most recent call last):
File "/usr/local/bin/rx-buffers-increase", line 24, in main()
File "/usr/local/bin/rx-buffers-increase", line 20, in main
RxBuffersIncreaser(dev, upper_bound).apply()
File "/usr/local/lib/python2.7/dist-packages/netutils_linux_tuning/rx_buffers.py", line 64, in apply
self.investigate()
File "/usr/local/lib/python2.7/dist-packages/netutils_linux_tuning/rx_buffers.py", line 33, in investigate
with open(path.join(ns, 'ifcfg-' + self.dev)) as config:
IOError: [Errno 2] No such file or directory: '/etc/sysconfig/network-scripts/ifcfg-eth0'

Актуально ли это для виртуальных серверов, куда проброшен зеркальный трафик?

Отчасти да, но это нужно делать:


  1. На виртуалке.
  2. На хосте.
  3. Ковырять дополнительно прямой проброс железа (ядер и сетёвок) в виртуалку.

и всё равно хорошей производительности в итоге не добиться.


Но если идеальная работа не преследуется, то вполне сойдёт :)

gentoo:
network-top
Traceback (most recent call last):
File "/usr/bin/network-top", line 7, in NetworkTop().run()
File "/usr/lib64/python2.7/site-packages/netutils_linux_monitoring/network_top.py", line 24, in __init__
self.parse_options()
File "/usr/lib64/python2.7/site-packages/netutils_linux_monitoring/network_top.py", line 117, in parse_options
top.post_optparse()
File "/usr/lib64/python2.7/site-packages/netutils_linux_monitoring/link_rate.py", line 152, in post_optparse
self.numa = Numa(self.options.devices, self.options.random)
File "/usr/lib64/python2.7/site-packages/netutils_linux_monitoring/numa.py", line 34, in __init__
self.detect_layouts()
File "/usr/lib64/python2.7/site-packages/netutils_linux_monitoring/numa.py", line 77, in detect_layouts
layouts = [list(map(int, row.split(b',')[2:4])) for row in rows]
ValueError: invalid literal for int() with base 10: ''

Если в 2.0.8 повторяется, можете скинуть вывод lscpu -p?

В 2.0.10 было так же.
Сейчас накатил 2.1.1. Работает :)

32 битная система, полагаю?

Нет, экспериментировал на такой машине:
undro netutils-linux # uname -a
Linux undro 4.4.21-gentoo #1 SMP Wed Feb 15 05:32:25 VLAT 2017 x86_64 Intel(R) Core(TM) i5-2500 CPU @ 3.30GHz GenuineIntel GNU/Linux
undro netutils-linux # lscpu -p
# The following is the parsable format, which can be fed to other
# programs. Each different item in every column has an unique ID
# starting from zero.
# CPU,Core,Socket,Node,,L1d,L1i,L2,L3
0,0,0,,,0,0,0,0
1,1,0,,,1,1,1,0
2,2,0,,,2,2,2,0
3,3,0,,,3,3,3,0
Поглядел на одном из софтроутеров, network-top моргает портянкой в 500 вланов.
А irq-top приятный на вид — https://ibb.co/bvXcsv

--device-regex вам в помощь, чтобы от vlan'ов с ума не сходить :)

Да, спасибо, увидел :)

Кстати, что за магия такая, что у вас все сетёвки генерят абсолютно одинаковое число прерываний?

Кол-во генерируемых прерываний фиксируется параметром InterruptThrottleRate для модуля ixgbe.

А, помню такое. 4к прерываний на ядро вроде как слишком уж жёсткий лимит выходит в итоге.

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

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

Ещё, пользователи тулзов наверняка оценили бы возможность настраивать ещё и RFS и XPS.

Не, вы правы конечно, если прибить запуск юзерспэйс приложений на ядра не занимающиеся обработкой пакетов — профит будет, но в случае если это тупая молотилка трафика (в основном такими занимаюсь, небольшая профессиональная деформация) — то вряд ли.


Про RFS — тут опять же надо вклиниваться в процесс запуска приложения, которое должно определенный сорт трафика потреблять, а не только выполнить правильную команду для ethtool. Что-то универсальное для этого запилить сложновато. Хотя, если есть идеи — welcome to the github issues, я бы с удовольствием сделал.

Для RFS достаточно включить RPS и задать ненулевое значение в файлах /sys/class/net/eth*/queues/rx-*/rps_flow_cnt. Подробнее в https://www.kernel.org/doc/Documentation/networking/scaling.txt.
Это улучшайзер RPS, который запоминает на каком ядре находится процесс, обрабатывающий соединение.
Согласен, тем более RFS умеет избегать «out of order packets» при миграции потоков приложения по ядрам, т.е. даже если потоки не привязаны к ядрам — это не критично: https://www.kernel.org/doc/Documentation/networking/scaling.txt
When the scheduler moves a thread to a new CPU while it has outstanding
receive packets on the old CPU, packets may arrive out of order. To
avoid this, RFS uses a second flow table
to track outstanding packets
for each flow

(привязка приложения к нодам во время запуска приложения (numactl, taskset) или потоков к ядрам на уровне приложения (sched_setaffinity, pthread_setaffinity_np) — очень полезная, но отдельная задача)

При RPS один и тот же пакет обрабатывается в kernel-space TCP/IP-stack на одном CPU-Core, и затем в user-space вашего приложения в потоке работающем на другом CPU-Core, это добавляет лишний обмен между ядрами процессора.
При RFS все пакеты одного соединения обрабатываются в kernel-space и user-space на одном ядре.

Пардон, попутал с Receive Flow Hash Indirectiction.
Да, RFS уместен, в случае если кто-то в userspace пакетики получает, но в случае форварда это, как мне кажется только лишний оверхед (прыжок пакета в Flow Table).

Про XPS: добавил тулзу autoxps в версии 2.2.5

Хм. У меня network-top показывает 2 строки:

# /proc/interrupts

CPU0 CPU1 CPU2 CPU3

31 26 196 94 interrupts
81 67 60 43 interrupts

Столбцы — ясно. Но что означают строки — непонятно.

По дефолту он скрывает строки, в которых все прерывания подрастают меньше, чем на 80 в секунду. Его цель показать то, что несет большую часть нагрузки на ядра процессора/выявлять шторм прерываний. Можете использовать: network-top -l 0

Хорошая статья. Готовый код всегда лучше общих рассуждений.
Встречались сетевые карты mellanox ...

Используете библиотеку VMA для обмена по LAN если на обоих серверах установлены Mellanox Ethernet-карты, или в ваших кейсах почти весь трафик внешний?
http://www.mellanox.com/page/software_vma?mtag=vma
The result is a reduction in latency by as much as 300% and an increase in application throughput by as much as 200% per server as compared to applications running on standard Ethernet or InfiniBand interconnect networks.

Спасибо!
Увы, не использовал, трафик обычно — зеркало со свитчей.

Sign up to leave a comment.

Articles