3 необычных кейса о сетевой подсистеме Linux
В этой статье представлены три небольшие истории, которые произошли в нашей практике: в разное время и в разных проектах. Объединяет их то, что они связаны с сетевой подсистемой Linux (Reverse Path Filter, TIME_WAIT, multicast) и иллюстрируют, как глубоко зачастую приходится анализировать инцидент, с которым сталкиваешься впервые, чтобы решить возникшую проблему… и, конечно, какую радость можно испытать в результате полученного решения.
История первая: о Reverse Path Filter
Клиент с большой корпоративной сетью решил пропускать часть своего интернет-трафика через единый корпоративный файрвол, расположенный за маршрутизатором центрального подразделения. С помощью iproute2 трафик, уходящий в интернет, был направлен в центральное подразделение, где уже было настроено несколько таблиц маршрутизации. Добавив дополнительную таблицу маршрутизации и настроив в ней маршруты перенаправления на файрвол, мы включили перенаправление трафика из других филиалов и… трафик не пошел.
Схема прохождения трафика через таблицы и цепочки Netfilter
Начали выяснять, почему не работает настроенная маршрутизация. На входящем туннельном интерфейсе маршрутизатора трафик обнаруживался:
Однако на исходящем интерфейсе пакетов не было. Стало ясно, что фильтруются они на маршрутизаторе, однако явно установленных правил отбрасывания пакетов в iptables не было. Поэтому мы начали последовательно, по мере прохождения трафика, устанавливать правила, отбрасывающие наши пакеты и после установки смотреть счетчики:
Проверили последовательно nat PREROUTING, mangle PREROUTING. В mangle FORWARD счетчик не увеличивался, а значит — пакеты теряются на этапе маршрутизации. Проверив снова маршруты и правила, начали изучать, что именно происходит на этом этапе.
В ядре Linux для каждого интерфейса по умолчанию включен параметр Reverse Path Filtering ( rp_filter ). В случае, когда вы используете сложную, асимметричную маршрутизацию и пакет с ответом будет возвращаться в источник не тем маршрутом, которым пришел пакет-запрос, Linux будет отфильтровывать такой трафик. Для решения этой задачи необходимо отключить Reverse Path Filtering для всех ваших сетевых устройств, принимающих участие в маршрутизации. Чуть ниже простой и быстрый способ сделать это для всех имеющихся у вас сетевых устройств:
Возвращаясь к кейсу, мы решили проблему, отключив Reverse Path Filter для интерфейса tap0 и теперь хорошим тоном на маршрутизаторах считаем отключение rp_filter для всех устройств, принимающих участие в асимметричном роутинге.
История вторая: о TIME_WAIT
В обслуживаемом нами высоконагруженном веб-проекте возникла необычная проблема: от 1 до 3 процентов пользователей не могли получить доступ к сайту. При изучении проблемы мы выяснили, что недоступность никак не коррелировала с загрузкой любых системных ресурсов (диск, память, сеть и т.д.), не зависела от местоположения пользователя или его оператора связи. Единственное, что объединяло всех пользователей, которые испытывали проблемы, — они выходили в интернет через NAT.
Механизм закрытия TCP-соединения
И выполните команду:
История третья: об OSPF и мультикастовом трафике
Обслуживаемая корпоративная сеть была построена на базе tinc VPN и прилегающими к ней лучами IPSec и OVPN-соединений. Для маршрутизации всего этого адресного пространства L3 мы использовали OSPF. На одном из узлов, куда агрегировалось большое количество каналов, мы обнаружили, что небольшая часть сетей, несмотря на верную конфигурацию OSPF, периодически пропадает из таблицы маршрутов на этом узле.
Упрощенное устройство VPN-сети, используемой в описываемом проекте
В первую очередь проверили связь с маршрутизаторами проблемных сетей. Связь была стабильной:
Продиагностировав OSPF, мы удивились еще больше. На узле, где наблюдались проблемы, маршрутизаторы проблемных сетей отсутствовали в списке соседей. На другой стороне проблемный маршрутизатор в списке соседей присутствовал:
Следующим этапом исключили возможные проблемы с доставкой ospf hello от 172.24.0.1. Запросы от него приходили, а вот ответы — не уходили:
Заключение
Какой бы сложной ни была проблема, она всегда решаема и зачастую — с помощью изучения документации. Буду рад увидеть в комментариях описание вашего опыта поиска решения сложных и необычных проблем.
Настройка сетевого стека Linux для высоконагруженных систем
Максимизируем количество входящих соединений
Приглашаем всех желающих посетить открытый демо-урок «Практикум по написанию Ansible роли». На этом вебинаре участники вместе с экспертом будут писать, тестировать и отлаживать ansible роли. Это важно для тех, кто хочет автоматизировать настройку инфраструктуры, поскольку это один из инструментов, который это позволяет сделать. Сетевой стек — одна из самых запутанных вещей в Linux. И не только из-за сложности некоторых концепций и терминов, но и из-за изменения смысла некоторых параметров в разных версиях ядра. В этой статье приведена информация для ядра 2.2 и выше, а также, там где это возможно, указано различие между версиями вплоть до 5.5.
Очередь приема и netdev_max_backlog
net.core.netdev_max_backlog — параметр задается на ядро процессора.
Очередь ожидающих запросов на соединение и tcp_max_syn_backlog
Если в состоянии «SYN_RECV» находятся много соединений, то можно также подстроить продолжительность нахождения SYN-пакета в этой очереди.
SYN Cookie
Если SYN cookie отключены, то клиент просто повторяет отправку SYN-пакета. Если включены (net.ipv4.tcp_syncookies), то соединение не создается и не помещается в SYN backlog, но клиенту отправляется SYN+ACK так, как если бы это было сделано на самом деле. SYN cookie могут быть полезны при нормальной нагрузке, но при всплесках трафика некоторая информация о соединении может быть потеряна и клиент столкнется с проблемами, когда соединение будет установлено. Подробнее о SYN cookie можно прочитать в статье Грэма Коула (Graeme Cole) SYN cookies ate my dog (SYN cookie съели мою собаку), в которой подробно объясняется, почему включение SYN cookie на высоконагруженных серверах может привести к проблемам.
Повторы SYN+ACK
Что происходит, если SYN+ACK отправлен, но ответа ACK нет? В этом случае сетевой стек сервера повторит отправку SYN+ACK. Задержка между попытками вычисляется таким образом, чтобы обеспечить восстановление сервера. Если сервер получает SYN и отправляет SYN+ACK, но не получает ACK, то тайм-аут повторной передачи вычисляется по экспоненте (Exponental Backoff) и, следовательно, зависит от количества повторных попыток. Количество повторных попыток отправки SYN+ACK задается параметром ядра net.ipv4.tcp_synack_retries (по умолчанию равно 5). Повторные попытки будут через следующие интервалы: 1с, 3с, 7с, 15с, 31с. При шести попытках последняя будет примерно через 63 секунды после первой. Это позволяет удержать SYN-пакет в очереди ожидания более 60 секунд до истечения времени ожидания пакета. Если очередь SYN backlog мала, то не требуется большого количества соединений, чтобы возникла ситуация, когда полуоткрытые соединения никогда не завершатся и тогда никакие соединения не смогут быть установлены. Установите количество повторных попыток SYN+ACK равным 0 или 1, чтобы избежать такого поведения на высоконагруженных серверах.
Повторы SYN
Несмотря на то что повторные SYN-пакеты отправляются клиентом во время ожидания SYN+ACK, они могут влиять и на высоконагруженные серверы, работающие с прокси-соединениями. Например, сервер nginx, устанавливающий несколько десятков прокси-соединений к бэкенд-серверу, из-за всплесков трафика может на некоторое время перегрузить сетевой стек, а повторные попытки создадут дополнительную нагрузку на бэкэнд как в очереди приема, так и в очереди ожидания (SYN backlog). Это, в свою очередь, может повлиять на клиентские соединения. Повторные попытки SYN контролируются параметром net.ipv4.tcp_syn_retries (по умолчанию 5 или 6 в зависимости от дистрибутива). Ограничьте количество повторных попыток SYN до 0 или 1, чтобы не было долгих повторных попыток отправки в течение 63–130 с.
Более подробно о проблемах с клиентскими соединениями при обратном прокси-сервере читайте в статье Linux Kernel Tuning for High Performance Networking: Ephemeral Ports.
Очередь установленных соединений ожидающих принятия (accept queue) и somaxconn
somaxconn и параметр backlog в listen()
Значения по умолчанию для очереди
Значение по умолчанию для net.core.somaxconn берется из константы SOMAXCONN, которая в ядрах Linux вплоть до версии 5.3 имеет значение 128, но в 5.4 она была увеличена до 4096. Однако, на момент написания этой статьи, ядро 5.4 еще не очень распространено, поэтому в большинстве систем значение будет 128, если вы не модифицировали net.core.somaxconn.
Часто приложения для размера очереди по умолчанию используют константу SOMAXCONN, если этот размер не задается в конфигурации приложения. Хотя некоторые приложения устанавливают и свои значения по умолчанию. Например, в nginx размер очереди равен 511, который автоматически усекается до 128 в ядрах Linux до версии 5.3.
Изменение размера очереди
Потоки
Если очередь большая, то подумайте также об увеличении количества потоков, которые обрабатывают запросы в приложении. Например, установка для nginx очереди ожидания в 20480 для HTTP-listener без достаточного количества worker_connections для управления очередью приведет к тому, что сервер будет отказываться отвечать на запросы на установку соединения.
Соединения и файловые дескрипторы
Системные ограничения
Любое сокетное соединение использует файловый дескриптор. Максимальное количество дескрипторов, которые могут быть созданы в системе, задается параметром ядра fs.file-max. Посмотреть количество используемых дескрипторов можно следующим образом:
Вывод показывает, что используется 1976 файловых дескрипторов. Выделено, но не используется 12 (для ядер 2.6+), а максимальное количество — 2048. В высоконагруженной системе значение должно быть достаточно большим, чтобы справиться как с большим количеством соединений, так и с потребностями в файловых дескрипторах других процессов.
Пользовательские ограничения
Помимо системного ограничения количества файловых дескрипторов, у каждого пользователя есть свои лимиты. Они настраиваются в системном файле limits.conf (nofile) или, при запуске процесса под управлением systemd, в unit-файле systemd (LimitNOFILE). Чтобы увидеть значение по умолчанию запустите:
Для systemd (на примере nginx):
Настройка
Для настройки системных ограничений установите параметр ядра fs.max-file в максимальное количество файловых дескрипторов, которое может быть в системе (с учетом некоторого буфера). Например:
Для настройки пользовательского лимита установите достаточно большое значение, чтобы хватило сокетам и файловым дескрипторам рабочих процессов (также с некоторым буфером). Пользовательские ограничения устанавливаются в /etc/security/limits.conf, в conf-файле в /etc/security/limits.d/ или в unit-файле systemd. Например:
Количество worker’ов
Аналогично файловым дескрипторам, количество worker’ов или потоков, которые может создать процесс, ограничено как на уровне ядра, так и на уровне пользователя.
Системные ограничения
Пользовательские ограничения
Есть свои ограничения и у каждого пользовательского процесса. Это также настраивается с помощью файла limits.conf (nproc) или unit-файла systemd (LimitNPROC). Для просмотра максимального количества потоков, которое может создать пользователь запустите:
Для systemd (на примере nginx):
Настройка
Обратный прокси и TIME_WAIT
При большом всплеске трафика прокси-соединения, застрявшие в «TIME_WAIT», суммарно могут потреблять много ресурсов при закрытии соединения. Это состояние говорит, что клиент получил последний FIN-пакет от сервера (или вышестоящего worker’а) и находится в ожидании для корректной обработки пакетов. Время нахождения соединения в состоянии «TIME_WAIT» по умолчанию составляет 2 x MSL (Maximum Segment Length — максимальная длина сегмента), что составляет 2 x 60 с. В большинстве случаев это нормальное и ожидаемое поведение, и значение по умолчанию в 120 с вполне приемлемо. Однако много соединений в состоянии «TIME_WAIT» может привести к тому, что приложение исчерпает эфемерные порты для соединений к клиентскому сокету. В этом случае следует уменьшить FIN тайм-аут.
Собираем все вместе
Очередь приема (receive queue) должна быть рассчитана на обработку всех пакетов, полученных через сетевой интерфейс, не вызывая отбрасывания пакетов. Также необходимо учесть небольшой буфер на случай, если всплески будут немного выше, чем ожидалось. Для определения правильного значения следует отслеживать файл softnet_stat на предмет отброшенных пакетов. Эмпирическое правило — использовать значение tcp_max_syn_backlog, чтобы разрешить как минимум столько же SYN-пакетов, сколько может быть обработано для создания полуоткрытых соединений. Помните, что этот параметр задает количество пакетов, которое каждый процессор может иметь в своем буфере, поэтому разделите значение на количество процессоров.
Размер SYN очереди ожидания (SYN backlog queue) на высоконагруженном сервере должен быть рассчитан на большое количество полуоткрытых соединений для обработки редких всплесков трафика. Здесь эмпирическое правило заключается в том, чтобы установить это значение, по крайней мере, на максимальное количество установленных соединений, которое слушатель может иметь в очереди приема, но не выше, чем удвоенное количество установленных соединений. Также рекомендуется отключить SYN cookie, чтобы избежать потери данных при больших всплесках соединений от легитимных клиентов.
Очередь установленных соединений, ожидающих принятия (accept queue) должна быть рассчитана таким образом, чтобы в периоды сильного всплеска трафика ее можно было использовать в качестве временного буфера для установленных соединений. Эмпирическое правило — устанавливать это значение в пределах 20–25% от числа рабочих потоков.
Параметры
В этой статье были рассмотрены следующие параметры ядра:
И следующие пользовательские ограничения:
Заключение
Все параметры в этой статье приведены в качестве примеров и не должны вслепую применяться на ваших продакшн-серверах без тестирования. Есть и другие параметры ядра, которые влияют на производительность сетевого стека. Но в целом, это наиболее важные параметры, которые я использовал при настройке ядра для высоконагруженных систем.
Мониторим базу PostgreSQL — кто виноват, и что делать
Я уже рассказывал, как мы «ловим» проблемы PostgreSQL с помощью массового мониторинга логов на сотнях серверов одновременно. Но ведь кроме логов, эта СУБД предоставляет нам еще и множество инструментов для анализа ее состояния — грех ими не воспользоваться.
Правда, если просто смотреть на них с консоли, можно очень быстро окосеть без какой-либо пользы, потому что количество доступных нам данных превышает все разумные пределы.
Поэтому, чтобы ситуация все же оставалась контролируемой, мы разработали надстройку над Zabbix, которая поставляет метрики, формирует экраны и задает единые правила мониторинга для всех серверов и баз на них.
Сегодняшняя статья — о том, какие выводы можно сделать, наблюдая в динамике различные метрики баз PostgreSQL-сервера, и где может скрываться проблема.
Состояние соединений
Самое первое, с чего начинаются все разборки на тему «что у нас с базой сейчас/было плохо» — это наблюдение за сводным состоянием pg_stat_activity:
На левом графике мы видим все соединения, которые чего-то ждут, на правом — которые что-то делают. В зависимости от версии PG состояние соединения определяется по pg_stat_activity.state/wait_event и/или тексту самого запроса.
На что обращать внимание:
Блокировки
Раз уж мы затронули в предыдущем пункте мониторинг блокировок, то стоит заметить, что PostgreSQL любит их накладывать направо и налево:
Нас из них больше всего интересуют два вида:
Обычно такая ситуация возникает, если у вас в приложении «текут» и не освобождаются ресурсы: соединения с базой, контексты транзакций или advisory-блокировки. Поэтому обращайте внимание на общую динамику.
Transactions per second (TPS)
Отдельно хочу акцентировать внимание — не пренебрегайте выводом max-значений метрик!
На этом графике мы как раз хорошо видим ситуацию внезапного пикового увеличения количества проведенных ( commit ) транзакций. Это не один-в-один соответствует нагрузке на сервер и транзакции могут быть разной сложности, но рост в 4 раза явно показывает, что серверу стоит иметь определенный резерв производительности, чтобы и такой пик переживать беспроблемно.
Количество операций над записями
Сначала обратим внимание на записи, которые у нас вычитываются из индексов/таблиц:
Впрочем, даже если ratio идеально равно 1, но пик пришелся на returned/fetched — тоже хорошего не жди. Обычно это может означать наличие в плане какой-то неприятности вроде:
Раз уж мы начали проверять, «что» у нас там читается — давайте посмотрим и «как» это происходит. То есть какой объем записей у нас читается по индексам, а какой — в результате Seq Scan :
Понятно, что тут любой внеплановый рост показателей должен вызвать подозрение. Например, если вы по каким-то нуждам каждую ночь вычитываете целиком табличку на 10M записей, то возникновение такого пика днем — повод к разборкам.
Равно как и любые массово-аномальные вставки/обновления/удаления:
Использование кэша данных
В реальности все не совсем так, и является поводом к доскональному анализу запросов около времени пика:
Самый длительный запрос/транзакция
Для MVCC долго активные запросы и транзакции в нагруженных системах — беда для производительности. Подробно и в картинках про это можно прочитать тут, а тут — как можно все-таки выжить в таких условиях.
Как показывает наш опыт, визуального представления этих метрик уже достаточно, чтобы примерно представлять, куда дальше «копать»:
filecheck .ru
Вот так, вы сможете исправить ошибки, связанные с netWaiting.exe
Информация о файле netWaiting.exe
Процесс NetWaiting принадлежит программе NetWaiting от неизвестно.
Описание: netWaiting.exe не является необходимым для Windows. Файл netWaiting.exe находится в подпапках «C:\Program Files». Размер файла для Windows 10/8/7/XP составляет 20,480 байт.
Иконка для этой программы находится в трее, рядом с часами. У процесса есть видимое окно. Нет информации по файлу. Это не системный процесс Windows. Поэтому технический рейтинг надежности 41% опасности.
Если вы хотите полностью удалить программу, перейдите в Панель управления ⇒ Программы ⇒ NetWaiting.
Важно: Некоторые вредоносные программы маскируют себя как netWaiting.exe, особенно, если они расположены в каталоге c:\windows или c:\windows\system32. Таким образом, вы должны проверить файл netWaiting.exe на вашем ПК, чтобы убедиться, что это угроза. Мы рекомендуем Security Task Manager для проверки безопасности вашего компьютера.
Комментарий пользователя
Лучшие практики для исправления проблем с netWaiting
Если у вас актуальные проблемы, попробуйте вспомнить, что вы делали в последнее время, или последнюю программу, которую вы устанавливали перед тем, как появилась впервые проблема. Используйте команду resmon, чтобы определить процесс, который вызывает проблемы. Даже если у вас серьезные проблемы с компьютером, прежде чем переустанавливать Windows, лучше попробуйте восстановить целостность установки ОС или для Windows 8 и более поздних версий Windows выполнить команду DISM.exe /Online /Cleanup-image /Restorehealth. Это позволит восстановить операционную систему без потери данных.
netWaiting сканер
Security Task Manager показывает все запущенные сервисы Windows, включая внедренные скрытые приложения (например, мониторинг клавиатуры или браузера, авто вход). Уникальный рейтинг надежности указывает на вероятность того, что процесс потенциально может быть вредоносной программой-шпионом, кейлоггером или трояном.
Бесплатный aнтивирус находит и удаляет неактивные программы-шпионы, рекламу, трояны, кейлоггеры, вредоносные и следящие программы с вашего жесткого диска. Идеальное дополнение к Security Task Manager.
Reimage бесплатное сканирование, очистка, восстановление и оптимизация вашей системы.
«Address Already in Use» или как избежать проблем при завершении TCP соединения
Корректное отключение
Для корректного завершения сетевого подключения обе стороны должны послать пакеты с сигналом о завершении (FIN), которые указывают что стороны не будут больше отсылать данные, также каждая сторона должна подтвердить (ACK) получение сигнала о завершении сетевого обмена данными. FIN инициируется когда приложение вызывает метод close(), shutdown() или exit(). После завершения работы метода close() ядро переходит в режим ожидания подтверждения от второй стороны приема сигнала о завершении. Это делает возможной ситуацию когда процесс инициировавший отключение будет завершен прежде чем ядро освободит рессурсы связанные с подключением, и снова разрешит использовать порт для связывания с другим процесоом (в этом случае, при попытке использования порта мы получим исключение AddressAlreadyInUse).
На рисунке показаны все воможные состояния, которые могут быть во время корректного завершения, в зависимости от порядка получения пакетов FIN и ACK от удаленной стороны. Обратите внимание, если вы инициировали завершение подключения (левая половина рисунка), то другая сторона не будет ожидать подтверждения получения вами пакета FIN (правая половина рисунка). Сотояние TIME_WAIT требуется на случай если подтверждение (ACK) которое вы отправили не было получено на другой стороне, или на случай появления ложных пакетов по какой-то причине. Я не знаю почему на стороне сервера не сделали состояние TIME_WAIT, хотя если клиент инициирует закрытие, это безусловно и не должно требовать ожидания. Состояние TIME_WAIT может удерживать порт в течение нескольких минут после завершения процесса. Время удержания варьируется в зависимости от операционной системы, в некоторых операционных системах оно является динамическим, стандартные значения лежат в диапазоне от 1 до 4 минут.
Если обе стороны успеют инициировать сигнал завершения, раньше чем получат его от другой стороны, то обе стороны будут вынуждены пройти через ожидание (TIME_WAIT).
Корректное отключение слушающей стороны
Слушающий сокет может быть закрыт немедленно, при отсутствии входящих подключений, его состояние переходит сразу в CLOSED. При наличии входящих подключений, будет произведен переход к FIN_WAIT_1 и затем к TIME_WAIT.
Обратите внимание, на стороне слушающего сокета невозможно гарантировать чистое закрытие. Пока вы проверяете использование соединения методом select() до закрытия, существует крошечная, но реальная возможность появления входящего подключения после вызова select() и до вызова close().
Непредвиденное отключение удаленной стороны
При внезапном отключении сервера, локальная сторона инициирует закрытие соединения, и в этом случае TIME_WAIT неизбежен. Если удаленная сторона исчезает из-за сбоя сети или перезагрузки машины (редкие случаи), локальный порт будет оставаться привязанным вплоть до истечения таймаута состояния TIME_WAIT. Хуже того, некоторые старые операционные системы, не реализуют таймаут для состояния FIN_WAIT_2, и могут оставаться в нем бесконечно долго, в этом случае спасти может только перезагрузка системы.
Если же локальное приложение (клиент) падает в процессе активного соединения, порт будет занят пока не завершится состояние TIME_WAIT, то же верно для приложений, закрытых в процессе подключения к удаленной стороне(pending).
Способы избежания проблем
Опция SO_REUSEADDR
Можно использовать метод setsockopt(), для установки опции SO_REUSEADDR, что позволит создавать привязку к порту даже если он еще находится в состоянии TIME_WAIT (привязка к порту будет разрешена только для одного процесса). Это самый простой и эффективный метод избежать сообщения «address already in use».
Но, как ни странно, использование опции SO_REUSEADDR, может привести к более трудноотлавливаемым ошибкам чем «address already in use». SO_REUSEADDR позволяет использовать порт застрявший в TIME_WAIT, но вы все еще сможете использовать этот порт в том процессе, в котором он привязан изначально.


