TCP: не хватает памяти — рассмотрите возможность настройки tcp_mem

Недавно мы столкнулись с интересной производственной проблемой. Это приложение работало на нескольких экземплярах AWS EC2 за Elastic Load Balancer. Приложение работало на ОС GNU/Linux, Java 8, сервере приложений Tomcat 8. Внезапно один из экземпляров приложения перестал отвечать на запросы. Все остальные экземпляры приложения правильно обрабатывали трафик. Всякий раз, когда HTTP-запрос отправлялся этому экземпляру приложения из браузера, мы получали следующий ответ для печати в браузере.

Proxy Error 

The proxy server received an invalid response from an upstream server. 
The proxy server could not handle the request GET /.

Reason: Error reading from remote server

Мы использовали наш инструмент APM (мониторинг производительности приложений) для изучения проблемы. С помощью инструмента APM мы могли наблюдать идеальное использование ЦП и памяти. С другой стороны, с помощью инструмента APM мы могли наблюдать, что трафик не поступал в этот конкретный экземпляр приложения. Это действительно озадачивало. Почему не приходил трафик?

Мы вошли в этот проблемный экземпляр AWS EC2. Мы выполнили команды vmstat, iostat, netstat, top, df, чтобы посмотреть, сможем ли мы обнаружить какую-либо аномалию. К нашему удивлению, все эти замечательные инструменты не сообщали о каких-либо проблемах.

В качестве следующего шага мы перезапустили сервер приложений Tomcat, на котором работало это приложение. Это тоже не имело никакого значения. Тем не менее, этот экземпляр приложения вообще не отвечал.

DMESG-команда
Затем мы выполнили команду dmesg для этого экземпляра EC2. Эта команда печатает буфер сообщений ядра. Вывод этой команды обычно содержит сообщения, созданные драйверами устройств. В выводе, сгенерированном этой командой, мы заметили, что следующие интересные сообщения повторяются:

[4486500.513856] TCP: out of memory -- consider tuning tcp_mem
[4487211.020449] TCP: out of memory -- consider tuning tcp_mem
[4487369.441522] TCP: out of memory -- consider tuning tcp_mem
[4487535.908607] TCP: out of memory -- consider tuning tcp_mem
[4487639.802123] TCP: out of memory -- consider tuning tcp_mem
[4487717.564383] TCP: out of memory -- consider tuning tcp_mem
[4487784.382403] TCP: out of memory -- consider tuning tcp_mem
[4487816.378638] TCP: out of memory -- consider tuning tcp_mem
[4487855.352405] TCP: out of memory -- consider tuning tcp_mem
[4487862.816227] TCP: out of memory -- consider tuning tcp_mem
[4487928.859785] TCP: out of memory -- consider tuning tcp_mem
[4488215.969409] TCP: out of memory -- consider tuning tcp_mem
[4488642.426484] TCP: out of memory -- consider tuning tcp_mem
[4489347.800558] TCP: out of memory -- consider tuning tcp_mem
[4490054.414047] TCP: out of memory -- consider tuning tcp_mem
[4490763.997344] TCP: out of memory -- consider tuning tcp_mem
[4491474.743039] TCP: out of memory -- consider tuning tcp_mem
[4491859.749745] TCP: out of memory -- consider tuning tcp_mem
[4492182.082423] TCP: out of memory -- consider tuning tcp_mem
[4496318.377316] TCP: out of memory -- consider tuning tcp_mem
[4505666.858267] TCP: out of memory -- consider tuning tcp_mem
[4521592.915616] TCP: out of memory -- consider tuning tcp_mem

Мы были заинтригованы, увидев это сообщение об ошибке: «TCP: недостаточно памяти — рассмотрите возможность настройки tcp_mem». Это означает, что ошибка нехватки памяти происходит на уровне TCP. Нас всегда учили, что ошибка нехватки памяти возникает только на уровне приложения и никогда на уровне TCP.

Проблема была интригующей, потому что мы дышим этой проблемой OutOfMemoryError изо дня в день. Мы создали инструменты для устранения неполадок, такие как GCeasy, HeapHero чтобы облегчить инженерам отладку OutOfMemoryError, которая происходит на уровне приложения (приложения Java, Android, Scala, Jython…). Мы написали несколько блогов об этом OutOfMemoryError тема. Но мы были поражены, увидев, что OutOfMemory происходит на уровне драйвера устройства. Мы никогда не думали, что может возникнуть проблема на уровне драйвера устройства, в том числе и в стабильной операционной системе Linux. Озадаченные этой проблемой, мы не знали, как действовать дальше.

Таким образом, мы прибегли к божьей помощи Google 😊. Поиск в Google по запросу «TCP: недостаточно памяти — рассмотрите возможность настройки tcp_mem» показал только 12 результатов поиска. Но для одной статьи ни в одной из них не было большого содержания ☹. Даже та статья была написана на иностранном языке, которого мы не понимали. Итак, мы не уверены, как решить эту проблему.

Теперь, не имея других решений, мы пошли дальше и внедрили универсальное решение, т.е. «перезагрузку». Мы перезапустили инстанс EC2, чтобы предотвратить немедленное возгорание. Ура!! Перезагрузка сервера сразу устранила проблему. Судя по всему, этот сервер не перезагружался в течение нескольких дней (например, более 70 дней), возможно, из-за того, что это приложение могло иметь насыщенные ограничения памяти TCP.

Мы обратились за помощью к одному из наших умных друзей, который работает в технологической компании мирового уровня. Этот друг спросил нас, какие значения мы устанавливаем для следующих свойств ядра:

**core.netdev_max_backlog
*core.rmem_max
*core.wmem_max
*ipv4.tcp_max_syn_backlog
*ipv4.tcp_rmem
*net.ipv4.tcp_wmem

Честно говоря, мы впервые слышим об этих свойствах. Мы обнаружили, что ниже приведены значения, установленные для этих свойств на сервере:

net.core.netdev_max_backlog = 1000
net.core.rmem_max = 212992
net.core.wmem_max = 212992
net.ipv4.tcp_max_syn_backlog = 256
net.ipv4.tcp_rmem = 4096        87380   6291456
net.ipv4.tcp_wmem = 4096        20480   4194304

Наш друг предложил изменить значения, как указано ниже:

net.core.netdev_max_backlog=30000
net.core.rmem_max=134217728
net.core.wmem_max=134217728
net.ipv4.tcp_max_syn_backlog=8192
net.ipv4.tcp_rmem=4096 87380 67108864
net.ipv4.tcp_wmem=4096 87380 67108864

Он упомянул, что установка этих значений устранит проблему, с которой мы столкнулись. Делимся с вами ценностями (поскольку это может вам помочь). По-видимому, наши ценности были очень низкими по сравнению с ценностями, которые он предоставил.

Вывод
Вот несколько выводов, которые мы хотели бы сделать:

  • Даже современные стандартные инструменты APM (Application Performance Monitoring) не полностью решают проблемы с производительностью приложений, с которыми мы сталкиваемся сегодня.
  • Команда «dmesg» — ваш друг. Возможно, вы захотите выполнить эту команду, когда ваше приложение перестанет отвечать на запросы, это может указать вам на ценную информацию.
  • Проблемы с памятью не обязательно должны возникать в коде, который мы пишем 😊, это может случиться даже на уровне TCP/Kernel.

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *