Хабрахабр

[Из песочницы] Эксплуатация кроликов (RabbitMQ) в режиме «Выжить любой ценой»

«Компания» — оператор связи ПАО «Мегафон»
«Нода» — сервер RabbitMQ.
«Кластер» — совокупность, в нашем случае трех, нод RabbitMQ работающих как единое целое.
«Контур» — совокупность кластеров RabbitMQ, правила работы с которыми определяются на стоящем перед ними балансировщике.
«Балансировщик», «хап» — Haproxy – балансировщик, выполняющий функции переключения нагрузки на кластеры в рамках контура. Для каждого контура используется пара серверов Haproxy, работающих параллельно.
«Подсистема» — публикатор и/или потребитель сообщений, передаваемых через кролика
«СИСТЕМА» — совокупность Подсистем, являющая собой единое программно-аппаратное решение, используемое в Компании, характеризующееся распределённостью по всей территории России, но обладающее несколькими центрами, куда стекается вся информация и где происходят основные расчёты и вычисления.
СИСТЕМА – географически распределённая система – от Хабаровска и Владивостока до Санкт-Петербурга и Краснодара. Архитектурно это несколько центральных Контуров, разделенных по особенностям подсистем, к ним подключённым.

Какая задача возлагается на транспорт в реалиях телекома?

В двух словах: на каждое действие абонента следует реакция Подсистем, которые в свою очередь информирует другие Подсистемы о событиях и последующих изменениях. Сообщения порождаются любыми действиями с СИСТЕМОЙ, не только со стороны абонентов, но и со стороны сотрудников Компании, и со стороны Подсистем (очень большое количество задач выполняется в автоматическом режиме).

Особенности транспорта в телекоме: большой, нет не так, БОЛЬШОЙ поток разнообразных данных, передаваемых через асинхронный транспорт.

сообщений / секунду, объём передаваемых данных может доходить до 170-190 Мегабайт / секунду. Некоторые Подсистемы живут на отдельных Кластерах в силу тяжеловесности потоков сообщений – ни на кого другого на кластере просто не остаётся ресурсов, например, при потоке сообщений 5-6 тыс. При таком профиле нагрузки попытка приземлить на этот кластер ещё кого ни будь, приведёт к печальным последствиям: поскольку ресурсов для обработки всех данных одновременно не хватает, кролик начнёт загонять входящие соединения во flow – начнётся простой публикаторов, со всеми последствиями для всех Подсистем и СИСТЕМЫ в целом.

Основные требования к транспорту:

  1. Доступность транспорта должны быть 99,99%. На практике это выливается в требование обеспечения работы 24/7 и способность автоматически реагировать на любые аварийные ситуации.
  2. Обеспечение сохранности данных: % потерянных сообщений на транспорте должен стремиться к 0.

Например, на сам факт совершения вызова, через асинхронный транспорт пролетает несколько разных сообщений. какие-то сообщения предназначены для подсистем, живущих в этом же Контуре, а какие-то предназначены для передачи в центральные узлы. Одно и то же сообщение может быть востребовано несколькими подсистемами, поэтому на этапе публикации сообщения в кролика происходит его копирование и направление к разным потребителям. А в некоторых случаях копирование сообщений вынужденно реализовывается на промежуточном Контуре – когда информацию надо доставить от Контура в Хабаровске, до контура в Краснодаре. Передача выполняется через один из центральных Контуров, где делаются копии сообщений, для центральных получателей.

Таким образом получается несколько тысяч разных маршрутов передачи сообщений, некоторые пересекаются, некоторые существуют изолированно. Кроме событий, вызванных действиями абонента, через транспорт ходят сообщения служебные, которыми обмениваются Подсистемы. Достаточно назвать количество вовлечённых в маршруты очередей на разных Контурах, чтобы понять примерный масштаб транспортной карты: На центральных контурах 600, 200, 260, 15…и на удалённых Контурах по 80-100…

К реализации этих требований мы и переходим. При такой вовлечённости транспорта требования о 100% доступности всех транспортных узлов уже не кажутся чрезмерными.

Как мы решаем поставленные задачи

Кроме непосредственно RabbitMQ, для балансировки нагрузки и обеспечения автоматического реагирования на аварийные ситуации, используется Haproxy.

