Как настроить архитектуру микросервисов в Ruby: пошаговое руководство

Опубликовано: 2022-03-11

Что такое микросервисы?

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

Микросервисы заменяют классические монолитные внутренние серверы
Твитнуть

В архитектуре микросервисов описанный монолитный бэкенд заменяется набором распределенных сервисов. Такой дизайн позволяет лучше разделить обязанности, упростить обслуживание, повысить гибкость в выборе технологий для каждой службы, а также упростить масштабируемость и отказоустойчивость. В то же время у сложных распределенных систем есть свои проблемы. У них больше шансов столкнуться с условиями гонки, и их труднее отлаживать, так как проблемы не просто определить для одной службы, а вместо этого они распределяются по многим. Если не приложить усилий, чтобы следовать лучшим практикам при построении такой системы, вы можете оказаться в окружении пожаров, которые не знаете, как потушить. Особое внимание следует уделить контрактам полезной нагрузки сервисов, поскольку изменения в одном сервисе могут повлиять на всех его клиентов и, следовательно, на весь набор серверных сервисов.

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

Как настроить архитектуру микросервисов

В настоящее время существует множество способов настройки микросервисов, и в этом руководстве мы сосредоточимся на архитектуре брокера.

Брокерская архитектура

Архитектура брокера с брокером (B) посередине и четырьмя окружающими его микросервисами, назовите их N, S, E, W. Путь запроса/ответа начинается на входе за пределами архитектуры, затем следует по пути N, B, E, B, S, B, W, B, E, B, N, прежде чем, наконец, выйти в качестве вывода.

Брокерская архитектура — это один из способов заставить ваши сервисы взаимодействовать друг с другом.
Твитнуть

Брокерская архитектура — это один из способов заставить ваши сервисы взаимодействовать друг с другом. В нем все службы окружают сервер обмена сообщениями, брокер и все подключены к нему. Службы отправляют сообщения брокеру, который затем знает, какая другая служба или службы ему нужны для пересылки этих сообщений. Таким образом, сервисам не нужно хранить информацию о других сервисах. Вместо этого они полагаются на брокера, который позаботится обо всем обмене сообщениями, и это позволяет им быть изолированными и сосредоточиться только на своем конкретном домене. Брокер также может хранить сообщения, когда их получатели отключены, что позволяет не заставлять отправителей и получателей работать одновременно, что обеспечивает еще большую изоляцию. Конечно, у этого решения есть недостатки, поскольку брокер может быстро стать узким местом, поскольку все коммуникации должны проходить через него, а также он может стать единой точкой отказа для вашего бэкэнда. Однако есть несколько способов смягчить эти проблемы. Один из способов — запустить несколько экземпляров брокера параллельно, что позволит повысить отказоустойчивость системы. Другим способом было бы использование других архитектур. Альтернативные архитектуры отличаются от архитектуры, которую мы реализуем в этом руководстве, тем, что не используют брокера, либо используют другую архитектуру брокера, либо используют другой протокол обмена сообщениями, например HTTP.

Связь между службами

В этом руководстве мы будем использовать ZeroMQ для связи между службами и брокером.

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

ZeroMQ предоставляет уровень абстракции протокола, который обрабатывает составные асинхронные сообщения через случайные транспорты. Преимущества использования ZeroMQ для обмена сообщениями между службами и брокером выходят за рамки этого руководства, поэтому мы не будем их здесь рассматривать, но если вы хотите узнать о них больше, ознакомьтесь со следующей статьей Quora. Если вы заинтересованы в поиске других способов взаимодействия ваших сервисов друг с другом, я предлагаю вам взглянуть на статью «Брокер против брокера», чтобы узнать, чего еще можно достичь.

Создание набора микросервисов

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

Итак, начинаем строить.

Начиная

Во-первых, давайте удостоверимся, что у вас есть все необходимое для запуска брокера и сервиса. Во-первых, начните с загрузки и установки Node.js, ZeroMQ и Git на свой компьютер. Если вы используете OSX, для каждого из них есть доморощенные пакеты, и в большинстве дистрибутивов Linux также есть пакет для каждого из них, так что у вас не должно возникнуть с этим проблем. Пользователи Windows могут просто использовать приведенные выше ссылки для скачивания.

