dev:ops:rabbitmq:queue-migration
Различия
Показаны различия между двумя версиями страницы.
| Предыдущая версия справа и слеваПредыдущая версия | |||
| dev:ops:rabbitmq:queue-migration [2026/04/23 11:48] – удалено - внешнее изменение (Дата неизвестна) 127.0.0.1 | dev:ops:rabbitmq:queue-migration [2026/04/23 11:48] (текущий) – ↷ Страница перемещена из ops:rabbitmq:queue-migration в dev:ops:rabbitmq:queue-migration Михаил Андреев | ||
|---|---|---|---|
| Строка 1: | Строка 1: | ||
| + | ====== Миграция очередей event_bus через RabbitMQ shovel ====== | ||
| + | |||
| + | Runbook на случай, | ||
| + | |||
| + | < | ||
| + | PRECONDITION_FAILED - inequivalent arg ' | ||
| + | in vhost '/': | ||
| + | </ | ||
| + | |||
| + | Первый прецедент — 17.04.2026, очереди '' | ||
| + | |||
| + | ===== TL;DR ===== | ||
| + | |||
| + | Если в код '' | ||
| + | |||
| + | **Нельзя просто удалить очередь** — все накопленные сообщения пропадут. | ||
| + | |||
| + | **Правильный путь** — shovel archive workflow (см. ниже). Минимизирует потери: | ||
| + | |||
| + | ===== Workflow ===== | ||
| + | |||
| + | На примере очереди '' | ||
| + | |||
| + | ==== 1. Создать архивную очередь с теми же bindings ==== | ||
| + | |||
| + | Важно: bindings создаём //до// любых других действий. С этого момента любая новая публикация в '' | ||
| + | |||
| + | <code bash> | ||
| + | ssh root@srv-prod-postgre.olvr | ||
| + | rabbitmqadmin -u admin -p admin declare queue name=foo_archive durable=true | ||
| + | for rk in key1 key2; do | ||
| + | rabbitmqadmin -u admin -p admin declare binding \ | ||
| + | source=event_bus destination=foo_archive routing_key=$rk | ||
| + | done | ||
| + | </ | ||
| + | |||
| + | ==== 2. Shovel: слить старую очередь в archive ==== | ||
| + | |||
| + | '' | ||
| + | |||
| + | <code bash> | ||
| + | rabbitmqctl set_parameter shovel foo-drain '{ | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | }' | ||
| + | </ | ||
| + | |||
| + | Отслеживаем прогресс через HTTP API (rabbitmqctl под нагрузкой таймаутится): | ||
| + | |||
| + | <code bash> | ||
| + | curl -s -u admin:admin \ | ||
| + | ' | ||
| + | curl -s -u admin:admin \ | ||
| + | ' | ||
| + | </ | ||
| + | |||
| + | Ждём пока '' | ||
| + | |||
| + | ==== 3. Удалить старую очередь, | ||
| + | |||
| + | <code bash> | ||
| + | rabbitmqctl clear_parameter shovel foo-drain | ||
| + | rabbitmqadmin -u admin -p admin delete queue name=foo | ||
| + | |||
| + | # Создаём новую с нужными аргументами ДО рестарта консьюмера | ||
| + | # (чтобы не было гонки между declare консьюмера и нашим) | ||
| + | rabbitmqadmin -u admin -p admin declare queue name=foo durable=true \ | ||
| + | ' | ||
| + | for rk in key1 key2; do | ||
| + | rabbitmqadmin -u admin -p admin declare binding \ | ||
| + | source=event_bus destination=foo routing_key=$rk | ||
| + | # И сразу снимаем binding с архива, | ||
| + | rabbitmqadmin -u admin -p admin delete binding \ | ||
| + | source=event_bus destination_type=queue destination=foo_archive \ | ||
| + | properties_key=$rk | ||
| + | done | ||
| + | </ | ||
| + | |||
| + | ==== 4. Рестарт консьюмера ==== | ||
| + | |||
| + | <code bash> | ||
| + | ssh root@srv-prod-app.olvr \ | ||
| + | " | ||
| + | </ | ||
| + | |||
| + | Проверяем что консьюмер подключился: | ||
| + | |||
| + | <code bash> | ||
| + | curl -s -u admin:admin \ | ||
| + | ' | ||
| + | # Ожидаем: | ||
| + | </ | ||
| + | |||
| + | ==== 5. Shovel archive → новая очередь ==== | ||
| + | |||
| + | <code bash> | ||
| + | rabbitmqctl set_parameter shovel foo-restore '{ | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | }' | ||
| + | </ | ||
| + | |||
| + | Консьюмер (если он шустрый) будет разгребать '' | ||
| + | |||
| + | ==== 6. Чистка ==== | ||
| + | |||
| + | <code bash> | ||
| + | rabbitmqctl clear_parameter shovel foo-restore | ||
| + | rabbitmqadmin -u admin -p admin delete queue name=foo_archive | ||
| + | </ | ||
| + | |||
| + | ===== Грабля 1: НЕ shovel через dest-exchange ===== | ||
| + | |||
| + | **Не использовать** '' | ||
| + | |||
| + | * На '' | ||
| + | * DLX не ловит unrouted, только rejected/ | ||
| + | |||
| + | 17.04.2026 так потеряно 83 сообщения '' | ||
| + | |||
| + | Всегда использовать '' | ||
| + | |||
| + | ===== Грабля 2: hot-patch vendor пропадает при deploy ===== | ||
| + | |||
| + | В инциденте 17.04 в контейнерах '' | ||
| + | |||
| + | Если вынуждены делать hot-patch: | ||
| + | - Обязательно заводить Jira-задачу на нормальный фикс (пересоздание очереди по этому runbook). | ||
| + | - Пометить в '' | ||
| + | |||
| + | ===== Грабля 3: rabbitmqctl может таймаутиться ===== | ||
| + | |||
| + | Под нагрузкой shovel (особенно для больших очередей — 500K+ сообщений) '' | ||
| + | |||
| + | ===== Верификация после починки ===== | ||
| + | |||
| + | - '' | ||
| + | - '' | ||
| + | - '' | ||
| + | |||
| + | ===== Связанные ссылки ===== | ||
| + | |||
| + | * OLV-3520 — ИОЛЛА: не приходят уведомления о заказах (корневая причина — очередь '' | ||
| + | * OLV-3521 — ИОЛЛА: двойная оплата переговорных (корневая причина — очередь '' | ||
| + | * [[https:// | ||
| + | * AmqpService.php: | ||
| + | |||
| + | ~~DISCUSSION~~ | ||
