Глава 3. Экскурс вглубь свойств сообщения

Эта глава рассматривает

  • Свойства сообщение и их воздействие на доставку сообщений

  • Применение свойств сообщения для создания некоторого контракта между издателем и потребителем

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

При различных типах сообщений и отсутствии стандартизации формата сообщений становится трудно предсказывать как некий определённый тип сообщений должен упорядочиваться и какие данные должны содержать определённые типа сообщений. Разработчики должны публиковать сообщения в некоем формате, который имеет смысл для их приложения и их применения самого по себе. Хотя они и выполнили свои собственные задачи, такой образ мышления был близоруким. Мы стали замечать что сообщения могут применяться вновь и вновь во множестве приложений и произвольные решения о формате становятся проблематичными. Стремясь облегчить растущую головную боль вокруг этих проблем мы уделяли больше внимания описанию отправляемого сообщения как в документации, так и как часть самого по себе сообщения.

Для обеспечения согласованного метода для самостоятельного описания наших сообщений мы рассмотрели Basic.Properties, некую структуру данных AMQP, которая передаётся совместно с каждым сообщением, публикуемым через AMQP в RabbitMQ. Применение Basic.Properties открывает имеющиеся двери для более интеллектуальных потребителей - приложения потребителей, которые могут автоматически преобразовывать получаемые сообщения, удостоверять само происхождение некоторого сообщения и его тип перед обработкой, а также много чего ещё. В данной главе мы рассмотрим Basic.Properties вглубь, обсуждая каждое его свойство и для чего оно предназначено.

Надлежащее использование свойств

Как вы помните по Главе 2, при публикации вами сообщения в RabbitMQ ваше сообщение составляется из трёх типов кадров нижнего уровня согласно спецификации AMQP: кадра метода Basic.Publish, кадра заголовка содержимого и кадра тела. Эти три типа кадров работают сообща в последовательности чтобы направить ваши сообщения по их назначению и гарантировать их целостность после доставки (Рисунок 3-1).

 

Рисунок 3-1


Три компонента публикуемого в RabbitMQ метода

Все содержащиеся в кадре заголовка свойства сообщения являются предварительно определённым набором значений, определяемых структурой данных Basic.Properties (Рисунок 3-2). Некоторые свойства, такие как delivery-mode имеют хорошо определённые значения в спецификации AMQP, в то время как другие, например type, не имеют точного определения.

 

Рисунок 3-2


Basic.Properties, включая объявленное устаревшим в AMQP-0-8 свойство cluster-id

В некоторых случаях RabbitMQ применяет чётко определённые свойства для реализации определённого поведения в зависимости от самого сообщения. Неким примером такого использования может служить упомянутое ранее свойство delivery-mode. Значение свойства delivery-mode сообщит RabbirMQ позволено ли ему сохранять данное сообщение в памяти при помещении этого сообщения в некую очередь или ему требуется вначале сохранить данное сообщение на диск.

[Совет]Совет

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

Раз уж мы рассмотрели процесс стандартизации сообщений, эти свойства сообщения AMQP могут послужить полезной отправной точкой для определения и переноса метаданных о некотором сообщении. такие метаданные, в свою очередь, позволяют своему читателю создавать строгие контракты между издателями и потребителями. Многие из имеющихся атрибутов, начиная с content-type и типа сообщения (type) вплоть до timestamp и идентификатора приложения (app-id), доказали свою полезность не только для состоятельности в процессе разработки, но и при их использовании в повседневной работе. Если коротко, применяя свойства сообщения вы можете создавать сообщения с самоопределением, аналогично тому как XML рассматривается как разметка данных с самостоятельным определением.