Запуск брокера

После установки всех необходимых зависимостей давайте запустим нашего брокера. В этом руководстве мы используем реализацию брокера Node.js, которая является частью ZMQ Service Oriented Suite. Вы можете найти его код и документацию на GitHub. Чтобы запустить брокера, сначала клонируйте загрузочный файл брокера на свой компьютер. Этот репозиторий является начальной загрузкой для использования указанной выше библиотеки брокера. Обратите внимание, что этот шаг не требуется, поскольку исходная библиотека сама по себе является работоспособной, но разница между ними заключается в том, что в репозитории начальной загрузки вы можете изменить конфигурации по умолчанию.

Итак, сначала используйте следующую команду Git, чтобы загрузить проект на свой компьютер:

 $ git clone [email protected]:dadah/zmq-broker-bootstrap.git

После этого перейдите в созданный каталог:

 $ cd zmq-broker-bootstrap

Теперь установите зависимости пакета:

 $ npm install

Брокер готов. Чтобы запустить брокера, выполните следующую команду:

 $ bin/zss-broker run

Вы можете найти файлы конфигурации для каждой среды в каталоге config/ . Это конфигурация разработки по умолчанию:

 { "broker": { "backend": "tcp://127.0.0.1:7776", "frontend": "tcp://127.0.0.1:7777" }, "log": { "consolePlugin": { "level": "debug" } } }

Параметр backend определяет адрес ip:port серверной и клиентской части брокера. Внутренний адрес — это место, где брокер получает запросы от служб и отвечает на них, а внешний адрес — это место, где он получает и отправляет клиентам службы. Вы также можете установить уровень ведения журнала, изменив log.consolePlugin.level . Возможные значения: trace , debug , info , warn и error , и они определяют объем информации, которую выводит процесс брокера.

Запуск службы

После того, как вы запустили брокера, пришло время разработать свой первый микросервис Ruby. Начните с открытия нового окна консоли. Затем создайте каталог, в котором будут храниться ваши службы, а затем перейдите в этот каталог. В этом руководстве мы используем клиент Ruby и службу ZMQ SOA Suite. Доступен загрузочный сервис «Hello world», поэтому давайте воспользуемся им для запуска нашего первого микросервиса.

Перейдите в каталог сервисов и клонируйте репозиторий начальной загрузки:

 $ git clone [email protected]:dadah/zmq-service-suite-ruby-bootstrap.git

Перейдите в только что созданный каталог:

 $ cd zmq-service-suite-ruby-bootstrap

Теперь установите все зависимости:

 $ bundle install

Чтобы запустить службу, выполните следующую команду:

 $ bin/zss-service run

Здорово. Вы запустили свой первый сервис.

Если вы перейдете к окну консоли, в котором вы оставили работающего брокера, вы увидите следующий вывод:

 2015-12-15 16:45:05 | INFO | BROKER - Async Broker is waiting for messages... 2015-12-15 16:45:14 | DEBUG | BACKEND - received from: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: 76f50741-913a-43b9-94b0-36d8f7bd75b1 2015-12-15 16:45:14 | DEBUG | BACKEND - routing from: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: 76f50741-913a-43b9-94b0-36d8f7bd75b1 to SMI.UP request... 2015-12-15 16:45:14 | INFO | SMI - SMI register for sid: HELLO-WORD instance: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b! 2015-12-15 16:45:14 | DEBUG | BACKEND - reply to: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: 76f50741-913a-43b9-94b0-36d8f7bd75b1 with status: 200 2015-12-15 16:45:15 | DEBUG | BACKEND - received from: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: 3b3a0416-73fa-4fd2-9306-dad18bc0502a 2015-12-15 16:45:15 | DEBUG | BACKEND - routing from: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: 3b3a0416-73fa-4fd2-9306-dad18bc0502a to SMI.HEARTBEAT request... 2015-12-15 16:45:15 | DEBUG | BACKEND - reply to: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: 3b3a0416-73fa-4fd2-9306-dad18bc0502a with status: 200 2015-12-15 16:45:16 | DEBUG | BACKEND - received from: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: b3044c24-c823-4394-8204-1e872f30e909 2015-12-15 16:45:16 | DEBUG | BACKEND - routing from: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: b3044c24-c823-4394-8204-1e872f30e909 to SMI.HEARTBEAT request... 2015-12-15 16:45:16 | DEBUG | BACKEND - reply to: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: b3044c24-c823-4394-8204-1e872f30e909 with status: 200

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

