Контекст:
Мы используем кластер RabbitMQ 2.8.4 HA для обмена сообщениями в центре обработки данных среднего размера (сотни-тысячи серверов). Функции обмена сообщениями имеют решающее значение для нашего приложения.
Мы используем API клиента C для операций AMQP/RabbitMQ и API HTTP для плагина управления RabbitMQ для периодического мониторинга состояния очереди и отправки оповещений на основе размера/пропускной способности и т. д.
Единственными портами/подключениями, разрешенными от клиентов к серверам обмена сообщениями, являются порты AMQP и HTTP для API управления.
Руководство решило, что в ближайшем будущем простой кластера обмена сообщениями (который приводит к простою определенных запрашивающих частей приложения) неприемлем. Через несколько месяцев это станет возможным, но до тех пор проблемы, связанные с продажами, не позволят нам проводить обслуживание системы обмена сообщениями. Это отстой, но мы (люди инфраструктуры/devops) не можем совершать эти звонки.
Проблема:
Некоторое время мы были жертвами проблемы, обсуждаемой вэтот ТАК вопрос. После шторма подключений или длительного периода, в течение которого новые клиенты подключаются и очень часто используют систему AMQP, API управления RabbitMQ показывает сотни тысяч подключений, которые он перечисляет как «работающие», но которые больше не существуют. netstat
, lsof
и другие диагностические данные доказывают, что сокеты, соответствующие этим подключениям, не открыты на клиентах; API управления просто не может удалить записи по какой-то причине. rabbitmqctl list_connections
иногда показывает, что некоторые из несуществующих подключений все еще открыты, но он всегда показывает намного меньше, чем API управления, и его обнаружение «устаревания» кажется лучше, чем у API, и в конечном итоге он удаляет ложные подключения из своего списка.
Когда мы пытаемся удалить одно из этих "ложных" подключений через веб-интерфейс, страница не реагирует на нажатие "удалить", и подключение остается в списке. Когда мы пытаемся удалить его, отправив DELETE в JSON API, мы получаем ошибку сервера 500, указывающую на то, что подключение недействительно, поэтому его нельзя удалить (точно так же, как описано в связанном вопросе SO выше).
После длительного накопления этих несуществующих объектов связи происходят три плохие вещи, в произвольном порядке:
- Сервер RabbitMQ имеет огромные скачки памяти (которые возникают из ниоткуда; они не соответствуют медленному увеличению скорости соединения в API управления, хотя потребление памяти медленно растет со временем). Это часто приводит к сбою.
- API управления перестает отвечать на запросы (истекают тайм-ауты на клиентах API).
- Сам сервер RabbitMQ начинает время от времени отклонять соединения от клиентов AMQP, которые ничего не делают с HTTP/API управления.
В случаях, когда эта проблема начинает нарушать работу нашего приложения, нам приходится делать одно из двух: * Перезапустить весь кластер обмена сообщениями, что плохо, потому что это приводит к кратковременному простою, и плохо, потому что сообщения могут быть потеряны во время этого процесса. * Перезапустить и очистить базу данных API управления, что плохо, потому что мы не можем использовать API управления, и еще хуже, потому что это часто нарушает работу API управления таким образом, что он не запустится должным образом, пока мы не перезапустим весь кластер, как в первом пункте.
Большинство людей, столкнувшихся с подобными проблемами, решают их, обновляясь до RabbitMQ 3.*. У нас нет ни времени, ни разрешения, ни разрешения на простой для такого проекта. Даже в условиях периодических отключений на несколько минут при перезапуске кластера из-за этой проблемы мы не были авторизованы на обновление. Это чисто политическое ограничение, но прискорбная реальность.
Вопрос:
Учитывая, что мы не сможем обновить RabbitMQ в ближайшем будущем и нам необходимо продолжать использовать API управления, как мы можем решить проблему постоянных устаревших соединений, которые вызывают сбои кластера обмена сообщениями?
У нас есть возможность разрабатывать новый/другой клиентский код и запускать задания на самих серверах обмена сообщениями, но у нас нет возможности использовать его rabbitmqctl
локально или через ssh
какую-либо из клиентских машин.
Что мы пробовали:
- Мы пробовали переключать клиентские библиотеки AMQP в надежде, что лучший клиент очистит за собой и не оставит устаревших соединений, но безрезультатно. Проблема сохраняется.
- Мы пробовали играть с настройками
tcp_keepalive
иexit_on_close
TCP на самих серверах RabbitMQ. Никакая комбинация этих значений не решает проблему. - Мы создали скрипт, который перебирает все соединения, возвращаемые из списка соединений JSON API, и отправляет DELETE для каждого, которое было открыто дольше, чем требовалось бы, если бы оно использовалось. Все такие запросы встречают ошибки сервера 500, как описано в вопросе SO, ссылка на который приведена выше.
решение1
Периодически приходится все перезапускать.
Другой вариант — бэкпортировать исправление из 3.x в вашу текущую версию, но если вам не разрешено обновляться, вам, вероятно, не разрешат сделать и это. И это почти наверняка будет гораздо больше работы, чем обновление, особенно если код RabbitMQ был значительно переработан.
Пока вы не сможете изменитьполитикаситуации, это ваши варианты.