Web-Developer
0,0
рейтинг
16 августа 2012 в 13:26

Разработка → RabbitMQ tutorial 1 — Hello World из песочницы tutorial



RabbitMQ позволяет взаимодействовать различным программам при помощи протокола AMQP. RabbitMQ является отличным решением для построения SOA (сервис-ориентированной архитектуры) и распределением отложенных ресурсоемких задач.

Под катом перевод первого из шести уроков официального сайта. Примеры на python, но его знание вовсе не обязательно. Аналогичные примеру программы можно воспроизвести практически на любом популярном ЯП. [так выглядят комментарии переводчика, т.е. меня]


Вступление


RabbitMQ ‒ это брокер сообщений. Его основная цель ‒ принимать и отдавать сообщения. Его можно представлять себе, как почтовое отделение: когда Вы бросаете письмо в ящик, Вы можете быть уверены, что рано или поздно почтальон доставит его адресату [видимо, автор ни разу не имел дела с Почтой России]. В этой аналогии RabbitMQ является одновременно и почтовым ящиком, и почтовым отделением, и почтальоном.

Наибольшее отличие RabbitMQ от почтового отделения в том, что он не имеет дела с бумажными конвертами ‒ RabbitMQ принимает, хранит и отдает бинарные данные ‒ сообщения.

В RabbitMQ, а также обмене сообщениями в целом, используется следующая терминология:

  • Producer (поставщик) ‒ программа, отправляющая сообщения. В схемах он будет представлен кругом с буквой «P»:

  • Queue (очередь) ‒ имя «почтового ящика». Она существует внутри RabbitMQ. Хотя сообщения проходят через RabbitMQ и приложения, хранятся они только в очередях. Очередь не имеет ограничений на количество сообщений, она может принять сколь угодно большое их количество ‒ можно считать ее бесконечным буфером. Любое количество поставщиков может отправлять сообщения в одну очередь, также любое количество подписчиков может получать сообщения из одной очереди. В схемах очередь будет обозначена стеком и подписана именем:


  • Consumer (подписчик) ‒ программа, принимающая сообщения. Обычно подписчик находится в состоянии ожидания сообщений. В схемах он будет представлен кругом с буквой «C»:



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

Hello World!


Первый пример не будет особо сложным ‒ давайте просто отправим сообщение, примем его и выведем на экран. Для этого нам потребуется две программы: одна будет отправлять сообщения, другая ‒ принимать и выводить их на экран.
Общая схема такова:



Поставщик отправляет сообщения в очередь с именем «hello», а подписчик получает сообщения из этой очереди.

Библиотека RabbitMQ

RabbitMQ использует протокол AMQP. Для использования RabbitMQ необходима библиотека, поддерживающая этот протокол. Такие библиотеки можно найти практически для каждого языка программирования. Python ‒ не исключение, для него есть несколько библиотек:


В примерах будет использована библиотека pika. Ее можно установить при помощи менеджера пакетов pip:

$ sudo pip install pika==0.9.5

Если отсутствуют pip или git-core, то сначала необходимо установить их:
  • Для Ubuntu:

    $ sudo apt-get install python-pip git-core
    

  • Для Debian:

    $ sudo apt-get install python-setuptools git-core
    $ sudo easy_install pip
    

  • Для Windows (для установки easy_install необходимо запустить MS Windows Installer для setuptools):

    > easy_install pip
    > pip install pika==0.9.5
    



Отправка сообщений




Наша первая программа send.py будет просто отправлять одно сообщение в очередь.

#!/usr/bin/env python
import pika

connection = pika.BlockingConnection(pika.ConnectionParameters(
               'localhost'))
channel = connection.channel()

Мы подключились к брокеру сообщений, находящемуся на локальном хосте. Для подключения к брокеру, находящемуся на другой машине, достаточно заменить «localhost» на IP адрес этой машины.

