Когда я только начал планировать эту статью, я думал, что опишу различия между протоколами AMQP и HTTP, подробно расскажу про все заголовки и зачем они нужны, и как устроены потоки передаваемых сообщений и пакетов, и прочее, и прочее, и прочее… А потом я понял, что всё это уже написали до меня. Кому надо узнать справочную информацию о протоколах, может просто погуглить. А если вы надеетесь получить эти базовые знания из этой статьи, дайте-ка я нагуглю их за вас: AMQP, HTTP. А вот если вас интересует разбор реальных случаев применения AMQP и HTTP и аргументы за и против каждого протокола, то вы пришли по адресу.

Как мы столкнулись с AMQP

Недавно мы в Live and Dev начали переводить крупный монолитный проект по электронной коммерции на микросервисы, и нам нужно было придумать, как синхронизировать данные между ядром и регионами. Ядро — это место, где расположена центральная база данных и часть проекта, отвечающая собственно за онлайн-торговлю. Регионы — это части света, где находятся компоненты (Европа, Америка, Азия). Проекту идеально подошел шаблон издатель-подписчик, потому что все данные, которые требовалось синхронизировать, всегда передаются в одном направлении. При этом шаблон позволяет менять направление и сделать подписчика издателем новых данных. То есть в случае, если в будущем возникнет нужна организовать синхронизацию в двух направлениях, такая возможность у нас есть.

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

Итак, мы наконец поняли, что делать, но ещё не придумали, как. У каждого из нас были идеи одна гениальнее другой! Начали, конечно, с самого простого варианта «сохраним где-нибудь неподтвержденные данные, и будем продолжать пробовать их передать, пока не сработает». Мы даже пытались настраивать очереди сообщений через Redis (работает хорошо, но ненадежно). А потом наткнулись на платформу RabbitMQ и протокол AMQP. Надо признать, до этого большинство членов команды про этот протокол вообще не знали. Опыта работы с очередями сообщений у нас не было, так что пришлось многому учиться с нуля. Помучившись на этапе проб и ошибок, мы наконец приручили эту технологию, а что было дальше, вы знаете. Для внутренних сообщений, которые должны выполняться асинхронно, мы используем RabbitMQ. В каждом регионе у нас по AMQP-брокеру плюс один в ядре. Для передачи сообщений между ядром и регионами мы используем плагин Shovel.

AMQP и HTTP: за и против

Мы уже год пользуемся технологией цепочек сообщений, накопили достаточный опыт, достигли отличных результатов. Брокеры RabbitMQ — основа передачи данных между компонентами нашего продукта. И все равно мы чуть ли не каждый день спорим, что лучше, AMQP или HTTP. Народ иногда даже ругается на этой почве, и приходится начинать длинные бессмысленные дискуссии о том, хорошая или плохая штука эти ваши RabbitMQ и AMQP. Обычно звучат четыре мнения (ну, по крайней мере я столько насчитал) по этому вопросы (что использовать для внутренней асинхронной передачи данных между компонентами):

  1. Мне нравится HTTP.
  2. А мне нравится AMQP.
  3. Мне без разницы, пользуюсь тем, что выбрали до меня.
  4. Не важно, какой протокол использовать, лишь бы данные были синхронизированы.

Чтобы не отклоняться от темы статьи, точки зрения из пунктов 3 и 4 предлагаю обсудить в комментариях. А тут давайте сфокусируемся на первых двух мнениях.