В этой главе мы рассмотрим каждое из базовых свойств, выделенных в Рисунке 3-2:

  • Применение свойства content-type позволяет пользователю знать как интерпретировать само тело сообщения

  • Использование content-encoding указывает что тело данного сообщения может быть сжато или закодировано неким особым образом

  • Свойства message-id и correlation-id уникально идентифицируют сообщения и отклики на сообщение, отслеживая данное сообщение в вашем рабочем потоке

  • Усиление свойством timestamp уменьшает размер сообщения и создаёт некое каноническое определение того когда было создано сообщение

  • Срок истечения времени жизни сообщения содержится в свойстве expiration

  • Для того чтобы указать RabbitMQ записывать ли ваши сообщения в очереди её хранением на диске или в оперативной памяти применяется delivery-mode

  • Использование app-id и user-id помогает выявлять имеющих проблемы издателей

  • Применение свойства type определяет некий контракт с издателями и потребителями

  • Маршрутизация откликов сообщений при реализации шаблона пользуется свойством reply-to.

  • Свойства таблицы headers применяются для свободной формы определений свойств и маршрутизации RabbirMQ

Мы также затронем то, почему вы захотите избегать использования свойства priority и что случится с вашим свойством cluster-id и почему вы не можете применять его.

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

[Замечание]Замечание

Когда я применяю термин "контракт" в отношении сообщения, я подразумеваю спецификации для его формата и содержимого сообщения. В программировании это термин часто применяется для описания предварительно определённой спецификации API, объектов и систем. Спецификации контракта часто содержат точную информацию о передаваемых и принимаемых данных, например, допустимый тип данных, их формат и все условия, которые должны быть применимы к ним.

Создание контракта явного сообщения с content-type

Как я быстро определил, очень просто найти новые способы применения публикации сообщений с помощью RabbitMQ. Наше первичное приложение потребителя было написано на Python, но в скором времени сообщения потреблялись приложениями, написанными на PHP, Java и C.

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

Структура данных Basic.Properties определяет свойство content-type для транспортировки необходимого формата ваших данных в передаваемом теле сообщения (Рисунок 3-3).

 

Рисунок 3-3


Свойство content-type является самым первым свойством в Basic.Properties.

Как и в различных стандартных спецификациях HTTP, content-type переправляет определяемый тип MIME тела своего сообщения. Если ваше приложение отправляет упорядоченные в виде JSON значения данных, например, установив значение свойства content-type в application/json, это позволяет ещё- не- разработанному приложению инспектировать данный тип сообщения по его получению и корректным образом декодировать данное сообщение.

[Замечание]Размышления о самоописании сообщений и содержимом сообщений

Широко применяются стандартные форматы упорядочения данных, такие как JSON, Msgpack (msgpack.org) или XML. Эти форматы позволяют создавать любое количество потребительских приложений практически на любом языке программирования. Поскольку данные самостоятельно себя описывают в этих форматах, более просто писать последующие потребительские приложения, причём их легче декодировать из провода вне вашего основного приложения.

Кроме того, определяя конкретный формат упорядочения в передаваемом свойстве content-type, вы сможете надёжно защищать свои приложения. Когда потребители могут автоматически распознавать получаемые поддерживаемые ими форматы упорядочения и имеют возможность выборочно обрабатывать сообщения, вам нет нужды беспокоиться о том что произойдёт когда применяется и маршрутизируется в тех же самых очередях какой- то новый формат представления.

Если для своего потребительского кода вы применяете некую инфраструктуру, вы можете пожелать сделать его умным в отношении того что делать с получаемыми сообщениями. При наличии такой инфраструктуры предварительной обработки поступающих сообщений прежде чем обработать их в своём потребительском коде, тело сообщения может автоматически разбираться и загружаться в естественные структуры данных в вашем языке программирования. Например, в Python ваша инфраструктура может определять получаемый тип сообщения в его заголовке content-type и, применяя эту информацию, она может выполнять автоматический разбор тела сообщения и помещать содержимое в dict, list или иной естественный тип данных. Это в конечном итоге снизит сложность вашего кода в вашем потребительском приложении.

Уменьшение размера сообщения при помощи gzip и content-encoding

Отправляемые через AMQP сообщения по умолчанию не сжимаются. Это может быть проблематично с чрезмерно подробной разметкой, такой как XML, или даже с большими сообщениями, использующими менее интенсивно разбиваемые на поля форматы, такие как JSON или YAML. Ваши издатели могут сжимать сообщения до их публикации и распаковывать их при получении, подобно тому, как веб- страницы могут быть сжаты на сервере с помощью gzip, а браузер может распаковывать их на лету до построения изображения.