Перед отправкой сообщения мы должны убедиться, что очередь, получающая сообщение, существует. Если отправить сообщение в несуществующую очередь, RabbitMQ его проигнорирует. Давайте создадим очередь, в которую будет отправлено сообщение, назовем ее «hello»:

channel.queue_declare(queue='hello')

Теперь все готово для отправки сообщения. Наше первое сообщение будет содержать строку «Hello World!» и будет отправлено в очередь с именем «hello».

Вообще, в RabbitMQ сообщения не отправляются непосредственно в очередь, они должны пройти через exchange (точка обмена). Но сейчас мы не будем заострять на этом внимание, точки обмена будут рассмотрены в третьем уроке. Сейчас достаточно знать, что точку обмена по-умолчанию можно определить, указав пустую строку. Это специальная точка обмена ‒ она позволяет определять, в какую именно очередь отправлено сообщение. Имя очереди должно быть определено в параметре routing_key:

channel.basic_publish(exchange='',
                      routing_key='hello',
                      body='Hello World!')
print " [x] Sent 'Hello World!'"

Перед выходом из программы необходимо убедиться, что буфер был очищен и сообщение дошло до RabbitMQ. В этом можно быть уверенным, если использовать безопасное закрытие соединения с брокером.

connection.close()

Получение сообщений




Наша вторая программа receive.py будет получать сообщения из очереди и выводить их на экран.

Также как и в первой программе сначала необходимо подключиться к RabbitMQ. Для этого следует использовать тот же код, как и ранее. Следующий шаг, как и прежде ‒ убедиться, что очередь существует. Команда queue_declare не будет создавать новую очередь, если она уже существует, поэтому сколько бы раз не была вызвана эта команда, все-равно будет создана только одна очередь.

channel.queue_declare(queue='hello')

Вы можете задаться вопросом, почему мы объявляем очередь снова, ведь она уже была объявлена в первой программе. Это нужно, чтобы быть уверенным в существовании очереди, так будет, если сначала будет запущена программа send.py. Но мы не знаем, какая программа будет запущена раньше. В таких случаях лучше объявить очередь в обеих программах.

Мониторинг очередей

Если Вы хотите посмотреть, какие очереди существуют в RabbitMQ на данный момент, Вы можете сделать это с помощью команды rabbitmqctl (потребуются права суперпользователя):

$ sudo rabbitmqctl list_queues
Listing queues ...
hello    0
...done.

(для Windows ‒ без sudo)

[в нашей компании используют более удобный скрипт мониторинга:]

watch 'sudo /usr/sbin/rabbitmqctl list_queues name messages_unacknowledged messages_ready messages durable auto_delete consumers | grep -v "\.\.\." | sort | column -t;'

[скрипт выводит и обновляет каждые 2 секунды таблицу со списком очередей: имя очереди; количество сообщений в обработке; количество сообщений готовых к обработке; общее количество сообщений; устойчивость очереди к перезагрузке сервиса; является ли временной очередью; количество подписчиков]

Получение сообщений из очереди более сложный процесс, чем отправка. Получение осуществляется при помощи подписки с использованием callback функции. При получении каждого сообщения библиотека Pika вызывает эту callback функцию. В нашем примере она будет выводить на экран текст сообщения.

def callback(ch, method, properties, body):
    print " [x] Received %r" % (body,)

Далее, нам нужно обозначить, что callback функция будет получать сообщения из очереди с именем «hello»:

channel.basic_consume(callback,
                      queue='hello',
                      no_ack=True)

Здесь необходимо быть уверенным в том, что очередь, на которую мы хотим подписаться, была объявлена. Мы сделали это ранее с помощью команды queue_declare.

Параметр no_ack будет рассмотрен позже [во втором уроке].
И, наконец, запуск бесконечного процесса, который ожидает сообщения из очереди и вызывает callback функцию, когда это необходимо.

print ' [*] Waiting for messages. To exit press CTRL+C'
channel.start_consuming()