Предложить-то я предложил, но на самом деле для меня начинается самая сложная часть статьи. Дело в том, что «нравится» — не самое подходящее слово. Имеют ли разработчики вообще право на вкусы в технических вопросах? Или нам все-таки следует анализировать факты и выбирать то, что лучше всего подходит в каждом конкретном случае? Все-таки в нашей работе главное не инстинкты, а факты (хотя чутьё тоже важно!). Поэтому переходим к чистым фактам:

  1. Оба протокола разрешают передачу данных между компонентами
  2. Оба протокола прозрачны (всегда есть возможность отследить запросы и возвращаемые ответы)
  3. Оба протокола хорошо документирваны
  4. AMQP работает в асинхронном режиме
  5. HTTP — синхронный протокол
  6. В HTTP легко устранять баги
  7. Разработчики хорошо знают HTTP
  8. HTTP хорошо отображается в интерфейсе
  9. AMQP легко поддерживать и масштабировать
  10. AMQP гарантирует доставку сообщений
  11. Если вы используете HTTP, вам потребуется какой-нибудь механизм обнаружения сервисов
  12. Протоколу AMQP нужно знать, где расположен брокер, чтобы получить доступ к очереди для чтения или записи сообщений
  13. RabbitMQ использует механизмы разветвления и встроенные плагины shovel и federation для перемещения сообщений между брокерами
  14. Если RabbitMQ перезагружается во время незавершенной обработки сообщения, оно будет автоматически перенаправлено в очередь, где его обработает другая серверная служба
  15. HTTP поддерживается практически на всех языках программирования
  16. RabbitMQ (а, значит, и AMQP) поддерживается на нескольких языках программирования (JAVA, .NET, Ruby, Python, PHP, Objective-C, Scala, Groovy и Grails, Clojure, Jruby, Javascript, C, C ++, GO, Erlang, Haskell, OCaml, Unity 3D, Perl, Common Lisp, COBOL)

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

Плюсы HTTP

  • Устранять ошибки в HTTP-запросах очень легко, причем делать это можно многократно. Отладка сообщений AMQP сложнее (понадобится подключение к очереди, библиотеки, возможно, придется разрабатывать скрипт).
  • Разработчики знают HTTP: не нужно дополнительно обучать каждого новичка на проекте.
  • HTTP — самый поддерживаемый протокол в интернете. Поэтому полезно, чтобы у вашего API была HTTP-версия

Плюсы AMQP

  • У AMQP надежная доставка сообщений. Это асинхронный протокол, так что о доставке можно вообще не волноваться.
  • Для доставки и получения сообщений достаточно знать хост или IP кластера брокеров AMQP. В протоколе HTTP хосты и IP могут варьироваться в зависимости от региона.
  • Доступен метод разветвлений, в рамках которого одно сообщение информирует несколько разных компонентов. То есть сообщений становится меньше.

Что нужно учитывать при работе с AMQP

Чтобы доставлять и получать AMQP-сообщения, нужен брокер. Брокер — это ни что иное, как сервер, который получает, сохраняет и доставляет сообщения. В зависимости от издержек и инфраструктуры проекта брокеры способны усложнить вам жизнь, ведь вам придется настраивать и поддерживать один, несколько или целую федерацию брокеров.

Мы отдали управление серверами на аутсорс в CloudAMQP. С одной стороны теперь не приходится беспокоиться об обслуживании брокеров, но с другой — это дополнительные расходы.

Заключение (почти)

Мое мнение такое: если вы собрались общаться с внешним миром (то есть делаете публичный API), у HTTP есть всё необходимое. Везде поддерживается, все его знают и используют. Кроме того, если обнаружится проблема с передачей данных, это не ваша головная боль. Это клиенту API придется снова выполнять запрос, если что-то пошло не так.

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

У меня нет сомнений, что и HTTP, и AMQP — это очень крутые протоколы. Но только один из них по умолчанию, что очень важно, повышает надежность передачи данных, и только один легко масштабируется почти без дополнительных настроек. А поскольку запросы не блокируют работу сервисов, вы можете использовать ресурсы для других процессов.

И еще один аргумент в пользу AMQP. Зачем заново изобретать колесо и создавать собственные процессы для повышения надежности? Зачем добавлять дополнительный код, который потом нужно поддерживать? Просто потому что можем? Мой совет простой: если делаете асинхронные запросы, используйте AMQP с RabbitMQ.

Настоящее заключение

Вы наверное уже поняли, что вся эта дискуссия не имеет смысла. Искать ответ на вопрос, что лучше, HTTP или AMQP, так же нелепо, как сравнивать квадратное с мягким. Мы в Live and Dev не раз попадали в эту ловушку.

Не надо так. Сосредоточьтесь на том, что действительно важно. Почему мы выбираем ту или иную технологию? Какие достоинства и недостатки есть у нашего выбора? И как извлечь из него максимум?

Конечно, обзор выбранной инфраструктуры — вещь полезная, но только если не забывать учитывать, когда и почему мы её используем.

Перевод статьи «AMQP vs. HTTP» by Federico José Sörenson Sánchez