Чтобы обозначить этот процесс в явном виде AMQP определяет свойство content-encoding (Рисунок 3-4).

 

Рисунок 3-4


Свойство content-encoding указывает применяется ли особенное кодирование в самом теле сообщения.

Теперь более предпочтительно изменить имеющийся контракт данного опубликованного и потреблённого в производстве сообщения, тем самым минимизировав любые потенциальные эффекты имеющегося изначально кода. Однако, если размер сообщения воздействует на общую производительность и стабильность, его заголовок content-encoding позволит вашим потребителям заранее квалифицировать сообщения, гарантируя что они смогут декодироваться из какого бы то ни было формата тела данного отосланного сообщения.

[Замечание]Замечание

Не путайте content-encoding с content-type. Как и в спецификации HTTP, content-encoding применяется дл\ указания некоторого уровня кодирования после content-type. Это поле модификатора, которое часто применяется для указания того, что всё содержимое тела данного сообщения было сжато с применением gzip или какой- то иной формы сжатия. Некоторые клиенты AMQP автоматически устанавливают значение content-encoding в UTF-8, однако это неверное поведение. Спецификация AMQP постулирует,что content-encoding применяется для хранения MIME кодировки содержимого.

Чтобы провести параллель, MIME язык разметки электронной почты применяет поле content-encoding для указания определённой кодировки в каждой из своих различных частей данного электронного письма. В электронном письме наиболее применяемыми типами являются Base64 и Quoted-Printable. Кодирование Base64 применяется для гарантии того, что передаваемые двоичные данные в этом сообщении не нарушат протокол SMTP, содержащий только текст. Например, если вы создаёте некое сообщение электронного письма на основании HTTP со встроенными изображениями, эти встроенные изображения скорее всего будут закодированы в Base64.

В отличии от SMTP, однако, AMQP является бинарным протоколом. Всё содержимое в теле его сообщения передаётся так, как если бы оно не было закодировано или преобразовывалось в соответствующих процессах упорядочения (marshaling) и разборки (remarshaling). Вне зависимости от формата любое содержимое может быть передано без рассмотрения нарушений данного протокола.

[Замечание]Усиление применимости потребительских инфраструктур

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

Мы обсудим общие потребительские схем более подробно в Главе 5.

Совмещение свойства content-encoding со свойством content-type придаёт дополнительную мощность потребляющему приложению в обработке некоторого подробного контракта его издателей. Это позволяет вам создавать непробиваемый в последующем код, упрочняя его по отношению к неожиданным ошибкам, вызываемыми изменениями в формате сообщений. Например, в некий момент жизненного цикла вашего приложения вы можете обнаружить, что сжатие bzip2 лучше подходит для содержимого ваших сообщений. Если ваш код в потребляющем приложении опрашивает свойство content-encoding, он может затем отвергать сообщения, которые не может декодировать. Те потребители, которые знают что они могут развёртывать только при помощи zlib или deflate будут отвергать новые сообщения, сжатые bzip2, оставляя их в очереди для прочих потребляющих приложений, которые способны выполнять развёртывание сообщений bzip2.

Ссылочные сообщения с применением message-id и correlation-id

В спецификации AMQP message-id и correlation-id определены "для приложений пользователя" и не имеют формально определяемого поведения (Рисунок 3-5). Это означает, что то что касается самой спецификации, вы можете применять их в любых целях по своему усмотрению. Оба поля допускают до 255 байт закодированных UTF-8 данных и хранят несжатые значения, встраиваемые в структуру данных Basic.Properties.

 

Рисунок 3-5


Свойства message-id и correlation-id могут применяться для отслеживания персональных сообщений и сообщений откликов по мере их прохождения в вашей системе.

Message-id