Потребление из Сервиса

Итак, теперь у нас запущена служба, как нам ее использовать?

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

 $ bin/zss-client

Вы должны увидеть что-то вроде этого:

 15-49-15 16:49:54 | INFO | ZSS::CLIENT - Request 90a88081-3485-45b6-91b3-b0609d64592a sent to HELLO-WORD:*#HELLO/WORLD with 1.0s timeout 15-49-15 16:49:54 | INFO | ZSS::CLIENT - Received response to 90a88081-3485-45b6-91b3-b0609d64592a with status 200 "Hello World"

Если вы перейдете к окну консоли, где запущена ваша служба, вы должны увидеть это:

 Started hello-word daemon... 15-45-15 16:45:14 | INFO | ZSS::SERVICE - Starting SID: 'HELLO-WORD' ID: 'hello-word#aaa65374-8585-410a-a41d-c8a5b024553b' Env: 'development' Broker: 'tcp://127.0.0.1:7776' 15-49-15 16:49:54 | INFO | ZSS::SERVICE - Handle request for HELLO-WORD:*#HELLO/WORLD 15-49-15 16:49:54 | INFO | ZSS::SERVICE - Reply with status: 200

Хорошо. Вы только что запустили и использовали свой микросервис «Hello World». Однако это не то, к чему мы стремились. Мы хотим построить наш сервис(ы). Тогда давайте к этому.

Создание вашего сервиса

Во-первых, давайте остановим наш сервис «Hello World». Перейдите в окно консоли службы и нажмите Ctrl+C , чтобы остановить службу. Далее нам нужно превратить наш сервис «Hello World» в сервис «Person».

Структура кода

Давайте начнем с просмотра дерева кода проекта. Это выглядит так:

Иерархия файлов/папок нашего примера проекта zmq-service-suite-ruby-bootstrap. Это подробно описано ниже, но обратите внимание, что последние три упомянутых файла .rb на самом деле находятся в lib/repositories, а не в самой lib.

  • Каталог bin — это место, где вы храните сценарии, запускающие вашу службу.
  • В каталоге config хранятся все файлы конфигурации.
    • В файл boot.rb вы можете добавить все свои сервисные зависимости. Если вы откроете его, вы заметите, что там уже перечислено много зависимостей. Если вам нужно добавить что-то еще, вы должны сделать это здесь.
    • В файле application.yml хранятся все настройки вашего приложения. Мы рассмотрим этот файл позже.
    • В каталоге config/initializers вы можете добавить свои сценарии инициализации. Вы можете, например, добавить сюда настройки для соединений ActiveRecord или Redis. Сценарии, которые вы добавляете в этот каталог, будут запускаться при запуске службы.
  • В каталоге db/migrate вы можете хранить свои миграции ActiveRecord или Sequel, если они у вас есть. Если вы этого не сделаете, вы можете полностью удалить этот каталог.
  • Каталог lib — это место, где находится ваш основной код приложения.
    • Файл settings.rb просто загружает файл application.yml и делает его доступным для всей службы, чтобы вы могли получить доступ к своим конфигурациям из любого места. Например, Settings.broker.backend возвращает серверный адрес брокера, который вы указали в файле YML выше.
    • В файле service_register.rb вы регистрируете свои сервисы и сервисные маршруты. Мы объясним это позже.
    • Файл hello_world_service.rb определяет конечные точки службы «Hello World».
    • Каталог lib/daos — это место, где вы храните свои объекты ActiveModel, если вы используете ActiveRecord, или любые другие объекты доступа к данным, которые вы можете в конечном итоге создать, например, ваши модели Sequel.
    • В lib/dtos хранятся ваши объекты передачи данных. Именно эти объекты в конечном итоге отправляются обратно клиентам службы.
    • Каталог lib/repositories хранит ваши репозитории. Репозитории — это объекты, которые позволяют службам получать доступ к данным, и это единственные объекты, которым разрешено обрабатывать DAO. Поэтому, если службе нужна группа экземпляров «Hello World», она запросит их у репозитория. Репозиторий, в свою очередь, использует соответствующие DAO для извлечения соответствующих данных из базы данных. Затем данные сопоставляются с подходящей коллекцией DTO «HelloWorld» или «HelloWorld», которая возвращается службе.
    • lib/repositories/mappers — это место, где вы храните свои карты. Мапперы — это объекты, которые преобразуют DAO в DTO и наоборот.

