Пришёл этот протокол из банковской сферы, когда один из разработчиков различных критичных участков системы решил описать наконец то, что он частенько делал для коммуникации компонент. То был John O’Hara из банка «JP Morgan Chase & Co». Почему банки? Видимо, потому что эта сфера очень чувствительна к ошибкам доставки и прочего pub/sub. Да и количество сообщений там велико.
Многие банки делали свои системы передачи сообщений, имелись даже коммерческие решения, а O’Hara написал протокол, чтобы положить конец разброду и шатанию.
И в банковской сфере таки стало по-спокойнее с этим. Появились разные реализации (AMQP-брокеры). Одна из наиболее известных — RabbitMQ.
К слову, далеко не все для обмена сообщениями используют этот протокол. В народе также прижились очереди на Redis, его pubsub — решения по-проще, надёжность не на том уровне, зато по скорости обходит кролика.
В AMQP используются следующие понятия
- Message — передаваемая информация.
- Exchange — точка обмена. На неё шлются сообщения, которые она сразу раскидывает их по очередям, не хранит.
- Queue — сами очереди. В них как раз хранятся сообщения, пока клиенты их не разберут.
- Routing key — маршрут, по которому передать сообщение (в какую очередь положить).
- Producer — источник сообщения.
- Consumer — получатель сообщения.
Также есть 3 вида сообщений, их обработки exchange’ем, складывания в очереди:
- fanout — кинуть на все очереди, которые прицеплены к exchange.
- direct — кинуть на очередь с определённым route key. Route key указывается при отправке и собственно указывает на конкретный маршрут, куда надо доставить сообщение.
- topic — в очередь будут ложиться все сообщения, чей route key будет подходить по маске (work.* -> {work.manager, work.dev}).
Про архитектуру протокола
AMQP включает в себя сохранение / форвардинг сообщений, публикацию / подписку (pubsub) на сообщения и передачу файлов.
Начинается описание протокола аж с формата кодирования информации в бинарный вид для передачи по TCP/SCTP/UPD. Что даёт хорошую интеграцию с различными протоколами транспортных уровней + оптимизирует работу с сетью.
Далее идёт RPC протокол для клиент-серверного общения. Ну и, как водится в энтерпрайзах XML!
Поддерживает JMS (Java Message Service) — популярен в кругах энтерпрайз разработки. Это некий элемент популизма — добавлено для простоты перехода. Однако, некоторые возможности потребовали расширения JMS. Например, мандатный способ доставки (Mandatory Delivery Mode): когда шлётся сообщение, но не может быть доставлено, клиент может выбрать как поступать точке обмена: просто выкинуть сообщение, либо сообщить клиенту об этом.
Протокол поощряет асинхронный стиль. Многие клиенты-consumers написаны в event oriented programming парадигме.
К слову, протокол общения клиент-сервер сильно разнится от версии к версии, так что если сервер 0-8, то и клиент тоже…
Схема работы
- Клиент (producer) посылает сообщение на точку обмена (exchange).
- Точка обмена кладёт сообщение в очереди, в зависимости от типа сообщений и route key’ев.
- Сообщения лежат в очереди, пока их не заберут клиенты, подписавшиеся на них.
- Клиенты получают сообщения и обрабатывают.
Пример
Есть класс задач, которые делать нужно, они тяжёлые и могут подождать. То, к примеру, отправка писем, генерация различных размеров картинки для предпросмотра, etc. Для таких задач используют отложенное выполнение — один из вариантов масштабирования. Но масштабирование здесь идёт не в смысле кол-ва серверов, а во времени.
Как будет выглядеть план реализации отложенных задач на AMQP:
- Создаётся durable (можно настраивать «живучесть» точек обмена — exchange persistency) точка обмена «job», работающая в режиме fanout.
- Создается durable очередь «job» и соединяется с точкой обмена.
- Producer (несколько) шлёт в точку обмена сообщения с флагом «persistent».
- Consumer (несколько) подсоединяется к очереди «job» с флагом «ACK» (не удалять из очереди, пока consumer не подтвердит выполнение).
Exchange — один, очередь — одна, producer’ов — много, consumer’ов — много.
Сообщение находится либо в очереди, либо передано только одному consumer’у.