Некоторые типы сообщений, в примеру, такие как события регистрации, скорее всего не нуждаются в связанных с ними уникальных идентификаторах сообщения, однако легко представить типы сообщений, которым они бы не помешали, скажем, ордеры продажи или запросы на сопровождение. Свойство message-id позволяет данному сообщению переносить данные в своём заголовке, которые уникальным образом идентифицируют его в потоке через различные компоненты в слабо связанной системе.

Correlation-id

Хотя и формальное определение для correlation-id в имеющейся спецификации AMQP отсутствует, оно используется для указания того, что данное сообщение является откликом на другое сообщение, перенося значение message-id того сообщения. Другим вариантом является его применение для переноса некоего идентификатора транзакции или иных аналогичных данных, которые могут относиться к определённому сообщению.

Установка даты порождения: свойство timestamp

Одним из наиболее полезных полей в Basic.Properties является свойство timestamp (Рисунок 3-6). Наряду с message-id и correlation-id timestamp определяется как "используемый для приложения". Даже если ваше сообщение не применяет его, значение свойства timestamp очень полезно когда вы пробуете диагностировать любой вид неожиданного поведения в своём потоке сообщений, проходящем через RabbitMQ. Используя значение свойства timestamp для указания того, когда приложение было создано, потребители могут калибровать производительность доставки сообщения.

 

Рисунок 3-6


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

Существует ли соглашение об уровне обслуживания (SLA, service level agreement), которое должны выполнять ваши процессы? Вычисляя timestamp в свойствах сообщения, ваши потребительские приложения могут принимать решение, будут ли они обрабатывать сообщение, отбрасывать его или даже публиковать предупреждающее сообщение в приложении мониторинга, чтобы кто-то знал, что возраст сообщения превышает желаемое значение.

Значение timestamp отправляется как эпоха Unix или timestamp на основе целого значения, указывающее численная величина, исчисляемая с полуночи 1 января 1070. Например, полночь 2 февраля 2002 должна быть представлена как целочисленное значение 1329696000. Будучи закодированным как целочисленная величина, timestamp занимает всего лишь 8 байт в объёме вашего сообщения. К сожалению, для значения timestamp нет контекста временной зоны, поэтому предлагается применять UTC или иную подходящую зону времени по всем вашим сообщениям. Устанавливая стандарт часового пояса, вы избегаете любых проблем в будущем, которые могут возникнуть как результате того, что ваши сообщения перемещаются по часовым поясам географически распределённых брокеров RabbitMQ.

Автоматическое истечение срока сообщения

Свойство expiration сообщает RabbitMQ когда стоит отвергать сообщение если оно не было потреблено. Хотя свойство expiration (Рисунок 3-7) имеется в обеих версиях AMQP, и в 0-8, и в 0-9-1, оно не поддерживалось в RabbitMQ вплоть до выпуска версии 3.0. Кроме того, само определение свойства expiration слегка странное; оно предписывает "применяться для реализации; никакого формального поведения", что подразумевает, что RabbitMQ может тем не менее реализовать его по своему усмотрению. Одна завершающая странность состоит в том, что оно определено как короткая строка, допускающая до 255 символов, в то время как другое представляющее единицы времени свойство, timestamp, является целочисленным значением.

 

Рисунок 3-7


Для использования свойства expiration в rabbitMQ, установите необходимое строковое значение для мременного штампа Unix, обозначающее максимальное значение, для которого данное сообщение всё ещё остаётся в силе.

Из- за имеющейся неопределённости в спецификации, применяемое значение expiration с большой вероятностью может иметь различные реализации при применении различных брокеров обмена сообщениями или даже различные версии одного и того же брокера обмена сообщениями. Для автоматического исетчения срока действия сообщений при использовании в RabbitMQ рассматриваемого свойства expiration оно должно содержать некую эпоху Unix, или временной штамп на основе целочисленного значения, но хранить его в виде строки. Вместо хранения некоторого временного штампа в формате ISO-8601, например, "2002-02-20T00:00:00-00", вы должны установить его строковое значение в эквивалент, представленный как "1329696000".

При применении данного свойства expiration, если некое сообщение публикуется в имеющемся сервере с уже истекшим штампом времени, такое сообщение не будет перенаправляться ни в какие очереди, а вместо этого будет отвергаться.