Файл application.yml из каталога config выглядит так:

 defaults: &defaults broker: backend: tcp://127.0.0.1:7776 frontend: tcp://127.0.0.1:7777 logging: console: level: info development: <<: *defaults test: <<: *defaults production: <<: *defaults

Этот параметр просто устанавливает внутренний и внешний адрес брокера, а также уровень ведения журнала.

Если все это пока звучит запутанно, не беспокойтесь, так как дальше мы будем двигаться дальше.

Услуга «Лицо»

Итак, продолжим наш сервис «Персона». Начнем с настройки подключения к базе данных. Откройте файл config/initializers/active_record.rb и раскомментируйте там единственную строку. Затем добавьте следующую запись в конфигурацию разработки в application.yml , чтобы она выглядела так:

 defaults: &defaults broker: backend: tcp://127.0.0.1:7776 frontend: tcp://127.0.0.1:7777 logging: console: level: info database: adapter: postgresql database: zss-tutorial-development

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

 $ rake db:create

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

Далее идет миграция. Для этого просто создайте файл db/migrate с именем 000_creates_persons.rb :

 $ touch db/migrate/000_creates_persons_table.rb

Откройте файл и создайте миграцию, как при обычной миграции Rails:

 class CreatesPersons < ActiveRecord::Migration def change create_table :persons do |t| t.name t.timestamps end end end

Далее запустите его:

 $ rake db:migrate == 0 CreatesPersons: migrating ================================================ -- create_table(:persons) DEPRECATION WARNING: `#timestamp` was called without specifying an option for `null`. In Rails 5, this behavior will change to `null: false`. You should manually specify `null: true` to prevent the behavior of your existing migrations from changing. (called from block in change at /Users/francisco/Code/microservices-tutorial/db/migrate/000_creates_persons.rb:6) -> 0.0012s == 0 CreatesPersons: migrated (0.0013s) =======================================

Теперь, когда мы создали нашу таблицу, давайте создадим для нее модель. Создайте файл lib/daos/person.rb :

 $ touch lib/daos/person.rb

Отредактируйте его следующим образом:

 module DAO class Person < ActiveRecord::Base end end

Есть ваша модель. Теперь вам нужно создать модель DTO для «Персона», чтобы вы могли вернуть ее клиенту. Создайте файл lib/dtos/person.rb :

 $ touch lib/dtos/person.rb

Отредактируйте его следующим образом:

 module DTO class Person < Base attr_reader :id, :name end end

Затем вам нужно создать Mapper для преобразования DAO «Person» в DTO «Person». Создайте файл lib/repositories/mappers/person.rb и отредактируйте его следующим образом:

 module Mapper class Person < Mapper::Base def self.to_dao dto_instance DAO::Person.new id: dto_instance.id, name: dto_instance.name end def self.to_dto dao_instance DTO::Person.new id: dao_instance.id, name: dao_instance.name end end end

Здесь Mapper::Base требует, чтобы вы реализовали self.to_dao и self.to_dto . Если вы не хотите этого делать, вы можете вместо этого реализовать self.map и переопределить Mapper::Base.map , который вызывает to_dao или to_dto , в зависимости от того, является ли атрибут, который он получает, DAO или DTO.

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

Давайте тогда создадим репозиторий. Создайте файл lib/repositories/person.rb :

 $ touch lib/dtos/person.rb

Отредактируйте его следующим образом:

 module Repository class Person < Repository::Base def get DAO::Person.all.map do |person| Mapper::Person.map(person) end end end end

