My server has some strange behaviour and I just cant find the cause. I've been looking everywhere.
I will pay 200$ worth of bitcoin to anyone who can figure this out.
When requesting any resource from apache (page, image, css, js), it sometimes takes a very long time to respond. About half of the time, the connection gets reset. (on Chrome: net::ERR_CONNECTION_RESET) Это случается редко, случайным образом и совершенно непредсказуемо. Что еще более сбивает с толку, хотя кажется, что один запрос завис, я могу сделать дополнительные запросы, которые отлично работают.
Я запускаю apache2.4 mpm-prefork с php7.0 на debian 9. Apache модуль использует mod_rewrite и ssl-сертификат от certbot. В некоторых случаях php вызывает inkscape для рендеринга svgs в png.
Загрузка сервера очень мала (0,02), и на нем не работает только apache.
Я продолжил и проанализировал TCP-трафик с помощью Wireshark, и обнаружил подозрительное поведение. Когда соединение зависает, есть некоторые нарушения порядка TCP, Вот файлы pcap, обрезанные до последних ~ 30 секунд.
Если кто-нибудь со знанием дела может быстро взглянуть на него и рассказать мне, что происходит, я ' я буду в восторге.
Мне удалось сделать ошибку воспроизводимой , по крайней мере, с включенным KeepAlive. Когда запрос завершен и контент обслуживается, tcp-соединение закрывается с помощью FIN-ACK через 5 секунд. При повторном запросе во временном окне 5-12 секунд после FIN-ACK соединение зависает.
Однако, когда KeepAlive отключен, этого больше не происходит, хотя ошибка возникает еще чаще при загрузке нескольких ресурсов одновременно. Но тогда это уже невозможно воспроизвести.
Я бы проверил размер TCP-пакетов, проходящих между сервером и клиентом. ЕСЛИ они приближаются к размеру 1500, есть вероятность, что они будут отброшены из-за множества возможностей:
Если бит DNF установлен в пакете и пакет где-то фрагментируется, это может быть проблемой, которая приводит к тому, что пакет отбрасывается
12114] Если для MTU установлено значение 1500, а пакеты проходят через туннели, шифрование и т. Д., Что приводит к добавлению дополнительных заголовков к пакету, то это также приведет к падению ваших пакетов. Попробуйте установить для MTU на обоих концах используемых вами интерфейсов значение ниже 1500, возможно, 1420 или даже ниже.
Уверен, что я нашел проблему :-), так как со мной случилось то же самое.
Я думаю, у вас есть ДВА или более процессов, обслуживающих порт 80 (или 443, если речь идет о соединениях SSL). Вы можете проверить это следующим образом, используя команду для порта 80 и вывод моей системы, в которой возникла проблема:
# netstat -tupan | grep ":80.*LISTEN"
Proto Recv-Q Send-Q Local Foreign State PID/Program name
Address Address
tcp6 0 0 :::80 :::* LISTEN 22718/apache2
tcp6 0 0 :::80 :::* LISTEN 1794/apache2
Два процесса, обслуживающие одни и те же IP-адреса с одного и того же порта, действительно возможны с параметрами порта SO_REUSEADDR
и SO_REUSEPORT
, см. здесь и здесь (раздел о «Linux> = 3.9»).
Что ядро делает с SO_REUSEPORT
предназначен для распределения входящих TCP-соединений по процессам, обслуживающим этот порт, недетерминированным образом. Один процесс - это ваш Apache, который правильно обслуживает запрос, а другой - "что-то еще", которое никогда ни на что не отвечает. В моем случае это был другой процесс Apache2.
Если у вас есть два процесса Apache, сначала выясните, какой из них является «зомби». Для этого остановите свой обычный сервер Apache ( service apache2 stop
) и проверьте, какой из них остался ( netstat -tupan | grep ": 80. * LISTEN"
). Это «зомби». Обратите внимание на его PID.
Чтобы узнать больше о том, кто или что запустил этот «зомби-процесс»:
Выполните cat / proc /
с PID этого «зомби-процесса» . Если отображается 4294967295
, это означает, что его запустила система, а не пользователь ( причина ). В противном случае вы можете найти UID пользователя.
Выполните ps auxf
и определите время безотказной работы вашего «зомби» процесса. Если он соответствует времени безотказной работы системы, это означает, что процесс каким-то образом был запущен во время загрузки.
Чтобы (возможно) узнать больше о том, что происходит внутри этого «зомби-процесса», вы можете подключиться к нему с помощью strace
. Это создаст множество трудных для чтения журналов, но, поскольку воспроизвести проблему наличия этого «зомби-процесса» может быть нелегко, кажется полезным хотя бы собрать некоторые из этих журналов (особенно HTTP-запросов, идущих к этому процессу), прежде мы убиваем процесс. Вы должны выполнить с PID вашего процесса вместо $ PID
:
strace -o strace.log -f -p $ PID
Чтобы решить проблему на данный момент, завершите процесс «зомби», указав его PID для $ PID
: kill $ PID
или, если необходимо, kill -9 $ PID
.
Проверьте, запущен ли этот "зомби-процесс" и снова работает после перезагрузки, и если да, вам нужно будет исследовать и устранить причину , .
Возможно (но не тривиально) вручную создать «зомби-процесс» Apache2, который будет работать параллельно с обычным сервером Apache и просто «ничего не отвечать». Вот почти - но не совсем полные инструкции:
Создайте копии соответствующих файлов конфигурации:
cp / etc / apache2 / envvars / etc / apache2 / envvars-zombie
cp /etc/apache2/apache2.conf /etc/apache2/apache2-zombie.conf
Отредактируйте / etc / apache2 / envvars-zombie
и в начале скрипта статически установите SUFFIX = "- zombie"
, переопределив в нем условное присвоение.
Изменить /etc/apache2/apache2-zombie.conf
и предотвратить включение любых файлов конфигурации VirtualHost. В моем случае я бы изменил соответствующую строку на:
# IncludeOptional sites-enabled /
Убедитесь, что порты прослушивания по умолчанию включены в ваш файл apache2-zombie.conf
. В моем случае это уже произошло через Include ports.conf
.
Создайте каталоги файлов блокировки и журналов, необходимые для нового экземпляра Apache2, и сделайте их доступными для пользователя, от имени которого будет работать ваш новый Apache2:
mkdir / var / log / apache2-zombie
чавн www-данных / вар / журнал / apache2-зомби /
mkdir / вар / блокировка / apache2-зомби
чавн www-данные / вар / блокировка / apache2-зомби /
Теперь у вас должна быть возможность запустить свой «зомби» процесс Apache следующим образом:
cd / etc / apache2 /
источник envvars-zombie
/ usr / sbin / apache2 -f apache2-zombie.conf -k начало
Убедитесь, что на стандартных портах Apache2 действительно запущен второй процесс: netstat -tupan | grep ": 80. * LISTEN"
.
Этот второй сервер Apache2 еще не является «зомби», потому что он все равно будет отвечать «404 Not Found» или (поскольку мы не настроили SSL) приведет к ошибке SSL при выполнении запроса на порт 443. Но вы уже можете наблюдать эффект, что несколько запросов поступают на этот новый сервер и приводят к этим ошибкам недетерминированным образом. (Я дошел до этого момента на практике…)
Чтобы создать «правильный» зомби-Apache, настройте простой скрипт, который будет принимать HTTP-запрос и ничего не делать ( sleep ()
) для несколько минут, чтобы браузер отказался, соответственно.чтобы время ожидания TCP-соединения истекло. Установите его для хоста Apache по умолчанию. Таким образом, он будет использоваться для всех HTTP-запросов к порту, поскольку мы отключили все конфигурации VirtualHost, поэтому Apache не может найти более подходящий хост для любого запроса и выберет хост по умолчанию.