Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

Система обмена сообщениями ZeroMQ

Глава 24 из книги "Архитектура приложений с открытым исходным кодом", том 2.

Оригинал: "ZeroMQ".
Автор: Martin Sústrik, перевод: Н.Ромоданов

24.11. Шаблоны обмена сообщениями

В любой системе обмена сообщениями, наиболее важной проблемой проекта является то, каким способом пользователю приходится указывать какие сообщения направляются и в каком направлении. Существуют два основных подхода, и я считаю, что такая дихотомия вполне универсальна и применима практически для любой проблемы, возникающей в области программного обеспечения.

Один из подходов заключается в принятии философии Unix «делать одно и делать это хорошо». Это означает, что область проблемы должна быть искусственно ограничена небольшой и хорошо понятной частью. Затем программа должна решить эту ограниченную задачу правильно и исчерпывающее. Примером такого подхода в сфере обмена сообщениями является MQTT. Это протокол распределенных сообщений для группы потребителей. Он не может использоваться ни для чего другого (скажем, для RPC), но он прост в использовании и хорошо работает с распределенными сообщениями.

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

В ØMQ выбрана первая модель, поскольку в ней предполагается, что полученным продуктом сможет пользоваться в основном каждый, тогда как обобщенная модель для того, чтобы ей пользоваться, требует экспертов в области обмена сообщений. Чтобы это продемонстрировать, давайте посмотрим, как модель влияет на сложность API. Далее приведена реализация клиентской части RPC, построенная поверх обобщенной системы (AMQP):

connect ("192.168.0.111")
exchange.declare (exchange="requests", type="direct", passive=false,
    durable=true, no-wait=true, arguments={})
exchange.declare (exchange="replies", type="direct", passive=false,
    durable=true, no-wait=true, arguments={})
reply-queue = queue.declare (queue="", passive=false, durable=false,
    exclusive=true, auto-delete=true, no-wait=false, arguments={})
queue.bind (queue=reply-queue, exchange="replies",
    routing-key=reply-queue)
queue.consume (queue=reply-queue, consumer-tag="", no-local=false,
    no-ack=false, exclusive=true, no-wait=true, arguments={})
request = new-message ("Hello World!")
request.reply-to = reply-queue
request.correlation-id = generate-unique-id ()
basic.publish (exchange="requests", routing-key="my-service",
    mandatory=true, immediate=false)
reply = get-message ()

С другой стороны, ØMQ разбивает ландшафт обмена сообщениями на так называемые «шаблоны сообщений». Примерами шаблонов являются «публикация/подписка», «запрос/ответ» или «распараллеливаемый конвейер». Каждый шаблон обмена сообщениями полностью ортогонален другим шаблонам и может рассматриваться как отдельный инструмент.

Далее приведена еще одна реализация вышеприведенного приложения, выполненная в ØMQ с использованием шаблона «запрос/ответ». Обратите внимание на то, что все настройки сводятся к одному шагу выбора правильного шаблона обмена сообщениями («REQ»):

s = socket (REQ)
s.connect ("tcp://192.168.0.111:5555")
s.send ("Hello World!")
reply = s.recv ()

До этого момента мы утверждали, что конкретные решения лучше, чем обобщенные. Мы хотим, чтобы наши решения, чтобы быть как можно более конкретными. Тем не менее, мы одновременно хотим, насколько это окажется возможным, предложить нашим клиентам максимально широкий спектр функциональных возможностей. Как мы можем решить это кажущееся противоречие?

Ответ состоит из двух шагов:

  1. Определение слоя стека, который касается конкретной проблемной области (например, транспорт, маршрутизация, презентация и т.д.).
  2. Предоставление нескольких реализаций слоя. Это должны быть непересекающиеся реализации, отдельные для каждого варианта использования.

Давайте посмотрим на пример транспортного уровня стека Internet. Он предназначен для предоставления таких сервисов, как передача потоков данных, управления потоками, обеспечение надежности передачи и т.д., которые реализуются поверх сетевого уровня (IP). Он реализуется в соответствие с определением нескольких непересекающихся решений: TCP для соединений, ориентированных на надежную передачу потока, UDP для соединения с ненадежной пакетной передачей, SCTP для передачи нескольких потоков, DCCP для ненадежных соединений и так далее.

Обратите внимание, что каждая реализация полностью ортогональна: конечная точка UDP не может обмениваться сообщениями с конечной точкой TCP. А конечная точка SCTP не может обмениваться сообщениями с конечной точкой DCCP. Это означает, что в любой момент к стеку могут быть добавлены новые реализации без влияния на существующие части стека. И наоборот, о неудачных реализациях можно будет забыть и можно будет выбросить их без ущерба для жизнеспособности транспортного уровня в целом.

Тот же принцип относится и к шаблонам обмена сообщениями так, как это сделано в ØMQ. Шаблоны обмена сообщениями формируют слой (так называемый «слой масштабируемости») поверх транспортного уровня (TCP и аналоги). Реализациями этого слоя являются индивидуальные шаблоны обмена сообщениями. Они строго ортогональны — конечная точка «публикации/подписки» не может обмениваться сообщениями с конечной точкой «запроса/ответа» и т.д. Строгое разделение между шаблонами в свою очередь означает, что по мере необходимости могут быть добавлены новые шаблоны и что неудачные эксперименты с новыми шаблонами не повредят существующим шаблонам.

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

24.12. Заключение

Поскольку наш мир заселяется большим количеством маленьких компьютеров, подключаемых через Интернет - мобильными телефонами, считывателями меток RFID, планшетами и ноутбуками, устройствами GPS и т. д. - проблема распределенных вычислений перестает быть областью академической науки и становится повседневной проблемой, которую решает каждый разработчик. Решения, к сожалению, в основном являются предметно-ориентированными хакерскими трюками. Эта статья подытоживает наш опыт построения крупномасштабной распределенной системы на систематической основе. Она фокусируется на проблемах, которые представляют интерес с точки зрения архитектуры программ, и мы надеемся, что разработчики и программисты из сообщества сторонников открытого кода посчитают ее полезной.

Creative Commons. Перевод был сделан в соответствие с лицензией Creative Commons. С русским вариантом лицензии можно ознакомиться здесь.


Далее: К началу статьи