В этом репозитории есть только метод экземпляра get , который просто получает всех людей из базы данных и сопоставляет их с набором DTO людей — довольно просто. Давайте сейчас соберем все это вместе. Осталось только создать службу и конечную точку, которая вызывает этот репозиторий. Для этого создадим файл lib/person_service.rb :

 $ touch lib/person_service.rb

Отредактируйте его следующим образом:

 class PersonService < BaseService attr_reader :person_repo def initialize @person_repo = Repository::Person.new end def get payload, headers persons = person_repo.get() if persons.empty? raise ZSS::Error.new(404, "No people here") else persons.map &:serialize end end end

Сервис «Person» инициализирует репозиторий в своем инициализаторе. Все общедоступные методы экземпляра службы «Person» имеют полезную нагрузку и заголовки, которые вы можете опустить, если они вам не нужны. Оба являются Hashie::Mash , и они хранят переменные, отправленные в конечную точку, в виде атрибутов или заголовков, а их ответы имитируют ответы HTTP, поскольку каждый ответ имеет код состояния, который клиенты могут использовать, чтобы узнать результат запросов, отправленных на сервер. service вместе с полезной нагрузкой ответа службы. Коды ответов такие же, как вы ожидаете от HTTP-сервера. Например, успешный запрос вернет код состояния 200 вместе с полезной нагрузкой ответа. Если произойдет какая-либо ошибка службы, код состояния будет 500, а если что-то не так с параметрами, отправленными на сервер, код состояния будет 400. Служба может ответить большинством кодов состояния HTTP вместе со своей полезной нагрузкой. Итак, если, например, вы хотите, чтобы ваша служба сообщала своим клиентам, когда им не разрешен доступ к определенной конечной точке, вы можете сделать это, ответив кодом 403. Вы можете увидеть еще один пример кодов ответов, если вернетесь к нашему сервисному коду выше. В конечной точке get мы возвращаем код состояния 404 вместе с необязательным сообщением «Нет людей здесь», когда люди не найдены, точно так же, как HTTP-сервер возвращает 404, если нет доступных ресурсов. Если репозиторий действительно возвращает людей, то служба сериализует DTO и возвращает их клиенту. Каждый DTO имеет сериализатор по умолчанию, который возвращает объект JSON с ключами и соответствующими значениями, определенными как attr_reader или attr_accessible в определении DTO. Конечно, вы можете переопределить сериализатор, определив свой метод сериализации в своих классах DTO.

Теперь, когда у нас определена служба, нам нужно ее зарегистрировать. Это последний шаг. Откройте файл lib/service_register.rb и замените все вхождения «HelloWorld» на «Person», чтобы в итоге файл выглядел примерно так:

 module ZSS class ServiceRegister def self.get_service config = Hashie::Mash.new( backend: Settings.broker.backend ) service = ZSS::Service.new(:person, config) personInstance = PersonService.new service.add_route(personInstance, :get) return service end end end

Как вы, наверное, заметили, в вызове add_route есть небольшое изменение. Мы удалили строку «HELLO/WORLD». Это связано с тем, что строка необходима только в том случае, если служебный глагол не соответствует методу, который его реализует. В нашем случае при вызове службы person с помощью команды GET вызывается метод get , поэтому строку можно опустить.

В классе ServiceRegister вы должны определить метод self.get_service . Этот метод инициализирует службу и подключает ее к серверной части брокера. Затем он сопоставляет маршруты в этой службе с методами в одном или нескольких определениях службы. Например, в следующем случае он создает службу и привязывает ее к брокеру:

 config = Hashie::Mash.new( backend: Settings.broker.backend ) service = ZSS::Service.new(:person, config)

Затем он создает обработчик службы:

 personInstance = PersonService.new

Далее обработчик сервиса привязывается к сервису:

 service.add_route(personInstance, :get)

Наконец, он должен вернуть экземпляр службы.

 return service

Теперь остался только один последний шаг, прежде чем мы сможем запустить нашу службу «Персона»; нам нужно создать для него исполняемый скрипт. У нас уже есть один для «HelloService». Итак, откройте файл bin/zss-service , замените «hello-word» на «person» и сохраните файл. Вернитесь в консоль и выполните:

 $ bin/zss-service run Starting person: PID: ./log LOGS: ./log Started person daemon... 15-29-15 19:29:54 | INFO | ZSS::SERVICE - Starting SID: 'PERSON' ID: 'person#d3ca7e1f-e229-4502-ac2d-0c01d8c285f8' Env: 'development' Broker: 'tcp://127.0.0.1:7776'

