У меня есть виртуальная машина Ubuntu, работающая внутри Xen XCP на базе Ubuntu. На нем размещается настраиваемая HTTP-служба на основе FCGI за nginx
.
Под нагрузкой от ab
первое ядро процессора перегружено, а остальные недогружены.
В /proc/interrupts
я вижу это CPU0 обслуживает на порядок больше прерываний, чем любое другое ядро. Большинство из них происходят из eth1
.
Что я могу сделать для повышения производительности этой виртуальной машины? Есть ли способ более равномерно сбалансировать прерывания?
Кровавые подробности:
$ uname -a Linux MYHOST 2.6.38-15-virtual #59-Ubuntu SMP Fri Apr 27 16:40:18 UTC 2012 i686 i686 i386 GNU/Linux $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 11.04 Release: 11.04 Codename: natty $ cat /proc/interrupts CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7 283: 113720624 0 0 0 0 0 0 0 xen-dyn-event eth1 284: 1 0 0 0 0 0 0 0 xen-dyn-event eth0 285: 2254 0 0 3873799 0 0 0 0 xen-dyn-event blkif 286: 23 0 0 0 0 0 0 0 xen-dyn-event hvc_console 287: 492 42 0 0 0 0 0 295324 xen-dyn-event xenbus 288: 0 0 0 0 0 0 0 222294 xen-percpu-ipi callfuncsingle7 289: 0 0 0 0 0 0 0 0 xen-percpu-virq debug7 290: 0 0 0 0 0 0 0 151302 xen-percpu-ipi callfunc7 291: 0 0 0 0 0 0 0 3236015 xen-percpu-ipi resched7 292: 0 0 0 0 0 0 0 60064 xen-percpu-ipi spinlock7 293: 0 0 0 0 0 0 0 12355510 xen-percpu-virq timer7 294: 0 0 0 0 0 0 803174 0 xen-percpu-ipi callfuncsingle6 295: 0 0 0 0 0 0 0 0 xen-percpu-virq debug6 296: 0 0 0 0 0 0 60027 0 xen-percpu-ipi callfunc6 297: 0 0 0 0 0 0 5374762 0 xen-percpu-ipi resched6 298: 0 0 0 0 0 0 64976 0 xen-percpu-ipi spinlock6 299: 0 0 0 0 0 0 15294870 0 xen-percpu-virq timer6 300: 0 0 0 0 0 264441 0 0 xen-percpu-ipi callfuncsingle5 301: 0 0 0 0 0 0 0 0 xen-percpu-virq debug5 302: 0 0 0 0 0 79324 0 0 xen-percpu-ipi callfunc5 303: 0 0 0 0 0 3468144 0 0 xen-percpu-ipi resched5 304: 0 0 0 0 0 66269 0 0 xen-percpu-ipi spinlock5 305: 0 0 0 0 0 12778464 0 0 xen-percpu-virq timer5 306: 0 0 0 0 844591 0 0 0 xen-percpu-ipi callfuncsingle4 307: 0 0 0 0 0 0 0 0 xen-percpu-virq debug4 308: 0 0 0 0 75293 0 0 0 xen-percpu-ipi callfunc4 309: 0 0 0 0 3482146 0 0 0 xen-percpu-ipi resched4 310: 0 0 0 0 79312 0 0 0 xen-percpu-ipi spinlock4 311: 0 0 0 0 21642424 0 0 0 xen-percpu-virq timer4 312: 0 0 0 449141 0 0 0 0 xen-percpu-ipi callfuncsingle3 313: 0 0 0 0 0 0 0 0 xen-percpu-virq debug3 314: 0 0 0 95405 0 0 0 0 xen-percpu-ipi callfunc3 315: 0 0 0 3802992 0 0 0 0 xen-percpu-ipi resched3 316: 0 0 0 76607 0 0 0 0 xen-percpu-ipi spinlock3 317: 0 0 0 16439729 0 0 0 0 xen-percpu-virq timer3 318: 0 0 876383 0 0 0 0 0 xen-percpu-ipi callfuncsingle2 319: 0 0 0 0 0 0 0 0 xen-percpu-virq debug2 320: 0 0 76416 0 0 0 0 0 xen-percpu-ipi callfunc2 321: 0 0 3422476 0 0 0 0 0 xen-percpu-ipi resched2 322: 0 0 69217 0 0 0 0 0 xen-percpu-ipi spinlock2 323: 0 0 10247182 0 0 0 0 0 xen-percpu-virq timer2 324: 0 393514 0 0 0 0 0 0 xen-percpu-ipi callfuncsingle1 325: 0 0 0 0 0 0 0 0 xen-percpu-virq debug1 326: 0 95773 0 0 0 0 0 0 xen-percpu-ipi callfunc1 327: 0 3551629 0 0 0 0 0 0 xen-percpu-ipi resched1 328: 0 77823 0 0 0 0 0 0 xen-percpu-ipi spinlock1 329: 0 13784021 0 0 0 0 0 0 xen-percpu-virq timer1 330: 730435 0 0 0 0 0 0 0 xen-percpu-ipi callfuncsingle0 331: 0 0 0 0 0 0 0 0 xen-percpu-virq debug0 332: 39649 0 0 0 0 0 0 0 xen-percpu-ipi callfunc0 333: 3607120 0 0 0 0 0 0 0 xen-percpu-ipi resched0 334: 348740 0 0 0 0 0 0 0 xen-percpu-ipi spinlock0 335: 89912004 0 0 0 0 0 0 0 xen-percpu-virq timer0 NMI: 0 0 0 0 0 0 0 0 Non-maskable interrupts LOC: 0 0 0 0 0 0 0 0 Local timer interrupts SPU: 0 0 0 0 0 0 0 0 Spurious interrupts PMI: 0 0 0 0 0 0 0 0 Performance monitoring interrupts IWI: 0 0 0 0 0 0 0 0 IRQ work interrupts RES: 3607120 3551629 3422476 3802992 3482146 3468144 5374762 3236015 Rescheduling interrupts CAL: 770084 489287 952799 544546 919884 343765 863201 373596 Function call interrupts TLB: 0 0 0 0 0 0 0 0 TLB shootdowns TRM: 0 0 0 0 0 0 0 0 Thermal event interrupts THR: 0 0 0 0 0 0 0 0 Threshold APIC interrupts MCE: 0 0 0 0 0 0 0 0 Machine check exceptions MCP: 0 0 0 0 0 0 0 0 Machine check polls ERR: 0 MIS: 0
Посмотрите в /proc/irq/283
каталог. Eсть smp_affinity_list
файл, который показывает, какие процессоры получат прерывание 283. Для вас этот файл, вероятно, содержит "0" (и smp_affinity
вероятно содержит "1").
Вы можете записать диапазон ЦП в smp_affinity_list
файл:
echo 0-7 | sudo tee /proc/irq/283/smp_affinity_list
Или вы можете написать битовую маску, где каждый бит соответствует процессору, чтобы smp_affinity
:
printf %x $((2**8-1)) | sudo tee /proc/irq/283/smp_affinity
Тем не мение, irqbalance известно, что он имеет собственное представление о том, какое сродство должно иметь каждое прерывание, и может отменить ваши обновления. Так что лучше всего полностью удалить irqbalance. Или, по крайней мере, остановите его и отключите от перезагрузки.
Если даже без irqbalance вы получаете лишний smp_affinity
для прерывания 283 после перезагрузки вам придется вручную обновить соответствие ЦП в одном из ваших сценариев запуска.
Источник, указанный выше, взят с Симпозиума Linux, и я рекомендую вам прочитать пару абзацев на SMP IRQ Affinity потому что это убедит вас более эффективно, чем этот пост.
Напомним, что у каждого процессора есть собственный кеш, помимо возможности доступа к основной памяти, проверьте эту диаграмму. Когда запускается прерывание, ядро ЦП должно будет получить инструкции для обработки прерывания из основной памяти, что занимает гораздо больше времени, чем если бы инструкции были в кеше. После того, как процессор выполнит задачу, он будет иметь эти инструкции в кеше. Теперь предположим, что одно и то же ядро ЦП почти все время обрабатывает одно и то же прерывание, функция обработчика прерываний вряд ли покинет кеш ядра ЦП, увеличивая производительность ядра.
В качестве альтернативы, когда IRQ сбалансирован, он может назначить прерывание, которое будет обрабатываться постоянно другим ЦП, тогда новое ядро ЦП, вероятно, не будет иметь функции обработчика прерывания в кэше, и потребуется много времени, чтобы получить правильный обработчик из основного объем памяти.
Исключение: если вы редко используете прерывание eth1, что означает, что проходит достаточно времени, чтобы кеш был перезаписан при выполнении других задач, что означает, что у вас есть данные, периодически поступающие через этот интерфейс с длительными периодами между ними ... тогда вы, скорее всего, не увидите этих преимуществ для они есть, когда вы используете процесс с высокой частотой.
Если ваше прерывание происходит очень часто тогда просто привязывайте это прерывание для обработки только определенным процессором. Эта конфигурация находится в
/proc/'IRQ number'/smp_affinity
или
/proc/irq/'IRQ number'/smp_affinity
См. Последний абзац в SMP IRQ Affinity из источника, указанного выше, в нем есть инструкции.
Вы можете изменить частоту срабатывания флага прерывания, либо увеличив размер MTU (jumbo-кадры), если это позволяет сеть, либо изменив так, чтобы флаг поднимался после получения большего количества пакетов вместо каждого пакета, ИЛИ изменив значение тайм-аут, поэтому увеличьте прерывание через определенное время. Будьте осторожны с опцией времени, потому что ваш буфер может быть заполнен до того, как истечет время. Это можно сделать с помощью эттоол который указан в связанном источнике.
этот ответ приближается к тому времени, когда люди не будут его читать, поэтому я не буду вдаваться в подробности, но в зависимости от вашей ситуации есть много решений ... проверьте источник :)
Если у вас есть подходящая модель сетевой карты Intel, вы можете значительно повысить производительность.
Процитируем первый абзац:
Многоядерные процессоры и новейшие адаптеры Ethernet (включая 82575, 82576, 82598 и 82599) позволяют оптимизировать потоки пересылки TCP путем назначения потоков выполнения отдельным ядрам. По умолчанию Linux автоматически назначает прерывания ядрам процессора. В настоящее время существуют два метода автоматического назначения прерываний: внутренний балансировщик IRQ и демон балансировки IRQ в пространстве пользователя. Оба предлагают компромиссы, которые могут снизить использование ЦП, но не максимизируют скорость пересылки IP. Оптимальную пропускную способность можно получить, вручную привязав очереди адаптера Ethernet к определенным ядрам процессора.
Для переадресации IP пара очереди передачи / приема должна использовать одно и то же ядро процессора и уменьшать любую синхронизацию кэша между разными ядрами. Это может быть выполнено путем назначения прерываний передачи и приема определенным ядрам. Начиная с ядра Linux 2.6.27, несколько очередей можно использовать на 82575, 82576, 82598 и 82599. Кроме того, несколько очередей передачи были включены в сигнальных прерываниях расширенного обмена сообщениями (MSI-X). MSI-X поддерживает большее количество прерываний, которые можно использовать, что позволяет более детально управлять и нацеливать прерывания на определенные ЦП.