Как реализована маршрутизация сообщений в RabbitMQ?
Что проверяют
Понимаете ли вы модель AMQP 0-9-1: продюсер пишет не в очередь, а в обменник, и судьбу сообщения решают привязки. Следом часто спрашивают, что происходит с сообщением, которое не подошло ни одной очереди.
Как отвечать
Цепочка такая: продюсер публикует сообщение в exchange с routing key, очередь привязана к exchange binding-ключом, exchange сравнивает одно с другим по своим правилам и кладёт копию в каждую подходящую очередь.
- direct: точное совпадение routing key и binding key. Одну очередь можно привязать несколькими ключами, несколько очередей одним;
- fanout: ключ игнорируется, копия уходит во все привязанные очереди. Подходит для рассылки событий;
- topic: ключ из слов через точку. В привязке
*означает ровно одно слово,#ноль или больше слов. Очередь с привязкойorder.*.createdполучитorder.eu.created, но неorder.eu.retail.created; - headers: маршрут по заголовкам сообщения, аргумент
x-matchсо значениемallилиanyзадаёт, все ли заголовки должны совпасть; - default exchange: безымянный direct-обменник
"", к которому каждая очередь автоматически привязана по своему имени. Поэтомуbasic_publish(exchange="", routing_key="tasks", body=data)выглядит как отправка прямо в очередь.
В Python это pika (синхронный, BlockingConnection нельзя делить между потоками) или aio-pika для asyncio. Типичная связка: exchange_declare(exchange="events", exchange_type="topic"), затем queue_bind(queue="billing", exchange="events", routing_key="order.#").
Для надёжности назовите publisher confirms (channel.confirm_delivery() в pika), флаг mandatory=True для возврата немаршрутизируемых сообщений, alternate exchange и dead letter exchange (x-dead-letter-exchange) для отвергнутых и просроченных.
Где спотыкаются
Не знают, что сообщение без подходящей привязки молча удаляется. Без mandatory или alternate exchange такая потеря не видна ни в логах, ни в ошибках.
Путают * и #, а заодно routing key сообщения с binding key очереди.
Ждут от fanout фильтрации по ключу или сваливают всё в одну очередь и фильтруют на стороне потребителя, хотя это задача topic или headers.