Вот и все. Вы только что впервые запустили свой сервис «Персона». Теперь давайте проверим это. Откройте файл bin/zss-client , измените переменную sid на «person» и измените вызов клиента с hello_world() на get() . После этого запустите клиент в новом окне:

 $ bin/zss-client /Users/francisco/.rvm/gems/ruby-2.1.2/gems/zss-0.3.4/lib/zss/client.rb:41:in `new': No people here (ZSS::Error) from /Users/francisco/.rvm/gems/ruby-2.1.2/gems/zss-0.3.4/lib/zss/client.rb:41:in `call' from /Users/francisco/.rvm/gems/ruby-2.1.2/gems/zss-0.3.4/lib/zss/client.rb:55:in `method_missing' from bin/zss-client:12:in `<main>'

Как видите, вы поймали ZSS::Error . Это связано с тем, что мы выдаем ошибку, когда служба не находит людей, а в базе данных нашей службы еще нет людей.

Тогда давайте обработаем эту ошибку. Откройте zss-client и отредактируйте его следующим образом:

 begin client = ZSS::Client.new(sid, config) p client.get() rescue ZSS::Client => e if e.code == 404 p e.message else raise e end end

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

 $ bin/zss-client "No people here"

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

 $ rake service:console

Добавьте несколько человек:

 $ rake service:console [1] pry(main)> DAO::Person.create name: 'John' => #<DAO::Person:0x007fe51bbe9d00 id: 1, name: "John", created_at: 2015-12-16 13:22:37 UTC, updated_at: 2015-12-16 13:22:37 UTC> [2] pry(main)> DAO::Person.create name: 'Mary' => #<DAO::Person:0x007fe51c1dafe8 id: 2, name: "Mary", created_at: 2015-12-16 13:22:42 UTC, updated_at: 2015-12-16 13:22:42 UTC> [3] pry(main)> DAO::Person.create name: 'Francis' => #<DAO::Person:0x007fe51bc11698 id: 3, name: "Francis", created_at: 2015-12-16 13:22:53 UTC, updated_at: 2015-12-16 13:22:53 UTC> [4] pry(main)> exit

Теперь снова запустите клиент.

 $ bin/zss-client [{"id"=>1, "name"=>"John"}, {"id"=>2, "name"=>"Mary"}, {"id"=>3, "name"=>"Francis"}]

Вот оно.

Заключительные соображения

Просматривая код, представленный в этом руководстве, вы можете подумать, что есть много ненужных шагов, таких как создание репозиториев или DTO, и вы будете правы. Все, что вам нужно, чтобы иметь функционирующую службу «Person», — это ваш класс обслуживания и ваш DAO, которые вы можете вызывать непосредственно из класса обслуживания. Тем не менее рекомендуется следовать шаблону, описанному в этой статье, поскольку он позволяет отделить логику службы от манипуляций с хранилищем данных. Сервисы должны быть сосредоточены только на своей логике, а репозитории должны обрабатывать все взаимодействия с вашим хранилищем данных. DTO определяют полезную нагрузку и сериализацию ваших сервисов, а DAO занимаются только получением данных из хранилища. Соглашения и методы, описанные в этом руководстве, известны как шаблон репозитория, который вы можете увидеть на изображении ниже.

Шаблон репозитория. Крайний левый блок — это «клиентская бизнес-логика», которая сохраняется и выполняет запросы из среднего блока, который представляет собой стек, состоящий из «преобразователя данных» над «репозиторием» над «объектом запроса», но разделенных пунктирными линиями. Сохранение и запрос соединены соединениями из внешних блоков, помеченных как «бизнес-сущность». Наконец, в крайнем правом поле «источник данных» есть стрелка, указывающая на «сопоставитель данных», и двунаправленные стрелки на «объект запроса».

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

Я надеюсь, что это поможет вам начать работу с микросервисами. Если вы хотите проверить код службы, полная версия доступна на GitHub.