Несколько слов об программно-аппаратном окружении, в котором существуют наши кролики:

  • Все сервера кроликов виртуальные, с параметрами 8-12 CPU, 16 Gb Mem, 200 Gb HDD. Как показал опыт, даже использование жутких не виртуальных серверов на 90 ядер и кучей ОЗУ обеспечивает небольшой прирост производительности при значительно больших затратах. Используемые версии: 3.6.6 (на практике – самая устойчивая из 3.6) с эрлангом 18.3, 3.7.6 с эрлангом 20.1.
  • Для Haproxy требования значительно ниже: 2 CPU, 4 Gb Mem, версия haproxy – 1.8 stable. Загруженность по ресурсам, на всех серверах haproxy, не превышает 15% CPU/Mem.
  • Располагается весь зоопарк в 14 ЦОДах на 7 площадках по всей стране, объединённых в единую сеть. В каждом из ЦОДов располагается Кластер из трёх Нод и один Хап.
  • Для удалённых Контуров используются по 2 ЦОДа, для каждого из центральных Контуров — по 4.
  • Центральные Контуры взаимодействуют как между собой, так и с удалёнными Контурами, в свою очередь удалённые Контуры работают только с центральными, прямой связи между собой не имеют.
  • Конфигурации Хапов и Кластеров в рамках одного Контура полностью идентичны. Точкой входа для каждого Контура псевдоним на несколько A-DNS записей. Таким образом, чтобы не произошло, будет доступен хотя бы один хап и хотя бы один из Кластеров (хотя бы одна нода в Кластере) в каждом Контуре. Поскольку случай выхода из строя даже 6 серверов в двух ЦОДах одновременно крайне маловероятен, принимается доступность близкая к 100%.

Выглядит задуманное (и реализованное) всё это примерно так:

image

image

Теперь немного конфигов.

Конфигурация haproxy

frontend center-rmq_5672

bind

*:5672

mode

tcp

maxconn

10000

timeout client

3h

option

tcpka

option

tcplog

default_backend

center-rmq_5672

frontend center-rmq_5672_lvl_1

bind

localhost:56721

mode

tcp

maxconn

10000

timeout client

3h

option

tcpka

option

tcplog

default_backend

center-rmq_5672_lvl_1

backend center-rmq_5672

balance

leastconn

mode

tcp

fullconn

10000

timeout

server 3h

server

srv-rmq01 10.10.10.10:5672 check inter 5s rise 2 fall 3 on-marked-up shutdown-backup-sessions

server

srv-rmq03 10.10.10.11:5672 check inter 5s rise 2 fall 3 on-marked-up shutdown-backup-sessions

server

srv-rmq05 10.10.10.12:5672 check inter 5s rise 2 fall 3 on-marked-up shutdown-backup-sessions

server

localhost 127.0.0.1:56721 check inter 5s rise 2 fall 3 backup on-marked-down shutdown-sessions

backend center-rmq_5672_lvl_1

balance

leastconn

mode

tcp

fullconn

10000

timeout

server 3h

server

srv-rmq02 10.10.10.13:5672 check inter 5s rise 2 fall 3 on-marked-up shutdown-backup-sessions

server

srv-rmq04 10.10.10.14:5672 check inter 5s rise 2 fall 3 on-marked-up shutdown-backup-sessions

server

srv-rmq06 10.10.10.5:5672 check inter 5s rise 2 fall 3 on-marked-up shutdown-backup-sessions

Первая секция фронта описывает точку входа – ведущую на основной Кластер, вторая секция предназначена для балансировки резервного уровня. Если просто описать в секции backend все резервные сервера кроликов (инструкция backup), то срабатывать будет так же – при полной недоступности основного кластера, соединения пойдут на резервный, однако, все соединения пойдут на ПЕРВЫЙ в списке backup сервер. Для обеспечения балансировки нагрузки на все резервные ноды, как раз и вводим ещё один фронт, который делаем доступным только с localhost и именно его назначаем backup сервером.

Таким образом для реализации четырёх-цодового решения нам требуется только дописать ещё два локальных фронта и две backend секции соответствующих серверов кроликов. Приведённый пример описывает балансировку удалённого Контура – который работает в рамках двух ЦОДов: сервера srv-rmq – живут в ЦОД №1, srv-rmq{02,04,06} – в ЦОД №2.