Также стоит отметить, что у RabbitMQ имеются и прочие средства управления сроком истечения времени действия ваших сообщений только при определённых обстоятельствах. При определении некоей очереди вы можете передать ей аргумент x-message-ttl одновременно с её определением. Данное значение также должно быть неким временным штампом эпохи Unix, однако оно применяет точность в миллисекундах (value*1000) в качестве некоторого целого значения. Данное значение инструктирует свою очередь автоматически отвергать сообщения, если указанное время истекло. Этот аргумент очереди x-message-ttl и параметры его измерения при его использовании будут более подробно обсуждены в Главе 5.

Балансировка скорости и безопасности с помощью delivery-mode

Свойство delivery-mode является байтовым полем, которое указывает использующему его брокеру обмена сообщениями что вы желаете оставить данное сообщение на диске прежде чем оно будет доставлено любому ожидающему его потребителю (Рисунок 3-8). В RabbitMQ оставление (persisting) некоторого сообщения означает, что оно будет оставаться в данной очереди пока не будет потреблено, даже в случае перезапуска данного сервера RabbitMQ. Данное свойство delivery-mode имеет два возможных значения: 1 для не оставляемых сообщений и 2 для оставляемых сообщений.

 

Рисунок 3-8


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

[Замечание]Замечание

При первом изучении различных терминов и установок в RabbitMQ, оставление (persistence) может зачастую путаться с с установкой durable (долговременное) в очереди. Атрибут долговременности очереди указывает RabbitMQ должно ли данное определение очереди выживать при повторном запуске своего сервера или кластера RabbitMQ. Только значение delivery-mode некоторого сообщения будет указывать rabbitMQ будет ли оставаться какое- то сообщение или нет. Очередь может содержать оставляемые и не оставляемые сообщения. Долговременность очереди обсуждается в Главе 4.

Как иллюстрирует Рисунке 3-9, определение вашего сообщения как не оставляемого позволит RabbitMQ применять очереди, располагаемые только в оперативной памяти.

 

Рисунок 3-9


Публикация сообщений в очереди оперативной памяти.

Так как ввод/ вывод в оперативной памяти быстрее дискового ввода/ вывода, определение delivery-mode равным 1 будет осуществлять доставку ваших сообщений с настолько малой латентностью, насколько она возможна. В моём случае с регистрацией веб приложения данный выбор режима доставки может быть более простым, нежели в прочих случаях. Хотя и желательно не терять никакие события регистрации в случае падения какого- то сервера RabbitMQ, как правило, это не строгое требование. В случае когда данные события регистрации участника утрачены, вряд ли пострадает сам бизнес. В данном случае мы применяем delivery-mode:1. Однако, если вы применяете RabbitMQ для публикации данных финансовой транзакции, а архитектура вашего приложения сосредоточена на обеспечении доставки вместо пропускной способности обмена сообщения, вы можете разрешить оставление определив delivery-mode:2. как показывает Рисунок 3-10, при определении режима доставки равным 2, сообщения оставляются в очереди, базирующейся на диске.

 

Рисунок 3-10


Публикация сообщений в очереди, располагающиеся на диске.

Хотя это предоставляет некую гарантию того, что сообщения не будут утрачены в случае краха брокера обмена сообщениями, это влечёт за собой потенциальные трудности с производительностью и масштабированием. Свойство delivery-mode имеет настолько значительное воздействие на доставку и производительность, что оно более подробно рассматривается в Главе 4.

Удоствоверение происхождения сообщения через app-id и user-id

Свойства app-id и user-id предоставляют другой уровень информации о сообщении и имеют множество потенциальных применений Рисунок 3-11. Как и в случае прочих свойств, которые могут применяться для специфического поведения контракта в данном сообщении, эти два свойства способны переносить информацию, которую ваше потребительское приложение может проверять перед обработкой.

 

Рисунок 3-11


Свойства app-id и user-id являются последними в имеющихся значениях Basic.Properties и они могут применяться для идентификации своего источника сообщения.

