Breaking down CPU speed: How utilization impacts performance
Инженеры GitHub провели исследование, чтобы найти оптимальный баланс между загрузкой CPU и скоростью его работы.
Для этого они зеркалили продовый трафик в отдельное окружение и замеряли latency обработки операций при разной степени утилизации процессора. Задача была с одной стороны оставаться в рамках SLA, а с другой — не позволять ресурсам простаивать.
В результате, для их типичной рабочей нагрузки (IO-bound) и используемых процессоров (Intel), оптимальная утилизация CPU оказалась в районе 61%.
Интересно, что Б. Грегг в своей книге "Systems Performance" часто упоминает порог в 60% как точку, после которой ресурс (будь то диск или CPU) может стать узким местом в системе.
Цитата:
P.S. Теперь дело "за малым": настроить процессы resource management и capacity planning, чтобы держать утилизацию в районе этих цифр. Изи)
Инженеры GitHub провели исследование, чтобы найти оптимальный баланс между загрузкой CPU и скоростью его работы.
Для этого они зеркалили продовый трафик в отдельное окружение и замеряли latency обработки операций при разной степени утилизации процессора. Задача была с одной стороны оставаться в рамках SLA, а с другой — не позволять ресурсам простаивать.
В результате, для их типичной рабочей нагрузки (IO-bound) и используемых процессоров (Intel), оптимальная утилизация CPU оказалась в районе 61%.
Интересно, что Б. Грегг в своей книге "Systems Performance" часто упоминает порог в 60% как точку, после которой ресурс (будь то диск или CPU) может стать узким местом в системе.
Цитата:
Netflix commonly uses ASGs that target a CPU utilization of 60%, and will scale up and down with the load to maintain that target.
P.S. Теперь дело "за малым": настроить процессы resource management и capacity planning, чтобы держать утилизацию в районе этих цифр. Изи)
The GitHub Blog
Breaking down CPU speed: How utilization impacts performance
The Performance Engineering team at GitHub assessed how CPU performance degrades as utilization increases and how this relates to capacity.
👍18🤨1🤝1
Scaling in the Linux Networking Stack (scaling.txt)
Документ от разработчиков ядра Linux описывает пять техник, которые помогают повысить производительность сетевого стека в многоядерных системах.
Это:
* RSS: Receive Side Scaling
* RPS: Receive Packet Steering
* RFS: Receive Flow Steering
* Accelerated Receive Flow Steering
* XPS: Transmit Packet Steering
В нашей инфраструктуре мы уже давно и успешно используем RSS.
Это аппаратная технология, суть следующая.
Когда поступает сетевой пакет, на основе его заголовков вычисляется хеш. Полученное значение сопоставляется с таблицей, где каждому значению соответствует определенная очередь (RX).
Каждая RX-очередь привязана к конкретному ядру процессора.
Таким образом:
1. Обработка трафика распределяется между несколькими CPU, что позволяет эффективно использовать ресурсы;
2. Все пакеты одного соединения попадают в одну очередь. Это исключает проблему "out of order" пакетов.
Однако бывают ситуации, когда распределить обработку трафика между ядрами не получается, и отдельное ядро или группа ядер оказывается сильно перегруженной:
- одно конкретное соединение прокачивает кратно больший объем трафика, чем другие;
- RX-очередей в системе меньше, чем доступных CPU.
Мы, например, сталкивались с такими проблемами при использовании MetalLB в L2-режиме: весь трафик шел через одну машину MetalLB (мастер) и "приклеивался" к одной RX-очереди на Ingress Controller. Остальные ядра и RX-очереди при этом простаивали.
В подобных случаях может помочь другая техника, описанная в том же документе — RPS (Receive Packet Steering).
RPS — это программная реализация RSS. Она позволяет распределить RX-очереди по конкретным ядрам, выравнивая нагрузку между ними.
Но есть и минусы:
- Программная реализация создает дополнительную нагрузку на CPU, что проявляется в увеличении числа IRQ на графике загрузки процессора;
- Снижается "локальность" данных в кэшах процессора, что может повлиять на производительность.
(на скрине RPS включили после 16:00)
———
Тема сложная, и я не уверен, что до конца понимаю, как это все работает;)
Было бы интересно узнать, какие техники масштабирования трафика используете вы и как справляетесь с подобными проблемами.
Дальнейшее чтение:
- сам документ scaling.txt
- расшифровка доклада от Одноклассников, где ребята решали похожие проблемы;
- примерно тоже самое, но забугорный доклад по перформансу сетевого стека.
tags: #network #tuning #linux #кейс
Документ от разработчиков ядра Linux описывает пять техник, которые помогают повысить производительность сетевого стека в многоядерных системах.
Это:
* RSS: Receive Side Scaling
* RPS: Receive Packet Steering
* RFS: Receive Flow Steering
* Accelerated Receive Flow Steering
* XPS: Transmit Packet Steering
В нашей инфраструктуре мы уже давно и успешно используем RSS.
Это аппаратная технология, суть следующая.
Когда поступает сетевой пакет, на основе его заголовков вычисляется хеш. Полученное значение сопоставляется с таблицей, где каждому значению соответствует определенная очередь (RX).
Каждая RX-очередь привязана к конкретному ядру процессора.
Таким образом:
1. Обработка трафика распределяется между несколькими CPU, что позволяет эффективно использовать ресурсы;
2. Все пакеты одного соединения попадают в одну очередь. Это исключает проблему "out of order" пакетов.
Однако бывают ситуации, когда распределить обработку трафика между ядрами не получается, и отдельное ядро или группа ядер оказывается сильно перегруженной:
- одно конкретное соединение прокачивает кратно больший объем трафика, чем другие;
- RX-очередей в системе меньше, чем доступных CPU.
Мы, например, сталкивались с такими проблемами при использовании MetalLB в L2-режиме: весь трафик шел через одну машину MetalLB (мастер) и "приклеивался" к одной RX-очереди на Ingress Controller. Остальные ядра и RX-очереди при этом простаивали.
В подобных случаях может помочь другая техника, описанная в том же документе — RPS (Receive Packet Steering).
RPS — это программная реализация RSS. Она позволяет распределить RX-очереди по конкретным ядрам, выравнивая нагрузку между ними.
Но есть и минусы:
- Программная реализация создает дополнительную нагрузку на CPU, что проявляется в увеличении числа IRQ на графике загрузки процессора;
- Снижается "локальность" данных в кэшах процессора, что может повлиять на производительность.
(на скрине RPS включили после 16:00)
———
Тема сложная, и я не уверен, что до конца понимаю, как это все работает;)
Было бы интересно узнать, какие техники масштабирования трафика используете вы и как справляетесь с подобными проблемами.
Дальнейшее чтение:
- сам документ scaling.txt
- расшифровка доклада от Одноклассников, где ребята решали похожие проблемы;
- примерно тоже самое, но забугорный доклад по перформансу сетевого стека.
tags: #network #tuning #linux #кейс
👍13
Ingress NGINX Controller vs ClusterIP (IPtables): Балансировка.
Задумывались ли вы почему балансировка через Ingress NGINX Controller показывает более ровное распределение трафика по Подам в сравнении с ClusterIP (IPtables)?
Я до недавнего времени не очень, но "сигналы с мест" требовали разобраться.
Балансировка через ClusterIP (IPtables)
ClusterIP (далее svc) это сущность Kubernetes, позволяющая приземлять трафик в Под.
В свою очередь svc это просто набор IPtables правил (или правил аналогичных инструментов), "приклеивающий" запрос к конкретному Поду.
Примерно так:
Что можно интерпретировать как:
* Pod1 будет выбран в качестве апстрима в 33% случаев;
* далее в 50% Pod2;
* иначе апстримом станет Pod3.
Таким образом, если есть три входящих коннекта, они могут распределиться как по одному на каждый Под, так и все три упасть в один конкрентный.
Теория вероятностей.
Балансировка через Ingress NGINX Controller
Зная о том как функционирует svc, я по наивности полагал, что и Ingress Controller (далее IC) оперирует в качестве апстримов сущностью svc, что будет в итоге давать тот же "уровень" баланcировки.
Факты говорили об обратном, потому я пошел перепроверять.
Под каждый объект Ingress рендерится секция
В ней директива
В
——
Да и как иначе IC сможет обеспечивать разные типы балансировки? А по умолчанию используется round-robin.
Задумывались ли вы почему балансировка через Ingress NGINX Controller показывает более ровное распределение трафика по Подам в сравнении с ClusterIP (IPtables)?
Я до недавнего времени не очень, но "сигналы с мест" требовали разобраться.
Балансировка через ClusterIP (IPtables)
ClusterIP (далее svc) это сущность Kubernetes, позволяющая приземлять трафик в Под.
В свою очередь svc это просто набор IPtables правил (или правил аналогичных инструментов), "приклеивающий" запрос к конкретному Поду.
Примерно так:
iptables -t nat -A KUBE-SVC -m random --probability 0.33 -j DNAT --to <Pod1>
iptables -t nat -A KUBE-SVC -m random --probability 0.50 -j DNAT --to <Pod2>
iptables -t nat -A KUBE-SVC -j DNAT --to <Pod3>
Что можно интерпретировать как:
* Pod1 будет выбран в качестве апстрима в 33% случаев;
* далее в 50% Pod2;
* иначе апстримом станет Pod3.
Таким образом, если есть три входящих коннекта, они могут распределиться как по одному на каждый Под, так и все три упасть в один конкрентный.
Теория вероятностей.
Балансировка через Ingress NGINX Controller
Зная о том как функционирует svc, я по наивности полагал, что и Ingress Controller (далее IC) оперирует в качестве апстримов сущностью svc, что будет в итоге давать тот же "уровень" баланcировки.
Факты говорили об обратном, потому я пошел перепроверять.
Под каждый объект Ingress рендерится секция
server{}
шаблона nginx.tmpl
(пруф):{{ range $tcpServer := .TCPBackends }}
server {...}
{{ end }}
В ней директива
proxy_pass
указывает на некий upstream_balancer
: ### Attention!!!
# We no longer create "upstream" section for every backend.
# Backends are handled dynamically using Lua....
...
balancer_by_lua_block {
balancer.balance()
}
...
В
balancer.balance()
и живет логика выбора апстрима, где peer
== endpoint (считай Pod
):...
local peer = balancer:balance()
if not peer then
ngx.log(ngx.WARN, "no peer was returned, balancer: " .. balancer.name)
return
end
...
——
Да и как иначе IC сможет обеспечивать разные типы балансировки? А по умолчанию используется round-robin.
👍10👏3❤1😐1
Сетевой анализ с eBPF: измеряем Round Trip Time
Под катом:
* мои рассуждения о сложности интерпретации latency в современных системах;
* небольшой гайд по eBPF - напишем по шагам инструмент, который поможет отвечать на вопрос: "причина замедления в приложении или в инфраструктуре?".
Полезного чтения!
tags: #eBPF #Linux #SRE #TCP
Длительность (latency) — ключевой показатель производительности системы. На первый взгляд всё просто: рост задержки — признак деградации. Сложность в деталях...
Под катом:
* мои рассуждения о сложности интерпретации latency в современных системах;
* небольшой гайд по eBPF - напишем по шагам инструмент, который поможет отвечать на вопрос: "причина замедления в приложении или в инфраструктуре?".
Полезного чтения!
tags: #eBPF #Linux #SRE #TCP
www.alebedev.tech
Сетевой анализ с eBPF: измеряем Round Trip Time
Разбираем сложность интерпретации Latency и пишем свой инструмент на eBPF, который эту сложность снижает.
👍19
Алгоритмы управления потоком (Flow Control) в TCP служат для предотвращения перегрузки сети и потерь данных.
Исследования в этой области не прекращаются и на сегодня нам доступно множество вариантов:
*
*
*
*
*
*
*
* ...
По умолчанию в Linux используется
Так может нам просто переехать на новые рельсы?
Хотя кажется правильнее поставить вопрос по другому: в каких случаях какой алгоритм может быть предпочтительнее?
————
Алгоритмы Flow Control можно условно разделить на два типа:
1. Loss-based (ориентированы на потери пакетов):
2. Delay-based (ориентированы на изменения RTT):
Основная цель любой реализации Flow Control — максимально эффективно использовать пропускную способность канала, сохраняя баланс между скоростью передачи данных и предотвращением перегрузок.
Скорость регулируется через Congestion Window (окно перегрузки) — сколько данных можно отправить без получения подтверждения.
Разница между подходами к контролю перегрузки заключается в методах её определения.
Loss-based (CUBIC)
Алгоритмы этого типа оценивают перегрузку по потерям пакетов.
Пришел дублирующий ACK или сработал Retransmission Timeout (RTO)? Значит есть потери и следовательно канал перегружен - снижаем скорость.
Затем ориентируясь на поступающие ACK, скорость увеличивается, пока не обнаружатся новые потери.
Такой подход может забивать очереди в канале до предела, что и будет приводить к потерям. Реакция носит реактивный характер: перегрузка фиксируется только после её возникновения.
Delay-based (BBR)
В Delay-based алгоритмах, таких как BBR, перегрузка оценивается на основе изменения задержек:
* минимальный RTT (
* если текущий RTT (
Таким образом, BBR стремится избегать заполнения очередей, что позволяет сократить задержки.
Его подход более превентивный: предотвращение перегрузки до её появления.
————
Внутри дата-центров, где RTT низкий,
Вообщем как обычно надо быть осторожее!
Почитать:
- https://blog.apnic.net/2017/05/09/bbr-new-kid-tcp-block/
- https://book.systemsapproach.org/congestion.html
- https://tcpcc.systemsapproach.org/
tags: #network #tcp
Исследования в этой области не прекращаются и на сегодня нам доступно множество вариантов:
*
Reno
(1986)*
New Reno
(1999)*
CUBIC
(2004)*
FAST TCP
(2005)*
BBRv1
(2016)*
BBRv2
(2019)*
BBRv3
(2023)* ...
По умолчанию в Linux используется
CUBIC
. Однако создатели BBR (Google) выкладывают любопытные исследования, где резюмируют:BBR enables big throughput improvements on high-speed, long-haul links...
BBR enables significant reductions in latency in last-mile networks that connect users to the internet...
Так может нам просто переехать на новые рельсы?
Хотя кажется правильнее поставить вопрос по другому: в каких случаях какой алгоритм может быть предпочтительнее?
————
Алгоритмы Flow Control можно условно разделить на два типа:
1. Loss-based (ориентированы на потери пакетов):
Reno
, NewReno
, CUBIC
2. Delay-based (ориентированы на изменения RTT):
FAST TCP
, BBRv*
Основная цель любой реализации Flow Control — максимально эффективно использовать пропускную способность канала, сохраняя баланс между скоростью передачи данных и предотвращением перегрузок.
Скорость регулируется через Congestion Window (окно перегрузки) — сколько данных можно отправить без получения подтверждения.
Разница между подходами к контролю перегрузки заключается в методах её определения.
Loss-based (CUBIC)
Алгоритмы этого типа оценивают перегрузку по потерям пакетов.
Пришел дублирующий ACK или сработал Retransmission Timeout (RTO)? Значит есть потери и следовательно канал перегружен - снижаем скорость.
Затем ориентируясь на поступающие ACK, скорость увеличивается, пока не обнаружатся новые потери.
Такой подход может забивать очереди в канале до предела, что и будет приводить к потерям. Реакция носит реактивный характер: перегрузка фиксируется только после её возникновения.
Delay-based (BBR)
В Delay-based алгоритмах, таких как BBR, перегрузка оценивается на основе изменения задержек:
* минимальный RTT (
RTT_min
) принимается за эталон;* если текущий RTT (
RTT_now
) превышает RTT_min
, алгоритм предполагает, что канал перегружен, и снижает скорость передачи данных.Таким образом, BBR стремится избегать заполнения очередей, что позволяет сократить задержки.
Его подход более превентивный: предотвращение перегрузки до её появления.
————
CUBIC
проигрывает BBR
в сетях с высоким RTT, например, в интернете. Это происходит из-за медленного роста скорости после обнаружения потерь: ACK приходят с задержкой.Внутри дата-центров, где RTT низкий,
CUBIC
должен справляться лучше - быстрые ACK ускоряют рост скорости передачи данных.BBR
же в таких сетях может не дать преимуществ. При всплесках трафика он снижает скорость, чтобы избежать заполнения очередей, из-за чего канал используется не полностью. Кроме того, возможны конфликты между алгоритмами, когда та или иная реализация будет захватывать пропусную способность, вытесняя другие. Настоящие войны)Вообщем как обычно надо быть осторожее!
Почитать:
- https://blog.apnic.net/2017/05/09/bbr-new-kid-tcp-block/
- https://book.systemsapproach.org/congestion.html
- https://tcpcc.systemsapproach.org/
tags: #network #tcp
Google Cloud Blog
TCP BBR congestion control comes to GCP – your Internet just got faster | Google Cloud Blog
🔥20👍3🤝1
На Hacker News происходит множество обсуждений разной степени интересности и иногда попадаются настоящие самородки, где умные дядьки делятся с общественностью своими знаниями.
Одно из таких - Ask HN: How can I learn about performance optimization?
Народ из разных сфер разработки — обработки видео, геймдева, HFT и классической продуктовой — делится опытом и помогает выработать правильный майндсет: о чем думать и куда смотреть, когда речь заходит о производительности.
Отдельно стоит выделить совет:
Проще некуда, да? 🙂
Интересно, что в книге Systems Performance: Enterprise and the Cloud Брэндан Грегг, формулируя свои "мантры о производительности", начинает именно с этого принципа:
Одно из таких - Ask HN: How can I learn about performance optimization?
Народ из разных сфер разработки — обработки видео, геймдева, HFT и классической продуктовой — делится опытом и помогает выработать правильный майндсет: о чем думать и куда смотреть, когда речь заходит о производительности.
Отдельно стоит выделить совет:
cамый простой способ ускорить работу — делать меньше работы или не делать вовсе
Проще некуда, да? 🙂
Интересно, что в книге Systems Performance: Enterprise and the Cloud Брэндан Грегг, формулируя свои "мантры о производительности", начинает именно с этого принципа:
1. Don’t do it.
2. Do it, but don’t do it again.
3. Do it less.
4. Do it later.
5. Do it when they’re not looking.
6. Do it concurrently.
7. Do it more cheaply
Amazon
Systems Performance: Enterprise and the Cloud (Addison-Wesley Professional Computing Series)
covers concepts, strategy, tools, and tuning for operating systems and applications, using Linux-based operating systems as the primary example. A deep understanding of these tools and techniques is critical for developers today. Implementing the strategies…
👍11🔥7🫡2💯1
photo_2025-01-20_08-36-01.jpg
60.5 KB
Ранее я писал о баге Haproxy: после рестарта треды не завершались, что приводило к их накоплению, память иссякала и приходил OOM Killer.
Проблему решали костылем — директива hard-stop-after принудительно завершает треды после рестарта.
Но Haproxy не сдается и наносит ответный удар!
Симптомы схожи: утечка памяти.
Но сбой наступает когда (это гипотеза) заканчивается память для TCP-буферов (
На скрине такой период отмечен красным прямоугольником.
Где
Оказалось, что система насыщается "повисшими" соединениями, чьи буферы сокетов содержат данные:
где:
*
*
А раз есть не прочитанные данные, значит таймер TCP keepalive не взводится:
Был бы повод, а костыль найдется!
Ребята из CloudFlare писали в свое время статью When TCP sockets refuse to die, где в виде решения предлагалось использовать опцию сокета
В свою очередь Haproxy поддерживает ее через tcp-ut.
Посмотрим, как себя покажет.
tags: #tcp #linux #kernel #troubleshooting #кейс
Проблему решали костылем — директива hard-stop-after принудительно завершает треды после рестарта.
Но Haproxy не сдается и наносит ответный удар!
Причины еще предстоит выяснить, поэтому это скорее "заметка с полей"
Симптомы схожи: утечка памяти.
Но сбой наступает когда (это гипотеза) заканчивается память для TCP-буферов (
net.ipv4.tcp_mem
) - ядро с переменным успехом пытается освободить память для новых / существующих соединений, что приводит к затруднению в сетевых взаимодействиях.На скрине такой период отмечен красным прямоугольником.
# sysctl net.ipv4.tcp_mem
net.ipv4.tcp_mem = 90435 120582 180870
Где
180870
- максимальное значение (в страницах памяти) под все TCP сокеты в системе, что равно ~ 706MB. Оказалось, что система насыщается "повисшими" соединениями, чьи буферы сокетов содержат данные:
# ss -ntOai | awk '{for(i=1;i<=NF;i++)if($i~/^lastsnd:/){split($i,a,":");print a[2], $2, $4, $5}}' | sort -n | tail
#lastsnd # Recv-Q #Src #Dst
234423668 157355 10.11.12.4:57354 10.11.6.123:80
235316436 302417 10.11.12.4:56232 10.11.6.124:80
238200680 301585 10.11.12.4:37940 10.11.6.124:80
238726828 300103 10.11.12.4:58944 10.11.6.124:80
243816724 297015 10.11.12.4:51700 10.11.6.125:80
251456440 302959 10.11.12.4:52324 10.11.6.125:80
252237780 302464 10.11.12.4:47786 10.11.6.123:80
257868244 163453 10.11.12.4:41568 10.11.6.125:80
259905196 300433 10.11.12.4:40202 10.11.6.123:80
261307944 214022 10.11.12.4:54888 10.11.6.123:80 # это ~ 72 часа
где:
*
lastsnd
- время с последней отправки данных, в милисекундах;*
Recv-Q
- объем не прочитанных данных, в байтах.А раз есть не прочитанные данные, значит таймер TCP keepalive не взводится:
static void tcp_keepalive_timer (struct timer_list *t)
{
...
/* It is alive without keepalive 8) */
if (tp->packets_out || !tcp_write_queue_empty(sk))
goto resched;
...
resched:
inet_csk_reset_keepalive_timer (sk, elapsed);
goto out;
...
out:
bh_unlock_sock(sk);
sock_put(sk);
}
Был бы повод, а костыль найдется!
Ребята из CloudFlare писали в свое время статью When TCP sockets refuse to die, где в виде решения предлагалось использовать опцию сокета
TCP_USER_TIMEOUT
:...it specifies the maximum amount of time in milliseconds that transmitted data may remain unacknowledged, or buffered data may remain untransmitted (due to zero window size) before TCP will forcibly close the corresponding connection and return **ETIMEDOUT** to the application...
В свою очередь Haproxy поддерживает ее через tcp-ut.
Посмотрим, как себя покажет.
tags: #tcp #linux #kernel #troubleshooting #кейс
👍21🔥2
Я тут понял, что большинство контента в канале про прикладной уровень. Разбавим немного концептуальным.
———
The long way towards resilience — серия статей (аж 9 частей) про устойчивость как свойство IT-систем.
Автор разбирает понятие resilience: оно объединяет надёжность (учёт предсказуемых и непредсказуемых факторов) и способность системы развиваться под внешним воздействием.
Описываются шаги (или уровни зрелости), через которые может пройти организация, чтобы все таки назвать себя устойчивой:
- Фокус на разработке и запуске бизнес-функционала.
- Внедрение базовой надёжности через избыточность.
- Осознание, что сбои неизбежны — включение стратегий их смягчения.
- Подготовка к неожиданным ситуациям и неизвестным рискам.
- Достижение уровня, когда система не только выдерживает сбои, но и становится сильнее благодаря им.
Вдумчивого чтения на неделю.
———
The long way towards resilience — серия статей (аж 9 частей) про устойчивость как свойство IT-систем.
Автор разбирает понятие resilience: оно объединяет надёжность (учёт предсказуемых и непредсказуемых факторов) и способность системы развиваться под внешним воздействием.
Описываются шаги (или уровни зрелости), через которые может пройти организация, чтобы все таки назвать себя устойчивой:
- Фокус на разработке и запуске бизнес-функционала.
- Внедрение базовой надёжности через избыточность.
- Осознание, что сбои неизбежны — включение стратегий их смягчения.
- Подготовка к неожиданным ситуациям и неизвестным рискам.
- Достижение уровня, когда система не только выдерживает сбои, но и становится сильнее благодаря им.
Вдумчивого чтения на неделю.
Uwe Friedrichsen
The long way towards resilience - Part 1
What is resilience?
👍11🔥2
Гид по #TCP (собрание материалов о TCP из канала)
📦 Алгоритмы контроля перегрузки
- TCP Congestion Control в разных окружениях — как алгоритмы перегрузки работают при потере пакетов. Практические наблюдения.
- BBR vs CUBIC — выбираем подходящий под наше окружение алгоритм.
- Мониторинг TCP: метрики Zero Window — что такое Zero Window, как он сигнализирует о перегрузке получателя, и почему это важно мониторить.
- Как считается TCP Window Clamp — копаемся в исходниках Linux и разбираемся в механизмах TCP Window;
📈 Ретрансмиты
- Мое выступление на Perf Conf №10 — влияние потерь пакетов на производительность приложений.
- TCP Retransmission May Be Misleading — классификация типов ретрансмитов и их мониторинг
- TCP ретрансмиты и их направления — пишем eBPF код для визуализации направления ретрансмитов в Grafana;
🔗 TCP соединения
- Сетевой анализ с eBPF: измеряем Round Trip Time — пишем eBPF код для мониторинга Round Trip Time в Grafana;
- TCP Puzzlers — интерпретируй закрытие соединений правильно.
- A Complete Guide of 'ss' Output Metrics — полный разбор метрик утилиты ss.
📚 Разное
- Зависшие соединения в Haproxy и механизм работы TCP keepalive — читаем код ядра и устраняем проблемы зависших соединений.
- Рассуждения о размерах очередей и какие трейдофы у больших значений;
- Investigation of a Cross-regional Network Performance Issue — траблшутинг медленной сети между дата-центрами после обновления ядра Linux
📦 Алгоритмы контроля перегрузки
- TCP Congestion Control в разных окружениях — как алгоритмы перегрузки работают при потере пакетов. Практические наблюдения.
- BBR vs CUBIC — выбираем подходящий под наше окружение алгоритм.
- Мониторинг TCP: метрики Zero Window — что такое Zero Window, как он сигнализирует о перегрузке получателя, и почему это важно мониторить.
- Как считается TCP Window Clamp — копаемся в исходниках Linux и разбираемся в механизмах TCP Window;
📈 Ретрансмиты
- Мое выступление на Perf Conf №10 — влияние потерь пакетов на производительность приложений.
- TCP Retransmission May Be Misleading — классификация типов ретрансмитов и их мониторинг
- TCP ретрансмиты и их направления — пишем eBPF код для визуализации направления ретрансмитов в Grafana;
🔗 TCP соединения
- Сетевой анализ с eBPF: измеряем Round Trip Time — пишем eBPF код для мониторинга Round Trip Time в Grafana;
- TCP Puzzlers — интерпретируй закрытие соединений правильно.
- A Complete Guide of 'ss' Output Metrics — полный разбор метрик утилиты ss.
📚 Разное
- Зависшие соединения в Haproxy и механизм работы TCP keepalive — читаем код ядра и устраняем проблемы зависших соединений.
- Рассуждения о размерах очередей и какие трейдофы у больших значений;
- Investigation of a Cross-regional Network Performance Issue — траблшутинг медленной сети между дата-центрами после обновления ядра Linux
www.alebedev.tech
TCP Congestion Control in Action
Протестировал работу TCP Congestion Control в Linux в различных по качеству окружениях, поделюсь результатами.
👍21❤🔥1
Performance matters! pinned «Гид по #TCP (собрание материалов о TCP из канала) 📦 Алгоритмы контроля перегрузки - TCP Congestion Control в разных окружениях — как алгоритмы перегрузки работают при потере пакетов. Практические наблюдения. - BBR vs CUBIC — выбираем подходящий под наше…»
Ранее я публиковал заметку Мониторинг TCP: метрики Zero Window, где обсуждал, что такое Zero Window и как его отслеживать в Linux.
А на днях, анализируя сетевые метрики одной машины, обнаружил, что мое представление о счетчиках
Сегодня будем исправляться.
⚙️ Итак, TCP перед отправкой сегмента добавляет заголовок, в котором рассчитывается размер окна.
tcp_select_window(sk) — функция ядра, которая определяет размер окна и отвечает за увеличение счетчиков
Видно, что:
1. Рост
2. Рост
📍 Переформулируем, что это за показатели и для чего они нужны.
●
То есть сетевой стек планирует (Want) объявить Zero Window;
●
То есть мы "идем" в нулевое окно - ToZero.
●
FromZero звучит как "уходим от нулевого окна". Ну или мне так проще запомнить)
_________________________________________________________________
Все таки прав был Мюллер: "Верить в наше время нельзя никому. Исходникам можно."
А на днях, анализируя сетевые метрики одной машины, обнаружил, что мое представление о счетчиках
TCP*ZeroWindowAdv
оказалось неверным.Сегодня будем исправляться.
⚙️ Итак, TCP перед отправкой сегмента добавляет заголовок, в котором рассчитывается размер окна.
Напомню, размер окна определяет, сколько данных можно отправить получателю без подтверждения — так называемые in-flight данные, "в полете" то есть.
tcp_select_window(sk) — функция ядра, которая определяет размер окна и отвечает за увеличение счетчиков
TCP*ZeroWindowAdv
:static u16 tcp_select_window(struct sock *sk)
{
...
u32 old_win = tp->rcv_wnd;
u32 cur_win = tcp_receive_window(tp);
u32 new_win = __tcp_select_window(sk);
if (new_win < cur_win) {
...
if (new_win == 0)
NET_INC_STATS(sock_net(sk),
LINUX_MIB_TCPWANTZEROWINDOWADV);
new_win = ALIGN(cur_win, 1 << tp->rx_opt.rcv_wscale);
}
...
/* If we advertise zero window, disable fast path. */
if (new_win == 0) {
if (old_win)
NET_INC_STATS(sock_net(sk),
LINUX_MIB_TCPTOZEROWINDOWADV);
} else if (old_win == 0) {
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPFROMZEROWINDOWADV);
}
...
}
Видно, что:
1. Рост
TCP*ZeroWindowAdv
зависят только от состояния локального буфера приёма, то есть от того, сколько в нём свободного места.❌Ранее я ошибочно полагал, что TCPToZeroWindowAdv растёт, если мы получаем уведомление о Zero Window от удаленной стороны, но это не так.
2. Рост
TCPWantZeroWindowAdv
возможен без увеличения TCPToZeroWindowAdv
, так как последний требует дополнительной проверки размера окна через выравнивание (ALIGN)📍 Переформулируем, что это за показатели и для чего они нужны.
●
TCPWantZeroWindowAdv
увеличивается, когда локальная сторона не успевает вычитывать данные, и размер окна стремится к нулю. Однако Zero Window не обязательно будет направлен удалённой стороне. То есть сетевой стек планирует (Want) объявить Zero Window;
●
TCPToZeroWindowAdv
увеличивается, если после пересчёта размер окна остаётся нулевым, и тогда флаг добавляется в заголовок, что приводит к приостановке передачи данных. И это скверная ситуация.То есть мы "идем" в нулевое окно - ToZero.
●
TCPFromZeroWindowAdv
увеличивается, если окно ранее было равно нулю (old_win == 0
), но теперь его размер стал больше, что позволяет возобновить передачу данных.FromZero звучит как "уходим от нулевого окна". Ну или мне так проще запомнить)
_________________________________________________________________
Все таки прав был Мюллер: "Верить в наше время нельзя никому. Исходникам можно."
Telegram
Performance matters!
Мониторинг TCP: метрики Zero Window 🚀
Протокол TCP обеспечивает множество функций, включая управление перегрузками.
Для этого используется механизм скользящего окна (sliding window) — объём данных, который отправитель передаёт без подтверждения от получателя.…
Протокол TCP обеспечивает множество функций, включая управление перегрузками.
Для этого используется механизм скользящего окна (sliding window) — объём данных, который отправитель передаёт без подтверждения от получателя.…
🔥9👍3
(Не) очевидные особенности настроек TCP сокетов. Часть 1.
Задача: затюнить размеры сокетов у Nginx, чтобы без потерь переживать всплески трафика.
Уточним размер буфера чтения:
Нас интересует значение
Окей, допустим мы хотим сделать его равным 6291456 байт (~6мб).
В Nginx за размер буфер приема отвечает параметр
Вносим изменения в конфиг и перезапускаем Nginx:
Проверяем:
———
Среднее значение
Документация к
1. ядро будет удваивать переданное значение (что и увидим в`rb`)
2. дефолтное (начальное) равно
3. максимум задается через
Окей, произведем расчеты:
Похоже, что мы уперлись в
Получаем искомое
Промежуточный итог: если мы выставляем руками размеры буферов на уровне приложение (опция
Следующая часть.
tags: #tcp #linux #kernel
Задача: затюнить размеры сокетов у Nginx, чтобы без потерь переживать всплески трафика.
Уточним размер буфера чтения:
# ss -ntlmO | grep ':80 '
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* skmem:(r0,rb131072,t0,tb16384,f0,w0,o0,bl0,d0)
Нас интересует значение
rb
- 131072 байт. Окей, допустим мы хотим сделать его равным 6291456 байт (~6мб).
В Nginx за размер буфер приема отвечает параметр
rcvbuf
, см. док .Вносим изменения в конфиг и перезапускаем Nginx:
# grep listen /etc/nginx/nginx.conf
listen 80 rcvbuf=6291456;
# systemctl restart nginx
Проверяем:
# ss -ntlmO | grep ':80 '
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* skmem:(r0,rb425984,t0,tb16384,f0,w0,o0,bl0,d0)
425984
не похоже на 6291456
;)———
# sysctl -a | grep rmem
net.core.rmem_default = 212992
net.core.rmem_max = 212992
net.ipv4.tcp_rmem = 4096 131072 18874368
...
Среднее значение
tcp_rmem
соответствует размеру буфера до изменений, а новое (425984
) не совпадает ни с чем.Документация к
rcvbuf
говорит, что настройка соответствует опции сокета SO_RCVBUF
:# man 7 socket
SO_RCVBUF
Sets or gets the maximum socket receive buffer in bytes. The kernel doubles this value (to allow space for bookkeeping overhead) when it is set using setsockopt(2), and this doubled value is returned by getsockopt(2). The default value is set by the /proc/sys/net/core/rmem_default file, and the maximum allowed value is set by the /proc/sys/net/core/rmem_max file...
1. ядро будет удваивать переданное значение (что и увидим в`rb`)
2. дефолтное (начальное) равно
rmem_default
;3. максимум задается через
rmem_max
.Причины удвоения (хотя там могут быть разные варианты) стоит искать в "man 7 tcp" и в "net.ipv4.tcp_adv_win_scale". Или в подробной статье от CloudFlare.
Окей, произведем расчеты:
425984 / 2 = 212992
.Похоже, что мы уперлись в
net.core.rmem_max
:# sysctl net.core.rmem_max=6291456
net.core.rmem_max = 6291456
# nginx -s reload
# ss -ntlmO | grep '0.0.0.0:80 '
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* skmem:(r0,rb12582912,t0,tb16384,f0,w0,o0,bl0,d0)
Получаем искомое
rb
в 12582912
(6mb * 2). Промежуточный итог: если мы выставляем руками размеры буферов на уровне приложение (опция
SO_RCVBUF
), следует учесть это и в net.core.rmem_max
.Следующая часть.
tags: #tcp #linux #kernel
The Cloudflare Blog
Optimizing TCP for high WAN throughput while preserving low latency
Tuning TCP servers for both low latency and high WAN throughput usually involves making tradeoffs. Due to the breadth of products and variety of traffic patterns at Cloudflare, we need both. In this post, we describe how we modified the Linux kernel to optimize…
🔥15
(Не) очевидные особенности настроек TCP сокетов. Часть 2.
Начало тут.
Есть мнение, что механизмы autotuning TCP в Linux не просто так придумали и в норме стоит пользоваться именно ими, а хардкод стоит избегать.
Потому разберемся с настройкой
Перефразирую:
- дефолтное значение
- максимальное значение
Делаем промежуточные вывод, что:
1.
2.
Проверим!
Начнем с конца:
Действительно, максимальный
Теперь проверим, что
Размер буфера выставляется равным дефолтному
——
Особо пытливым для перепроверки можно обратиться к исходникам:
2. либо в определении начального TCP окна:
что все таки не бьется с документацией.
Выходит обманывают нас разработчики или я так интерпретирую тексты :)
Окончательные выводы:
1.
2.
В итоге решение задачи может быть следующим:
tags: #tcp #linux #kernel
Начало тут.
Есть мнение, что механизмы autotuning TCP в Linux не просто так придумали и в норме стоит пользоваться именно ими, а хардкод стоит избегать.
Потому разберемся с настройкой
net.ipv4.tcp_rmem
и узнаем оказывает ли на него влияние net.core.rmem_max
:# man 7 tcp
...
tcp_rmem (since Linux 2.4)
This is a vector of 3 integers: [min, default, max]. These parameters are used by TCP to regulate receive buffer sizes. ...
min minimum size of the receive buffer used by each TCP socket. The default value is the system page size. (On Linux 2.4, the default value is 4 kB, lowered to PAGE_SIZE bytes in low-memory systems.)...
default the default size of the receive buffer for a TCP socket. This value overwrites the initial default buffer size from the generic global net.core.rmem_default defined for all protocols...
max the maximum size of the receive buffer used by each TCP socket. This value does not override the global net.core.rmem_max. This is not used to limit the size of the receive buffer declared using SO_RCVBUF on a socket...
Перефразирую:
- дефолтное значение
tcp_rmem
перезаписывает net.core.rmem_default
— это мы заметили в самом начале, до использования rcvbuf
;- максимальное значение
tcp_rmem
НЕ перезаписывает net.core.rmem_max
и НЕ используется при выставлении SO_RCVBUF
.Делаем промежуточные вывод, что:
1.
net.core.rmem_max
задает жесткий лимит на размер TCP буфера;2.
tcp_rmem
не участвует в игре при выставлении SO_RCVBUF
.Проверим!
Начнем с конца:
# sysctl -a | grep rmem
net.core.rmem_default = 212992
net.core.rmem_max = 6291456
net.ipv4.tcp_rmem = 4096 131072 18874368
### Выставляем максимальное значение tcp_rmem ниже rmem_max
# sysctl net.ipv4.tcp_rmem="4096 131072 851968"
net.ipv4.tcp_rmem = 4096 131072 851968
# grep listen /etc/nginx/nginx.conf
listen 80 rcvbuf=6291456;
# systemctl restart nginx
# ss -ntlmO | grep '0.0.0.0:80 '
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* skmem:(r0,rb12582912,t0,tb16384,f0,w0,o0,bl0,d0)
Действительно, максимальный
tcp_rmem
не сыграл.Теперь проверим, что
net.core.rmem_max
задает жесткий лимит над размером TCP сокетов:# sysctl -a | grep rmem
net.core.rmem_default = 212992
net.core.rmem_max = 6291456
net.ipv4.tcp_rmem = 4096 131072 851968
### Делаем net.core.rmem_max ниже чем дефолтный tcp_rmem, значение которого поднимем
# sysctl net.core.rmem_max=212992
net.core.rmem_max = 212992
# sysctl net.ipv4.tcp_rmem="4096 524288 851968"
net.ipv4.tcp_rmem = 4096 524288 851968
### Убираем директиву rcvbuf
# grep listen /etc/nginx/nginx.conf
listen 80;
# systemctl restart nginx
# ss -ntlmO | grep '0.0.0.0:80 '
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* skmem:(r0,rb524288,t0,tb16384,f0,w0,o0,bl0,d0)
Размер буфера выставляется равным дефолтному
tcp_rmem
(кстати без удвоений), который больше net.core.rmem_max
. ——
Особо пытливым для перепроверки можно обратиться к исходникам:
1. net.core.rmem_max
участвует либо в обработке опции SO_RCVBUF:...
case SO_RCVBUF:
...
__sock_set_rcvbuf(sk, min_t(u32, val, READ_ONCE(sysctl_rmem_max)));
2. либо в определении начального TCP окна:
...
space = max_t(u32, space, READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_rmem[2]));
space = max_t(u32, space, READ_ONCE(sysctl_rmem_max));
space = min_t(u32, space, *window_clamp);
*rcv_wscale = clamp_t(int, ilog2(space) - 15,
0, TCP_MAX_WSCALE);
что все таки не бьется с документацией.
Выходит обманывают нас разработчики или я так интерпретирую тексты :)
Окончательные выводы:
1.
net.core.rmem_max
играет только при ручном выставлении размеров сокетов (SO_RCVBUF
);2.
net.ipv4.tcp_rmem
напротив, не участвует в SO_RCVBUF
, зато позволяет использовать автоподстройку, что в большинстве случаев будет более гибким решением.В итоге решение задачи может быть следующим:
# sysctl net.ipv4.tcp_rmem="4096 1048576 12582912"
tags: #tcp #linux #kernel
Telegram
Performance matters!
(Не) очевидные особенности настроек TCP сокетов. Часть 1.
Задача: затюнить размеры сокетов у Nginx, чтобы без потерь переживать всплески трафика.
Уточним размер буфера чтения:
# ss -ntlmO | grep ':80 '
LISTEN 0 511 0.0.0.0:80 0.0.0.0:*…
Задача: затюнить размеры сокетов у Nginx, чтобы без потерь переживать всплески трафика.
Уточним размер буфера чтения:
# ss -ntlmO | grep ':80 '
LISTEN 0 511 0.0.0.0:80 0.0.0.0:*…
👍23
В главе When to Stop Analysis книги Systems Performance обсуждается, как определить момент, когда дальнейший анализ проблемы становится неэффективным из-за низкого соотношения затрат к выгоде (ROI).
Аппетит приходит во время игры, ага:)
Автор предлагает три критерия, когда стоит остановиться:
1. Если найденное решение покрывает основную часть проблемы (66+ % от деградации);
2. Если затраты на анализ превышают потенциальную выгоду (отрицательный ROI);
3. Если есть другие задачи с более высоким ROI.
На мой взгляд, удобнее смотреть на схему по другому — перевернуть с ног на голову и сверяться с ней на каждом шаге:
1. Выбираем наиболее приоритетную проблему — хорошо когда можем сделать количественную оценку (деньги, время);
2. Погружаемся в суть и ищем решение, которое закроет хотя бы 66% проблемы;
3. GOTO 1 — проводим переоценку: точно ли оставшиеся 34 % всё ещё важнее других задач?
Звучит просто, но сколько раз я залипал на часы, разбирая то, что к делу почти не относится — подсчёту не поддаётся:)
P.S. есть мнение, что подход будет работать далеко за пределами траблшутинга и IT.
Автор предлагает три критерия, когда стоит остановиться:
1. Если найденное решение покрывает основную часть проблемы (66+ % от деградации);
2. Если затраты на анализ превышают потенциальную выгоду (отрицательный ROI);
3. Если есть другие задачи с более высоким ROI.
На мой взгляд, удобнее смотреть на схему по другому — перевернуть с ног на голову и сверяться с ней на каждом шаге:
1. Выбираем наиболее приоритетную проблему — хорошо когда можем сделать количественную оценку (деньги, время);
2. Погружаемся в суть и ищем решение, которое закроет хотя бы 66% проблемы;
3. GOTO 1 — проводим переоценку: точно ли оставшиеся 34 % всё ещё важнее других задач?
Звучит просто, но сколько раз я залипал на часы, разбирая то, что к делу почти не относится — подсчёту не поддаётся:)
P.S. есть мнение, что подход будет работать далеко за пределами траблшутинга и IT.
Brendangregg
Systems Performance: Enterprise and the Cloud, 2nd Edition
Systems Performance: Enterprise and the Cloud, 2nd Edition (2020)
👍21
В нашей инфраструктуре мы давно используем PSI (Pressure Stall Information) для выявления перенасыщения (saturation) ресурсов: CPU, диск, память.
Есть мнение, что saturation — ключевой показатель, по которому легко понять состояние системы. Вокруг него построена методология USE Method.
PSI призван заменить Load Average, который не позволяет быстро и точно определять состояние системы.
Изначально PSI собирал данные per host — полезно, но шумно в контейнерных средах с множеством cgroup.
В Cgroup v2 появилась поддержка PSI для отдельных cgroup, а скоро cadvisor добавит сбор PSI по каждому контейнеру — вот тогда заживем!
P.S. Если будет запрос, могу в будущих заметках углубиться в детали. Дайте знать! 😊
tags: #cpu #k8s #metrics
Есть мнение, что saturation — ключевой показатель, по которому легко понять состояние системы. Вокруг него построена методология USE Method.
PSI призван заменить Load Average, который не позволяет быстро и точно определять состояние системы.
Изначально PSI собирал данные per host — полезно, но шумно в контейнерных средах с множеством cgroup.
В Cgroup v2 появилась поддержка PSI для отдельных cgroup, а скоро cadvisor добавит сбор PSI по каждому контейнеру — вот тогда заживем!
P.S. Если будет запрос, могу в будущих заметках углубиться в детали. Дайте знать! 😊
tags: #cpu #k8s #metrics
Brendangregg
The USE Method
👍59
Разовью тезис об ограниченности LA из предыдущего поста:
Load Average (средняя нагрузка) — обобщённая метрика, включающая в себя показатели совершенно разных подсистем (CPU и I/O). Это значит, что она не годится на роль интерпретатора проблем: «посмотрел и понял, где проблема».
Вторая особенность LA.
Метрика складывается (упрощённо) из суммы задач в (R)unnable и (D) состояниях.
Кейс 1
LA подскочил, видим большую нагрузку на CPU → скорее всего, у нас много задач, претендующих на процессор (Runnable state).
Система деградирует. Всё просто.
Кейс 2
LA подскочил, процессор не загружен → скорее всего, много заблокированных задач, ожидающих I/O-подсистему (D state).
Деградирует ли система? Возможно, да. Возможно, нет...
———
Конкретное значение LA мало о чём скажет. Вот 5 — это много или мало? А 55?
То есть всегда требуются дополнительные показатели, с которыми будем соотносить LA, например количество ядер на машине (что, судя по формуле выше, неверно).
Кейс 3
10 ядер на машине, LA = 5.00.
Что можем сказать? Ничего конкретного 🙂
В равной степени это могут быть:
- 0 заблокированных задач, 5 в Runnable (выглядит ок);
- 5 заблокированных, 0 в Runnable (выглядит не очень);
- 2 заблокированных, 3 в Runnable (это ок или не ок?).
И так далее.
———
Вывод: зачем использовать метрику, интерпретация которой требует стольких действий, чтобы хотя бы примерно очертить проблемное место?
PSI призван заменить Load Average, который не позволяет быстро и точно определять состояние системы.
Load Average (средняя нагрузка) — обобщённая метрика, включающая в себя показатели совершенно разных подсистем (CPU и I/O). Это значит, что она не годится на роль интерпретатора проблем: «посмотрел и понял, где проблема».
Вторая особенность LA.
Метрика складывается (упрощённо) из суммы задач в (R)unnable и (D) состояниях.
Кейс 1
LA подскочил, видим большую нагрузку на CPU → скорее всего, у нас много задач, претендующих на процессор (Runnable state).
Система деградирует. Всё просто.
Кейс 2
LA подскочил, процессор не загружен → скорее всего, много заблокированных задач, ожидающих I/O-подсистему (D state).
Деградирует ли система? Возможно, да. Возможно, нет...
———
Конкретное значение LA мало о чём скажет. Вот 5 — это много или мало? А 55?
То есть всегда требуются дополнительные показатели, с которыми будем соотносить LA, например количество ядер на машине (что, судя по формуле выше, неверно).
Кейс 3
10 ядер на машине, LA = 5.00.
Что можем сказать? Ничего конкретного 🙂
В равной степени это могут быть:
- 0 заблокированных задач, 5 в Runnable (выглядит ок);
- 5 заблокированных, 0 в Runnable (выглядит не очень);
- 2 заблокированных, 3 в Runnable (это ок или не ок?).
И так далее.
———
Вывод: зачем использовать метрику, интерпретация которой требует стольких действий, чтобы хотя бы примерно очертить проблемное место?
Telegram
Performance matters!
В нашей инфраструктуре мы давно используем PSI (Pressure Stall Information) для выявления перенасыщения (saturation) ресурсов: CPU, диск, память.
Есть мнение, что saturation — ключевой показатель, по которому легко понять состояние системы. Вокруг него построена…
Есть мнение, что saturation — ключевой показатель, по которому легко понять состояние системы. Вокруг него построена…
👍19
Про PSI, часть 3.
(часть 1, 2)
PSI (Pressure Stall Information) – это метрика показывает сколько времени задачи ждут доступа к ресурсам системы (CPU, память, диск). То есть отражает уровень насыщения (saturation): если значение больше нуля => есть конкуренция за ресурсы.
PSI делится на два типа:
- Some – одна и более задач ждут ресурс (это плохо, но может быть не критично)
- Full – все задачи находятся в ожидании ресурса (а это уже коллапс)
Примечание №1. Сегодня речь только про CPU.
Примеры:
- 2 CPU, 1 runnable задача → конкуренции за CPU нет, PSI = 0
- 2 CPU, 2 runnable задачи → конкуренции всё ещё нет, PSI = 0
- 2 CPU, 4 runnable задачи → две задачи исполняются, две ждут, PSI > 0 (две из четырех задач всегда ожидают своей очереди).
Примечание №2: под
Формула подсчета PSI (упрощенная):
где:
- runnable_tasks – общее число задач, готовых к выполнению;
- num_cpus – количество доступных CPU;
- delayed_tasks – задачи, ожидающие ресурсы;
- active_tasks – задачи, выполняемые в данный момент.
Примеры:
- для 2 CPU и 1 runnable задачи:
- для 2 CPU и 4 runnable задачи:
Это значит, что какие-то задачи всегда ожидают CPU (
Так чем полезен PSI?
Он даёт 100% чистый сигнал: если PSI > 0, значит, есть ожидание процессора, значит система замедляется.
Есть и недостаток - PSI не показывает тренды и реагирует лишь постфактум, когда проблема УЖЕ появилась.
Теперь вернемся к Load Average и представим сколько дополнительной информации нам потребуется, чтобы выявить перенасыщение CPU.
Ну как минимум количество runnable процессов и CPU на машине. Три показателя!
При этом рост LA может быть связан не только с CPU, но и с I/O, что усложняет интерпретацию и требует дополнительного времени на анализ.
А так хочется один простой показатель, по которому сразу понятно, есть проблема илиеще нет :)
——————-
❓На засыпку: почему на уровне системы может быть только PSI some? Бывают ли случаи когда появляется PSI full?
P.S. Скрин "на поразглядывать"
(часть 1, 2)
PSI (Pressure Stall Information) – это метрика показывает сколько времени задачи ждут доступа к ресурсам системы (CPU, память, диск). То есть отражает уровень насыщения (saturation): если значение больше нуля => есть конкуренция за ресурсы.
PSI делится на два типа:
- Some – одна и более задач ждут ресурс (это плохо, но может быть не критично)
- Full – все задачи находятся в ожидании ресурса (а это уже коллапс)
Примечание №1. Сегодня речь только про CPU.
Примеры:
- 2 CPU, 1 runnable задача → конкуренции за CPU нет, PSI = 0
- 2 CPU, 2 runnable задачи → конкуренции всё ещё нет, PSI = 0
- 2 CPU, 4 runnable задачи → две задачи исполняются, две ждут, PSI > 0 (две из четырех задач всегда ожидают своей очереди).
Примечание №2: под
runnable
я подразумеваю как исполняемые в данный момент, так и готовые к исполнению задачи.Формула подсчета PSI (упрощенная):
threads = min(runnable_tasks, num_cpus)
SOME = min(delayed_tasks / threads, 1)
FULL = (threads - min(active_tasks, threads)) / threads
где:
- runnable_tasks – общее число задач, готовых к выполнению;
- num_cpus – количество доступных CPU;
- delayed_tasks – задачи, ожидающие ресурсы;
- active_tasks – задачи, выполняемые в данный момент.
Примеры:
- для 2 CPU и 1 runnable задачи:
threads = min(1, 2) = 1
SOME = min(0 / 1, 1) = 0
FULL = (1 - min(1, 1)) / 1 = 0
- для 2 CPU и 4 runnable задачи:
threads = min(4, 2) = 2
SOME = min((4 - 2) / 2, 1) = min(2 / 2, 1) = 1 # или 100%
FULL = (2 - min(2, 2)) / 2 = 0 # или 0%
Это значит, что какие-то задачи всегда ожидают CPU (
some
), но в целом что-то да исполняется на процессоре.Так чем полезен PSI?
Он даёт 100% чистый сигнал: если PSI > 0, значит, есть ожидание процессора, значит система замедляется.
Есть и недостаток - PSI не показывает тренды и реагирует лишь постфактум, когда проблема УЖЕ появилась.
Теперь вернемся к Load Average и представим сколько дополнительной информации нам потребуется, чтобы выявить перенасыщение CPU.
Ну как минимум количество runnable процессов и CPU на машине. Три показателя!
При этом рост LA может быть связан не только с CPU, но и с I/O, что усложняет интерпретацию и требует дополнительного времени на анализ.
А так хочется один простой показатель, по которому сразу понятно, есть проблема или
——————-
❓На засыпку: почему на уровне системы может быть только PSI some? Бывают ли случаи когда появляется PSI full?
P.S. Скрин "на поразглядывать"
👍12❤1
Готовлюсь к внутреннему митапу с докладом о потерях сетевого трафика: как их диагностировать и устранять.
В основе GIF-анимация, иллюстрирующая путь и остановки входящего сетевого пакета в ядре Linux.
Очереди в ядре Linux
* RX queue. Первая остановка: очередь сетевой карты (см.
* QDisc. Приоритизация, модификация и многое другое возможны с помощью дисциплины очередей. Calico, Cilium и подобные ребята перехватывает пакеты именно здесь (eBPF)
* Input Packet Queue. Очередь перед стеком протоколов.
📍Для новых соединений
* SYN queue. Очередь, где SYN-сегменты дожидаются ACK;
* Accept queue. Приложение через
📍Для уже установленных соединений
* Out Of Order queue. При нарушении очередности (sequence number больше ожидаемого), пакет помещается в нее, до восстановления правильного порядка;
* Recv queue. TCP-буфер сокета, из него приложение читает данные системным вызовом
———
Подробнее я описывал весь процесс в двух частях: один, два.
P.S. Кстати, поддержать канал теперь можно на Бусти или просто донатом!
#network #tcp #kernel
В основе GIF-анимация, иллюстрирующая путь и остановки входящего сетевого пакета в ядре Linux.
Очереди в ядре Linux
* RX queue. Первая остановка: очередь сетевой карты (см.
ethtool -l eth0
)* QDisc. Приоритизация, модификация и многое другое возможны с помощью дисциплины очередей. Calico, Cilium и подобные ребята перехватывает пакеты именно здесь (eBPF)
* Input Packet Queue. Очередь перед стеком протоколов.
📍Для новых соединений
* SYN queue. Очередь, где SYN-сегменты дожидаются ACK;
* Accept queue. Приложение через
accept()
подтверждает, что соединение установлено - зеленый свет для обмена данными.📍Для уже установленных соединений
* Out Of Order queue. При нарушении очередности (sequence number больше ожидаемого), пакет помещается в нее, до восстановления правильного порядка;
* Recv queue. TCP-буфер сокета, из него приложение читает данные системным вызовом
read()
.———
Подробнее я описывал весь процесс в двух частях: один, два.
P.S. Кстати, поддержать канал теперь можно на Бусти или просто донатом!
#network #tcp #kernel
🔥18👍9
На днях node-exporter зарелизил версию 1.9.0, где среди изменений мне бросилось в глаза:
В обсуждении к MR был комментарий от @SuperQ:
Что за рекомендации такие и кого они аффектят?
—————
Для начала чуть теории 📖
Обработчики прерываний бывает двух типов: аппаратные (Hard IRQ) и программные (SoftIRQ).
Hard IRQ вызываются устройствами (диск, клавиатура, сеть и т. д.) и немедленно обрабатываются процессором. Они могут прервать любой код, поэтому их обработку делают минимальной, чтобы быстрее освободить CPU для других задач.
SoftIRQ обрабатывает прерывания асинхронно в контексте ядра, не блокируя CPU. Поэтому ему отдают наиболее длительные этапы обработки.
В CPU Usage нагрузка от Hard IRQ отображается в
—————
Теперь вернемся к изначальному вопросу.
Оказывается
В redhat-like дистрибутивах эта опция включена, тогда как в debian и им подобным её по умолчанию отключают!
А дальше самое интересное.
Если
1. если прерывание произошло в user mode, то время его обработки будет учтено как
2. если прерывание произошло во время выполнения процесса в system mode, его обработка будет засчитана в
3. если прерывание произошло во время выполнения фоновых задач ядра (kworker, ksoftirqd), то его обработка будет засчитана в
В итоге точность анализа загрузки CPU снижается, что может вводить в заблуждение. Говорят, что погрешность может достигать 5–7%! А это хорошо бы проверить😉
Судя по документации ядра, опцию отключают из-за её небольшого влияния на производительность:
И это проверим:)
P.S. Подробнее, с примерами про подсчет irq читай в блоге Танел Подера.
#cpu #kernel
- [FEATURE] pressure: add IRQ PSI metrics [#3048]
В обсуждении к MR был комментарий от @SuperQ:
Nice, it's too bad `CONFIG_IRQ_TIME_ACCOUNTING` is recommend to be off so very few people will benefit from this by default.
Что за рекомендации такие и кого они аффектят?
—————
Для начала чуть теории 📖
Обработчики прерываний бывает двух типов: аппаратные (Hard IRQ) и программные (SoftIRQ).
Hard IRQ вызываются устройствами (диск, клавиатура, сеть и т. д.) и немедленно обрабатываются процессором. Они могут прервать любой код, поэтому их обработку делают минимальной, чтобы быстрее освободить CPU для других задач.
SoftIRQ обрабатывает прерывания асинхронно в контексте ядра, не блокируя CPU. Поэтому ему отдают наиболее длительные этапы обработки.
В CPU Usage нагрузка от Hard IRQ отображается в
%irq
, а от SoftIRQ в %softirq
.—————
Теперь вернемся к изначальному вопросу.
Оказывается
%irq
отображается только при включённой опции CONFIG_IRQ_TIME_ACCOUNTING
, иначе он всегда равен нулю. В redhat-like дистрибутивах эта опция включена, тогда как в debian и им подобным её по умолчанию отключают!
# mpstat 1
Linux 5.10.0-20-amd64 02/18/2025 _x86_64_ (8 CPU)
11:28:51 PM CPU %usr %nice %sys %iowait %irq %soft %steal %idle
11:28:52 PM all 40.15 0.00 1.38 0.00 0.00 0.63 0.00 57.84
11:28:53 PM all 28.81 0.00 1.78 0.25 0.00 0.51 0.13 68.53
11:28:54 PM all 35.29 0.00 2.25 0.00 0.00 0.25 0.00 62.20
11:28:55 PM all 17.68 0.00 1.14 0.00 0.00 0.38 0.25 80.56
11:28:56 PM all 16.31 0.00 1.99 0.00 0.00 0.25 0.25 81.20
# mpstat -I ALL 1
11:32:53 PM CPU intr/s
11:32:54 PM all 18466.00
11:32:55 PM all 11983.00
11:32:56 PM all 14019.00
%irq
нулевой, хотя кол-во прерываний десятки тысяч.А дальше самое интересное.
Если
CONFIG_IRQ_TIME_ACCOUNTING
отключена, нагрузка от Hard IRQ никуда не исчезнет (кэп🙂), а учитывается как:1. если прерывание произошло в user mode, то время его обработки будет учтено как
%user
того процесса, который выполнялся до прерывания.2. если прерывание произошло во время выполнения процесса в system mode, его обработка будет засчитана в
%sys
этого процесса.3. если прерывание произошло во время выполнения фоновых задач ядра (kworker, ksoftirqd), то его обработка будет засчитана в
%sys
системыВ итоге точность анализа загрузки CPU снижается, что может вводить в заблуждение. Говорят, что погрешность может достигать 5–7%! А это хорошо бы проверить😉
Судя по документации ядра, опцию отключают из-за её небольшого влияния на производительность:
Select this option to enable fine granularity task irq time
accounting. This is done by reading a timestamp on each
transitions between softirq and hardirq state, so there can be a
small performance impact.
If in doubt, say N here.
И это проверим:)
P.S. Подробнее, с примерами про подсчет irq читай в блоге Танел Подера.
#cpu #kernel
GitHub
Release 1.9.0 / 2025-02-17 · prometheus/node_exporter
[CHANGE] meminfo: Convert linux implementation to use procfs lib #3049
[CHANGE] Update logging to use Go log/slog #3097
[FEATURE] filesystem: Add node_filesystem_mount_info metric #2970
[FEATURE] b...
[CHANGE] Update logging to use Go log/slog #3097
[FEATURE] filesystem: Add node_filesystem_mount_info metric #2970
[FEATURE] b...
👍16🔥12
Из серии "Смотрите что нашел!"
Low latency tuning guide - сборник техник по оптимизации системы для минимизации задержек.
Внутри как привычные подходы вроде изоляции ядер и отключения гиперпоточности, так и совсем для меня новые:
- сокращение прерываний таймера планировщика через
- закрепление страниц в RAM с помощью
Особую ценность добавляет обилие ссылок для более глубокого погружения в предмет.
Упражнение: задавать себе вопросы из разряда: "Для low latency советуют SCHED_RR и SCHED_FIFO, а что если важнее пропускная способность? Как бы я изменил подход? Почему?"
#kernel #tuning #low_latency
Low latency tuning guide - сборник техник по оптимизации системы для минимизации задержек.
Внутри как привычные подходы вроде изоляции ядер и отключения гиперпоточности, так и совсем для меня новые:
- сокращение прерываний таймера планировщика через
nohz_full
, что будет снижать накладные расходы на context swithing.- закрепление страниц в RAM с помощью
mlockall(MCL_CURRENT | MCL_FUTURE)
, чтобы избежать их выгрузки на диск.Особую ценность добавляет обилие ссылок для более глубокого погружения в предмет.
Упражнение: задавать себе вопросы из разряда: "Для low latency советуют SCHED_RR и SCHED_FIFO, а что если важнее пропускная способность? Как бы я изменил подход? Почему?"
#kernel #tuning #low_latency
rigtorp.se
Low latency tuning guide
This guide describes how to tune your AMD64/x86_64 hardware and Linux system for running real-time or low latency workloads.
🔥22👍8👎1
Не знаю как и зачем пишутся статьи на 40 минут чтения, но факт есть:
The case of the vanishing CPU: A Linux kernel debugging story
Ещё не погружался, но все ключевые слова на месте: CPU throttling, ebpf, perf, kernel bug.
Будем разбирать.
The case of the vanishing CPU: A Linux kernel debugging story
Ещё не погружался, но все ключевые слова на месте: CPU throttling, ebpf, perf, kernel bug.
Будем разбирать.
ClickHouse
The case of the vanishing CPU: A Linux kernel debugging story
Read about how a Linux kernel memory bug led to instability in ClickHouse Cloud on GCP, and the challenges of diagnosing and resolving it.
👍16👎1