Если недоступны основные сервера – работаем с резервом. Поведение балансировщика с такой конфигурацией следующее: Пока жив хотя бы один основной сервер, используем его. Если хотя бы один основной сервер становится доступен – все соединения с резервными серверами разрываются и при восстановлении подключения уже попадают на основной Кластер.

Данное решение требует от Подсистем вполне законного и простого: уметь восстанавливать соединение с кроликом после разрыва связи. Опыт эксплуатации такой конфигурации показывает практически 100% доступность каждого из Контуров.

Итак, балансировку нагрузки на произвольное количество Кластеров и автоматическое переключение между ними мы обеспечили, пора переходить непосредственно к кроликам.

Поскольку кролик горизонтально не масштабируется (производительность кластера равна производительности самого медленного сервера), создаём все ноды с одинаковыми, оптимальными параметрами по CPU/Mem/Hdd. Каждый Кластер создан из трёх нод, как показывает практика – наиболее оптимальное количество нод, при котором обеспечивается оптимальный баланс доступность / отказоустойчивость / скорость работы. Располагаем сервера как можно ближе друг к другу – в нашем случае запиливаем виртуальные машины в рамках одной фермы.

Что касается предварительных условий, следование которым со стороны Подсистем обеспечит максимально устойчивую работу и выполнение требования о сохранении поступивших сообщений:

  1. Работа с кроликом идёт только по протоколу amqp/amqps – через балансировку. Авторизация под локальными учётками — в рамках каждого Кластера (ну и Контура в целом)
  2. Подсистемы подключаются к кролику в пассивном режиме: Никаких манипуляций с сущностями кролей (создание очередей/эксченджей/биндов) не допускается и ограничивается на уровне прав учётных записей – на конфигурирование прав просто не даём.
  3. Все необходимые сущности создаются централизовано, не средствами Подсистем и на всех Кластерах Контура делаются одинаково – для обеспечения автоматического переключения на резервный Кластер и обратно. Иначе можем получить картину: на резерв переключились, а очереди или бинда там нет, и можем получить на выбор либо ошибку подключения, либо пропажу сообщений.