app-id

Свойство app-id определяется в существующей спецификации AMQP как "короткая строка", допускающая до 255 символов UTF-8. Если ваше приложение имеет сосредоточенную вокруг API архитектуру с поддержкой версий, вы можете применять свойство app-id для переправки той специфичности API и версии, которая применялась при создании данного сообщения. В качестве метода усиления контракта между издателем и потребителем, опрос свойства app-id перед тем как выполнить обработку позволит вашему приложению отвергнуть полученное сообщение если оно происходит от неизвестного или не поддерживаемого источника.

Другое возможное применение для app-id состоит в сборе статистических данных. Например, если вы применяете сообщения для переправки событий регистрации, вы можете установить данное свойство app-id для платформы и версии того приложения, которое переключила это событие регистрации. В среде, в которой вы можете иметь приложения на базе веб интерфейса, настольные системы и мобильных клиентов, это может стать великолепным способом прозрачным образом как исполнять некий контракт, так и выделять данные для отслеживания регистраций в соответствии с платформой, причём без какой бы то ни было инспекции самого тела сообщения. Это в особенности удобно если вы желаете иметь потребителей с единственной целью допускали сбор статистики потребителей, которые ожидают те же самые сообщения что и ваш потребитель, обрабатывающий регистрацию. Предоставляя такое свойство app-id сбор статистики потребителем не требует разбора или декодирования самого тела сообщения.

[Совет]Совет

Когда вы пытаетесь отслеживать непослушные сообщения в своих очередях, принуждение к применению app-id может упростить такое выявление обратного пути к источнику данного неправильного сообщения. Это особенно полезно в крупных средах, где многие приложения совместно применяют одну и ту же инфраструктуру RabbitMQ и новый издатель может ошибочно применять тот же самый обмен и ключ маршрутизации что и уже имеющееся публикующее приложение.

user-id

При использовании аутентификации пользователя может показаться очевидным применение свойства user-id для указания того пользователя, который зарегистрировался, но в большинстве случаев это нецелесообразно. RabbitMQ проверяет все сообщения опубликованные со значением в имеющемся свойстве user-id для того пользователя RabbitMQ, который опубликовал это сообщение и если эти два значения не совпадают, данное сообщение отклоняется. Например, если ваше приложение прошло аутентификацию в RabbitMQ с пользователем "www", а его свойство user-id установлено в значение "linus", данное сообщение будет отвергнуто.

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

Определение особенностей сообщения свойством типа сообщения

Версия 0-9-1 спецификации AMQP определило свойство type в Basic.Properties как "название типа сообщения" сообщив, что оно служит для применения в приложении и не имеет формализованного определения Рисунок 3-12. Хотя имеющееся значение routing-key в комбинации с exchange зачастую может переносить столько информации о данном сообщении, сколько ему требуется для определения своего содержимого, данное свойство type добавляет иной инструмент вашему приложению, который способен определять как обрабатывать сообщение.

 

Рисунок 3-12


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

[Замечание]Когда самостоятельно определяющиеся форматы упорядочения не являются достаточно быстрыми

Свойство type может оказываться очень полезным при создании самостоятельно определяемых сообщений, в особенности когда само тело сообщения не упорядочено в самостоятельно определяемом формате данных. Такие самостоятельно определяющиеся форматы данных как JSON и XML рассматриваются кое- кем как черезчур многословные. Он также мгут нести не нужные накладные расходы на саму линию связи или на оперативную память, а также приводить к замедлению из- за упорядочения и разбора в некоторых языках. Если какая- то из этих проблем имеется и у вас, вы можете выбрать некий формат упорядочения, такой как Apache Thrift или Google Protobuf). В отличии от MessagePack. Эти кодируемые двоично форматы сообщений не являются самостоятельно описываемыми и требуют некоторого внешнего фала описания для упорядочения и разбора. Такая внешняя зависимость и отсутствие самостоятельного определения делают возможной меньшие полезные нагрузки в линии связи, однако имеют собственные компромиссы.

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

