Интро
Данная статья будет полезна тем, кто хочет начать работать с очередями сообщений или хочет перевести работающий проект с зарубежных облачных сервисов, либо с сервисов обслуживаемых собственными силами. В данной статье не будут затронуты вопросы: "Что такое очереди сообщений?", "Для чего нужны очереди сообщений?" и прочие вопросы, ответов на которые очень много на хабре и других ресурсах причем на различных языках. Зато в этой статье вы найдете демо-проекты позволяющие быстро попробовать минимальный функционал, информацию о работе с облачными российскими сервисами очередей с помощью популярных библиотек, ну и описание проблем, которые у меня возникли.
О себе и проекте над которым работаю
Для начала предлагаю немного познакомиться, чтобы понимать проблематику вопроса и иметь маленькое представление о авторе (мне) и его компетенциях, кому не интересно могут перейти дальше к сути вопроса.
Собственно зовут меня Константин, на данный момент я работаю над проектом Энерготроника и квалифицируя себя как Full Stack разработчик и Team Lead небольшой команды. Основной язык программирования C#.
Основная задача проекта Энерготроника - облегчить обслуживание и работу с оборудованием в первую очередь для узлов учета тепла (вычислители, теплосчетчики и различные датчики), но также и другого оборудования (электросчетчики, корректоры газа, водосчетчики и прочее). Для тех, кто не знал раньше: во многих домах и на многих предприятиях устанавливается оборудование для контроля потребления ресурсов, а именно тепла и горячего водоснабжения, если говорить об узлах учета тепла. Это оборудование чаще всего устанавливается в подвалах или подсобных помещениях, к оборудованию подключается GPRS-модем для дистанционной работы с ним. А дальше возникают различные вопросы:
съем показания и передача их в ресурсоснабжающую организацию;
контроль сроков поверки оборудования;
контроль исправной работы оборудования (отсутствие утечек, обнаружения некоректного учета, контроль перегревов и недогревов, контроль выхода из строя датчиков и многое другое).
и другие не маловажные вопросы.
Собственно одной из проблем, которые решает наш сервис является работа с различным оборудованием, так как задача одна, а производителей оборудования много и у каждого особенное решение, различные программные продукты с разным функционалом. Поэтому если речь идет об обслуживании нескольких приборов учета от различных производителей - рекомендую подробно познакомиться с нашим сервисом.
Ну и кратенько о технических аспектах. Сервис построен в основном с использованием .NET платформы и большая часть программного кода на языке C#. Соответственно для решения выше описанных задач, при укрупненном рассмотрение используется следующее:
сервис реализующий опрос приборов учета в соответствии с требованиями производителей и особенностями каждого типа приборов;
сервис реализующий стандартизацию данных;
сервис выполняющий проверку на корректность данных;
несколько баз данных с бэкапированием;
веб-интерфейс.
Вдаваться в подробности, где тут нужны очереди сообщений не буду, программист с опытом думаю и так догадается, где они могут пригодиться. Скажу лишь, что сейчас это все выполнено в виде монолита и очереди не используются совсем. В планах же добавить использование очередей где надо, потихоньку постараться перейти к микросервисной архитектуре и еще кучу немаловажных архитектурных и функциональных задач.
Российские облачные сервисы очередей
Собственно перейдем к облачным сервисам очередей, думаю у всех на слуху зарубежные облачные провайдеры вроде Amazon, Azure и других. Но если ваша компания работает на территории России и нацелена на местный рынок, думаю использовать услуги российских облачных провайдеров с юридической точки зрения проще, да и расчеты в рублях более предсказуемы, ну и в конце концов пинг до серверов лучше (хотя тут могу ошибаться, проводил только поверхностные тесты).
Если попытаться поискать российских облачных провайдеров можно легко найти следующих: Yandex.Cloud, Mail.ru Cloud Solutions, SBERCLOUD, #CloudMTS, Selectel и думаю есть еще более мелкие провайдеры, но мне они не попадались. Чтобы немного разбавить текст и передохнуть предлагаю посмотреть на логотипых этих облачных провайдеров.
По моему мнению самым крупным из представленных и с наибольшим количеством сервисов, является Yandex.Cloud, причем у них мы уже используем сервис S3 хранилища (для хранения бэкапов и работы с файлами наших пользователей в нашем продукте). Также мы пробовали использовать их услуги по хостингу статических файлов и даже пытались хостить React приложение реализованное с помощью Next.js, но тут результат был неудовлетворительным, роутинг такого приложения работает некорректно. В итоге пришлось написать соответствующую идею для развития сервиса на соответствующей платформе Yandex.Cloud, если интересно более подробное описание проблемы, рекомендую ознакомиться с идеей по ссылке.
Ну и собственно об облачных очередях сообщений, как оказалось данный сервис есть не у всех облачных провайдеров, а только у двух: Yandex.Cloud и Mail.ru Cloud Solutions. Поэтому дальше будем говорить только о них. У каждого из них свои заявленные достоинства, о которых можно прочитать в соответствующей документации, вот ссылка для Yandex.Cloud и вот ссылка для Mail.ru Cloud Solutions.
Если кратко, то внутренняя реализация у обоих провайдеров своя, у кого лучше - не знаю, но выполню сравнение основных характеристик заявленных в документации. И думаю важно отметить, что судя по всему сервис от Mail.ru Cloud Solutions находится в бэте (кстати судя по документации на время бэта тестирования использование сервиса бесплатно) и у него пока не доступны FIFO очереди.
Yandex.Cloud |
Mail.ru Cloud Solutions |
|
Бесплатное количество запросов в месяц |
100 000 |
1 000 000 |
Плата за исходящий трафик |
свыше 10 гб |
упоминаний не нашел |
Квота на количество запросов в стандартную очередь в секунду |
300 |
5000 (по главной странице), по документации не ограничено |
Квота на количество запросов в FIFO очередь в секунду |
30 |
300 |
Цена за каждый следующий 1 млн запросов после бесплатного в стандартной очереди, р |
30.48 |
29.99 |
Цена за каждый следующий 1 млн запросов после бесплатного в FIFO очереди, р |
38.22 |
29.99 |
Количество очередей в облаке |
10 |
500 |
Если посмотреть документацию Amazon по квотам Mail.ru Cloud Solutions является полным аналогом, у Yandex.Cloud же скорость обработки ниже и порог бесплатных запросов в месяц кончается быстрее. Также думаю стоит отметить, что при большом объеме запросов (свыше 100 млн) у Mail.ru Cloud Solutions ценны за 1 млн запросов будут еще чуть дешевле. И еще хочу обязательно обратить внимание на количество очередей, для одной из задач в нашем проекте планируется порядка 100 очередей, со временем может быть и больше. И пообщавшись с технической поддержкой Yandex.Cloud я узнал, что увеличение квоты до абстрактных 1000 очередей в рамках одного аккаунта точно не возможно, так как архитектура этого не предполагает.
Таким образом при сухом сравнение документации явно предпочтение стоит отдать Mail.ru Cloud Solutions. Но если еще оценивать общую экосистему, то у Yandex.Cloud значительно лучше веб-интерфейс для управления всеми сервисами, техподдержка с четким SLA (которое кстати иногда нарушается на бесплатном тарифе) и интеграцией в веб-интерфейс, более обширный перечень дополнительных услуг и настроек по другим сервисам, а также очень гибкий ACL и документация организована на порядок лучше.
Ну и самое важное для меня, что оба этих облачных провайдера для сервиса очередей заявляют поддержку Amazon SQS, т.е. в теории мы можем взять любую утилиту, CLI, библиотеку позволяющие работать с Amazon SQS и работать с российским аналогом без каких-либо проблем. А это значительно облегчает задачу, потому что бибилиотек для работы с Amazon SQS значительно больше, чем библиотек для работы с Yandex.Cloud или Mail.ru Cloud Solutions (если такие вообще существуют). Опять же Amazon почти для всех своих сервисов предоставляет готовые SDK для разных языков программирования, но помимо SDK существуют сторонние библиотеки, оборачивающие Amazon SDK и дающие дополнительные возможности.
Библиотеки C# для работы с сервисами очередей
Начиная писать код для работы с очередями, думаю стоит подумать о том, чтобы не зависеть от конкретной реализации RabbitMQ (можно взять управляемый у облачных провайдеров, либо хостить самостоятельно за бесплатно), Azure Service Bus, ActiveMQ, Amazon SQS, MSMQ и других решений. Можно конечно выбрать какой-то из вариантов и написать код с использованием API этого сервиса, а если через какое-то время понадобится изменить сервис очередей, то переписать код с использованием API другого сервиса. У использования API конкретной реализации сервиса очередей, конечно есть и плюс, а именно использование достоинств и особенностей какой-то конкретно реализации. Однако по моему мнению значительно лучше использовать библиотеку, которая позволит используя один и тот же код работать с любым из выше перечисленных сервисов очередей.
MassTransit
Если говорить об общеизвестных библиотеках подходящих для использования в C#, на ум сразу приходит библиотека MassTransit. О работе с ней много статей как на английском, так и на русском, к примеру вот. Собственно про другие библиотеки на момент начала работы над задачей реализации взаимодействия с сервисами очередей я и не слышал, всегда шла речь либо о привязке к какому-то конкретному сервису и его API, либо о MassTransit.
Реализуем небольшой пример для публикации сообщений в очередь используя библиотеку Masstransit:
Перед написанием кода нужно зарегистрировать у облачных провайдеров, получить грант или закинуть денег, и создать ключи для доступа.
Создать проект, в моем случае проект создан по стандартному шаблону "Worker Service" на .NET5.
Добавить с помощью NuGet пакеты: MassTransit.AmazonSQS, MassTransit Microsoft.Extensions.DependencyInjection. Эти пакеты с помощью своих зависимости уже загрузят основной пакет MassTransit и AWSSDK.
Конфигурируем MassTransit.
Важное отступление для Yandex.Cloud необходимо указать регион "ru-cental1", для Mail.ru Cloud Solutions все работаетбез лишних плясок с бубномсо стандартным регионом. И как оказалось не так просто (нет готовых рабочих примеров или я их не смог найти) изменить настройки региона в Amazon SDK для .NET на вариант, который не заложен статической константой. После долгих мучений, поисков, уговоров техподдержки Yandex.Cloud решение все таки нашлось (его предложили специалисты Yandex.Cloud, когда вопрос пробился через первый уровень техподдержки), делюсь с вами:
services.AddMassTransit(x =>
{
x.UsingAmazonSqs((context, cfg) =>
{
AmazonSQSConfig _sqsConfig = new AmazonSQSConfig
{
ServiceURL = "https://message-queue.api.cloud.yandex.net",
AuthenticationRegion = "ru-central1"
};
cfg.Host("ru-central1", h =>
{
h.Config(_sqsConfig);
h.AccessKey("your-iam-access-key");
h.SecretKey("your-iam-access-key");
});
});
});
5. Если хотим вместо Yandex.Cloud использовать Mail.ru Cloud Solutions нужно ServiceURL заменить на https://sqs.mcs.mail.ru, регион для них не важен, так что можно оставить ru-central1, а можно и тот, что заложен в SDK по умолчанию. На всякий случай уточню, что AccessKey и SecretKey тоже надо заменить на те, что созданы у Mail.ru Cloud Solutions.
6. Добавляем в Worker публикацию сообщений.
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await _bus.Publish(new Message { Text = $"The time is {DateTimeOffset.Now}" });
await Task.Delay(1000, stoppingToken);
}
}
6. Запускаем отладку и смотрим работу.
7. А вот и проблема! Собственно после вызова задачи Publish программа впадает в бесконечное ожидание. Если почитать детальней документацию MassTransit можно заметить, что оказывается данная библиотека для реализации своего функционала на базе облачных сервисов Amazon использует не только SQS, но еще и SNS сервис. Проверяем наших российских облачных провайдеров и обнаруживаем, что аналогов SNS сервиса на момент написания статьи нет, в случае с Yandex.Cloud я создал соответствующую идею в сообществе. Для кто считает, что такой аналог нужен, вот ссылка чтобы поддержать идею.
Идем дальше проверяем, может быть можно использовать MassTransit с частичным функционалом, но только на базе API Amazon SQS?
Ответ, теоретически возможно, о чем написано на stackoverflow. Базируясь на этом ответе, отказываемся от Publish в сторону Send, чтобы не использовать SNS сервис. При таком подходе надо самостоятельно указывать очередь, которая будет использоваться для публикации сообщений. Если ориентироваться на интерфейс Amazon SNS метод Send действительно позволяет при работе задействовать только SQS сервис и ничего не создает в SNS сервисе, других доказательств я не нашел. Что касается работы у российских облачных провайдеров после вызова метода Send не происходит ничего, он как-будто выполняется успешно, но никаких сообщений в очереди не появляется.
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
var endpoint = await _bus.GetSendEndpoint(new Uri("queue:QueueName"));
await endpoint.Send(new Message { Text = $"The time is {DateTimeOffset.Now}" });
await Task.Delay(1000, stoppingToken);
}
}
Полный код всех примеров для MassTransit можно найти в репозитории GitHub.
Rebus
Когда работа с MassTransit зашла в тупик и я уже думал начать использовать чистые API для Amazon SQS предлагаемыми Amazon SDK, я нашел интересную библиотеку, которая решает те же задачи, что и библиотека MassTransit, по крайней мере если верить документации.
Собственно подробней с библиотекой можно познакомиться в официальном репозитории на GitHub, где есть и wiki.
Так как про библиотеку Rebus не так много информации на русском (на хабре нашлось только одно упоминание) переведу кусочек wiki в виде краткой выжимки, чтобы дать понять какие цели преследует автор в сравнении с остальными библиотеками решающими похожие задачи.
На создание Rebus автора вдохновила библиотека NServiceBus, которая по его мнению является наиболее известной реализацией шины сообщений для .NET. В NServiceBus ему нравится почти все, что касается обмена сообщениями. Но библиотека NServiceBus, по мнению автора Rebus, больше похожа на фреймворк, а Rebus автор позиционирует именно как небольшую библиотеку. Так как вдохновлялся автор Rebus именно NServiceBus, функционал этих двух библиотек очень похож.
Что касается библиотеки MassTransit автор Rebus считает ее самой известной бесплатной реализацией шины сообщений для .NET, но после долгих попыток настроить MassTransit в 2010 году, он сдался и создал свой вариант - Rebus.
Таким образом думаю из этой краткой выдержки понятно, что Rebus, хотя бы по задумке его автора, должен быть более простым для понимания и более легким для конфигурирования. Ну и после опыта с MassTransit сразу отмечу, что для работы ему не нужен Amazon SNS, согласно wiki его можно использовать для решения дополнительных задач, но по умолчанию все работает без него.
Кстати для тех, кто избегает бесплатных библиотек только из-за того что нет поддержки и гарантий, в случае с Rebus, есть версия Rebus Pro, которая дает как раз таки гарантии, поддержку и бонусом менеджер очередей (подразумевается UI).
Реализуем небольшой пример для публикации сообщений в очередь используя библиотеку Rebus:
Перед написанием кода нужно зарегистрировать у облачных провайдеров, получить грант или закинуть денег, и создать ключи для доступа.
Создать проект, в моем случае проект создан по стандартному шаблону "Worker Service" на .NET5.
Добавить с помощью NuGet пакеты: Rebus.AmazonSqs, Rebus.ServiceProvider.
-
Конфигурируем Rebus.
AmazonSQSConfig _sqsConfig = new AmazonSQSConfig { ServiceURL = "https://message-queue.api.cloud.yandex.net", AuthenticationRegion = "ru-central1" }; var credentials = new Amazon.Runtime.BasicAWSCredentials("your-iam-access-key", "your-iam-secret-key"); services.AddRebus(rebus => rebus .Routing(r => r.TypeBased().Map<Message>("QueueName")) .Transport(t => t.UseAmazonSQSAsOneWayClient(credentials, _sqsConfig)) .Options(t => t.SimpleRetryStrategy(errorQueueAddress: "ErrorQueue")));
5. Если хотим вместо Yandex.Cloud использовать Mail.ru Cloud Solutions нужно ServiceURL заменить на https://sqs.mcs.mail.ru, регион для них не важен, так что можно оставить ru-central1, а можно и тот, что заложен в SDK по умолчанию. На всякий случай уточню, что AccessKey и SecretKey тоже надо заменить на те, что созданы у Mail.ru Cloud Solutions.
6. Добавляем в Worker публикацию сообщений.
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await _bus.Send(new Message { Text = $"The time is {DateTimeOffset.Now}" });
await Task.Delay(1000, stoppingToken);
}
}
7. А с этой библиотекой проблем нет, все работает. Были проблемы со стороны российских облачных провайдеров, первая связанна с указанием региона ru-central1 для Yandex.Cloud, ее решением я уже поделился. Другие проблемы были на стороне облачного провайдера Mail.ru Cloud Solutions, но их уже пофиксили.
Просто поделюсь с вами информацией об этих проблемах для того, чтобы вы знали, что такое может быть и не стоит идеализировать работу облачных провайдеров.
Проблема 1: в возвращаемых ответах url начинался с "/api", о чем не было сказано в документации и что ломало совместимость с Amazon SDK, после моего обращения возвращаемый url привели к написанному в документации.
Проблема 2: возвращаемые исключения при работе через Amazon SDK отличались от тех, которые использует Amazon и заявляет в своей документации.
Полный код всех примеров для Rebus можно найти в репозитории GitHub.
NServiceBus
Ну и последняя библиотека, которая служила вдохновением для авторов двух предыдущих, эта NServiceBus. Основной ее минус по сравнению с двумя предыдущими - она платная, но до лимита в 10 000 сообщений в день ее можно использовать бесплатно, однако этого лимита хватит либо совсем маленькому проекту, либо при разработке. Цены на первый взгляд адекватные, но они в долларах и как следствие компания зарубежная. Про свое мнение о работе с зарубежными компаниями я уже писал поэтому повторяться не буду. Однако в том, что она платная есть и плюс, есть явная поддержка и гарантии.
Так как есть 10 000 сообщений, в пределах которых использование библиотеки бесплатно, для полноты картины я решил познакомиться и с ней и проверить ее работу с российскими облачными сервисами очередей.
Так как библиотека коммерческая, у нее самая развернутая документация и можно взять готовые примеры тут. Но что странно я не смог заставить работать пример на .NET 5 даже с Amazon SQS, не говоря уже про российских облачных провайдеров.
Надеюсь после ваших комментариев этот пункт статьи будет дополнен.
Небольшое сравнение интерфейсов и функциональности Yandex.Cloud и Mail.ru Cloud Solutions
Ну и кратенько поделюсь своим субъективным мнением о российских облачных провайдерах, если абстрагироваться от цен и качества, то есть будем говорить только о функциональности и удовлетворенности.
Что мне нравится в Yandex.Cloud?
Количество сервисов, наверно их больше чем у любого российского облачного провайдера.
Возможность активировать темную тему.
Интегрированная в консоль управления техподдержка с четким и понятным SLA.
Много функциональности в консоли управления, в сравнении с другими.
Дополнительный функционал связанный с основными функциями (к примеру автоматическое получение и обновление сертификатов Let's Encrypt для своих прикрученных доменов, мониторинг в виде графиков).
Хорошая документация.
Отдельный интерфейс, где можно предлагать идеи и голосовать за идеи других пользователей. Правда тут тоже не без проблем, иногда идеи находятся на модерации неделю, месяц, в общем пока не напишешь в техподдержку.
Создание ключей и выдача прав для каждого из ключей.
Что мне НЕ нравится в Yandex.Cloud?
Качество техподдержки, так как вопросы я задаю когда уже все попробовал (попробовал метод "научного тыка", поискал в документации, поискал в интернете), то ответы чаще всего либо "создавайте идею", либо приходиться побороться с сотрудниками техподдержки, чтобы они передали вопрос к техническим специалистам, а те уже дали разумный ответ.
Квоты, они чаще всего достаточно низкие.
Мало примеров для .NET, для каких-то сервисов они есть, но чаще их нету. Для других языков программирования примеров значительно больше.
Мешанина в интерфейсе. Сервисов и дополнительных функций настолько много, что часто забываешь где они находятся, и открываешь документацию, чтобы вспомнить где находится редко используемая функция и как попасть в ее настройки.
-
Мониторинг, хоть он и есть почти везде, но его настройки очень узкие - чаще всего приходится пользоваться как есть и дополнительные сценарии посмотреть не получается.
Теперь перейдем к Mail.ru Cloud Solutions с ними я поработал минимально, так что если чего-то не нашел, но вы знаете что это есть - пишите в комментариях.
Что мне нравится в Mail.ru Cloud Solutions?
Конфигурация бокового меню. Был приятно удивлен когда узнал, что можно выключить не нужные сервисы.
Зачатки мониторинга. Полноценного мониторинга для всех сервисов я не нашел, но то что я нашел, заставляет думаю что он будет полностью настраиваемым, а именно включай только то что тебе нужно.
Просмотр сообщений внутри очереди. В Yandex.Cloud настолько детально углубиться в сервис не возможно, да и в Amazon тоже такого нет.
Качество техподдержки. Сотрудники отвечают немного медленнее Yandex.Cloud и в каком-то отдельном интерфейсе, но их ответ почти всегда означает решение проблемы.
Что мне НЕ нравится в Mail.ru Cloud Solutions?
Тут стоит заметить, что в список можно записать все то, что мне нравится в Yandex.Cloud так как я привык к этому функционалу, поэтому повторяться не буду и помечу только несколько дополнительных пунктов.
Интерфейс работы с документацией. Надо делать много кликов, чтобы увидеть хоть какую-то информацию.
"Сырость". Похоже многие сервисы только только запушены и находятся в бэте, а часть кнопок нарисованы в интерфейсе, но пока недоступны.
В качестве небольшого вывода. Скорей всего при использование чистых API вы столкнетесь с меньшим количеством проблем, но даже при использование библиотек рассмотренных в статье услугами российских облачных сервисных провайдеров вполне можно пользоваться. Я очень надеюсь, что это направление будет развиваться, что скоро мы увидим аналог Amazon SNS от наших облачных провайдеров.
Лично мне бы хотелось видеть побольше сервисов по модели "Pay-as-you-go". Мне кажется он наиболее удобен для развивающихся проектов, когда твои расходы минимальны на старте и растут по мере роста проекта. Хотя тот же Yandex.Cloud последнее время создает больше сервисов вроде "Managed Service for Apache Kafka", где надо платить постоянно и много.
А еще мне бы хотелось увидеть более полноценную конкуренцию, то есть чтобы все упомянутые в начале статьи облачные провайдеры нарастили объем оказываемых услуг.
Статья для меня является первой, поэтому буду рад здравой критике, если кто-то поможет заставить полноценно работать пример по NServiceBus с Amazon делитесь в комментариях и я проверю его на российских облачных провайдерах, а после обновлю статью.