Теперь непосредственно настройки на кроликах:

  1. У локальных УЗ нет доступа к Web интерфейсу
  2. Доступ к Web организуется чрез LDAP – интегрируем с AD и получаем логирование кто и куда на вебке ходил. На уровне конфигурации ограничиваем права у учёток AD, мало того, что требуем нахождение в определённой группе, так и права даём только на «посмотреть». Группы monitoring более чем достаточно. А права администратора навешиваем на другую группу в AD, таким образом сильно ограничивается круг влияния на транспорт.
  3. Для облегчения администрирования и отслеживания:
    На всех VHOST сразу вешаем политику 0 уровня с применением на все очереди (pattern: .*):
    • ha-mode: all – хранить все данные на всех нодах кластера, снижается скорость обработки сообщений, но обеспечивается их сохранность и доступность.
    • ha-sync-mode: automatic – поручаем кролю автоматически синхронизировать данные на всех нодах кластера: так же увеличивается сохранность и доступность данных.
    • queue-mode: lazy – пожалуй одна из самых полезных опций, появившаяся в кроликах с версии 3.6 – немедленная запись сообщений на HDD. Данная опция кардинально снижает потребление ОЗУ и увеличивает сохранность данных при остановках/падениях нод или кластера в целом.

  4. Настройки в файле конфигурации (rabbitmq-main/conf/rabbitmq.config):
    • Секция rabbit: {vm_memory_high_watermark_paging_ratio, 0.5} – порог выгрузки сообщений на диск 50%. При включённом lazy служит больше как страховка, когда нарисуем политику, например, 1 уровня, в которую забудем включить lazy.
    • {vm_memory_high_watermark, 0.95} – ограничиваем кроля 95% всей ОЗУ, поскольку на серверах живёт только кролик, нет смысла вводить более жёсткие ограничения. 5% «широким жестом» так и быть – оставляем ОС, мониторингу и прочим полезным мелочам. Поскольку это значение является верхней границей — ресурсов хватает всем.
    • {cluster_partition_handling, pause_minority} – описывает поведение кластера при возникновении Network Partition, для трёх и более нодового кластера рекомендуется именно такой флаг – позволяет кластеру самому восстановиться.
    • {disk_free_limit, «500MB»} – тут всё просто, когда останется свободного места на диске 500 MB – публикация сообщений будет остановлена, будет доступно только вычитывание.
    • {auth_backends, [rabbit_auth_backend_internal, rabbit_auth_backend_ldap]} — порядок авторизации на кроликах: Сначала проверяется наличие УЗ в локальной базе и если не находится – идём на сервера LDAP.
    • Секция rabbitmq_auth_backend_ldap – конфигурация взаимодействия с AD: {servers, [«srv_dc1»,«srv_dc2»]} – список контроллеров домена, на которых и будет проходить аутентификация.
    • Параметры, непосредственно описывающие пользователя в AD, порт LDAP и прочее, сугубо индивидуальны и подробно описаны в документации.
    • Самое важное для нас – описание прав и ограничений на администрирование и доступ к Web интерфейсу кролей: tag_queries:
      [{administrator,{in_group, «cn=rabbitmq-admins,ou=GRP,ou=GRP_MAIN,dc=My_domain,dc=ru»}},
      {monitoring,
      {in_group, «cn=rabbitmq-web,ou=GRP,ou=GRP_MAIN, dc=My_domain,dc=ru»}
      }]
      – данная конструкция обеспечивает административные привилегии всем пользователям группы rabbitmq-admins и права monitoring (минимально достаточные для доступа на просмотр) для группы rabbitmq-web.
    • resource_access_query:
      {for,
      [{permission,configure, {in_group, «cn=rabbitmq-admins,ou=GRP,ou=GRP_MAIN,dc=My_domain,dc=ru»}},
      {permission,write, {in_group, «cn=rabbitmq-admins,ou=GRP,ou=GRP_MAIN,dc=My_domain,dc=ru»}},
      {permission, read, {constant, true}}
      ]
      }
      – обеспечиваем права на конфигурирование и запись только группе администраторов, всем остальным, кто успешно авторизуется права доступны только на чтение – вполне может вычитать сообщения через Web интерфейс.

Получаем сконфигурированный (на уровне файла конфигурации и настроек в самом кролике) кластер, который максимально обеспечивает доступность и сохранность данных. Этим мы реализуем требование – обеспечение доступности и сохранности данных…в большинстве случаев.

Есть несколько моментов, которые стоит учитывать при эксплуатации подобных высоко нагруженных систем:

  1. Все дополнительные свойства очередей (TTL, expire, max-length и прочее) лучше организовывать политиками, а не вешать параметрами при создании очередей. Получается гибко настраиваемая структура, которую можно подгонять на лету под изменяющиеся реалии.
  2. Использование TTL. Чем длиннее очередь, тем выше будет нагрузка на CPU. Чтобы не допустить «пробивания потолка» лучше длину очереди так же ограничить через max-length.
  3. Кроме самого кролика на сервере крутится ещё некоторое количество служебных приложений, которым, как ни странно, тоже требуются ресурсы CPU. А прожорливый кролик, по умолчанию, занимает все доступные ядра…Может получиться неприятная ситуация: борьба за ресурсы, которая запросто приведёт к тормозам на кролике. Избежать возникновения такой ситуации можно, например, так: Изменить параметры запуска эрланга – ввести принудительное ограничение на количество используемых ядер. Делаем это следующим образом: находим файл rabbitmq-env, ищем параметр SERVER_ERL_ARGS= и добавляем к нему +sct L0-Xc0-X +S Y:Y. Где X-число ядер-1 (отсчёт начинается с 0), Y – Количество ядер -1 (отсчёт с 1). +sct L0-Xc0-X – меняет привязку к ядрам, +S Y:Y – изменяет число шедулеров, запускаемых эрлангом. Так для системы из 8 ядер добавляемые параметры примут вид: +sct L0-6c0-6 +S 7:7. Этим мы отдаём кролику только 7 ядер и рассчитываем, что ОС запуская другие процессы поступит оптимально и повесит их на не нагруженное ядро.