В моём примере публикации событий регистрации участника, когда наступает время сохранить это событие в хранилище данных, мы считаем полезным переносить значение типа сообщения вместе с самим сообщением. Для подготовки этих событий к сохранению в хранилище данных они вначале должны быть запомнены во временном местоположении, а затем некий пакетный процесс считывает их и сохраняет их уже в необходимом хранилище. Поскольку это очень распространённый процесс, отдельный потребитель выполняет все фазы выделения общего процесса ETL (extract-transform-load - выделить- преобразовать- загрузить) с помощью какой- то общей очереди для обработки всех имеющихся сообщений. Такой потребитель очереди ETL обрабатывает множество типов сообщений и использует имеющееся свойство type для принятия решения о том, в какой системе, таблице или кластере сохранять выделяемые данные.

[Замечание]Замечание

Обработка ETL является некоторой стандартной практикой при которой выделяются данные OLTP и в конечном итоге загружаются в некое хранилище данных с целью выработки отчётов. Если вы желаете подробнее ознакомиться с обработкой ETL, в Wikipedia имеется очень хорошая статья с описанием каждого этапа, производительности ETL, обычно возникающих проблем и связанных с этим предметов. .

Применение reply-to для динамических рабочих потоков

В запутанном и кратком определении в спецификации AMQP свойство span class="term">reply-to не имеет формально определяемого поведения и также отдаётся на откуп для использования приложением (Рисунок 3-13). В отличии от упоминавшихся ранее свойств, оно имеет предупреждение: reply-to может применяться для обозначения частного отклика очереди в виде реплик на сообщение. Хотя точное определение частного отклика очереди и не постулируется в спецификации AMQP, данное свойство запросто может переносить либо определённое имя очереди, либо ключ маршрутизации в качестве ответа в некотором обмене через который данное сообщение первоначально было опубликовано.

 

Рисунок 3-13


Свойство reply-to не имеет формального определения, однако может нести некий ключ маршрутизации или название очереди, которые могут применяться для откликов на данное сообщение.

[Предостережение]Предостережение

В версии 0-9-1 спецификации AMQP имеется некое предупреждение для reply-to, которое постулирует что оно "может содержать определённое название какой- то частной очереди отклика в случае применения в сообщениях запроса". В определении этого свойства достаточно двусмысленности, поэтому его следует использовать с осторожностью. Хотя вряд ли будущие версии RabbitMQ будут обеспечивать маршрутизацию ответных сообщений во время публикации, лучше принять меры предосторожности, чем потом сожалеть. Учитывая поведение RabbitMQ в отношении свойства user-to и неоднозначность спецификации в отношении данного свойства, RabbitMQ не будет необоснованным отрицать публикацию какого- то сообщения, если ответные сообщения не будут маршрутизироваться из-за информации в свойстве reply-to.

Индивидуализация свойств при помощи атрибутов заголовка

Свойство headers является таблицей ключ/ значение, которое допускает произвольные, определяемые пользователем ключи и значения (Рисунок 3-14). Ключи могут быть строками ASCII или Unicode, которые имеют максимальную длину в 255 символов. Значения могут быть любым допустимым типом значения AMQP.

 

Рисунок 3-14


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

В отличии от прочих свойств, данное свойство headers позволяет вам добавлять любые данные, которые вы пожелаете в данный заголовок таблицы. Оно также имеет и иное уникальное свойство: RabbitMQ способен перенаправлять сообщения но основе тех значений, которыми заполнен такой headers таблицы вместо того чтобы полагаться на имеющийся ключ маршрутизации. Маршрутизация сообщений через данное свойство headers рассматривается в Главе 6.

Приоритеты атрибутов

В RabbitMQ 3.5.0 было реализовано поле priority как это определено в спецификации AMQP. Оно определяется как некое целое с возможными значениями от 0 до 9 подлежащими к применению для установки приоритета сообщения в очереди. Согласно спецификации, если публикуется некое сообщение с приоритетом 9, а вслед за ним публикуется сообщение с приоритетом 0, вновь подключающийся потребитель получит тот сообщение, которое имеет приоритет 0 прежде чем сообщение с приоритетом 9. Занимательно, что RabbitMQ реализует это поле priority как байтовое значение без знака, поэтому приоритетами могут быть значения от 0 до 266, однако для сопровождения возможности взаимодействия сетевых сред в соответствии со спецификацией применяемое значение приоритета следует ограничивать в пределах от 0 до 9 См. Рисунок 3-15.

 

