Пользователь
0,0
рейтинг
16 ноября 2010 в 11:32

Администрирование → Большие потоки трафика и управление прерываниями в Linux

В этой заметке я опишу методы увеличения производительности линуксового маршрутизатора. Для меня эта тема стала актуальна, когда проходящий сетевой трафик через один линуксовый маршрутизатор стал достаточно высоким (>150 Мбит/с, > 50 Kpps). Маршрутизатор помимо роутинга еще занимается шейпированием и выступает в качестве файрволла.

Для высоких нагрузок стоит использовать сетевые карты Intel, на базе чипсетов 82575/82576 (Gigabit), 82598/82599 (10 Gigabit), или им подобные. Их прелесть в том, что они создают восемь очередей обработки прерываний на один интерфейс – четыре на rx и четыре на tx (возможно технологии RPS/RFS, появившиеся в ядре 2.6.35 сделают то же самое и для обычных сетевых карт). Также эти чипы неплохо ускоряют обработку трафика на аппаратном уровне.
Для начала посмотрите содержимое /proc/interrupts, в этом файле можно увидеть что вызывает прерывания и какие ядра занимаются их обработкой.
# cat /proc/interrupts 
           CPU0       CPU1       CPU2       CPU3       
  0:         53          1          9        336   IO-APIC-edge      timer
  1:          0          0          0          2   IO-APIC-edge      i8042
  7:          1          0          0          0   IO-APIC-edge    
  8:          0          0          0         75   IO-APIC-edge      rtc0
  9:          0          0          0          0   IO-APIC-fasteoi   acpi
 12:          0          0          0          4   IO-APIC-edge      i8042
 14:          0          0          0        127   IO-APIC-edge      pata_amd
 15:          0          0          0          0   IO-APIC-edge      pata_amd
 18:        150       1497      12301     473020   IO-APIC-fasteoi   ioc0
 21:          0          0          0          0   IO-APIC-fasteoi   sata_nv
 22:          0          0         15       2613   IO-APIC-fasteoi   sata_nv, ohci_hcd:usb2
 23:          0          0          0          2   IO-APIC-fasteoi   sata_nv, ehci_hcd:usb1
 45:          0          0          0          1   PCI-MSI-edge      eth0
 46:  138902469      21349     251748    4223124   PCI-MSI-edge      eth0-rx-0
 47:  137306753      19896     260291    4741413   PCI-MSI-edge      eth0-rx-1
 48:       2916  137767992     248035    4559088   PCI-MSI-edge      eth0-rx-2
 49:       2860  138565213     244363    4627970   PCI-MSI-edge      eth0-rx-3
 50:       2584      14822  118410604    3576451   PCI-MSI-edge      eth0-tx-0
 51:       2175      15115  118588846    3440065   PCI-MSI-edge      eth0-tx-1
 52:       2197      14343     166912  121908883   PCI-MSI-edge      eth0-tx-2
 53:       1976      13245     157108  120248855   PCI-MSI-edge      eth0-tx-3
 54:          0          0          0          1   PCI-MSI-edge      eth1
 55:       3127      19377  122741196    3641483   PCI-MSI-edge      eth1-rx-0
 56:       2581      18447  123601063    3865515   PCI-MSI-edge      eth1-rx-1
 57:       2470      17277     183535  126715932   PCI-MSI-edge      eth1-rx-2
 58:       2543      16913     173988  126962081   PCI-MSI-edge      eth1-rx-3
 59:  128433517      11953     148762    4230122   PCI-MSI-edge      eth1-tx-0
 60:  127590592      12028     142929    4160472   PCI-MSI-edge      eth1-tx-1
 61:       1713  129757168     136431    4134936   PCI-MSI-edge      eth1-tx-2
 62:       1854  126685399     122532    3785799   PCI-MSI-edge      eth1-tx-3