Нюансы эксплуатации получившегося зоопарка

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

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

Например, многократное моргание сети, причем с периодичностью больше 5 секунд (именно такой таймаут выставлен в настройках Хапов, можно им конечно поиграться, но для проверки эффективности потребуется повторение сбоя, чего никому не хочется).

В такой ситуации может спасти остановка выпавшей ноды, но успеть это сделать вручную практически невозможно. Одну – две такие итерации кластер ещё выдержать может, но больше – уже шансы минимальны. Визуально – в данных по очередям стоит NaN. Чаще результатом является не просто выпадение ноды из кластера с сообщением «Network Partition», но и картина, когда данные по части очередей жили как раз этой ноде и не успели синхронизироваться на оставшиеся.

Переключение обеспечит хап, требуется только остановить кроликов на основном кластере – дело нескольких минут. И вот это уже однозначный сигнал – переключиться на резервный Кластер. В результате получаем восстановление работоспособности транспорта и можем спокойно приступить к анализу аварии и её устранению.

Поскольку Хапы у нас следят за кроликами именно по штатному порту, смещение его, например, на 5673 в настройках кролика позволит полностью безболезненно запускать кластер и попытаться восстановить его работоспособность и сообщения, оставшиеся на нём. Для того, чтобы вывести из-под нагрузки повреждённый кластер, с целью не допустить дальнейшей деградации, самое простое: заставить кролика работать на портах отличных от 5672.

Делаем в несколько шагов:

  1. Останавливаем все ноды сбойного кластера – хап переключит нагрузку на резервный Кластер
  2. Добавляем RABBITMQ_NODE_PORT=5673 в файл rabbitmq-env – при запуске кролика настройки эти настройки подтянутся, при этом Web интерфейс по-прежнему будет работать на 15672.
  3. Указываем новый порт на всех нодах безвременно почившего кластера и запускаем их.

При запуске произойдёт перестройка индексов и в подавляющем большинстве случаев все данные восстанавливаются в полном объёме. К сожалению, случаются сбои в результате которых приходится физически удалять все сообщения с диска, оставляя только конфигурацию – в папке с базой удаляются директории msg_store_persistent, msg_store_transient, queues (для версии 3.6) или msg_stores (для версии 3.7).

После такой радикальной терапии кластер запускается с сохранением внутренней структуры, но без сообщений.

И самый неприятный вариант (наблюдался один раз): Повреждения базы были таковы, что пришлось полностью удалять всю базу и пересобрать кластер с нуля.

Основное отличие: не требует для установки/настройки прав root, не устанавливается в систему (пересобранный кролик отлично запаковывается в tgz) и запускается от любого пользователя. Для удобства управления и обновления кроликов используется не готовая сборка в rpm, а разобранный с помощью cpio и переконфигурированный (изменили пути в скриптах) кролик. Возможен даже запуск нескольких экземпляров RabbitMQ на одной машине – для тестов вариант очень удобен – можно развернуть уменьшенную архитектурную копию боевого зоопарка. Такой подход позволяет гибко проводить обновление версий (если это не требует полной остановки кластера – в таком случае просто переключаем на резервный кластер и обновляемся, не забывая указать смещённый порт для работы).

В результате шаманства с cpio и путями в скриптах получили вариант сборки: две папки rabbitmq-base (в оригинальной сборке – папка mnesia) и rabbimq-main – сюда поместил все необходимые скрипты и самого кролика и эрланга.

В rabbimq-main/bin – симлинки к скриптам кролика и эрланга и скрипт слежения за кроликом (описание ниже).

В rabbimq-main/init.d – скрипт rabbitmq-server через который происходит старт/стоп/ротирование логов; в lib – сам кролик; в lib64 – erlang (используется урезанная, только для работы кролика, версия эрланга).

Если обновление затрагивает и управляющие скрипты – достаточно просто изменить в них пути на наши. Получившуюся сборку крайне просто обновлять при выходе новых версий – добавить содержимое rabbimq-main/lib и rabbimq-main/lib64 из новых версий и заменить симлинки в bin.

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