Ну а теперь все вместе


Полный код send.py:

#!/usr/bin/env python
import pika

connection = pika.BlockingConnection(pika.ConnectionParameters(
        host='localhost'))
channel = connection.channel()

channel.queue_declare(queue='hello')

channel.basic_publish(exchange='',
                      routing_key='hello',
                      body='Hello World!')
print " [x] Sent 'Hello World!'"
connection.close()

Полный код receive.py:

#!/usr/bin/env python
import pika

connection = pika.BlockingConnection(pika.ConnectionParameters(
        host='localhost'))
channel = connection.channel()

channel.queue_declare(queue='hello')

print ' [*] Waiting for messages. To exit press CTRL+C'

def callback(ch, method, properties, body):
    print " [x] Received %r" % (body,)

channel.basic_consume(callback,
                      queue='hello',
                      no_ack=True)

channel.start_consuming()

Теперь мы можем попробовать запустить наши программы в терминале. Сначала отправим сообщение при помощи программы send.py:

$ python send.py
[x] Sent 'Hello World!'

Выполнение этой программы будет завершаться после отправки каждого сообщения. Теперь сообщение нужно получить:

$ python receive.py
[*] Waiting for messages. To exit press CTRL+C
[x] Received 'Hello World!'

Отлично! Мы отправили наше первое сообщение через RabbitMQ. Как Вы могли заметить, выполнение программы receive.py не завершилось. Она будет ожидать следующих сообщений, а остановить ее можно, нажав Ctrl+C.
Попробуйте запустить send.py снова в новом окне терминала.

Мы изучили, как отправлять и получать сообщения через именованные очереди. В следующем уроке мы создадим простую очередь задач [ресурсоемких].