NMI:          0          0          0          0   Non-maskable interrupts
LOC:  418232812  425024243  572346635  662126626   Local timer interrupts
SPU:          0          0          0          0   Spurious interrupts
PMI:          0          0          0          0   Performance monitoring interrupts
PND:          0          0          0          0   Performance pending work
RES:   94005109   96169918   19305366    4460077   Rescheduling interrupts
CAL:         49         34         39         29   Function call interrupts
TLB:      66588     144427     131671      91212   TLB shootdowns
TRM:          0          0          0          0   Thermal event interrupts
THR:          0          0          0          0   Threshold APIC interrupts
MCE:          0          0          0          0   Machine check exceptions
MCP:        199        199        199        199   Machine check polls
ERR:          1
MIS:          0

В данном примере используются сетевые карты Intel 82576. Здесь видно, что сетевые прерывания распределены по ядрам равномерно. Однако, по умолчанию так не будет. Нужно раскидать прерывания по процессорам. Чтобы это сделать нужно выполнить команду echo N > /proc/irq/X/smp_affinity, где N это маска процессора (определяет какому процессору достанется прерывание), а X — номер прерывания, виден в первом столбце вывода /proc/interrupts. Чтобы определить маску процессора, нужно возвести 2 в степень cpu_N (номер процессора) и перевести в шестнадцатиричную систему. При помощи bc вычисляется так: echo "obase=16; $[2 ** $cpu_N]" | bc. В данном примере распределение прерываний было произведено следующим образом:
#CPU0
echo 1 > /proc/irq/45/smp_affinity
echo 1 > /proc/irq/54/smp_affinity

echo 1 > /proc/irq/46/smp_affinity
echo 1 > /proc/irq/59/smp_affinity
echo 1 > /proc/irq/47/smp_affinity
echo 1 > /proc/irq/60/smp_affinity

#CPU1
echo 2 > /proc/irq/48/smp_affinity
echo 2 > /proc/irq/61/smp_affinity
echo 2 > /proc/irq/49/smp_affinity
echo 2 > /proc/irq/62/smp_affinity

#CPU2
echo 4 > /proc/irq/50/smp_affinity
echo 4 > /proc/irq/55/smp_affinity
echo 4 > /proc/irq/51/smp_affinity
echo 4 > /proc/irq/56/smp_affinity

#CPU3
echo 8 > /proc/irq/52/smp_affinity
echo 8 > /proc/irq/57/smp_affinity
echo 8 > /proc/irq/53/smp_affinity
echo 8 > /proc/irq/58/smp_affinity

Также, если маршрутизатор имеет два интерфейса, один на вход, другой на выход (классическая схема), то rx с одного интерфейса следует группировать с tx другого интерфейса на одном ядре процессора. Например, в данном случае прерывания 46 (eth0-rx-0) и 59 (eth1-tx-0) были определены на одно ядро.
Еще одним весьма важным параметром является задержка между прерываниями. Посмотреть текущее значение можно при помощи ethtool -c ethN, параметры rx-usecs и tx-usecs. Чем больше значение, тем выше задержка, но тем меньше нагрузка на процессор. Пробуйте уменьшать это значение в часы пик вплоть до ноля.
При подготовке в эксплуатацию сервера с Intel Xeon E5520 (8 ядер, каждое с HyperThreading) я выбрал такую схему распределения прерываний:
#CPU6
echo 40 > /proc/irq/71/smp_affinity
echo 40 > /proc/irq/84/smp_affinity

#CPU7
echo 80 > /proc/irq/72/smp_affinity
echo 80 > /proc/irq/85/smp_affinity

#CPU8
echo 100 > /proc/irq/73/smp_affinity
echo 100 > /proc/irq/86/smp_affinity

#CPU9
echo 200 > /proc/irq/74/smp_affinity
echo 200 > /proc/irq/87/smp_affinity

#CPU10
echo 400 > /proc/irq/75/smp_affinity
echo 400 > /proc/irq/80/smp_affinity

