Построение сервис-ориентированной архитектуры
Концепция «монорельса» давно существует в мире Ruby — крупном Rails-приложении, которое пытается сделать все, но быстро становится громоздким и властным. Разработчики, оказавшиеся в такой ситуации, сейчас ищут лучший способ работы.
Одним из способов решения этой проблемы является разделение приложения Rails на различные части, которые работают вместе в сервис-ориентированной архитектуре (SOA). Оставляя функциональность веб-запросов и уровня данных приложению Rails и перемещая более сложный и менее CRUD-код в отдельные службы, гораздо проще разделить задачи и выбрать правильные инструменты для правильных заданий. В некоторых случаях лучшим инструментом для многих из этих заданий может быть другой язык или система (например, Erlang для распределенных систем, Java для тех случаев, когда вам нужны определенные библиотеки), но я обнаружил, что Ruby, как правило, является хорошим языком по умолчанию для использования, если ничто иное не выпрыгивает как очевидный выбор.
В прошлом году моя команда в Meducation решила разделить наш «монорельс» на сервис-ориентированную архитектуру. За последние 12 месяцев мы разбили его на части и теперь у нас 21 совместное приложение. У каждого сервиса есть свои проблемы и знания.
Мы эффективно относимся к принципу единой ответственности как к приложениям, а не только к классам. Создание и интеграция новых приложений в нашу экосистему — это быстро и дешево — на самом деле наш опыт создания и развертывания полнофункционального интегрированного приложения составляет менее часа. Ключом к достижению этого является создание надежных инструментов, которым мы доверяем, которые позволяют нам полностью сосредоточиться на бизнес-логике нашего приложения, а не на том, как все это объединить. Эта статья о первом из этих инструментов — Propono.
Propono (латинский глагол для публикации) — это Ruby Gem из паба / юга, созданный на основе Amazon Web Services (AWS). Он предлагает следующие преимущества:
- Он исключительно прост в настройке и использовании.
- Все обрабатывается AWS изначально, что означает:
- Автоматическая масштабируемость.
- Исключительная надежность.
- Практически нулевая стоимость — мы публикуем сотни тысяч сообщений в месяц и тратим менее 5 долларов.
- Никаких сторонних угроз безопасности, кроме Amazon.
Что такое паб / саб?
Мы описали Propono как паб / суб Ruby Gem. Давайте быстро разобьем, что это значит.
Pub / Sub (публикация / подписка) — это очень простая концепция. У вас есть несколько приложений, которые хотят отправлять сообщения (издатели), и несколько приложений, которые хотят получать сообщения (подписчики). Часто одно и то же приложение публикует некоторые сообщения и подписывается на другие. Сообщения публикуются по темам, а подписчики слушают темы, которые им небезразличны. Смотрите … простой.
Источник изображения: docs.oracle.com
Например, в Meducation у нас есть тема под названием «пользователь», на которую подписываются многие приложения. Когда новый пользователь регистрируется, веб-сайт публикует сообщение JSON для этой темы, которое фактически говорит: «Пользователь зарегистрировался и теперь имеет идентификатор # 239372». Подписанные приложения получают это сообщение и затем выполняют такие действия, как обновление нашего поиска. индексы, генерировать предложения друзей и отправить приветственное письмо.
С Propono, если у вас есть учетная запись AWS, публикация этого сообщения на веб-сайте и подписка на приложения — это один вклад. Давайте рассмотрим базовый пример, а затем посмотрим, как Propono работает с AWS под капотом.
Пропоно 101
Чтобы начать работу с Propono, вам нужна учетная запись AWS и пользователь IAM, у которого есть разрешения для SNS и SQS. Если вы просто пробуете Propono, вы можете поэкспериментировать с обычным пользователем IAM. Тем не менее, на производстве я бы рекомендовал настроить конкретного пользователя с политикой, которая разрешает доступ к SQS и SNS. например
{ "Version": "2012-10-17", "Statement": [ { "Sid": "Stmt1401034357000", "Effect": "Allow", "Action": [ "sqs:*", "sns:*" ], "Resource": [ "*" ] } ] }
Мы собираемся создать два приложения, которые могут общаться друг с другом — одно издательство и один подписчик. Для начала создайте каталог с именем learning_propono и добавьте Gemfile, который выглядит следующим образом:
source 'https://rubygems.org' gem 'propono'
Запустите bundle
и вы должны получить Gemfile.lock .
Теперь мы готовы создать нашего издателя и подписчика. Давайте создадим файл для каждого из них: publisher.rb и subscriber.rb . Оба должны требовать и настроить Propono с вашими учетными данными IAM. Откройте их оба в вашем любимом редакторе и заполните их следующим:
require 'propono' Propono.config do |config| config.access_key = "Your-IAM-Access-Key" config.secret_key = "Your-IAM-Secret-Key" config.queue_region = "eu-west-1" config.application_name = "Either-publisher-or-subscriber" end
Это все, что вам нужно для настройки Propono. В наших приложениях мы склонны помещать значения в файл propono.yml, который мы внедряем во время развертывания (через Chef) и читаем во время выполнения.
В subscriber.rb слушайте сообщения на тему «пользователя». Это так же просто, как сделать следующее:
Propono.listen_to_queue(:user) do |message| p "Message Received" p message end
Раскрутите консоль и запустите bundle exec ruby subscriber.rb
. Ваш подписчик будет сидеть и ждать сообщений в очереди user
. Если в этот момент вы получили ошибку, проверьте свои учетные данные IAM.
Оставьте его работающим и вернитесь к publisher.rb в вашем редакторе, чтобы опубликовать сообщение о новом пользователе в теме user
. Ниже конфига Propono поставьте следующее:
message = {entity: 'user', action: 'created', id: 123123} # Any string, hash, or array is valid here. Propono.publish(:user, message, async: false)
По умолчанию сообщения публикуются в отдельных темах. Поскольку мы хотим удостовериться, что этот поток завершает работу до того, как основной поток завершит свою работу и приложение закроется, мы вызываем async: false
для публикации в том же потоке.
Когда абонент еще работает, в другой консоли запустите bundle exec ruby publisher.rb
. Следите за окном своего подписчика, и через секунду или две вы увидите распечатанное сообщение.
Теперь у вас есть все возможности паба / саба в ваших руках. Вы можете публиковать сообщения из любого приложения и подписываться на них из любого другого. Просто.
Что на самом деле происходит?
Под поверхностью Propono использует Amazon Simple Notification Service (SNS) и Simple Queue Service (SQS) для хранения и распространения сообщений. Я кратко расскажу об обоих сервисах, а затем объясню, как мы используем их с Propono.
Служба простого уведомления (SNS)
На издательской стороне у нас есть SNS. Amazon описывает SNS как «быструю, гибкую, полностью управляемую службу push-сообщений… Чтобы предотвратить потерю сообщений, все сообщения, публикуемые в Amazon SNS, хранятся с избыточностью в нескольких зонах доступности… Отправка одного миллиона push-уведомлений на мобильные устройства стоит 1 доллар». С помощью SNS вы можете опубликовать сообщение один раз и доставить его один или несколько раз ».
Чтобы перевести этот маркетинг, SNS — это очень дешевый и надежный сервис, который принимает сообщения и доставляет их одному или нескольким получателям. SNS имеет множество возможных применений, но в мире Propono он предоставляет темы, на которые мы публикуем сообщения. Когда мы публикуем сообщение, мы отправляем его в SNS, который затем ищет любые другие службы, которые заботятся о нем, и передает сообщение дальше.
Простая служба очередей (SQS)
На другом конце находятся наши подписчики, которые используют SQS для получения сообщений. Amazon описывает SQS как «быстрый, надежный, масштабируемый, полностью управляемый сервис очереди сообщений. Вы можете использовать SQS для передачи любого объема данных на любом уровне пропускной способности, не теряя сообщений и не требуя, чтобы другие службы были всегда доступны ».
Короче говоря, очереди SQS получают сообщения и хранят их там, пока служба не снимает их. Стоимость опять минимальная. В Propono ваше приложение подписывается на очередь SQS и получает сообщения по мере их поступления. Если ваше приложение закрывается, сообщения будут помещаться в очередь, пока оно не вернется снова.
Жизненный цикл сообщения
Давайте рассмотрим путешествие сообщения, начинающегося со строки:
Propono.publish(:user, {foo: 'bar'})
Первое, что происходит при запуске этого кода, — это то, что Propono создает тему user
по SNS. После выполнения этого кода, если вы посмотрите на консоль SNS , вы увидите тему user
. На этом этапе у него не будет подписок, поэтому он фактически игнорирует все отправленные ему сообщения.
Теперь давайте посмотрим на другую сторону
Propono.listen_to_queue(:user) do |message| # ... end
Код проверяет наличие user
темы в SNS и создает ее, если она не существует. Однако он также ищет наличие очереди для этих сообщений для этого приложения на стороне SQS. Когда вы настроили подписчика, вы выбрали имя приложения. Это имя приложения теперь объединяется с именем темы, чтобы дать нам имя очереди.
Например, если вы позвонили своему subscriber
приложения, выполнение приведенного выше кода создаст очередь с именем subscriber-user
. Посмотрите на свою консоль SQS, и вы увидите, что тема создана:
Вернитесь к консоли SNS и нажмите на тему пользователя, и вы заметите, что между темой SNS и очередью SQS создана новая подписка. Теперь любые сообщения, опубликованные в user
теме, будут отправляться в subscriber-user
тему subscriber-user
и сохраняться до тех пор, пока подписчик не прочитает их, используя listen_to_queue
.
Все это бесплатно для политик безопасности и сопоставлений, которые прозрачно обрабатываются Propono. На самом деле, много чего другого происходит. Вы, вероятно, заметили, что есть очереди ошибок, поврежденные очереди, медленные темы и множество других созданных кусочков. Я расскажу обо всем этом и о многих других способах использования Propono в будущем.
Я надеюсь, что это было полезное введение в Propono, и вы попробуете. Мы интенсивно используем его в производстве, и сейчас немало других компаний делают то же самое. Мы будем рады услышать ваши отзывы и будем рады вашим комментариям. Пожалуйста, не стесняйтесь присоединиться к репозиторию Propono Github или в разделе комментариев ниже. Спасибо за прочтение!