UPD: библиотеку, работающую с RabbitMQ, для своего любимого ЯП Вы можете найти на официальном сайте тут.
@zTrue
карма
30,5
рейтинг 0,0
Web-Developer
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (55)

  • +4
    А планируется просто перевести 5 простейших туториалов с сайта или все же подвести к статье про использование кролика в боевых условиях?
    • +2
      Мне RabbitMQ достаточно интересен, поэтому если смогу написать о чем-то чего на хабре еще нет, то обязательно это сделаю.
    • +2
      Думаю, про боевые условия должен написать тот, кто его использует в бою…
      нам он в бою не подошел из-за большого оверхеда. Мы сделали своё маленькое чудо.
      • +3
        Раскройте секрет: на что был оверхед?
        • 0
          на чтение из очереди,
          нам не подходила скорость чтения. точных цифр уже не помню,
          кажется на наших дев машинах чтение было 4,5К запросов
          нам этого не хватало
          на машинах помощнее, Алекс (гл разработчик, фамилию забыл, надо поднимать переписку) говорил, что сервер должен держать 12К

          вообще у кролика довольно-таки обширная функциональность и использовать как простой однопоточный сервер очередей не эффективно.
          • 0
            Red Hat Enterprise MRG рассматривали в качестве брокера? Они используют модифицированнуй qpid если не ошибаюсь…
            • 0
              рассматривали, но там что-то не срослось,
              плюс дело в самом AMQP — он избыточен
    • 0
      Вот статья на тему использования в боевых условиях на нашем проекте.
  • 0
    В данном случае в типе топика указывается перевод, т.к. это перевод официальной документации.
    • 0
      для постов из песочницы нельзя указать тип, по крайней мере у меня
      • 0
        ох уж эти правила…
    • +1
      О том, что это перевод, я писал в самом начале и тоже привел ссылку на официальный сайт.
  • +2
    Для питона, имхо, более актуальные либы от проекта Celery
    pypi.python.org/pypi/amqp/0.9.2 форк amqplib
    pypi.python.org/pypi/librabbitmq/0.9.9 обертка вокруг rabbitmq-c
    Обе совместимы с amqplib и используются в kombu, который заслуживает вообще отдельной статьи.
    • 0
      rabbitmq-c немного кривовата и с недавних пор уже не поддерживается разработчиками.
      ее надо допиливать и переписывать на неблокируемые соединения, что потихоньку делается фан-клубом
      но, в принципе, большинство функционала она покрывает
      • 0
        Будут проблемы с библиотеками вроде gevent
      • 0
        используют libevent
        а в чем собственно проблема?
    • 0
      или 0MQ:
      -http://pypi.python.org/pypi/django-ztask/0.1.5 пример 0MQ обертки для django
      • 0
        Ну 0MQ всё-таки далековато от названия статьи — это другой сервер с другим протоколом и для других целей.
        0MQ спроектирован для скорости.
        RabbitMQ это может быть не такой быстрый сервер, но имеющий огромное кол-во фич и работающий по стандартному протоколу.
        • 0
          поясните пожалуйста что значит «далековато» от названия статьи? Разговор идет о message queues (не о серверах), все они используются для одно цели — создавать message queues. И что значит стандартный протокол, который 0mq не поддерживает? Ну и заодно какие фичи rabbitmq не работают в 0mq?
          • 0
            год назад в разговоре с Питером (Pieter Hintjens), он упомянул, что именно его идеи были заимствованы для создания AMQP
          • 0
            Поясняю — я смотрю в тему и вижу целых три слова. Одно из них имя собственное, а два других… вообще устойчивое выражение в программирование никак не связное с конкретной предметной областью.
            Что значит стандартный? Ну я наверно несколько переборщил, но, относительно остальных подобных протоколов, AMQP самый распространенный.

            Популярные сервера — QPid, OpenAMQ и RabbitMQ.
            Стандартное средство обмена сообщений в fedora linux(соответственно в будущем в red hat, centos, oracle linux и т.д.).
            Другие серверы — Red Hat MRG, StormMQ, SwitMQ

            Какие фичи отсутствуют в 0MQ? Ну тут конечно могли бы сами погуглить, а еще лучше поставить себе RabbitMQ.
            Для начала советую ознакомится со списком плагинов(это не что-то сторонние, а то что идет в комплекте с сервером) www.rabbitmq.com/plugins.html
            Далее можете переходит к более сложным вещам — виртуальные хосты, роутинг сообщений, федерализация… Чего стоить только возможность наладить роутинг между серверами.

            Я бы мог подробнее на чем то остановится, но сложно оценить на каком уровне Вам рассказывать, если Вы не можете сравнить один из самых простых по функциональности сервер с один из самых навороченных.
            • 0
              Спасибо, я работал с несколькими MQ, в том числе и RabbitMQ. Насчет моего уровня и того что я не могу сравнить «самых простых по функциональности сервер(???) с один из самых навороченных» — скажу лишь, что с Питером (который придумал AMQP и 0MQ) я лично работал почти 2 месяца, используя 0MQ в проекте, который вы скорей всего даже знаете и не подозреваете, что там используется самый «простой» MQ.
              Прежде чем писать что-то вроде «сложно оценить на каком уровне Вам рассказывать» сначала спросите сами себя на каком уровне вы это знаете.
              • 0
                Я вроде по русски примеры привел. Давайте подробней.
                Виды кластеризации в 0MQ?
                Роутинг по содержанию сообщения?
                WEB административная панель? Причем с очень большой функциональностью.
                Поддержка других протоколов? Stomp?
                Shovel?
                Авторизация? ACL? SSL? LDAP?
                Аналог Firehorse есть?
                TTL? и роутинг протухших сообщений?

                0MQ вообще можно писать плагины? А кастомные авторизационные бэкэнды?

                Я давно использую AMQP в проекте, который Вы наверняка знаете, ага, причем раз в 12 дольше :) Неизвестными сервисами как странно меряться :-D
                А то что на базе простого сервера можно построить сложный сервис я не утверждал.

                Если хотите ответить, то хоть раз напишите что-то конкретное, а не просто пишите про Pieter Hintjens.
                • 0
                  я в таких детских дебатах не участвую :)
                  NDA, этика и бесполезность, ввиду того, что вы толком не знаете, что такое MQ. все просто, как говорится
                  «давай, до свидания»
                  • 0
                    Прощай двухмесячный разработчик noname проекта :) Спасибо за «вагон» аргументов :)
                    • 0
                      и тебе не хворать, «специалист по гуглению», спасибо за копипаст с первой страницы поисковика и удачи в разработке больших и «навороченных» проектов, да погугли заодним что такое NDA, пригодится.
                • 0
                  btw казалось бы, куда уж конкретней ссылаться на человека, который сделал наверно больше нас с вами для amqp. писькомерением вы тут никого не удивите, гугл у всех под рукой.
                  • 0
                    Да Вы прсто жжоте напалмом!
                    Причем тут протоколы? Сравнивали два сервера, а не протоколы.
                    Вы даже не утруждаете себя понять для каких целей создавались оба сервера и поэтому пишите всякие глупости.
                    Аргумента ниодного от Вас. Факт один — Вы общались с умным человеком, что не позволяет Вам спорить без аргументов ибо золотым Вы вряд ли стали от этого разговора.

                    Я сказал, что у RabbitMQ больше функций, чем у 0MQ и аргументировал.
                    А Вы хоть про маму с папой напишите и разговор дальше уводите от темы — не интересно с Вами общаться, т.к. нет полезной инфы в сообщениях.
                    • 0
                      Я где-то утверждал, что у RabbitMQ меньше функционала, чем у 0mq? статья про использование конкретного брокера задач под python, в которой есть ссылка на библиотеки, исполняющие ampq, к которым я добавил 0mq имплементацию (которую вы неверно заклеймили не использующей ampq, вот вам полезная «инфа» кстати). Про сервера вы вообще что-то непонятное выдумали.
                      А с Питером я работал, а не просто общался, разница есть.
                      • 0
                        Нет, Вы не утверждали, а задали совершенно дурацкий вопрос «Ну и заодно какие фичи rabbitmq не работают в 0mq? » на который получили в ответ список фич, но слились в итоге на проекты, Питера и протокол.
                        • 0
                          Я задал совершенно нормальный вопрос, потому что уже почти год не смотрел на rabbitMQ, это не был вопрос с подвохом, я реально хотел узнать разницу и узнал.вы же прямо говном простите, изошли, доказывая мне, что я не имею должного бэкграунда, чтоб это понять.
                        • 0
                          А пример с проектом и Питером, я привел, чтоб доказать, что хоть что-то я да понимаю. Вас же либо зависть берет, что вы мне все пеняете, что я его упомянул, либо вам удовольствие доставляет чморит всех и вся.
                    • 0
                      Кстати в 0mq можно использовать тот же RabbitMQ, потому что это лишь одна из имплементаций amqp
  • 0
    Может кому полезно будет, реализация клиента только используя Qt4. Реализовано почти все, но для полноценной работы хватает.
    github.com/fuCtor/QAMQP

    Может быть в скором времени напишу топик с примером использования.
  • +2
    Мне кажется, что «отправитель» и «получатель» звучит в данном контексте лучше, чем «продюсер» и «клиент». Впрочем, решать автору.
    • 0
      Согласен, звучит лучше, но я под «получатель» больше представляю саму по себе программу-получатель, а под «клиент» — ее уникальный экземпляр. Например, «3 получателя» — 3 разных программы получает сообщение, у каждой из которых может быть любое количество экземпляров (клиентов).
      В общем, хотелось бы в тексте различать эти понятия — если предложите альтернативы, готов рассмотреть.
      • 0
        А зачем делать такое различие? Оно только запутывает. Появляются вопросы «на сообразительность» вроде:
        — кому будет отправлено сообщение, экземпляру или программе?
        — сколько экземпляров получат сообщение, и сколько среди них будет программ?

        А так, у вас просто есть несколько получателей, и неважно, экземпляры это одной программы или разных программ.

        А сочетание «продюсер — клиент» как-то режет слух, в отличие от: «сервер — клиент», «продюсер — консьюмер», «производитель — потребитель».
        • 0
          Я думаю, вторая и следующие части учебника, ответят на Ваши вопросы, но раз пока что еще перевода на них нет, попробую объяснить.
          Количество программ-получателей определяется логикой взаимодействия программ в системе. Например, сообщение «SMS было отправлено», могут получать программа, списывающая деньги с баланса(1) и программа-логгер(2).
          Количество экземпляров одной программы-получателя определяется загруженностью очереди. Например, если выполнение задачи занимает много времени, и один экземпляр программы не успевает обрабатывать все поступающие сообщения, то следует запустить большее количество экземпляров.
          Обычно каждая программа-получатель имеет свою очередь, которую слушают 1..n+1 экземпляров этой программы.
          • 0
            Про логику и варианты построения очередей я все прекрасно понимаю, даже хотел Вам то же самое написать, но решил, что Вы и сами в курсе.

            Тем не менее, получатель звучит как тот, кто обработает сообщение. А программу можно назвать подписчиком, как советует следующий комментатор.
            • 0
              Исправил на «поставщик» и «подписчик», спасибо Вам и akalend за замечания, сам привык к английским вариантам «продюсер» и «консьюмер».
    • 0
      >Мне кажется, что «отправитель» и «получатель» звучит в данном контексте лучше
      Вообще-то в данном контексте должно быть «Поставщик» и «Подписчик»
      особенно относится ко вторым: идет «подписка» на сообщения данного канала,
      и клиент принимает сообщения не от конкретного Отправителя сообщения, а от конкретной очереди, т.е. в ту очередь сыпятся всякие сообщения от разных Поставщиков.
      А в свою очередь — данная «Очередь» принимает сообщения от конкретной «Станции», «Коммутатора» или «Обмена». Слово «Exchange» можно перевести по разному. Думаю, Обменник — наиболее приемлемо.
      Слать сообщения в «Обменник» — могут любые Поставщики.

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

      • 0
        и реализация этой логики осуществляется через «Привязки» В оригинале это Bind
        Мы можем привязать Очередь к Обменнику. Без реализации логики привязок Подписчик не получит сообщение от Поставщика
      • 0
        С терминологией в переводе надо как-то определится.
      • 0
        Вы правы, так было бы еще лучше. Отправитель и Получатель, скорее, относятся к адресному обмену сообщениями.
  • 0
    Может кто не то сравнивал RabbitMQ и Gearman? Расскажите о достоинствах и недостатках этих решений.
  • 0
    у меня с pika постоянно проблемы какие-то были. Смотрел puka — интерфейс удобнее, но пока не было возможности ей воспользоваться.
    • 0
      Если Вам не очень важно чтоб кода было поменьше, а скорость побольше, посмотрите kombu. С ним на много проще начинать общение с сообщениями :)
      pypi.python.org/pypi/kombu/
  • 0
    Аббревиатура MQ означает Messages Queue — Очередь сообщений.
    Любой более-менее уважающий себя вендор имеет свое решения для данного вида технологии.
    В винде даже есть встроенное решение MS MQ.
    В свое время пришлось плотно поработать с IBM MQ, пришлось даже переводить сишные заголовочные файлы на Дельфи.
    В общем на рынке есть не только RabbitMQ, как может сложиться впечатление из поста.
    • 0
      На рынке много решений MQ, но ХаброНарод, в основном, интересуют открытые решения.
      RabbitMQ реализует протокол AMQP, и таких решений не много.
      Каждое решение имеет свои преимущества и недостатки и заточено под определенные задачи.
  • 0
    см мои посты про RabbitMQ
  • 0
    Опубликовал следующую часть

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.