#CPU11
echo 800 > /proc/irq/76/smp_affinity
echo 800 > /proc/irq/81/smp_affinity

#CPU12
echo 1000 > /proc/irq/77/smp_affinity
echo 1000 > /proc/irq/82/smp_affinity

#CPU13
echo 2000 > /proc/irq/78/smp_affinity
echo 2000 > /proc/irq/83/smp_affinity

#CPU14
echo 4000 > /proc/irq/70/smp_affinity
#CPU15
echo 8000 > /proc/irq/79/smp_affinity

/proc/interrupts на этом сервере без нагрузки можно посмотреть тут. Не привожу это в заметке из-за громоздкости

UPD:
Если сервер работает только маршрутизатором, то тюнинг TCP стека особого значения не имеет. Однако есть параметры sysctl, которые позволяют увеличить размер кэша ARP, что может быть актуальным. При проблеме с размером ARP-кэша в dmesg будет сообщение «Neighbour table overflow».
Например:
net.ipv4.neigh.default.gc_thresh1 = 1024
net.ipv4.neigh.default.gc_thresh2 = 2048
net.ipv4.neigh.default.gc_thresh3 = 4096


Описание параметров:
gc_thresh1 — минимальное количество записей, которые должны быть в ARP-кэше. Если количество записей меньше, чем это значение, то сборщик мусора не будет очищать ARP-кэш.
gc_thresh2 — мягкое ограничение количества записей в ARP-кэше. Если количество записей достигнет этого значения, то сборщик мусора запустится в течение 5 секунд.
gc_thresh3 — жесткое ограничение количества записей в ARP-кэше. Если количество записей достигнет этого значения, то сборщик мусора незамедлительно запустится.
@peter23
карма
172,2
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Администрирование

