Миграция на сервис-ориентированную архитектуру

20 марта 2014, 13:58

Три способа «переехать» на SOA, лаконично описанные и снабженные иллюстрациями. Авторы рекомендуют свой материал для тех, у кого же есть какое-то представление о сервисно-ориентированной архитектуре. 

Мы написали Belly очень быстро. Для этого нам потребовалось объединить множество различных бизнес-возможностей в одно приложение. Мы использовали Rails (начиная с версии 3.0 и вплоть до версии 3.2), поскольку при применении Rails в качестве веб-фреймворка работа с ним идет быстро и доставляет одно удовольствие. В общем виде наша инфраструктура была построена так, как показано на следующей схеме (многие незначительные детали опущены, поскольку никак не связаны с остальной частью этой статьи). Если хотите разобраться подробнее – спрашивайте, с удовольствием расскажем, чем занимаемся.

Подробнее о миграции на SOA


Достаточно просто. Приложение Rails подкреплено несколькими хранилищами данных. Мы воспользовались базами данных MySQL и MongoDB. Большинство данных были реляционными, но в некоторых случаях оказалось более целесообразно применить хранилища документов. Наши клиенты (мобильные телефоны и планшеты iPad) обслуживались через API, входивший в состав приложения Rails. 

Со временем приложение усложнялось, поскольку нам приходилось обрабатывать все новые практические случаи. Одна из самых назойливых проблем заключалась в необходимости частого развертывания из-за внесения множества мелких изменений. Чтобы справиться с этим, мы отделили домашнюю страницу (веб-виды) от основной части приложения и начали потреблять API как клиент. Сработало! Меньше видов/ресурсов/файлов/уменьшился git-репозиторий => развертывание идет быстрее! В какой-то степени мы смогли этого достичь, но сфера применения приложения растет, а значит, она усложняется.    


Разделение ответственности

Но как? Проще пареной репы, если при инструментальном переоснащении программы можно начать все по новой и приостановить решение бизнес-задач на время такого переоснащения. Мы не можем себе этого позволить (пожалуй, и никто не может – подробнее об этом в следующем разделе). Поэтому мы построили сервисы.

Идея проста. Каждая зона ответственности обрабатывается отдельным сервисом. Есть один внешний API для обслуживания клиентов и ряд внутренних API, обеспечивающих коммуникацию между сервисами. Звучит удручающе для всех, кто высоко ценит простоту и скорость связей в базах данных. Но это не проблема. Как правило, для работы с данными не требуется множества связей. Если вы еще не знакомы с SOA, то этот пост может показаться немного вырванным из контекста. Те же, кто хотел разобраться в этой теме, но не знал, с чего начать, могут читать дальше – сейчас все будет понятно.

Концептуализация новых приложений – не такая сложная задача. Есть новая база данных, новый сервис, новый API. Самое сложное – найти способ миграции старых данных в парадигму SOA. В конце концов, все эти данные запрятаны глубоко в объектах ActiveRecords, причем все унаследованное приложение пронизано связями. Итак, если требуется извлечь информацию из старой базы данных, это можно сделать такими способами:

  1. Сделать новый сервис для обращения к информации, хранящейся в старой базе данных
  2. Сослаться на старую базу данных из нового сервиса и включить новые данные
  3. Начать с чистого листа, то есть, создать новую базу данных и новый сервис. Скопируйте данные и в путь.

В большинстве случаев метод 3 является идеальным, но непрактичным. Другим компонентам вашего Rails-приложения требуется доступ к этим данным, часто такой доступ должен происходить непосредственно через базу данных.
При применении метода 1 или метода 2 мы не вполне ориентируем большинство SOA-инфраструктур на верное развитие, которое помогло бы им правильно оформиться в долгосрочной перспективе (каждый сервис в итоге должен быть полностью подкреплен собственным хранилищем/хранилищами данных и вспомогательной инфраструктурой). Но эти методы помогают быстро создать программу, а позже вы сможете отдельно заняться распределением данных по отдельным хранилищам.
На следующих трех схемах показано, как каждый из трех методов отражается на вашей инфраструктуре. Обратите внимание: все методы по-прежнему подключены к одному API, поэтому конечный пользователь не ощущает на уровне приложения тех изменений, которые вы вносите в инфраструктуру.

Метод 1

Метод 1 предполагает создание сервиса без всяких дополнительных данных, поверх того, что уже имеется в нашем приложении. Теперь у вас есть внешний сервис, на который вы ссылаетесь из старого приложения по HTTP (или по другому протоколу передачи данных). Таким образом, вы по-прежнему можете модифицировать бизнес-логику в самодостаточном приложении. В идеале следует удалить в старом приложении все ссылки на базу данных (и на ее модели) из старого приложения. В итоге, это может привести к ситуации, описанной в методе 2, где мы не только ссылаемся на унаследованное хранилище данных, но и используем сервис-специфичное хранилище.

Метод 2

Метод 2 приводит к нарастающему хаосу зависимостей, но является наиболее быстрым способом создания готового сервиса. Реализуйте объектно-реляционное отображение в вашем новом сервисе, это поможет получить доступ к старой базе данных для нужной вам модели (если вы пишете на Ruby, то, скорее всего, здесь придется иметь дело с ActiveRecord или DataMapper). Кроме того, можно создать хранилище данных, специфичное для вашего сервиса. В конце концов, понадобится вообще уйти от использования старого хранилища данных в качестве ресурса, разделяемого между старым приложением и новым сервисом.

Метод 3

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

Конечная цель

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

Миграция получается немного шероховатой, но она вполне осуществима и позволяет не переписывать все и сразу.

Джей О’Коннор

Источник

подписка на главные новости 
недели != спам
# ит-новости
# анонсы событий
# вакансии
Обсуждение