ОРИГИНАЛЬНАЯ СТАТЬЯ
ПЕРЕВЕДЕНО СПЕЦИАЛЬНО ДЛЯ xss.pro
$600 на SSD для Solidity hacking by Jolah Milovsky---> 0x5B1f2Ac9cF5616D9d7F1819d1519912e85eb5C09
Это расширенная версия моего выступления на NginxConf 2017 6 сентября 2017 года. Как SRE в команде Dropbox Traffic, я отвечаю за нашу сеть Edge: ее надежность, производительность и эффективность. Сеть Dropbox — это прокси-уровень на основе nginx, предназначенный для обработки чувствительных к задержкам транзакций метаданных и передачи данных с высокой пропускной способностью. В системе, которая обрабатывает десятки гигабит в секунду при одновременной обработке десятков тысяч чувствительных к задержке транзакций, оптимизация эффективности / производительности осуществляется во всем стеке прокси, от драйверов и прерываний, через TCP/IP и ядро, до библиотеки и приложения. уровневые тюнинги. В этом посте мы обсудим множество способов настройки веб-серверов и прокси. Пожалуйста, не культивируйте их. Ради научного метода применяйте их один за другим, измеряйте их эффект и решайте, действительно ли они полезны в вашей среде.
Это не пост о производительности Linux, хотя я буду делать много ссылок на инструменты bcc, eBPF и perf, это ни в коем случае не исчерпывающее руководство по использованию инструментов профилирования производительности. Если вы хотите узнать о них больше, вы можете прочитать блог Брендана Грегга .
Это также не пост о производительности браузера. Я коснусь производительности на стороне клиента, когда расскажу об оптимизации, связанной с задержкой, но ненадолго. Если вы хотите узнать больше, вам следует прочитать «Высокопроизводительные браузерные сети » Ильи Григорика.
И это также не сборник лучших практик TLS. Хотя я буду упоминать библиотеки TLS и их настройки несколько раз, вы и ваша команда безопасности должны оценить влияние каждой из них на производительность и безопасность. Вы можете использовать Qualys SSL Test , чтобы проверить свою конечную точку на соответствие текущему набору лучших практик, а если вы хотите узнать больше о TLS в целом, рассмотрите возможность подписки на информационный бюллетень Feisty Duck Bulletproof TLS .
Аппаратное обеспечение
Процессор
Для хорошей асимметричной производительности RSA/EC вам нужны процессоры с поддержкой по крайней мере AVX2 (avx2 в /proc/cpuinfo) и предпочтительно с большие целочисленные арифметические операции (bmi и adx). Для симметричных случаев вам следует искать AES-NI для шифров AES и AVX512 для ChaCha+Poly. У Intel есть сравнение производительности различных поколений оборудования с OpenSSL 1.0.2, которое иллюстрирует эффект разгрузки оборудования. Варианты использования, чувствительные к задержкам, такие как маршрутизация, выиграют от меньшего количества узлов NUMA и отключения HT. Задачи с высокой пропускной способностью лучше справляются с большим количеством ядер и выиграют от Hyper-Threading (если они не привязаны к кешу) и, как правило, не слишком заботятся о NUMA. В частности, если вы идете по пути Intel, вы ищете как минимум процессоры Haswell/Broadwell и в идеале Skylake. Если вы выбираете AMD, EPYC имеет довольно впечатляющую производительность.Здесь вам нужно хотя бы 10G, а лучше даже 25G. Если вы хотите больше через один сервер по TLS, описанной здесь настройки будет недостаточно, и вам может потребоваться кадрирование TLS на уровень ядра (например FreeBSD , Linux ). Что касается программного обеспечения, вам следует искать драйверы с открытым исходным кодом с активными списками рассылки и сообществами пользователей. Это будет очень важно, если (но, скорее всего, когда) вы будете отлаживать проблемы, связанные с драйверами.
Память
Эмпирическое правило здесь заключается в том, что для задач, чувствительных к задержке, требуется более быстрая память, а для задач, чувствительных к пропускной способности, требуется больше памяти.Жесткий диск
Это зависит от ваших требований к буферизации / кешированию, но если вы собираетесь много буферизовать или кэшировать, вам следует выбрать хранилище на основе флэш-памяти. Некоторые заходят так далеко, что используют специализированную файловую систему для флэш-памяти (обычно лог-структурированную), но они не всегда работают лучше, чем обычные ext4/xfs. В любом случае, будьте осторожны, чтобы не сжечь флэш-память из-за того, что вы забыли включить TRIM или обновить прошивку.Операционные системы: Низкий уровень
Прошивка
Вы должны обновлять прошивку, чтобы избежать мучительных и длительных сеансов устранения неполадок. Старайтесь быть в курсе последних версий микрокода ЦП, материнской платы, сетевых карт и прошивок твердотельных накопителей. Это не означает, что вы всегда должны запускать последнюю версию — эмпирическое правило здесь состоит в том, чтобы запускать вторую версию с последней прошивкой, если только в последней версии не исправлены критические ошибки, но не отставать слишком далеко.Драйверы
Правила обновления здесь почти такие же, как и для прошивки. Старайтесь оставаться ближе к текущему. Одно предостережение здесь — попытаться отделить обновления ядра от обновлений драйверов, если это возможно. Например, вы можете упаковать свои драйверы с помощью DKMS или предварительно скомпилировать драйверы для всех используемых вами версий ядра. Таким образом, когда вы обновляете ядро и что-то работает не так, как ожидалось, на одну проблему нужно устранить меньше.Процессор
Ваш лучший друг здесь — это репозиторий ядра и инструменты, которые к нему прилагаются. В Ubuntu/Debian вы можете установить linux-tools пакет с несколькими утилитами, но сейчас мы используем только cpupower, turbostat, а также x86_energy_perf_policy. Чтобы проверить оптимизации, связанные с процессором, вы можете провести стресс-тестирование вашего программного обеспечения с помощью вашего любимого инструмента генерации нагрузки (например, Яндекс использует Яндекс.Танк ) . Тестирование производительности ».мощность процессора
Использование этого инструмента намного проще, чем сканирование /proc/. Чтобы увидеть информацию о вашем процессоре и его регуляторе частоты, вы должны запустить:
Код:
$ cpupower frequency-info
...
driver: intel_pstate
...
available cpufreq governors: performance powersave
...
The governor "performance" may decide which speed to use
...
boost state support:
Supported: yes
Active: yes
Убедитесь, что Turbo Boost включен, а для процессоров Intel убедитесь, что вы работаете с intel_pstate, не acpi-cpufreq, или даже pcc-cpufreq. Если вы все еще используете acpi-cpufreq, то вам следует обновить ядро или, если это невозможно, убедиться, что вы используете performanceгубернатор. При работе с intel_pstate, даже powersaveГубернатор должен работать хорошо, но вам нужно убедиться в этом самостоятельно.
Говоря о холостом ходу, чтобы увидеть, что на самом деле происходит с вашим процессором, вы можете использовать turbostatчтобы напрямую просмотреть MSR процессора и получить информацию о мощности, частоте и состоянии простоя:
Код:
# turbostat --debug -P
... Avg_MHz Busy% ... CPU%c1 CPU%c3 CPU%c6 ... Pkg%pc2 Pkg%pc3 Pkg%pc6 ...
Здесь вы можете увидеть реальную частоту процессора (да, /proc/cpuinfoлжет вам), и состояния бездействия ядра/пакета . Если даже с intel_pstateдрайвера ЦП проводит больше времени в режиме ожидания, чем вы думаете, вы можете:
- Установите governor на performance.
- Установите x86_energy_perf_policy на производительность.
- Использовать /dev/cpu_dma_latency интерфейс.
- Для UDP-трафика используйте busy-polling .
Соответствие ЦП
Вы можете дополнительно уменьшить задержку, применив привязку ЦП к каждому потоку/процессу, например, nginx имеет worker_cpu_affinity, которая может автоматически привязывать каждый процесс веб-сервера к его собственному ядру. Это должно устранить миграцию ЦП, уменьшить промахи кэша и ошибки страниц и немного увеличить количество инструкций за цикл. Все это проверяется через perf stat.К сожалению, включение сходства также может негативно сказаться на производительности, увеличивая время, которое процесс тратит на ожидание освобождения ЦП. Это можно отслеживать, запустив runqlat на одном из ваших nginxPID:
Код:
usecs : count distribution
0 -> 1 : 819 | |
2 -> 3 : 58888 |****************************** |
4 -> 7 : 77984 |****************************************|
8 -> 15 : 10529 |***** |
16 -> 31 : 4853 |** |
...
4096 -> 8191 : 34 | |
8192 -> 16383 : 39 | |
16384 -> 32767 : 17 | |
Если вы видите многомиллисекундные хвостовые задержки, то, вероятно, на ваших серверах происходит слишком много всего, кроме nginx - сам по себе, а affinity увеличит задержку, а не уменьшит ее.
Память
Все mm/настройки обычно очень специфичны для рабочего процесса, есть только несколько вещей, которые можно порекомендовать:- Установите ТНР на madvise и включайте их только тогда, когда вы уверены, что они полезны , в противном случае вы можете получить замедление , стремясь к уменьшению задержки на 20%.
- Если вы не используете только один узел NUMA, вы должны установить vm.zone_reclaim_mode до 0.
NUMA
Современные ЦП на самом деле представляют собой несколько отдельных кристаллов ЦП, соединенных очень быстрым межсоединением и совместно использующих различные ресурсы, начиная с кэш-памяти L1 на ядрах HT, через кэш-память L3 в корпусе, до каналов памяти и PCIe в сокетах. Это в основном то, чем является NUMA: несколько единиц исполнения и хранения с быстрым соединением.Подробный обзор NUMA и его последствий можно найти в « Серии NUMA Deep Dive Series » Фрэнка Деннемана .
Но, короче говоря, у вас есть выбор:
- Игнорируя его , отключив в BIOS или запустив программное обеспечение под numactl --interleave=all, вы можете получить посредственную, но несколько стабильную производительность.
- С помощью серверов с одним узлом, как это делает Facebook с платформой OCP Yosemite .
- Принимая его, оптимизируя размещение ЦП/памяти как в пространстве пользователя, так и в пространстве ядра.
Чтобы правильно использовать NUMA, вам нужно рассматривать каждый узел numa как отдельный сервер, для этого вы должны сначала проверить топологию, что можно сделать с помощью numactl --hardware:
Код:
$ numactl --hardware
available: 4 nodes (0-3)
node 0 cpus: 0 1 2 3 16 17 18 19
node 0 size: 32149 MB
node 1 cpus: 4 5 6 7 20 21 22 23
node 1 size: 32213 MB
node 2 cpus: 8 9 10 11 24 25 26 27
node 2 size: 0 MB
node 3 cpus: 12 13 14 15 28 29 30 31
node 3 size: 0 MB
node distances:
node 0 1 2 3
0: 10 16 16 16
1: 16 10 16 16
2: 16 16 10 16
3: 16 16 16 10
О чем нужно заботиться:
- количество узлов.
- размеры памяти для каждого узла.
- количество процессоров для каждого узла.
- расстояния между узлами.
Мы можем убедиться в этом, используя numastat:
Код:
$ numastat -n -c
Node 0 Node 1 Node 2 Node 3 Total
-------- -------- ------ ------ --------
Numa_Hit 26833500 11885723 0 0 38719223
Numa_Miss 18672 8561876 0 0 8580548
Numa_Foreign 8561876 18672 0 0 8580548
Interleave_Hit 392066 553771 0 0 945836
Local_Node 8222745 11507968 0 0 19730712
Other_Node 18629427 8939632 0 0 27569060
Вы также можете использовать numastat для вывода статистики использования памяти для каждого узла в /proc/meminfo:
Код:
$ numastat -m -c
Node 0 Node 1 Node 2 Node 3 Total
------ ------ ------ ------ -----
MemTotal 32150 32214 0 0 64363
MemFree 462 5793 0 0 6255
MemUsed 31688 26421 0 0 58109
Active 16021 8588 0 0 24608
Inactive 13436 16121 0 0 29557
Active(anon) 1193 970 0 0 2163
Inactive(anon) 121 108 0 0 229
Active(file) 14828 7618 0 0 22446
Inactive(file) 13315 16013 0 0 29327
...
FilePages 28498 23957 0 0 52454
Mapped 131 130 0 0 261
AnonPages 962 757 0 0 1718
Shmem 355 323 0 0 678
KernelStack 10 5 0 0 16
Теперь давайте рассмотрим пример более простой топологии.
Код:
$ numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 1 2 3 4 5 6 7 16 17 18 19 20 21 22 23
node 0 size: 46967 MB
node 1 cpus: 8 9 10 11 12 13 14 15 24 25 26 27 28 29 30 31
node 1 size: 48355 MB
Поскольку узлы в основном симметричны, мы можем привязать экземпляр нашего приложения к каждому узлу NUMA с помощью numactl --cpunodebind=X --membind=Xа затем разверните его на другом порту, таким образом вы можете повысить пропускную способность, используя оба узла, и уменьшить задержку, сохранив локальность памяти.
Вы можете проверить эффективность размещения NUMA по задержке ваших операций с памятью, например, используя bcc funclatencyдля измерения задержки операции с большим объемом памяти, например memmove.
На стороне ядра вы можете наблюдать эффективность, используя perf statи ищем соответствующие события памяти и планировщика:
# perf stat -e sched:sched_stick_numa,sched:sched_move_numa,sched:sched_swap_numa,migrate:mm_migrate_pages,minor-faults -p PID
...
1 sched:sched_stick_numa
3 sched:sched_move_numa
41 sched:sched_swap_numa
5,239 migrate:mm_migrate_pages
50,161 minor-faults
Последняя часть оптимизации, связанной с NUMA, для рабочих нагрузок с большой нагрузкой на сеть связана с тем фактом, что сетевая карта является устройством PCIe, и каждое устройство привязано к своему собственному узлу NUMA, поэтому некоторые процессоры будут иметь меньшую задержку при общении с сетью. Мы обсудим оптимизации, которые можно применить там, когда будем обсуждать привязку NIC→CPU, а пока давайте переключимся на PCI-Express…
PCIe
Обычно вам не нужно слишком углубляться в устранение неполадок PCIe, если у вас нет какой-либо аппаратной неисправности. Поэтому обычно стоит потратить минимум усилий, просто создав “link width”, “link speed” и, возможно, RxErr/ BadTLP оповещения для ваших устройств PCIe. Это сэкономит вам часы на устранении неполадок из-за неисправного оборудования или неудачного согласования PCIe. Вы можете использовать lspci для этого:
Код:
# lspci -s 0a:00.0 -vvv
...
LnkCap: Port #0, Speed 8GT/s, Width x8, ASPM L1, Exit Latency L0s <2us, L1 <16us
LnkSta: Speed 8GT/s, Width x8, TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
...
Capabilities: [100 v2] Advanced Error Reporting
UESta: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- ...
UEMsk: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- ...
UESvrt: DLP+ SDES+ TLP- FCP+ CmpltTO- CmpltAbrt- ...
CESta: RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr-
CEMsk: RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+
Однако PCIe может стать узким местом, если у вас есть несколько высокоскоростных устройств, конкурирующих за пропускную способность (например, когда вы сочетаете быструю сеть с быстрым хранилищем), поэтому вам может потребоваться физически разделить ваши устройства PCIe между процессорами, чтобы получить максимальную пропускную способность.
Также см. статью « Понимание конфигурации PCIe для максимальной производительности » на веб-сайте Mellanox, в которой более подробно рассматривается конфигурация PCIe, которая может быть полезна на более высоких скоростях, если вы наблюдаете потерю пакетов между картой и ОС.
Intel предполагает, что иногда управление питанием PCIe (ASPM) может привести к более высоким задержкам и, следовательно, к более высокой потере пакетов. Вы можете отключить его, добавив pcie_aspm=off в командную строку ядра.
Прежде чем мы начнем, стоит упомянуть, что и Intel и Mellanox имеют свои собственные руководства по настройке производительности, и независимо от того, какого поставщика вы выберете, полезно прочитать их оба. Также к драйверам обычно прилагается файл README и набор полезных утилит.
Следующим местом, где можно проверить рекомендации, являются руководства по вашей операционной системе, например, Руководство по настройке производительности сети Red Hat Enterprise Linux , в котором объясняется большинство оптимизаций, упомянутых ниже, и даже больше.
У Cloudflare также есть хорошая статья о настройке этой части сетевого стека в их блоге, хотя она в основном нацелена на варианты использования с низкой задержкой.
При оптимизации сетевых карт ethtool будет твоим лучшим другом.
Небольшое примечание: если вы используете более новое ядро (и вам действительно следует это сделать!), вам также следует изменить некоторые части вашего пользовательского пространства, например, для сетевых операций, которые вам, вероятно, нужны более новые версии: ethtool, iproute2, и возможно iptables / nftables
Ценную информацию о том, что происходит с вашей сетевой картой, можно получить через ethtool -S:
Код:
$ ethtool -S eth0 | egrep 'miss|over|drop|lost|fifo'
rx_dropped: 0
tx_dropped: 0
port.rx_dropped: 0
port.tx_dropped_link_down: 0
port.rx_oversize: 0
port.arq_overflows: 0
Проконсультируйтесь с производителем вашей сетевой карты для подробного описания статистики, например, у Mellanox есть специальная вики-страница для них .
Со стороны ядра вещей, на которые вы будете смотреть /proc/interrupts, /proc/softirqs, а также /proc/net/softnet_stat. Здесь есть два полезных инструмента: hardirqsа также softirqs. Ваша цель в оптимизации сети состоит в том, чтобы настроить систему так, чтобы у вас было минимальное использование ЦП без потери пакетов.
Прерывание
Настройка здесь обычно начинается с распределения прерываний по процессорам. Как именно вы должны это сделать, зависит от вашей рабочей нагрузки:
- Для максимальной пропускной способности вы можете распределить прерывания по всем NUMA-узлам в системе.
- Чтобы свести к минимуму задержку, вы можете ограничить прерывания одним NUMA-узлом. Для этого вам может понадобиться уменьшить количество очередей, чтобы они поместились в один узел (обычно это означает сокращение их количества вдвое с помощью ethtool -L).
Размер кольцевого буфера
Сетевые карты должны обмениваться информацией с ядром. Обычно это делается с помощью структуры данных, называемой «кольцом», текущий/максимальный размер этого кольца просматривается через ethtool -g:
Код:
$ ethtool -g eth0
Ring parameters for eth0:
Pre-set maximums:
RX: 4096
TX: 4096
Current hardware settings:
RX: 4096
TX: 4096
Вы можете отрегулировать эти значения в пределах предварительно установленных максимумов с помощью -G. Как правило, чем больше, тем лучше (особенно, если вы используете объединение прерываний), так как это даст вам больше защиты от всплесков и икоты в ядре, тем самым уменьшая количество отброшенных пакетов из-за отсутствия буферного пространства/пропущенного прерывания. Но есть пара предостережений:
- В старых ядрах или драйверах без BQL высокие значения могут быть связаны с большим объемом буфера на стороне передачи.
- Буферы большего размера также увеличивают нагрузку на кэш , поэтому, если вы столкнулись с такой проблемой, попробуйте уменьшить их.
Объединение прерываний позволяет отложить уведомление ядра о новых событиях, объединяя несколько событий в одно прерывание. Текущие настройки можно просмотреть через ethtool -c:
Код:
$ ethtool -c eth0
Coalesce parameters for eth0:
...
rx-usecs: 50
tx-usecs: 50
Вы можете либо использовать статические ограничения, жестко ограничивая максимальное количество прерываний в секунду на ядро, либо зависеть от оборудования, которое автоматически регулирует частоту прерываний в зависимости от пропускной способности. Включение объединения (с -C) увеличит задержку и, возможно, приведет к потере пакетов, поэтому вы можете избежать этого для чувствительных к задержке. С другой стороны, его полное отключение может привести к регулированию прерываний и, следовательно, ограничить вашу производительность.
Разгрузка
Современные сетевые карты относительно умны и могут переложить большую часть работы либо на аппаратное обеспечение, либо эмулировать эту разгрузку в самих драйверах.
Все возможные разгрузки можно получить с помощью ethtool -k:
Код:
$ ethtool -k eth0
Features for eth0:
...
tcp-segmentation-offload: on
generic-segmentation-offload: on
generic-receive-offload: on
large-receive-offload: off [fixed]
В выводе все ненастраиваемые разгрузки отмечены значком [fixed].
Обо всех них можно много говорить , но вот несколько практических правил:
- не включайте LRO, вместо этого используйте GRO.
- будьте осторожны с TSO, так как это сильно зависит от качества ваших драйверов/прошивки.
- не включайте TSO/GSO на старых ядрах, так как это может привести к чрезмерному раздуванию буфера. **** Управление пакетами Все современные сетевые карты оптимизированы для многоядерного оборудования , поэтому они внутренне разбивают пакеты на виртуальные очереди, обычно по одной на процессор. Когда это делается аппаратно, это называется RSS, когда ОС отвечает за балансировку нагрузки пакетов между ЦП, это называется RPS (с его аналогом TX, называемым XPS). Когда ОС также пытается быть умной и направляет потоки на процессоры, которые в данный момент обрабатывают этот сокет, это называется RFS. Когда это делает аппаратное обеспечение, это называется «ускоренная RFS» или сокращенно aRFS.
- Если вы используете более новое оборудование 25G+, у него, вероятно, достаточно очередей и огромной таблицы косвенных адресов, чтобы иметь возможность просто использовать RSS для всех ваших ядер. Некоторые старые сетевые карты имеют ограничения на использование только первых 16 процессоров.
- Вы можете попробовать включить RPS , если:
- у вас больше процессоров, чем аппаратных очередей, и вы хотите пожертвовать задержкой ради пропускной способности.
- вы используете внутреннее туннелирование (например, GRE/IPinIP), которое NIC не может использовать RSS;
- Не включайте RPS , если ваш ЦП довольно старый и не имеет x2APIC.
- Привязка каждого ЦП к собственной очереди TX через XPS , как правило, является хорошей идеей.
- Эффективность RFS сильно зависит от вашей рабочей нагрузки и от того, применяете ли вы к ней привязку ЦП.
Включенный директор потока (или fdir в терминологии Intel) работает по умолчанию в режиме Application Targeting Routing, который реализует aRFS путем выборки пакетов и направления потоков в ядро, где они предположительно обрабатываются. Его статистика также доступна через ethtool -S:
Код:
$ ethtool -S eth0 | egrep 'fdir'
port.fdir_flush_cnt: 0
...
Хотя Intel утверждает, что fdir в некоторых случаях увеличивает производительность , внешние исследования показывают, что он также может привести к переупорядочению пакетов до 1% , что может сильно повредить производительности TCP. Поэтому попробуйте протестировать его сами и посмотрите, полезен ли FD для вашей рабочей нагрузки, при этом следите за TCPOFOQueue .
Операционные системы: сетевой стек
Существует бесчисленное множество книг, видеороликов и руководств по настройке сетевого стека Linux. И, к сожалению, тонны «культивирования груза sysctl.conf», которые идут с ними. Несмотря на то, что последние версии ядра не требуют такой тщательной настройки, как это было 10 лет назад, а большинство новых функций TCP/IP включены и хорошо настроены по умолчанию, люди по-прежнему копируют и вставляют свои старые. sysctls.conf которые они использовали для настройки ядер 2.6.18/2.6.32.
Чтобы проверить эффективность оптимизации, связанной с сетью, вы должны:
- Собирать общесистемные метрики TCP через /proc/net/snmpа также /proc/net/netstat.
- Совокупные метрики для каждого соединения, полученные либо из ss -n --extended --info, или от звонка getsockopt(TCP_INFO)/ getsockopt(TCP_CC_INFO) внутри вашего веб-сервера.
- tcptrace (1) выборочных потоков TCP.
- Анализируйте показатели RUM из приложения/браузера.
Стоит отметить хорошее подробное описание сетевого стека Linux от PackageCloud, тем более что они делают акцент на мониторинге, а не на слепой настройке:
- Мониторинг и настройка сетевого стека Linux: получение данных
- Мониторинг и настройка сетевого стека Linux: отправка данных
Из недавних статей по сетевым технологиям Linux особенно выделяется статья « Создание Linux TCP Fast ». Ему удается объединить многолетние улучшения ядра Linux на 4 страницах, разбив стек TCP на стороне отправителя Linux на функциональные части:
Справедливое распределение очередей и интервалов
Fair Queueing отвечает за улучшение справедливости и уменьшение блокировки между потоками TCP, что положительно влияет на скорость потери пакетов. Pacing планирует пакеты со скоростью, установленной системой контроля перегрузки, равномерно распределенной во времени, что еще больше снижает потери пакетов, увеличивая пропускную способность.
В качестве примечания: Fair Queueing и Pacing доступны в linux через fq qdisc. Некоторые из вас могут знать, что они являются требованием для BBR (теперь уже нет), но оба они могут быть использованы с CUBIC, обеспечивая до 15-20% снижения потерь пакетов и, следовательно, лучшую пропускную способность на CC, основанных на потерях. Только не используйте его в старых ядрах (< 3.19), так как в конечном итоге вы будете перегружать чистые ACK и искалечите ваши uploads/RPC.
TSO autosizing и TSQ
Обе эти функции отвечают за ограничение буферизации внутри стека TCP и, следовательно, за уменьшение задержки без снижения пропускной способности.
Контроль перегрузки
Алгоритмы управления перегрузками сами по себе являются огромной темой, и в последние годы вокруг них велась активная работа. Некоторые из них были обозначены как: tcp_cdg (CAIA), tcp_nv (Facebook) и tcp_bbr (Google). Мы не будем слишком углубляться в обсуждение их внутренней работы, скажем только, что все они больше полагаются на увеличение задержки, чем на падение пакетов для индикации перегрузки. BBR является, пожалуй, наиболее хорошо документированным, протестированным и практичным из всех новых средств контроля перегрузки. Основная идея заключается в создании модели сетевого пути на основе скорости доставки пакетов и последующем выполнении циклов управления для максимизации пропускной способности при минимизации rtt. Это именно то, что мы ищем в нашем прокси-стеке.
Предварительные данные экспериментов BBR на наших Edge PoP показывают увеличение скорости загрузки файлов:
Здесь я хочу подчеркнуть, что мы наблюдаем увеличение скорости во всех процентилях. Это не относится к изменениям бэкэнда. Обычно они приносят пользу только пользователям p90+ (те, у кого самое быстрое подключение к Интернету), поскольку мы считаем, что у всех остальных уже ограничена пропускная способность. Настройки на уровне сети, такие как изменение контроля перегрузки или включение FQ/стимуляции, показывают, что пользователи не ограничены пропускной способностью, но, если можно так выразиться, они «ограничены TCP».
Если вы хотите узнать больше о BBR, у APNIC есть хороший начальный обзор BBR (и его сравнение с контролем перегрузок на основе потерь). Для получения более подробной информации о BBR вы, вероятно, захотите прочитать архивы списков рассылки bbr-dev (вверху закреплено множество полезных ссылок). Людям, заинтересованным в контроле перегрузки в целом, может быть интересно следить Исследовательской группы по контролю перегрузки Интернета .
Обработка ACK и обнаружение потерь
Но хватит о контроле за перегрузкой, давайте поговорим об обнаружении потерь, здесь еще раз запуск последнего ядра немного поможет. Новые эвристики, такие как TLP и RACK , постоянно добавляются в TCP, а старые, такие как FACK и ER, удаляются. После добавления они включены по умолчанию, поэтому вам не нужно настраивать какие-либо системные параметры после обновления.Приоритизация пользовательского пространства и HOL
API-интерфейсы сокетов пользовательского пространства обеспечивают неявную буферизацию и не позволяют переупорядочивать фрагменты после их отправки, поэтому в мультиплексных сценариях (например, HTTP/2) это может привести к блокировке HOL и инверсии приоритетов h2. TCP_NOTSENT_LOWATвариант сокета (и соответствующий net.ipv4.tcp_notsent_lowatsysctl) были разработаны для решения этой проблемы путем установки порога, при котором сокет считает себя доступным для записи (т.е. epollбудет лгать вашему приложению). Это может решить проблемы с приоритизацией HTTP/2, но также потенциально может отрицательно сказаться на пропускной способности, так что вы знаете, что делать — проверьте сами.Sysctls
Нельзя просто говорить об оптимизации сети, не упоминая sysctl, которые необходимо настроить. Но позвольте мне сначала начать с вещей, которые вы не надо трогать:- net.ipv4.tcp_tw_recycle=1— не используйте его — он уже сломан для пользователей за NAT, но если вы обновите свое ядро, он будет сломан для всех .
- net.ipv4.tcp_timestamps=0— не отключайте их, если вы не знаете обо всех побочных эффектах и не согласны с ними. Например, одним из неочевидных побочных эффектов является то, что вы потеряете масштабирование окна и параметры SACK для syncookies .
- net.ipv4.tcp_slow_start_after_idle=0— основная проблема с медленным стартом после простоя заключается в том, что «холостой ход» определяется как одно RTO, что слишком мало.
- net.ipv4.tcp_mtu_probing=1— полезно, если между вами и вашими клиентами есть ICMP-черные дыры (скорее всего, они есть).
- net.ipv4.tcp_rmem, net.ipv4.tcp_wmem— должен быть настроен в соответствии с BDP, только не забывайте, что больше не всегда лучше .
- echo 2 > /sys/module/tcp_cubic/parameters/hystart_detect— если вы используете fq+cubic, это может помочь при слишком раннем выходе tcp_cubic из медленного старта .
Уровень приложения: Средний уровень
Инструменты
Как и в случае с ядром, очень важно иметь актуальное пользовательское пространство. Вы должны начать с обновления своих инструментов, например, вы можете упаковать более новые версии perf, bcc, так далее.Когда у вас есть новые инструменты, вы готовы правильно настроить и наблюдать за поведением системы. В этой части поста мы будем в основном полагаться на профилирование на процессоре с помощью perf top, FlameGraphs и специальные гистограммы из bccх funclatency.
Цепочка инструментов компилятора
Наличие современной цепочки инструментов компилятора необходимо, если вы хотите скомпилировать оптимизированную для аппаратного обеспечения сборку, которая присутствует во многих библиотеках, обычно используемых веб-серверами. Помимо производительности, новые компиляторы имеют новые функции безопасности (например, -fstack-protector-strongили же SafeStack), который вы хотите применить к краю. Другой вариант использования современных наборов инструментов — это когда вы хотите запустить свои тестовые наборы для бинарных файлов, скомпилированных с помощью санитайзеров (например AddressSanitizer и других ).
Системные библиотеки
Также стоит обновить системные библиотеки, такие как glibc, поскольку в противном случае вы можете упустить недавние оптимизации в низкоуровневых функциях из -lc, -lm, -lrtи т. д. Здесь также применимо предупреждение «Проверь сам», поскольку время от времени возникают регрессии .ZLIB
Обычно за сжатие отвечает веб-сервер. В зависимости от того, сколько данных проходит через этот прокси, вы можете иногда видеть символы zlib в perf top, например:
Код:
perf top
...
8.88% nginx [.] longest_match
8.29% nginx [.] deflate_slow
1.90% nginx [.] compress_block
Существуют способы оптимизации на самых низких уровнях: и Intel, и Cloudflare, и отдельный проект zlib-ng имеют свои форки zlib, которые обеспечивают более высокую производительность за счет использования новых наборов инструкций.
Malloc
До сих пор при обсуждении оптимизаций мы в основном ориентировались на процессор, но давайте переключимся и обсудим оптимизации, связанные с памятью. Если вы используете много Lua с FFI или тяжелые модули сторонних разработчиков, которые сами управляют памятью, вы можете наблюдать повышенное использование памяти из-за фрагментации. Вы можете попробовать решить эту проблему, переключившись на jemalloc или tcmalloc.
Использование malloc также имеет следующие преимущества:
- Отделение бинарного файла nginx от окружения, так что обновление версии glibc и миграция ОС будут меньше влиять на него.
- Лучшая интроспекция, профилирование и статистика.
PCRE
Если вы используете много сложных регулярных выражений в конфигурации nginx или сильно полагаетесь на Lua, вы можете увидеть символы, связанные с pcre, в perf top. Вы можете оптимизировать это, скомпилировав PCRE с помощью JIT, а также включив его в nginx через pcre_jit on;.
Вы можете проверить результат оптимизации, посмотрев на FlameGraphs или используя funclatency:
Код:
# funclatency /srv/nginx-bazel/sbin/nginx:ngx_http_regex_exec -u
...
usecs : count distribution
0 -> 1 : 1159 |********** |
2 -> 3 : 4468 |****************************************|
4 -> 7 : 622 |***** |
8 -> 15 : 610 |***** |
16 -> 31 : 209 |* |
32 -> 63 : 91 | |
TLS
Если вы завершаете работу TLS на периферии без CDN, оптимизация производительности TLS может быть очень ценной. При обсуждении настроек мы будем в основном фокусироваться на эффективности на стороне сервера. Итак, в настоящее время первое, что вам нужно решить, это какую библиотеку TLS использовать: Vanilla OpenSSL , LibreSSL или BoringSSL . После выбора разновидности библиотеки TLS вам необходимо правильно ее собрать: OpenSSL, например, имеет набор встроенных эвристик, которые позволяют проводить оптимизацию на основе среды сборки; У BoringSSL есть детерминированные сборки, но, к сожалению, он гораздо более консервативен и просто отключает некоторые оптимизации по умолчанию . В любом случае, здесь выбор современного процессора должен наконец окупиться: большинство библиотек TLS могут использовать все, от AES-NI и SSE до ADX и AVX512. Вы можете использовать встроенные тесты производительности, которые поставляются с вашей библиотекой TLS, например, в случае с BoringSSL это bssl speed.Большая часть производительности зависит не от имеющегося у вас оборудования, а от наборов шифров, которые вы собираетесь использовать, поэтому вам нужно тщательно их оптимизировать. Также знайте, что изменения здесь могут (и будут!) влиять на безопасность вашего веб-сервера — самые быстрые наборы шифров не обязательно будут лучшими. Если вы не знаете, какие параметры шифрования использовать, лучше всего начать с Mozilla SSL Configuration Generator.
Асимметричное шифрование
Если ваш сервис находится на грани, то вы можете наблюдать значительное количество рукопожатий TLS и, следовательно, значительная часть вашего ЦП потребляется асимметричным шифрованием, что делает его очевидной целью для оптимизации. Чтобы оптимизировать использование ЦП на стороне сервера, вы можете переключиться на сертификаты ECDSA , которые обычно в 10 раз быстрее, чем RSA. Кроме того, они значительно меньше, что может ускорить рукопожатие при потере пакетов. Но ECDSA также сильно зависит от качества генератора случайных чисел вашей системы, поэтому, если вы используете OpenSSL, убедитесь, что у вас достаточно энтропии (с BoringSSL вам не нужно об этом беспокоиться ). В качестве примечания стоит отметить, что больше не всегда лучше, например, использование 4096 сертификатов RSA снизит вашу производительность в 10 раз:
Код:
$ bssl speed
Did 1517 RSA 2048 signing ... (1507.3 ops/sec)
Did 160 RSA 4096 signing ... (153.4 ops/sec)
Что еще хуже, меньший размер также не обязательно является лучшим выбором: используя необычное поле p-224 для ECDSA, вы получите на 60% худшую производительность по сравнению с более распространенным p-256:
Код:
$ bssl speed
Did 7056 ECDSA P-224 signing ... (6831.1 ops/sec)
Did 17000 ECDSA P-256 signing ... (16885.3 ops/sec)
Эмпирическое правило здесь заключается в том, что наиболее часто используемое шифрование, как правило, является наиболее оптимизированным.
При запуске должным образом оптимизированной библиотеки на основе OpenTLS с использованием сертификатов RSA вы должны увидеть следующtt в вашем perf top: коробки с поддержкой AVX2, но не с поддержкой ADX (например, Haswell) должны использовать AVX2:
Код:
6.42% nginx [.] rsaz_1024_sqr_avx2
1.61% nginx [.] rsaz_1024_mul_avx2
В то время как более новое оборудование должно использовать общее умножение Монтгомери с ADX:
Код:
7.08% nginx [.] sqrx8x_internal
2.30% nginx [.] mulx4x_internal
Симметричное шифрование
Если у вас есть много массовых передач, таких как видео, фотографии или более общие файлы, вы можете начать наблюдать символы симметричного шифрования в выводе профилировщика. Здесь вам просто нужно убедиться, что ваш процессор поддерживает AES-NI, и вы установите настройки на стороне сервера для шифров AES-GCM. Правильно настроенное оборудование должно иметь perf top:
Код:
8.47% nginx [.] aesni_ctr32_ghash_6x
Но не только вашим серверам придется иметь дело с шифрованием/дешифрованием — ваши клиенты разделят ту же нагрузку на гораздо менее мощном процессоре. Без аппаратного ускорения это может быть довольно сложно , поэтому вы можете рассмотреть возможность использования алгоритма, разработанного для быстрой работы без аппаратного ускорения, например, ChaCha20-Poly1305 . Это уменьшит TTLB для некоторых ваших мобильных клиентов.
ChaCha20-Poly1305 поддерживается в BoringSSL из коробки, для OpenSSL 1.0.2 можно рассмотреть возможность использования патчей Cloudflare . BoringSSL также поддерживает « группы шифров с равными предпочтениями », поэтому вы можете использовать следующую конфигурацию, чтобы позволить клиентам решать, какие шифры использовать в зависимости от их аппаратных возможностей (бесстыдно украдено из cloudflare/sslconfig ):
Код:
ssl_ciphers '[ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256|ECDHE-RSA-CHACHA20-POLY1305]:ECDHE+AES128:RSA+AES128:ECDHE+AES256:RSA+AES256:ECDHE+3DES:RSA+3DES';
ssl_prefer_server_ciphers on;
Уровень приложения: верхний уровень
Чтобы проанализировать эффективность ваших оптимизаций на этом уровне, вам потребуется собрать данные RUM. В браузерах вы можете использовать API синхронизации навигации и синхронизации ресурсов . Ваши основные показатели — TTFB и TTV/TTI. Наличие этих данных в легко запрашиваемых и графических форматах значительно упростит итерацию.
Сжатие
Сжатие в nginx начинается с mime.types файла, который определяет соответствие по умолчанию между расширением файла и типом MIME - ответа. Затем вам нужно определить, какие типы вы хотите передать вашему компрессору, например gzip_types. Если вам нужен полный список, вы можете использовать mime-db для автоматического создания вашего mime.typesи добавить тех, у кого .compressible == trueк gzip_types.При включении gzip будьте осторожны с двумя его аспектами:
- Увеличение использования памяти. Это можно решить, ограничив gzip_buffers.
- Увеличен TTFB из-за буферизации. Это можно решить с помощью [gzip_no_buffer].
Что касается самих настроек сжатия, давайте обсудим два отдельных варианта использования: статические и динамические данные.
- Для статических данных вы можете заархивировать максимальные коэффициенты сжатия, предварительно сжав свои статические ресурсы в процессе сборки. Мы довольно подробно обсуждали это в Развертывание Brotli для статического содержимого как для gzip, так и для brotli.
- Для динамических данных необходимо тщательно сбалансировать полный круговой путь: время на сжатие данных + время на их передачу + время на распаковку на клиенте. Поэтому установка максимально возможного уровня сжатия может быть неразумной не только с точки зрения использования ЦП, но и с точки зрения TTFB.
Буферизация
Буферизация внутри прокси-сервера может сильно повлиять на производительность веб-сервера, особенно в отношении задержки. Прокси-модуль nginx имеет различные ручки буферизации, которые можно переключать в зависимости от местоположения, каждая из которых полезна для своей цели. Вы можете отдельно управлять буферизацией в обоих направлениях через proxy_request_buffering, a также proxy_buffering. Если буферизация включена, верхний предел потребления памяти устанавливается client_body_buffer_sizeа также proxy_buffers, после достижения этих пороговых значений запрос/ответ буферизуется на диск. Для ответов это можно отключить, установив proxy_max_temp_file_sizeдо 0.Наиболее распространенные подходы к буферизации:
- Буферизация запроса/ответа до некоторого порога в памяти, а затем переполнение на диск. Если буферизация запросов включена, вы отправляете запрос на серверную часть только после того, как он будет полностью получен, а с буферизацией ответов вы можете мгновенно освободить серверный поток, как только он будет готов с ответом. Этот подход имеет преимущества улучшенной пропускной способности и защиты серверной части за счет увеличения задержки и использования памяти/ввода-выводов (хотя, если вы используете твердотельные накопители, это может не быть большой проблемой).
- Без буферизации. Буферизация может быть не лучшим выбором для чувствительных к задержкам маршрутов, особенно для тех, которые используют потоковую передачу. Для них вы можете отключить его, но теперь ваш сервер должен иметь дело с медленными клиентами (включая вредоносные low-read атаки типа
- Буферизация ответов, управляемая приложением, через X-Accel-Bufferingзаголовок.
TLS
Теперь мы собираемся поговорить о высокоуровневых аспектах TLS и улучшении задержки, которые можно сделать, правильно настроив nginx. Большинство оптимизаций, о которых я упомяну, High Performance Browser Networking « Оптимизация для TLS » HTTPS(er) » на nginx.conf 2014. Настройки, упомянутые в этой части, повлияют как на производительность, так и на безопасность. вашего веб-сервера, если вы не уверены, обратитесь к Руководству по TLS на стороне сервера Mozilla и/или к вашей группе безопасности.Для проверки результатов оптимизаций вы можете использовать:
- WebpageTest на предмет влияния на производительность.
- SSL Server Test от Qualys или Mozilla TLS Observatory на предмет влияния на безопасность.
Как любят говорить администраторы баз данных, «самый быстрый запрос — это тот, который вы никогда не сделаете». То же самое касается TLS — вы можете уменьшить задержку на один RTT, если кешируете результат рукопожатия. Есть два способа сделать это:
- Вы можете попросить клиента сохранить все параметры сеанса (в подписанном и зашифрованном виде) и отправить их вам во время следующего рукопожатия (аналогично cookie). На стороне nginx это настраивается через ssl_session_ticketsдиректива. Это не потребляет памяти на стороне сервера, но имеет ряд недостатков:
- Вам нужна инфраструктура для создания, ротации и распространения случайных ключей шифрования/подписи для сеансов TLS. Просто помните, что вам действительно не следует 1) использовать систему управления версиями для хранения ключей билетов 2) генерировать эти ключи из другого неэфемерного материала, например, даты или сертификата.
- PFS будет не для каждого сеанса, а для каждого ключа билета tls, поэтому, если злоумышленник получит ключ билета, он потенциально может расшифровать любой захваченный трафик в течение срока действия билета.
- Ваше шифрование будет ограничено размером вашего ключа билета. Нет особого смысла использовать AES256, если вы используете 128-битный ключ билета. Nginx поддерживает как 128-битные, так и 256-битные ключи билетов TLS.
- Не все клиенты поддерживают ключи билетов (хотя все современные браузеры их поддерживают).
- Или вы можете хранить параметры сеанса TLS на сервере и давать клиенту только ссылку (идентификатор). Это делается через ssl_session_cacheдиректива. Его преимущество заключается в сохранении PFS между сеансами и значительном ограничении поверхности атаки. Хотя ключи от билетов имеют недостатки:
- Они потребляют ~256 байт памяти за сеанс на сервере, что означает, что вы не можете хранить многие из них слишком долго.
- Они не могут быть легко разделены между серверами. Поэтому вам либо нужен балансировщик нагрузки, который будет отправлять одного и того же клиента на тот же сервер, чтобы сохранить локальность кеша, либо написать распределенное хранилище сеансов TLS поверх чего-то вроде ngx_http_lua_module.
Код:
ssl_session_tickets on;
ssl_session_timeout 1h;
ssl_session_ticket_key /run/nginx-ephemeral/nginx_session_ticket_curr;
ssl_session_ticket_key /run/nginx-ephemeral/nginx_session_ticket_prev;
ssl_session_ticket_key /run/nginx-ephemeral/nginx_session_ticket_next;
Вы всегда будете шифровать текущим ключом, но принимать сеансы, зашифрованные как следующим, так и предыдущим ключами.
Сшивание OCSP
Вы должны скрепить свои ответы OCSP, иначе:
- Ваше рукопожатие TLS может занять больше времени, поскольку клиенту потребуется связаться с центром сертификации, чтобы получить статус OCSP.
- Ошибка выборки OCSP может привести к снижению доступности.
- Вы можете поставить под угрозу конфиденциальность пользователей, поскольку их браузер свяжется со сторонней службой, указав, что они хотят подключиться к вашему сайту.
Код:
ssl_stapling_file /var/cache/nginx/ocsp/www.der;
Размер записи TLS
TLS разбивает данные на фрагменты, называемые записями, которые вы не можете проверить и расшифровать, пока не получите их целиком. Вы можете измерить эту задержку как разницу между TTFB с точки зрения сетевого стека и приложения.
По умолчанию nginx использует фрагменты размером 16 КБ, которые даже не вписываются в окно перегрузки IW10, поэтому требуют дополнительного кругового пути. Стандартный nginx предоставляет возможность устанавливать размеры записей через ssl_buffer_sizeдиректива:
- Чтобы оптимизировать для низкой задержки, вы должны установить что-то маленькое, например 4k. Дальнейшее его уменьшение будет более затратным с точки зрения использования ЦП.
- Чтобы оптимизировать для высокой пропускной способности, вы должны оставить его на уровне 16 КБ.
- Вам нужно настроить его вручную.
- Вы можете только установить ssl_buffer_sizeна основе конфигурации для каждого nginx или блока для каждого сервера, поэтому, если у вас есть сервер со смешанной рабочей нагрузкой по задержке/пропускной способности, вам необходимо пойти на компромисс.
TLS 1.3
Функции TLS 1.3 действительно звучат очень хорошо , но если у вас нет ресурсов для постоянного устранения неполадок TLS, я бы посоветовал не включать его, поскольку:
- Это пока черновик .
- Рукопожатие 0-RTT имеет некоторые последствия для безопасности . И ваше приложение должно быть к этому готово.
- Все еще существуют промежуточные устройства (антивирусы, DPI и т. д.), которые блокируют неизвестные версии TLS.
Eventloop
Nginx — это веб-сервер на основе цикла событий, что означает, что он может выполнять только одну операцию за раз. Несмотря на то, что кажется, что он делает все эти вещи одновременно, как при мультиплексировании с временным разделением, все, что делает nginx, — это просто быстро переключается между событиями, обрабатывая одно за другим . Все это работает, потому что обработка каждого события занимает всего пару микросекунд. Но если это начинает занимать слишком много времени, например, из-за того, что требуется переход на вращающийся диск, задержка может резко возрасти.Если вы начинаете замечать, что ваш nginx проводит слишком много времени внутри ngx_process_events_and_timersфункция, а распределение бимодальное, то вы, вероятно, страдаете от задержек цикла событий.
Код:
# funclatency '/srv/nginx-bazel/sbin/nginx:ngx_process_events_and_timers' -m
msecs : count distribution
0 -> 1 : 3799 |****************************************|
2 -> 3 : 0 | |
4 -> 7 : 0 | |
8 -> 15 : 0 | |
16 -> 31 : 409 |**** |
32 -> 63 : 313 |*** |
64 -> 127 : 128 |* |
AIO и пулы потоков
Поскольку основным источником зависаний цикла событий, особенно на вращающихся дисках, является ввод-вывод, вам, вероятно, следует сначала посмотреть на него. Вы можете измерить, насколько это на вас влияет, запустив fileslower:
Код:
# fileslower 10
Tracing sync read/writes slower than 10 ms
TIME(s) COMM TID D BYTES LAT(ms) FILENAME
2.642 nginx 69097 R 5242880 12.18 0002121812
4.760 nginx 69754 W 8192 42.08 0002121598
4.760 nginx 69435 W 2852 42.39 0002121845
4.760 nginx 69088 W 2852 41.83 0002121854
Чтобы исправить это, nginx поддерживает разгрузку операций ввода-вывода в пул потоков (у него также есть поддержка AIO, но нативные AIO в Unix имеют множество особенностей, поэтому лучше избегать этого, если вы не знаете, что делаете). Базовая установка состоит из простого:
Код:
aio threads;
aio_write on;
Для более сложных случаев можно настроить пользовательские thread_pool, например, по одному на диск, так что если один диск выйдет из строя, это не повлияет на остальные запросы. Пулы потоков могут значительно сократить количество зависших процессов nginx. Dсостояние, улучшая как задержку, так и пропускную способность. Но он не устранит остановку событийного цикла полностью, так как в настоящее время не все операции ввода-вывода передаются ему.
Написание журналов также может занять значительное время, так как это касается дисков. Вы можете проверить, так ли это, запустив ext4slower и ищем ссылки на журналы доступа/ошибок:
Код:
# ext4slower 10
TIME COMM PID T BYTES OFF_KB LAT(ms) FILENAME
06:26:03 nginx 69094 W 163070 634126 18.78 access.log
06:26:08 nginx 69094 W 151 126029 37.35 error.log
06:26:13 nginx 69082 W 153168 638728 159.96 access.log
Это можно обойти путем буферизации журналов доступа в памяти перед их записью с помощью bufferпараметр для access_logдиректива. Используя gzipКроме того, вы можете сжимать журналы перед их записью на диск, что еще больше снижает нагрузку на ввод-вывод.
Но чтобы полностью устранить задержки ввода-вывода при записи в журнал, вы должны просто писать журналы через syslog , таким образом, журналы будут полностью интегрированы с циклом событий nginx.
Открытый файловый кеш
Вызовы open(2) по своей сути блокируются, а веб-серверы регулярно открывают/читают/закрывают файлы, может быть полезно иметь кеш открытых файлов. Вы можете увидеть, сколько пользы посмотрев на ngx_open_cached_file:
Код:
# funclatency /srv/nginx-bazel/sbin/nginx:ngx_open_cached_file -u
usecs : count distribution
0 -> 1 : 10219 |****************************************|
2 -> 3 : 21 | |
4 -> 7 : 3 | |
8 -> 15 : 1 | |
Если вы видите, что слишком много открытых вызовов или некоторые из них занимают слишком много времени, вы можете посмотреть на включение кеша открытых файлов:
Код:
open_file_cache max=10000;
open_file_cache_min_uses 2;
open_file_cache_errors on;
После включения open_file_cacheвы можете наблюдать все промахи кеша, посмотрев на opensnoopи решить , нужно ли вам настраивать ограничения кеша :
Код:
# opensnoop -n nginx
PID COMM FD ERR PATH
69435 nginx 311 0 /srv/site/assets/serviceworker.js
69086 nginx 158 0 /srv/site/error/404.html
...