Комментарии (40)

  • +5
    Замечательная заметка. Вообще такому тюнингу, в случае многоядерного сервера, место не только на роутерах. У нас 8-ядерный сервер вставал раком при копировании большого объёма данных по сети. Оказалось райд и сетевуха «сидели» на одном проце. Разнесли — всё устаканилось.
  • +2
    про FreeBSD хорошо написано тут, в целом же, linux лучше справляется со значительной сетевой нагрузкой
  • 0
    Это все здорово, а для роутера (Linksys WRT54GL) на DD-WRT можно такое сделать? Или ему уже не судьба больше 50 мбит в WAN прокачать?
    • +15
      если туда впаять xeon то справится.
  • +1
    видел в песочнице, пожалел, что кончились инвайты. Кстати, а почему нет пометки, что из песочницы? В последнее время она автоматически добавлялась под заголовком топика.
    • +1
      Потому что я получил инвайт за другой пост, а этот пост написал уже как зарегистрированный пользователь :)
      • +3
        понятно. Велкам!
  • +1
    В закладки, спасибо!
  • +3
    Полезная статья, спасибо!
    По-моему заголовок широк по смыслу, может быть, стоит переименовать в «Управление прерываниями в Linux»?
  • 0
    за статью спасибо, однако не понятно, почему на 150 мегабитах в секунду встает эта проблема.

    на моей практике:
    раздача крупной статики на 400-600 мегабит/секунду ограничивалась дисковой подсистемой.
    router\firewall на достаточно слабой (~гигагерц) однопроцессовой машине не загружен при 100 мегабитном потоке в одну сторону и 70 мегабитном в другую. 2 карточки (на самом деле их 3, не меняет сути дела).

    Могу логи выдать в момент нагрузки, если интересно.

    Вопрос, видимо к постановке проблемы, входящим условиям. Не к описанному методу решения.
    • 0
      В моем случае сервер занимается маршрутизацией и в обработке трафика принимают активное участие шейпер, ULOG, файрволл. Основную нагрузку дают шейпер и ULOG, маршрутизация и фильтрация — на их фоне практически не нагружают систему.
      • +2
        Было бы отлично еще сюда написать и про настройки шейпинга (в отдельном посте)
        • +2
          Это есть в планах, в том числе использование хэш-таблиц для меньшей нагрузки шейпира на систему.
          • 0
            шейпЕра, конечно же, извините. Просто изначально писал «шейпинга».
          • 0
            замечательно, будем ждать.
        • +1
          действительно, было бы неплохо.
          Ну а если не хотите ждать, мне кажется здесь lartc.org/ есть всё
          • 0
            Спасибо, обязательно почитаю.
      • 0
        Выкиньте ULOG. ipt_netflow наше все!
        • 0
          Спасибо, обязательно попробую. Вообще ссылка на проект ipt_netflow уже с месяц висит в списке «Посмотреть, потестить», но никак руки не доходят.
      • 0
        ULOG можно заменить ipt_netflow. Неплохую разгрузку получите.
  • 0
    Давненько я не видел таких дельных статей! Автор — молодец! Спасибо за статью!
  • +4
    Если сервер работает только маршрутизатором, то тюнинг TCP стека особого значения не имеет. Однако есть параметры sysctl, которые позволяют увеличить размер кэша ARP, что может быть актуальным. Например:
    net.ipv4.neigh.default.gc_thresh1 = 1024
    net.ipv4.neigh.default.gc_thresh2 = 2048
    net.ipv4.neigh.default.gc_thresh3 = 4096

    Описания параметров добавлю в статью.
    • 0
      боюсь, что это преждевременная оптимизация опять. твикать ненагруженные узлы — только закапывать ошибки на будущее.
      • 0
        Да, в комментах это не указал, но в статье написал. Увеличивать кэш ARP стоит только тогда, когда столкнетесь с сообщение в dmesg: «Neighbour table overflow».
    • 0
      Эти параметры рекомендовано делать 1x, 4x и 8x
  • +1
    если нет необходимости в conntrack его тоже надо отрубить
    *raw
    -A PREROUTING -j NOTRACK
    COMMIT

    увеличить очередь
    ifconfig eth0 txqueuelen 10000

    потом смотреть ошибки и по необходимости увеличить буфер
    ethtool -G eth0 rx 1024

    если надо conntrack то увеличивать
    net.ipv4.netfilter.ip_conntrack_max и /sys/module/ip_conntrack/parameters/hashsize
    и уменьшать интервалы
    net.ipv4.netfilter.ip_conntrack_icmp_timeout
    net.ipv4.netfilter.ip_conntrack_udp_timeout_stream
    net.ipv4.netfilter.ip_conntrack_udp_timeout
    net.ipv4.netfilter.ip_conntrack_tcp_timeout_close
    net.ipv4.netfilter.ip_conntrack_tcp_timeout_time_wait
    net.ipv4.netfilter.ip_conntrack_tcp_timeout_last_ack
    net.ipv4.netfilter.ip_conntrack_tcp_timeout_close_wait
    net.ipv4.netfilter.ip_conntrack_tcp_timeout_fin_wait
    net.ipv4.netfilter.ip_conntrack_tcp_timeout_established
    net.ipv4.netfilter.ip_conntrack_tcp_timeout_syn_recv
    net.ipv4.netfilter.ip_conntrack_tcp_timeout_syn_sent

    уменьшать количество правил iptables, если надо много однотипных списков то использовать ipset

    и пр. пр. пр.
  • +3
    вообще прерывания неплохо автоматом раскидываются таким скриптиком

    
    ncpus=`grep -ciw ^processor /proc/cpuinfo`
    test "$ncpus" -gt 1 || exit 1
    
    n=0
    for irq in `cat /proc/interrupts | grep eth | awk '{print $1}' | sed s/\://g`
    do
        f="/proc/irq/$irq/smp_affinity"
        test -r "$f" || continue
        cpu=$[$ncpus - ($n % $ncpus) - 1]
        if [ $cpu -ge 0 ]
                then
                    mask=`printf %x $[2 ** $cpu]`
                    echo "Assign SMP affinity: eth$n, irq $irq, cpu $cpu, mask 0x$mask"
                    echo "$mask" > "$f"
                    let n+=1
        fi
    done
    
    
    
  • 0
    >Нужно раскидать прерывания по процессорам. Чтобы это сделать нужно выполнить команду echo N > /proc/irq/X/smp_affinity

    По-моему, раскидывать вручную — лишнее. Есть irqbalance (http://www.irqbalance.org). И в ядре, вроде, есть встроеный балансировщик (CONFIG_IRQBALABCE)
    • 0
      irqbalance при большой нагрузке и большом кол-ве очередей сносит мозг :)
    • 0
      Преимущество ручного раскидывания — группировка определенных очередей на одном ядре.
      А когда на одном из серверов использовал irqbalance — неоднократные кернел паники, после чего он был отключен.
      Опция CONFIG_IRQBALANCE отсутствует начиная с версии 2.6.27, т.к. признана устаревшей.
  • 0
    Кстати про тюнинг параметров драйверов Вы тоже ни слова не написали, а тема очень обширна :)
  • 0
    А что посоветуете если в iptables большое количество записей >50k в этом случае оно медленно, но верное умирает.
    Ну кроме перехода на ipset :) возможно есть какие-нибудь твики?
    • +1
      Распределение прерываний по ядрам поможет и в этом случае. Еще стоит оптимизировать правила с использованием ветвлений.
    • +1
      есть твики centos.alt.ru/?p=32, только лучше ipset.

  • +1
    По поводу тюнинга параметров сетевого драйвера. Я сегодня работал с e1000, удалось сократить с 39K interrupts при дефолтовых настройках до 220 параметром InterruptThrottleRate=100

    rmmod e1000
    modprobe e1000
    procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
    1 0 0 3680984 48968 35420 0 0 0 7 39964 35 0 1 99 0
    0 0 0 3680984 48968 35420 0 0 0 0 39954 33 0 1 99 0

    rmmod e1000
    modprobe e1000 InterruptThrottleRate=100
    0 0 0 3668768 49288 38696 0 0 0 0 220 35 0 0 100 0
    0 0 0 3668768 49288 38696 0 0 0 0 224 41 0 0 100 0

    Параметры e1000: www.intel.com/support/network/sb/CS-009209.htm
    • +2
      Параметр InterruptThrottleRate (если значение >100) задает количество прерываний, генерируемых в секунду. Эффект аналогичен заданию значений rx-usecs tx-usecs утилитой ethtool, что является более гибким вариантом, поэтому этот параметр e1000 не описывал. Задержки между прерываниями позволяют снизить нагрузку за счет увеличения задержек обработки трафика. Я рекомендую снижать их как можно сильнее, вплоть до ноля, пока нагрузка в часы пик будет в пределах нормы. Соответственно параметр InterruptThrottleRate повышать, пока нагрузка в пределах нормы.
  • 0
    какой профит? :)
  • +1
    «тюнинг TCP стека особого значения не имеет. Однако есть параметры sysctl, которые позволяют увеличить размер кэша ARP»

    Кэш ARP не относится к тюнингу TCP-стека
    • 0
      В фразе подразумевался смысл «тюнинг TCP стека особого значения не имеет, однако имеет значение тюнинг ARP кэша». Пожалуй фразу мне следовало построить по-другому. В любом случае, спасибо за замечание :)
  • 0
    Не очень понял «Чем больше значение, тем выше задержка, но тем меньше нагрузка на процессор. Пробуйте уменьшать это значение в часы пик вплоть до ноля.» Если так, то уменьшение значения в часы пик приведёт к дополнительному росту нагрузки на процессор ведь?

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