Создание микросервисов — страница 27 из 69

Рис. 5.12. Стандартная копия для чтения данных


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

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

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

Что, если данные нашего приложения лучше моделируются как граф в Neo4j? Или если нам лучше будет воспользоваться таким хранилищем документов, как MongoDB? А что, если для нашей системы создания отчетов захочется присмотреться к использованию основанной на понятии столбцов базе данных Cassandra, которая упрощает масштабирование более существенных объемов данных? Ограничивая себя необходимостью использования одной базы данных в обеих целях, мы часто лишаемся возможности подобного выбора и исследования новых вариантов.

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

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

Извлечение данных посредством служебных вызовов

Существует множество вариантов этой модели, но все они основаны на извлечении запрошенных данных из исходной системы посредством API-вызовов. Для очень простой системы создания отчетов, подобной панели мониторинга, на которой может быть нужно всего лишь показывать количество заказов, размещенных за последние 15 минут, это может оказаться вполне подходящим вариантом. Чтобы создать отчет на основе данных от двух и более систем, нужно для сбора этих данных сделать несколько вызовов.

Но при вариантах, требующих более крупных объемов данных, этот подход быстро становится непригодным. Представьте такой вариант использования, при котором нужно составить отчет о предпочтениях в покупках клиента нашего музыкального магазина за последние 24 месяца с рассмотрением различных тенденций в его поведении и того, как это влияло на выручку. Для этого необходимо извлечь большие объемы данных как минимум из клиентской и финансовой систем. Сохранять локальную копию этих данных в системе создания отчетов опасно, поскольку мы будем не в курсе происходящих изменений (задним числом могут изменяться даже исторические данные), поэтому для создания точного отчета нужны все финансовые и клиентские записи за последние два года. Даже при скромном числе клиентов можно будет заметить, что вскоре эта операция станет проводиться очень медленно.

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

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

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

Для упрощения создания отчетов данную проблему можно решить путем раскрытия пакетных API. Например, наш сервис клиентов может позволить прохождение по списку идентификаторов пользователей для извлечения данных о них в пакетах или даже раскрыть интерфейс, позволяющий пролистывать данные обо всех клиентах. Более экстремальным вариантом этого действия будет моделирование пакетного запроса в качестве самостоятельного ресурса. Например, клиентский сервис может раскрыть что-то вроде конечной точки ресурса BatchCustomerExport. Вызывающая система будет выдавать POST-запрос BatchRequest, возможно, передавая сведения о месте, где может находиться файл со всеми данными. Клиентский сервис в качестве ответа вернет код HTTP 202, показывающий, что запрос был принят, но еще не обработан. Затем вызывающая система может опрашивать ресурс, ожидая возвращения от него статуса выполнения 201 Created, свидетельствующего о выполнении запроса и о том, что вызывающая система может перейти к извлечению данных. Это может позволить потенциально большим файлам данных экспортироваться без издержек, связанных с их отправкой по HTTP. Вместо этого система может просто сохранить CSV-файл в место совместного доступа.

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

Программы перекачки данных

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

Рис. 5.13. Использование программы перекачки данных для их периодического перемещения в центральную отчетную базу данных


И вот здесь вы можете возразить: «Сэм, ты же говорил, что лучше не использовать программы, интегрированные посредством базы данных!» По крайней мере, я надеюсь на такое ваше замечание, учитывая настойчивость, с которой я высказывал возражения по данному вопросу! Этот подход при надлежащей реализации является весьма интересным исключением, в котором недостатки связанности более чем компенсированы легкостью создания отчетов.

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