Рисунок 3-15


Свойство priority может применяться для назначения приоритета в очередях для имеющихся сообщений.

Атрибуты, которые вы не можете использовать: cluster-id/reserved

Имеется ещё одно свойство, которому стоит уделит ваше внимание, причём с единственной целью чтобы дать вам знать что вы не можете его применять. Скорее всего вы уже заметили перечёркнутое свойство cluster-id на всех предыдущих рисунках (Рисунок 3-16).

 

Рисунок 3-16


Свойство cluster-id было переименовано как зарезервированное в AMQP 0-9-1 и его не следует применять.

Данное свойство cluster-id было определено в AMQP 0-8, однако впоследствии было удалено. и RabbitMQ никогда не реализовывал никакой вид поведения относительно него. AMQP 0-9-1 переименовал его в reserved и постулировал, что оно должно оставаться пустым. Хотя RabbitMQ в настоящее время не заставляет выполнять требование спецификации на то, чтобы оно было пустым, вам лучше избегать его совсем.

Выводы

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

Таблица 3-1 предоставляет быстрый обзор этих свойств. Вы можете вернуться и применить её в качестве справки для выяснения правильного применения свойств в своёи приложении.

Таблица 3-1. Свойства, предоставляемые Basic.Properties , в том числе их тип, брокер или приложение может их применять, а также либо предписанное применение, либо предложение их использования.
Свойство Тип Для применения в Предложение или предписание применения

app-id

short-string

Приложение

Полезно для задания приложения, опубликовавшего данные сообщения

content-encoding

short-string

Приложение

Определяет кодируется ли тело сообщения особым образом, например, с помощью zlib, deflate или Base64.

content-type

short-string

Приложение

Определяет тип данного сообщения с использованием типа MIME.

correlation-id

short-string

Приложение

Если данное сообщение ссылается на некое другое сообщение или уникально указываемое им, correlation-id является хорошим способом указания на то, на что ссылается данное сообщение.

delivery-mode

octet

RabbitMQ

Значение 1 сообщает RabbitMQ, что тот может оставлять данное сообщение в оперативной памяти, 2 указывает что его также следует записать на диск.

expiration

short-string

RabbitMQ

Значение штампа времени эпохи Unix в виде текстовой строки, которое указывает когда истекает срок действия данного сообщения.

headers

table

Оба

Таблица ключ/ значение в произвольном виде, которую вы можете применять для добавления дополнительных метаданных о своём сообщении; RabbitMQ, может выполнять маршрутизацию на основании их при вашем желании на то.

message-id

short-string

Приложение

Уникальный идентификатор, такой как UUID, который ваше приложение может применять для указания данного сообщения.

priority

octet

RabbitMQ

Свойство для определения значения приоритета в очередях.

timestamp

timestamp

Приложение

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

type

short-string

Приложение

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

user-id

short-string

Оба

Строка в произвольном виде, которую, если она используется, RabbitMQ будет проверять для сопоставления с подключённым сообщением и удалять данное сообщение в случае несоответствия.

Помимо применения свойств для самостоятельного описания сообщений, эти свойства могут переносить существенные метаданные о вашем сообщении, которые позволят вам создавать изощрённые механизмы маршрутизации и транзакций без необходимости загрязнять само тело сообщения контекстной информацией, принадлежащей данному сообщению. При вычислении данного сообщения для его доставки, RabbitMQ будет применять специфические свойства , такие как delivery-mode и таблицу headers чтобы гарантировать что ваши сообщения будут доставлены туда и таким образом как вы предписали. Однако эти значения являются всего лишь верхушкой айсберга, когда дело доходит до того, что необходимо обеспечить пуленепробиваемую доставку.