Падение ноды в 99% случаев сопровождается записью в лог, даже kill и тот оставляет следы, это позволило реализовать с помощью простого скрипта слежение за состоянием кроля. Поскольку падения кроликов событие хоть и редкое, но происходящее, требовалось воплотить механизм слежения за их самочувствием — поднятие в случае падения (с сохранением логов причин падения).

6 и 3. Для версий 3. 7 скрипт немного отличается в силу отличий записей в логах.

Для версии 3.6

#!/usr/bin/python<br>
import subprocess<br>
import os<br>
import datetime<br>
import zipfile<br>
<br>
def LastRow(fileName,MAX_ROW=200):<br>
&nbsp&nbsp&nbsp&nbspwith open(fileName,'rb') as f:<br>
&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspf.seek(-min(os.path.getsize(fileName),MAX_ROW),2)<br>
&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspreturn (f.read().splitlines())[-1]<br>
<br>
if os.path.isfile('/data/logs/rabbitmq/startup_log'):<br>
&nbsp&nbsp&nbsp&nbspif b'FAILED' in LastRow('/data/logs/rabbitmq/startup_log'):<br>
&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspproc = subprocess.Popen("ps x|grep rabbitmq-server|grep -v 'grep'", shell=True, stdout=subprocess.PIPE)<br>
&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspout = proc.stdout.readlines()<br>
&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspif str(out) == '[]':<br>
&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspcur_dt=datetime.datetime.now()<br>
&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsptry:<br>
&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspos.stat('/data/logs/rabbitmq/after_crush')<br>
&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspexcept:<br>
&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspos.mkdir('/data/logs/rabbitmq/after_crush')<br>
&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspz=zipfile.ZipFile('/data/logs/rabbitmq/after_crush/repair_log'+'-'+str(cur_dt.day).zfill(2)+str(cur_dt.month).zfill(2)+str(cur_dt.year)+'_'+str(cur_dt.hour).zfill(2)+'-'+str(cur_dt.minute).zfill(2)+'-'+str(cur_dt.second).zfill(2)+'.zip','a')<br>
&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspz.write('/data/logs/rabbitmq/startup_err','startup_err')<br>
&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspproc = subprocess.Popen("~/rabbitmq-main/init.d/rabbitmq-server start", shell=True, stdout=subprocess.PIPE)<br>
&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspout = proc.stdout.readlines()<br>
&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspz.writestr('res_restart.log',str(out))<br>
&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspz.close()<br>
&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspmy_file = open("/data/logs/rabbitmq/run.time", "a")<br>
&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspmy_file.write(str(cur_dt)+"\n")<br>
&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspmy_file.close()<br>

Для 3.7 изменяются только две строки

if (os.path.isfile('/data/logs/rabbitmq/startup_log')) and (os.path.isfile('/data/logs/rabbitmq/startup_err')):<br>
&nbsp&nbsp&nbsp&nbspif ((b' OK ' in LastRow('/data/logs/rabbitmq/startup_log')) or (b'FAILED' in LastRow('/data/logs/rabbitmq/startup_log'))) and not (b'Gracefully halting Erlang VM' in LastRow('/data/logs/rabbitmq/startup_err')):<br>

Заводим в crontab учётной записи под которой будет работать кролик (по умолчанию rabbitmq) выполнение этого скрипта (имя скрипта: check_and_run) каждую минуту (для начала просим админа выдать учётке права на использование crontab, ну а если права root есть – делаем сами):
*/1 * * * * ~/rabbitmq-main/bin/check_and_run

Второй момент использования пересобранного кроля — ротирование логов.

6)
Внеся небольшие изменения в rotate_logs_rabbitmq()
Добавляем: Поскольку мы не завязываемся на logrotate системы – используем функционал, предоставленный разработчиком: скрипт rabbitmq-server из init.d (для версии 3.

&nbsp&nbsp&nbsp&nbspfind ${RABBITMQ_LOG_BASE}/http_api/*.log.* -maxdepth 0 -type f ! -name "*.gz" | xargs -i gzip --force {}<br>
&nbsp&nbsp&nbsp&nbspfind ${RABBITMQ_LOG_BASE}/*.log.*.back -maxdepth 0 -type f | xargs -i gzip {}<br>
&nbsp&nbsp&nbsp&nbspfind ${RABBITMQ_LOG_BASE}/*.gz -type f -mtime +30 -delete<br>
&nbsp&nbsp&nbsp&nbspfind ${RABBITMQ_LOG_BASE}/http_api/*.gz -type f -mtime +30 -delete<br>

Результат запуска скрипта rabbitmq-server с ключом rotate-logs: логи сжимаются gzip-ом, и хранятся только за последние 30 дней. http_api – путь куда кролик складывает логи http – настраивается в файле конфигурации: {rabbitmq_management, [{rates_mode, detailed},{http_log_dir, path_to_logs/http_api"}]}

Информация крайне нужная, т.к. Заодно обращаю внимание на {rates_mode, detailed} – опция несколько увеличивает нагрузку, зато позволяет увидеть на WEB интерфейсе (и соответственно получить через API) информацию о том, кто публикует сообщения в эксченджи. А если озадачить все Подсистемы, работающие с кроликом, чтобы они заполняли параметры «Client properties» в свойствах своих подключений к кроликам, то можно будет на уровне коннектов детально получать информацию кто именно, куда и с какой интенсивностью публикует сообщения. все подключения идут через балансировщик – мы увидим только IP самих балансировщиков.

7 произошёл полный отказ от скрипта rabbimq-server в init.d. С выходом новых версий 3. Правда опять: немного изменим rotate_logs_rabbitmq(), поскольку в 3. С целью облегчения эксплуатации (однообразие команд управления независимо от версии кролика) и более плавного перехода между версиями, в пересобранном кролике мы продолжаем использование данного скрипта. 7 поменялся механизм именования логов после ротирования:

&nbsp&nbsp&nbsp&nbspmv ${RABBITMQ_LOG_BASE}/$NODENAME.log.0 ${RABBITMQ_LOG_BASE}/$NODENAME.log.$(date +%Y%m%d-%H%M%S).back<br>
&nbsp&nbsp&nbsp&nbspmv ${RABBITMQ_LOG_BASE}/$(echo $NODENAME)_upgrade.log.0 ${RABBITMQ_LOG_BASE}/$(echo $NODENAME)_upgrade.log.$(date +%Y%m%d-%H%M%S).back<br>
&nbsp&nbsp&nbsp&nbspfind ${RABBITMQ_LOG_BASE}/http_api/*.log.* -maxdepth 0 -type f ! -name "*.gz" | xargs -i gzip --force {}<br>
&nbsp&nbsp&nbsp&nbspfind ${RABBITMQ_LOG_BASE}/*.log.* -maxdepth 0 -type f ! -name "*.gz" | xargs -i gzip --force {}<br>
&nbsp&nbsp&nbsp&nbspfind ${RABBITMQ_LOG_BASE}/*.gz -type f -mtime +30 -delete<br>
&nbsp&nbsp&nbsp&nbspfind ${RABBITMQ_LOG_BASE}/http_api/*.gz -type f -mtime +30 -delete<br>

Теперь осталось только внести в crontab задание по ротированию логов – например каждый день в 23-00:
00 23 * * * ~/rabbitmq-main/init.d/rabbitmq-server rotate-logs

Перейдём к задачам, которые требуется решать в рамках эксплуатации «кроличьей фермы»:

  1. Манипуляции с сущностями кроликов — создание/удаление сущностей кролика: эксченджей, очередей, биндов, шовелов, пользователей, политик. Причем делать это абсолютно идентично на всех Кластерах Контура.
  2. После переключения на / с резервного Кластера требуется перенести сообщения, которые на нём остались на текущий Кластер.
  3. Создание резервных копий конфигураций всех Кластеров всех Контуров
  4. Полная синхронизация конфигураций Кластеров в рамках Контура
  5. Производить остановку/запуск кроликов
  6. Производить анализ текущих потоков данных: все ли сообщения ходят и если ходят, то куда надо или…
  7. Найти и отловить проходящие сообщения по каким-либо критериям

Эксплуатация нашего зоопарка и решение озвученных задач средствами поставляемого штатного rabbitmq_management плагина возможна, но крайне неудобна, именно поэтому была разработана и реализована оболочка для управления всем многообразием кроликов.

Теги
Показать больше

Похожие статьи

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

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

Кнопка «Наверх»
Закрыть