КулЛиб - Классная библиотека! Скачать книги бесплатно
Всего книг - 714649 томов
Объем библиотеки - 1414 Гб.
Всего авторов - 275119
Пользователей - 125173

Последние комментарии

Новое на форуме

Новое в блогах

Впечатления

iv4f3dorov про Дорнбург: Змеелов в СССР (Альтернативная история)

Очередное антисоветское гавно размазанное тонким слоем по всем страницам. Афтырь ты мудак.

Рейтинг: 0 ( 1 за, 1 против).
A.Stern про Штерн: Анархопокалипсис (СИ) (Фэнтези: прочее)

Господи)))
Вы когда воруете чужие книги с АТ: https://author.today/work/234524, вы хотя бы жанр указывайте правильный и прологи не удаляйте.
(Заходите к автору оригинала в профиль, раз понравилось!)

Какое же это фентези, или это эпоха возрождения в постапокалиптическом мире? -)
(Спасибо неизвестному за пиар, советую ознакомиться с автором оригинала по ссылке)

Ещё раз спасибо за бесплатный пиар! Жаль вы не всё произведение публикуете х)

Рейтинг: 0 ( 0 за, 0 против).
чтун про серию Вселенная Вечности

Все четыре книги за пару дней "ушли". Но, строго любителям ЛитАниме (кароч, любителям фанфиков В0) ). Не подкачал, Антон Романович, с "чувством, толком, расстановкой" сделал. Осталось только проду ждать, да...

Рейтинг: +2 ( 2 за, 0 против).
Влад и мир про Лапышев: Наследник (Альтернативная история)

Стиль написания хороший, но бардак у автора в голове на нечитаемо, когда он начинает сочинять за политику. Трояк ставлю, но читать дальше не буду. С чего Ленину, социалистам, эссерам любить монархию и терпеть черносотенцев,убивавших их и устраивающие погромы? Не надо путать с ворьём сейчас с декорациями государства и парламента, где мошенники на доверии изображают партии. Для ликбеза: Партии были придуманы ещё в древнем Риме для

  подробнее ...

Рейтинг: 0 ( 0 за, 0 против).
Влад и мир про Романов: Игра по своим правилам (Альтернативная история)

Оценку не ставлю. Обе книги я не смог читать более 20 минут каждую. Автор балдеет от официальной манерной речи царской дворни и видимо в этом смысл данных трудов. Да и там ГГ перерождается сам в себя для спасения своего поражения в Русско-Японскую. Согласитесь такой выбор ГГ для приключенческой фантастики уже скучноватый. Где я и где душонка царского дворового. Мне проще хлев у своей скотины вычистить, чем служить доверенным лицом царя

  подробнее ...

Рейтинг: +1 ( 1 за, 0 против).

От монолита к микросервисам [Сэм Ньюмен] (pdf) читать онлайн

Книга в формате pdf! Изображения и текст могут не отображаться!


 [Настройки текста]  [Cбросить фильтры]

Monolith to Microservices
Evolutionary Patterns to Transform
Your Monolith

Sam Newman

Beijing • Boston • Farnham • Sebastopol • Tokyo

O’REILLY

Сэм Ньюмен

ОТ МОНОЛИТА
К МИКРОСЕРВИСАМ

Санкт-Петербург

« БХВ-Петербург»
2021

УДК 004.43
ББК 32.973.26-02
Н93

Ньюмен С.
Н93

От монолита к микросервисам: Пер. с англ. — СПб.: БХВ-Петербург,
2021. — 272 с.: ил.
ISBN 978-5-9775-6723-7
Новая книга Сэма Ньюмена подробно описывает проверенный метод перевода
существующей монолитной системы на микросервисы, поддерживающий работу
организации в обычном режиме. Она дополняет его бестселлер «Создание микро­
сервисов». Руководство содержит наглядные примеры, шаблоны миграции, массу
практических советов по переводу монолитной системы на платформу для микро­
служб, различные сценарии и стратегии успешной миграции, начиная с первичного
планирования и заканчивая декомпозицией приложений и баз данных. Описанные
шаблоны и методы можно использовать для миграции уже существующей архи­
тектуры.

Для системных архитекторов, разработчиков
и ИТ-специалистов
УДК 004.43
ББК 32.973.26-02
Группа подготовки издания:

Руководитель проекта
Зав. редакцией
Перевод с английского
Компьютерная верстка
Оформление обложки

Евгений Рыбаков
Екатерина Сависте
Андрея Логунова
Ольги Сергиенко
Карины Соловьевой

©2021 BHV
Authorized Russian translation of the English edition of Monolith to Microservices ISBN 9781492047841
© 2020 Sam Newman
This translation is published and sold by permission of O’Reilly Media, Inc., which owns or controls all rights to publish
and sell the same.
©2021 BHV
Авторизованный русский перевод английского издания Monolith to Microservices ISBN 9781492047841
© 2020 Sam Newman
Этот перевод публикуется и продается с разрешения компании O’Reilly Media, Inc., являющейся правообладателем
на публикацию и продажу издания.

Подписано в печать 13.01.21.
Формат 70x1001/i6. Печать офсетная. Усл. печ. л. 21,93.
Тираж 1000 экз. Заказ № 006.
"БХВ-Петербург", 191036, Санкт-Петербург, Гончарная ул., 20

Отпечатано с готового оригинал-макета
ООО "Принт-М", 142300, М.О., г Чехов, ул Полиграфистов, д 1

ISBN 978-1-492-04784-1 (англ.)
ISBN 978-5-9775-6723-7 (рус.)

© Sam Newman, 2020
© Перевод на русский язык, оформление
ООО "БХВ-Петербург", ООО "БХВ", 2021

Оглавление

Об авторе......................................................................................................................... 13
Предисловие................................................................................................................... 15
Чему вы научитесь......................................................................................................................... 15
Условные обозначения, принятые в книге...................................................................................16
Благодарности ................................................................................................................................. 17

Глава 1. Основные сведения о микрослужбах......................................................... 21
Что такое микрослужбы?.............................................................................................................. 21
Независимая развертываемость............................................................................................ 22
Моделируются вокруг бизнес-домена................................................................................. 22
Владеют своими собственными данными........................................................................... 25
Какие преимущества приносят микрослужбы?.................................................................. 26
Какие проблемы они создают?............................................................................................. 27
Пользовательские интерфейсы............................................................................................. 28
Технология............................................................................................................................. 28
Размер..................................................................................................................................... 29
И владение.............................................................................................................................. 30
Монолит......................................................................................................................................... 32
Однопроцессный монолит.................................................................................................... 32
И модульный монолит........................................................................................................... 33
Распределенный монолит..................................................................................................... 34
Сторонние черно-ящичные системы.................................................................................... 35
Трудности монолитов............................................................................................................ 35
Преимущества монолитов..................................................................................................... 35
О сопряженности и связности...................................................................................................... 36
Связность................................................................................................................................ 38
Сопряженность...................................................................................................................... 38
Имплементационная сопряженость..................................................................................... 39
Временная сопряженность.................................................................................................... 42
Сопряженность развертывания............................................................................................ 43
Доменная сопряженность...................................................................................................... 44
Доменно-обусловленный дизайн................................................................................................. 47
Агрегат.................................................................................................................................... 48
Ограниченный контекст........................................................................................................ 50
Отображение агрегатов и ограниченных контекстов в микрослужбы............................. 50
Дальнейшее чтение................................................................................................................ 51
Резюме............................................................................................................................................ 51
5

Глава 2. Планирование миграции............................................................................ 53
Понимание цели............................................................................................................................ 53
Три ключевых вопроса......................................................................................................... 55
Почему вы, возможно, выберете микрослужбы?....................................................................... 55
Повысить автономию групп.................................................................................................55
Как еще это сделать?...............................................................................................56
Сократить время до рынка....................................................................................................57
Как еще это сделать?...............................................................................................57
Выполнить эффективное по стоимости масштабирование с учетом нагрузки............... 57
Как еще это сделать?...............................................................................................58
Повысить робастность.......................................................................................................... 58
Как еще это сделать?...............................................................................................59
Промасштабировать число разработчиков......................................................................... 60
Как еще это сделать?.............................................................................................. 61
Внедрить новую технологию................................................................................................61
Как еще это сделать?...............................................................................................61
Когда микрослужбы будут плохой идеей?..................................................................................63
Неясный домен.......................................................................................................................63
Стартапы................................................................................................................................. 64
Софт инсталлируется и управляется клиентом.................................................................. 65
Отсутствует веская причина!................................................................................................65
Компромиссы................................................................................................................................. 66
Приглашение людей в ’’путешествие”.........................................................................................67
Изменение организаций................................................................................................................68
Закрепление чувства насущной необходимости................................................................ 68
Создание направляющей коалиции......................................................................................69
Развитие видения и стратегии..............................................................................................70
Коммуницирование видения перемен.................................................................................70
Расширение полномочий сотрудников по широкому кругу действий............................ 71
Генерирование краткосрочных выигрышей........................................................................72
Консолидация выигрышей и порождение новых изменений........................................... 73
Заякоревание новых подходов в культуре...........................................................................73
Важность поступательной миграции...........................................................................................74
Главное — производство......................................................................................................74
Стоимость изменения....................................................................................................................75
Обратимые и необратимые решения...................................................................................75
Более легкие места для эксперимента.................................................................................77
Так с чего же мы начнем?.............................................................................................................77
Доменно-обусловленный дизайн................................................................................................ 77
Как далеко заходить?.............................................................................................................78
Событийный штурм...............................................................................................................79
Использование доменной модели для приоритизации...................................................... 79
Комбинированная модель............................................................................................................. 81
Реорганизация групп..................................................................................................................... 83
Сдвиг в структуре.................................................................................................................. 83
Не одна мерка для всех.........................................................................................................84
Внесение изменений..............................................................................................................86
Изменение навыков...............................................................................................................88

6

|

Оглавление

Как узнать, что транзит работает?............................................................................................... 91
Наличие регулярных контрольных точек............................................................................ 91
Количественные показатели................................................................................................. 92
Качественные показатели..................................................................................................... 92
Избегать эффекта понесенных расходов............................................................................. 93
Оставаясь открытым для новых подходов.......................................................................... 94
Резюме............................................................................................................................................ 94

Глава 3. Разложение монолита................................................................................... 97
Изменять монолит или не изменять?........................................................................................... 97
Вырезать, скопировать или реимплементировать?............................................................ 98
Рефакторизация монолита.................................................................................................... 99
Модульный монолит?............................................................................................. 99
Поступательные переписывания..........................................................................100
Шаблоны миграции...................................................................................................................... 100
Шаблон', приложение ’’Фикус-удавка"....................................................................................... 101
Как он работает..................................................................................................................... 101
Где его использовать............................................................................................................ 103
Пример: обратный прокси-селектор HTTP........................................................................105
Шаг 1: вставить прокси-селектор.........................................................................105
Шаг 2: мигрировать функциональность .............................................................. 106
Шаг 3: перенаправить вызовы..............................................................................107
Данные?................................................................................................................................. 107
Варианты прокси-селектора................................................................................................ 108
Поступательное внедрение.................................................................................... 110
Смена протоколов................................................................................................................. 111
И сетки для служб................................................................................................................. 113
Пример: FTP.......................................................................................................................... 115
Пример: перехват сообщений.............................................................................................. 116
Маршрутизация на основе содержимого............................................................ 116
Селективное потребление..................................................................................... 117
Другие протоколы................................................................................................................ 118
Другие примеры шаблона "Фикус-удавка"........................................................................118
Изменение поведения во время мигрирования функциональности........................................ 119
Шаблон'. "Композиция пользовательского интерфейса"......................................................... 120
Пример: страничная композиция........................................................................................ 120
Пример: виджетная композиция.........................................................................................121
И мобильные приложения.....................................................................................123
Пример: микрофронтэнды................................................................................................... 124
Где его использовать............................................................................................................125
Шаблон'. "Ветвление по абстракции"..........................................................................................126
Как он работает.....................................................................................................................126
Шаг 1: создать абстракцию.................................................................................. 127
Шаг 2: использовать абстракцию........................................................................ 127
Шаг 3: создать новую имплементацию............................................................... 128
Шаг 4: переключить имплементацию................................................................. 129
Шаг 5: очистка........................................................................................................131
В качестве механизма отката...............................................................................................133
Где его использовать........................................................................................................... 134

Оглавление

|

7

Шаблон: ’’Параллельное выполнение’’...................................................................................... 134
Пример: сравнение ценообразования кредитных деривативов....................................... 135
Пример: листинги компании Homegate............................................................................. 136
Методы верификации.......................................................................................................... 137
Использование "шпионов”.................................................................................................. 137
Библиотека Scientist хостинга GitHub................................................................................ 139
’’Темный” запуск и выпуск ’’канареечных” релизов......................................................... 139
Где его использовать........................................................................................................... 139
Шаблон: ’’Сотрудник-декоратор”............................................................................................... 140
Пример: программа лояльности......................................................................................... 140
Где его использовать........................................................................................................... 141
Шаблон: ’’Захват изменений в данных”..................................................................................... 142
Пример: выпуск карточек лояльности............................................................................... 142
Имплементация захвата изменений в данных................................................................... 143
Триггеры базы данных.......................................................................................... 143
Опросники журналов транзакций........................................................................ 144
Пакетный копировальщик дельты....................................................................... 145
Где его использовать........................................................................................................... 145
Резюме.......................................................................................................................................... 146

Глава 4. Декомпозиция базы данных...................................................................... 147
Шаблон: ’’Совместная база данных”.......................................................................................... 147
Шаблоны преодоления........................................................................................................ 148
Где его использовать........................................................................................................... 149
Но это невозможно сделать!....................................................................................................... 149
Шаблон: "Проекция базы данных”............................................................................................ 150
База данных как публичный контракт............................................................................... 151
Представляемые проекции.................................................................................................. 152
Ограничения......................................................................................................................... 153
Владение............................................................................................................................... 153
Где его использовать........................................................................................................... 153
Шаблон: "Служба обертывания базы данных"......................................................................... 154
Где его использовать........................................................................................................... 155
Шаблон: "Интерфейс база-данных-как-служба”...................................................................... 157
Имплементация механизма отображения.......................................................................... 158
Сравнение с проекциями базы данных.............................................................................. 159
Где его использовать........................................................................................................... 159
Передача владения....................................................................................................................... 159
Шаблон: "Монолит с выставлением агрегата наружу”............................................................ 160
В качестве пути к большему числу служб......................................................................... 162
Где его использовать........................................................................................................... 162
Шаблон: "Смена владельца данных"......................................................................................... 162
Где его использовать........................................................................................................... 164
Синхронизация данных............................................................................................................... 164
Шаблон: "Синхронизировать данные в приложении”............................................................. 166
Шаг 1: массово синхронизировать данные....................................................................... 166
Шаг 2: синхронизировать при записи, читать из старой схемы...................................... 167
Шаг 3: синхронизировать при записи, читать из новой схемы....................................... 168
Зачем использовать этот шаблон....................................................................................... 168
Где его использовать........................................................................................................... 169
8

|

Оглавление

Шаблон'. ’’Трассировочная запись’’............................................................................................. 170
Синхронизация данных........................................................................................................ 173
Пример: заказы в Square....................................................................................................... 174
Создание новой службы........................................................................................ 175
Синхронизировать данные.................................................................................... 176
Мигрирование потребителей................................................................................ 177
Где его использовать............................................................................................................ 178
Разбиение базы данных................................................................................................................ 178
Физическое и логическое разделение баз данных............................................................ 179
Что выделять сначала: базу данных или код?............................................................................180
Сначала выделить базу данных................................................................................................... 181
Шаблон'. ’’Один репозиторий на один ограниченный контекст”............................................. 182
Где его использовать............................................................................................................ 183
Шаблон. ’’Одна база данных на один ограниченный контекст”.............................................. 184
Где его использовать............................................................................................................ 185
Сначала выделить код.................................................................................................................. 185
Шаблон'. ’’Монолит как слой доступа к данным”......................................................................186
Где его использовать............................................................................................................ 188
Шаблон: ’’Мультисхемное хранение”......................................................................................... 188
Где его использовать............................................................................................................ 189
Выделить базу данных и код вместе........................................................................................... 189
Так что же мне выделять сначала?..............................................................................................190
Примеры выделения схемы......................................................................................................... 190
Шаблон: ’’Разложить таблицу”.................................................................................................... 191
Где его использовать............................................................................................................ 193
Шаблон: ’’Перенести связь по внешнему ключу в код”........................................................... 193
Перенос операции соединения............................................................................................ 194
Согласованность данных....................................................................................... 196
Проверять перед удалением.................................................................................. 196
Улаживать удаление изящно............................................................................................... 196
Не разрешать удаление.......................................................................................... 197
И как же тогда обрабатывать удаление?............................................................. 197
Где его использовать............................................................................................................ 198
Пример: совместные статические данные..................................................................................198
Шаблон: ’’Дублировать статические справочные данные”...................................................... 199
Где его использовать........................................................................................................... 200
Шаблон: ’’Выделенная схема справочных данных”................................................................. 200
Где его использовать........................................................................................................... 201
Шаблон: ’’Библиотека статических справочных данных”....................................................... 201
Где его использовать........................................................................................................... 204
Шаблон: ’’Служба статических справочных данных”.............................................................. 204
Где его использовать........................................................................................................... 206
Что бы я сделал?.................................................................................................................. 206
Транзакции................................................................................................................................... 207
ACID-транзакции................................................................................................................. 207
По-прежнему ACID, но не хватает атомарности?............................................................ 208
Двухфазные фиксации......................................................................................................... 210
Распределенные транзакции — просто скажи ’’нет”........................................................ 212

Оглавление

|

9

Саги............................................................................................................................................... 213
Режимы сбоя саги................................................................................................................215
Откаты в саге........................................................................................................................ 215
Переупорядочивание шагов для уменьшения откатов..................................... 217
Смешивание ситуаций сбоя назад и сбоя вперед.............................................. 218
Имплементация саг..............................................................................................................219
Оркестрированные саги........................................................................................ 219
Хореографированные саги...................................................................................221
Смешивание стилей.............................................................................................................223
Что использовать: хореографию или оркестровку?.......................................... 223
Саги против распределенных транзакций.........................................................................224
Резюме.......................................................................................................................................... 225

Глава 5. Болезни роста...............................................................................................227
Чем больше служб, тем больше боли........................................................................................ 227
Владение кодом в широком масштабе.......................................................................................229
Как эта проблема проявляется?..........................................................................................229
Когда эта проблема возникает?.......................................................................................... 230
Потенциальные решения..................................................................................................... 230
Переломные изменения............................................................................................................... 231
Как эта проблема проявляется?.......................................................................................... 231
Когда эта проблема возникает?.......................................................................................... 231
Потенциальные решения..................................................................................................... 232
Устранять ’’нечаянные” переломные изменения............................................... 232
Хорошенько подумать, прежде чем вносить переломные изменения............ 233
Давать потребителям время на миграцию......................................................... 233
Отчетность................................................................................................................................... 235
Когда эта проблема возникает?.......................................................................................... 236
Потенциальные решения..................................................................................................... 236
Мониторинг и устранение неполадок........................................................................................ 237
Когда эти проблемы возникают?........................................................................................ 238
Как эти проблемы проявляются?....................................................................................... 238
Потенциальные решения..................................................................................................... 238
Агрегирование журналов..................................................................................... 238
Трассировка........................................................................................................... 239
Испытание в производстве................................................................................... 241
В направлении наблюдаемости............................................................................242
Локальный опыт разработчиков.................................................................................................242
Как эта проблема проявляется?.......................................................................................... 243
Когда эта проблема возникает?.......................................................................................... 243
Потенциальные решения..................................................................................................... 243
Выполнение слишком многого.................................................................................................. 244
Как эта проблема проявляется?.......................................................................................... 244
Когда эти проблемы возникают?........................................................................................ 244
Потенциальные решения..................................................................................................... 245
Сквозное тестирование............................................................................................................... 246
Как эта проблема проявляется?.......................................................................................... 246
Когда эта проблема возникает?.......................................................................................... 247

10

|

Оглавление

Потенциальные решения..................................................................................................... 247
Ограничить охват функциональных автоматизированных испытаний...........247
Использовать контракты, обусловливаемые потребителем.............................. 247
Использовать автоматическую ремедиацию релиза
и прогрессивную доставку................................................................................... 248
Постоянно уточнять циклы обратной связи относительно качества................249
Глобальная оптимизация против локальной оптимизации...................................................... 249
Как эта проблема проявляется?.......................................................................................... 250
Когда эта проблема возникает?.......................................................................................... 250
Потенциальные решения..................................................................................................... 251
Робастность и отказоустойчивость............................................................................................ 252
Как эта проблема проявляется?.......................................................................................... 252
Когда эта проблема возникает?.......................................................................................... 252
Потенциальные решения..................................................................................................... 253
"Осиротевшие” службы.............................................................................................................. 253
Как эта проблема проявляется?.......................................................................................... 254
Когда эта проблема возникает?.......................................................................................... 254
Потенциальные решения..................................................................................................... 254
Резюме.......................................................................................................................................... 256

Заключение................................................................................................................... 257

Приложение 1. Библиография.................................................................................. 259
Приложение 2. Указатель шаблонов....................................................................... 261

Предметный указатель............................................................................................... 263

Оглавление

|

11

Об авторе

Сэм Ньюмен— разработчик, архитектор, писатель и оратор, который работал
с разными компаниями в разных областях по всему миру. Он работает независимо,
концентрируя свое внимание в основном на облачных вычислениях, непрерывной
доставке и микрослужбах. Его предыдущая книга — бестселлер ’’Создание микро­
сервисов”, также изданный в издательстве O’Reilly.

Когда он не ’’прыгает с одной подножки вагона на другую”, его можно найти
в сельской местности Восточного Кента, занимающимся различными видами спорта.

13

Предисловие

Еще несколько лет назад некоторые из нас лишь поговаривали о том, что, дескать,
микрослужбы (микросервисы1) — интересная идея. И вот не успели мы оглянуться,
как они стали архитектурой, принятой по умолчанию в сотнях компаний по всему
миру (многие, вероятно, запущены как стартапы, призванные решать проблемы,
вызванные микрослужбами), что заставило всех ’’перейти на бег”, чтобы успеть
’’запрыгнуть на подножку последнего вагона”, который, как они опасаются, вот-вот
исчезнет за горизонтом.

Должен признаться, здесь есть часть моей вины. С тех пор как в 2015 году я напи­
сал свою собственную книгу ’’Создание микросервисов ” (Building Microservices) на
эту тему, я зарабатываю на жизнь, работая с людьми, помогая им понять данный
тип архитектуры. Я всегда пытался сделать одно — прорваться сквозь хайп и по­
мочь компаниям определиться, подходят ли им микрослужбы или нет. Для многих
моих клиентов с существующими (не ориентированными на микрослужбы) систе­
мами трудность состояла в том, как внедрить архитектуры, основанные на микро­
службах. Как взять существующую систему и выполнить перепланировку ее архи­
тектуры, не останавливая всю остальную работу? Вот где на помощь приходит эта
книга. Что еще важнее, я постараюсь дать вам честную оценку трудностей, связан­
ных с архитектурой на основе микрослужб, и помочь вам понять, стоит ли начинать
это ’’путешествие”.

Чему вы научитесь
Эта книга задумана как глубокое погружение в образ мыслей и порядок действий
при разложении существующих систем на архитектуру, основанную на микро­
службах. Мы коснемся многих тем, связанных с архитектурой на основе микро­
служб, но в центре внимания будет находиться декомпозиция. В качестве более
общего руководства по архитектуре на основе микрослужб хорошим местом для
старта была бы моя предыдущая книга ’’Создание микросервисов ”. На самом деле
я настоятельно рекомендую вам рассматривать ту книгу как дополнение к этой.

Глава 1 содержит общий обзор того, что такое микрослужбы, и далее разведаны
идеи, которые привели нас к такого рода архитектуре. Этот материал будет хоро­
шим подспорьем для новичков в микрослужбах, но я также настоятельно призываю
даже более опытных разработчиков не пропускать эту главу. Чувствую, что
в шквале технологий некоторые стержневые идеи микрослужб часто упускаются из
виду: к этим концепциям книга будет возвращаться снова и снова.1
1 Далее "микрослужбы", см. Комментарии переводчика (после Предисловия).

15

Глубоко разбираться в микрослужбах совсем неплохо, но знать, подходят они вам
или нет, — это нечто другое. В главе 2 я расскажу, как оценить пригодность микро­
служб для ваших условий, а также дам некоторые действительно важные рекомен­
дации по управлению транзитом с монолита на архитектуру, основанную на микро­
службах. Здесь мы коснемся всего, от доменно-обусловленного дизайна до моделей
организационных изменений — жизненно важных основ, которые окажут вам не­
оценимую помощь, даже если вы решите не использовать архитектуру на основе
микрослужб.
В главах 3 и 4 мы глубже погрузимся в технические аспекты, связанные с декомпо­
зицией монолита, изучая реальные примеры и выделяя шаблоны миграции. Глава 3
сосредоточена на аспектах декомпозиции приложений, а глава 4 представляет со­
бой глубокое погружение в вопросы, связанные с данными. Если вы действительно
хотите перейти с монолитной системы на архитектуру, основанную на микрослуж­
бах, то вам придется разобрать некоторые базы данных на части!

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

Условные обозначения, принятые в книге
В книге используются следующие типографские условные обозначения:
♦ Курсив— указывает новые термины, URL-адреса, адреса электронной почты,
имена файлов и расширения файлов.
♦ моноширинный шрифт — применяется для листингов программ, а также внутри аб­

зацев для ссылки на элементы программ, такие, как переменные или имена, ин­
струкции языка и ключевые слова.
♦ полужирный моноширинный прифт — выделяет команды либо другой текст, который
должен быть напечатан пользователем буквально.

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

♦ моноширинный шрифт курсивом—

Данный элемент обозначает подсказку или совет.

Данный элемент обозначает общее замечание.

Данный элемент обозначает предупреждение или предостережение.

16

|

Предисловие

На веб-странице книги перечислены ошибки, приведены примеры и дополнитель­
ная информация. Вы можете обратиться к этой странице по адресу:

https://oreil.ly/monolith-to-microservices.

Благодарности
Без помощи и понимания моей замечательной жены Линди Стивенс эта книга была
бы невозможной. Эта книга для нее. Линди, прости, что я так ворчал, когда при­
ближались и проходили разные сроки завершения. Я также хотел бы поблагодарить
прекрасный клан Гиллман Стейне за всю их поддержку — мне повезло, что у меня
такие замечательные родные.
Эта книга во многом выиграла благодаря людям, которые любезно пожертвовали
свое время и энергию на то, чтобы прочитать различные черновики и дать ценные
идеи. Я особенно хочу поблагодарить Криса О’Делла, Дэниела Брайанта, Пита
Ходжсона, Мартина Фаулера, Стефана Шрасса и Дерека Хаммера за их усилия
в этом деле. Были также люди, которые непосредственно внесли свой вклад во
многих отношениях, поэтому я также хотел бы здесь поблагодарить Грэма Тэкли,
Эрика Доэрненберга, Марчина Засепу, Майкла Фетера, Рэнди Шоуп, Кифа Морри­
са, Питера Гилларда-Мосса, Мэтта Хита, Стива Фримена, Рене Ленгвината, Сару
Уэллс, Риса Эванса и Берка Сохана. Если вы найдете ошибки в этой книге, то эти
ошибки будут моими, а не их.

Коллектив издательства O’Reilly также оказал невероятную поддержку, и я хотел
бы высоко оценить труд моих редакторов Элеоноры Брю и Алисии Янг, в дополне­
ние к Кристоферу Гузиковски, Мэри Трезелер и Рейчел Румелиотис. Также хочу
сказать большое спасибо Хелен Кодлинг и ее коллегам по всему миру за то, что они
продолжают таскать мои книги на различные конференции, Сьюзен Конант за то,
что она помогает мне оставаться в здравом уме, ориентируясь в меняющемся мире
издательского дела, и Майку Лукидесу за то, что он изначально привлек меня к ра­
боте с O'Reilly. Я знаю, что есть еще много людей ”за кулисами", которые оказыва­
ли помощь, так что спасибо вам всем.
Помимо тех, кто непосредственно внес свой вклад в эту книгу, также хочу назвать
и тех, кто осознанно или нет, помог этой книге появиться. Поэтому хотел бы по­
благодарить (в произвольном порядке) Мартина Келппманна, Бена Стопфорда, Чарити Мейджорс, Алистера Кокберна, Грегора Хупе, Бобби Вулфа, Эрика Эванса,
Ларри Константина, Лесли Лэмпорта, Эдварда Йордона, Дэвида Парнаса, Майка
Блэнда, Дэвида Вудса, Джона Оллспоу, Альберто Брандолини, Фредерика Брукса,
Синди Сридхаран, Дейва Фарли, Джез Хамбл, Джина Кима, Джеймса Льюиса, Ни­
коль Форсгрен, Гектора Гарсиа-Молину, Sheep & Cheese, Кеннет Салема, Адриан
Кольера, Пэе Хелланд, Крестен Торупа, Хенрика Книберга, Андерса Иварссона,
Мануэль Пайс, Стива Смита, Бернда Ракера, Мэтью Скелтона, Алексиса Ричардсо­
на, Джеймса Говернера и Кейн Стивенс.

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

|

17

зать только одно: мне очень жаль, что я забыл поблагодарить вас лично, и я наде­
юсь, что вы сможете простить меня.
Наконец, время от времени некоторые спрашивают меня об инструментах, которые
мне потребовались для написания этой книги. Я писал в AsciiDoc, используя код
Visual Studio вместе с плагином AsciiDoc, построенным Джоао Пинто (Joao Pinto).
Книга находилась под контролем системы управления версиями Git, с системой
Atlas O’Reilly. Я писал в основном на своем ноутбуке с внешней механической кла­
виатурой Razer, но ближе к концу также активно использовал iPad Pro с Gitклиентом Working Сору, для того чтобы закончить последние несколько разделов.
Это позволило мне писать во время путешествия, обеспечив возможность в одном
памятном случае писать о рефакторизации базы данных на пароме до Оркнейских
островов. Вызванная этим морская болезнь стоила того.

18

|

Предисловие

Комментарии переводчика

Служба или сервис?
В настоящем переводе за основу принят широко известный методологический
принцип ’’Бритвы Оккама”, согласно которому следует избегать многообразия
в терминологии без крайней на то необходимости (он формулируется и по-дру­
гому — не следует порождать ’’пустых” сущностей).
В ситуации, когда отсутствуют стандарты перевода научно-технических терминов,
основными критериями служат авторитетные источники информации, каковыми
являются Википедия1, как унифицирующий (и нужно признать, иногда не бесспор­
ный) источник знаний, и гиганты ИТ-индустрии.

Такие глобальные компании ИТ-индустрии, как Microsoft и IBM (их российские
филиалы) в своей документации придерживаются перевода и интерпретации анг­
лийского термина ’’microservice”, именно как микрослужбы2,3.
Микрослужбами называют тысячи независимых веб-стандартов, языков програм­
мирования, платформ баз данных и компонентов веб-серверов, используемых в со­
временном жизненном цикле разработки ПО в качестве средств разработчиков.
Организации, применявшие традиционный подход, предпочитали архитектуру,
ориентированную на услуги, которая представляла собой сочетание оборудования
и ПО, предоставляемых одной ИТ-компанией. Микрослужбы обеспечивают под­
держку тысяч различных компонентов, предоставляемых независимыми компа­
ниями по разработке или сообществами по созданию решений с открытым исход­
ным кодом, в облачных приложениях и на веб-серверах. ИТ-отделам требовался
новый подход к управлению микрослужбами в производственной инфраструктуре,
состоящей из изолированных многоарендных сред в гипермасштабных центрах об­
работки данных (ЦОД) на базе публичных облаков. В связи с этим многие ИТотделы внедряли решения по виртуализации со стандартами программно­
определяемого ЦОД на базе технологии Service Mesh. Микрослужбы представляют
собой структурные блоки или основные компоненты, платформы и структуры, на
базе которых создается и выполняется программный код на веб-серверах в облач­
ном ЦОД.

1 См. https://ru.Wikipedia.org/wiki/Веб-служба
2 См. https://docs.microsoft.com/ru-ru/dotnet/architecture/microservices.
3 См. https://www.ibm.com/developerworks/ru/library/cl-bluemix-microservices-in-action-part-l-trs/.

19

Следует добавить еще одну важную для понимания деталь. В информатике со вре­
мен ее формирования в 1960-х годах сложились определенные традиции перевода
технических терминов, и с тех времен ничего не поменялось; изменились лишь лю­
ди, которые в последнее время все больше употребляют англицизмы, что очень
часто затуманивает смысл и суть дела. Каждый термин принадлежит иерархии тер­
минов, составляющей так называемое ’’древо знаний”. Когда мы говорим ’’шаблон
архитектурного дизайна” (pattern), мы четко определяем место этого термина в ука­
занной иерархии. С другой стороны, перевод ’’паттерн” эту связь обрывает. То же
касается, скажем, термина ’’каркас” (framework), который в зависимости от контек­
ста, может быть вычислительным или математическим каркасом программирова­
ния и разработки. И, опять-таки, перевод ’’фреймворк” помимо своей непроизноси­
мое™ на русском эту связь обрывает. Все указанное относится и к термину
’'microservice”.
По всем этим причинам в настоящей книге термин ’’microservice” переведен как
’’микрослужба ”.

20

|

Комментарии переводчика

ГЛАВА 1

Основные сведения
о микрослужбах
Скажем так, все обострилось в один миг и быстро вышло из-под контроля!
- Рон Бургуиди, Ведущий

Прежде чем мы углубимся в приемы работы с микрослужбами, важно, чтобы у нас
было общее, совместное понимание того, что такое архитектура на основе микро­
служб. Я хотел бы обратиться к некоторым распространенным заблуждениям,
которые встречаю регулярно, а также к нюансам, которые часто упускаются. Вам
понадобится этот прочный фундамент знаний, чтобы извлечь максимальную пользу
из остальной части книги. В данной главе приведено объяснение архитектуры на
основе микрослужб, кратко рассказано о том, как микрослужбы развивались (что,
естественно, означает рассмотрение монолитов), а также дан анализ некоторых
преимуществ и трудностей работы с микрослужбами.

Что такое микрослужбы?
Микрослужбы — это независимо развертываемые службы, моделируемые вокруг
бизнес-домена. Они общаются друг с другом через сети и предлагают на выбор
целый ряд вариантов архитектуры для решения задач, с которыми вы можете
столкнуться. Отсюда следует, что архитектура на основе микрослужб базируется на
многочисленных сотрудничающих микрослужбах.
Рассматриваемый архитектурный тип ориентирован на службы (service-oriented
architecture, SOA); не углубляясь в вопрос о том, как должны очерчиваться контуры
служб, отметим, что ключом является их независимая развертываемость. Преиму­
щество микрослужб также в том, что они нейтральны к технологиям.

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

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

21

Независимая развертываемость
Независимая развертываемость — это идея о том, чтобы вносить изменения в мик­
рослужбу иразвертывать ее в производственной среде без необходимости исполь­
зовать какие-либо другие службы. Что еще важнее, дело не просто в том, что мы
можем это осуществить, а в том, как вы управляете развертываниями в своей сис­
теме на самом деле. Это дисциплина, которую вы практикуете в большинстве
ваших релизов. Это простая идея, которая, тем не менее, сложна в исполнении.
Если из этой книги вы извлечете только одну полезную вещь, то она должна быть
такой: обеспечить внедрение концепции независимой развертываемости микро­
служб. Приобретите привычку вносить изменения в свое производство в отдельной
микрослужбе без развертывания чего-либо еще. Из этого последует много хоро­
шего.
Для обеспечения гарантии независимой развертываемости наши службы должны
быть слабо сопряжены — другими словами, мы должны иметь возможность изме­
нять одну службу без необходимости менять что-либо еще. Это означает, что нам
нужны ясные, четко определенные и стабильные контракты между службами. Не­
которые варианты имплементации это затрудняют, например, использование
совместных баз данных является особенно проблемным. Стремление к слабо со­
пряженным службам со стабильными интерфейсами направляет наше мышление
прежде всего на отыскание контуров служб.

Моделируются вокруг бизнес-домена
Внесение изменения через контур процесса обходится дорого. Если для внедрения
функции вам нужно изменить две службы и выполнить оркестровку указанных
двух изменений, то это займет больше времени, чем внесение одинакового измене­
ния внутри одной службы (или, если на то пошло, монолита). Из этого следует, что
мы хотим обеспечить, чтобы трансграничные изменения между службами вноси­
лись нами как можно реже.
Следуя тому же подходу, который я употребил в книге ’’Создание микросервисов”,
в этой книге используется поддельный домен и фиктивная компания с целью иллю­
страции некоторых концепций, когда невозможно поделиться реальными история­
ми. Речь идет о компании Music Corp, крупной многонациональной организации,
которая так или иначе остается в бизнесе, несмотря на то что она почти полностью
сосредоточена на продаже компакт-дисков.

Упираясь руками и ногами, мы решили перенести Music Corp в XXI век, и в рамках
этой компании мы оцениваем существующую системную архитектуру. На рис. 1.1
мы видим простую трехслойную архитектуру. У нас есть веб-интерфейс пользова­
теля, слой бизнес-логики в форме монолитного бэкэнда (серверной части) и храни­
лища данных в традиционной базе данных. Эти слои, как обычно, принадлежат
разным операционным группам.
Мы хотим внести в нашу функциональность простое изменение: нам нужно, чтобы
наши заказчики могли указывать свой любимый жанр музыки. При этом потребу22

|

Гпава 1

Рис. 1.1. Системы компании Music Corp как традиционная трехслойная архитектура

ется изменить пользовательский интерфейс (UI), показывая в нем жанры на выбор,
чтобы бэкэнд обеспечивал появление жанра в UI и изменение значения и чтобы
база данных принимала это изменение. Эти изменения должны управляться каждой
группой, как показано на рис. 1.2, и они должны быть развернуты в правильном
порядке.

Рис. 1.2. Вносить изменения во всех трех слоях оказывается труднее

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

|

23

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

’’Любая организация, которая строит дизайн системы... неизбежно произведет
дизайн, структура которого является копией коммуникационной структуры
организации”.
- Мелвин Конвей (Melvin Conway),
Каким образом комитеты изобретают (How Do Committees Invent)?

Трехъярусная архитектура — хороший пример этого закона в действии. В прошлом
ИТ-организации группировали людей в соответствии с их стержневыми компетен­
циями: администраторы баз данных — в группе с другими администраторами баз
данных; разработчики на Java — в группе с другими разработчиками на Java; и раз­
работчики фронтэнда (фронтальной части) (которые в настоящее время знают та­
кие экзотические вещи, как JavaScript и разработка собственных мобильных при­
ложений) были еще в одной группе. Мы группируем людей на основе их стержне­
вых компетенций, поэтому мы создаем ИТ-активы, которые выравниваются по
этим группам.
Указанный факт объясняет, почему эта архитектура так распространена. Она не­
плохая; она просто оптимизирована вокруг одного множества сил — так же как мы
традиционно группируем людей — вокруг дружеских отношений. Но силы изме­
нились. Наши стремления относительно программно-информационного обеспече­
ния1 изменились. Мы теперь объединяем людей в поликвалифицированные группы
с целью сократить эстафетные передачи и обособленные подразделения. Мы хотим
осуществлять доставку софта гораздо быстрее, чем когда-либо прежде. Это застав­
ляет нас принимать различные решения, касающиеся организации наших групп и
разделения наших систем на части.

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

1 Понятия "софт" и "программно-информационное обеспечение" в переводе используются взаимоза­
меняемо. Последний термин используется именно в такой формулировке, исходя из зарубежной трак­
товки термина software, как "программ и операционной информации, необходимых компьютеру" (ср.
https://en.wikipedia.org/wiki/Software), т. е. софт — это логика и данные, которыми оперирует ком­
пьютер — Пер.

24

|

Гпава 1

Давайте сравним эту архитектуру с потенциальной альтернативой, показанной на
рис. 1.3. У нас есть специализированная служба ’’Клиенты”, которая предоставляет
UI, позволяющий клиентам обновлять свою информацию, при этом состояние кли­
ента также хранится в той же службе. Выбор любимого жанра ассоциирован с кон­
кретным клиентом, поэтому данное изменение гораздо более локализовано. На
рис. 1.3 мы также показываем список имеющихся жанров, извлекаемых из службы
’’Каталог”, вероятно, что-то, что уже там имелось. Мы также видим, что новая
служба ’’Рекомендации” обращается к нашей информации о любимом жанре, чемуто, что легко последует в дальнейшем релизе.

Область первоначальных изменений
Рис. 1.3. Специализированная служба "Клиент" значительно облегчает регистрацию

любимого музыкального жанра клиента

В такой ситуации наша служба ’’Клиент” инкапсулирует тонкую ’’дольку” каждого
из трех уровней: она имеет немножечко UI, немножечко прикладной логики и не­
множечко хранения данных, но все эти слои инкапсулированы в одной службе.
В итоге бизнес-домен становится первостепенной силой, движущей нашу систем­
ную архитектуру, которая, надо надеяться, облегчит внесение изменений и упро­
стит организацию наших групп вокруг бизнес-домена. Это представляется настоль­
ко важным, что прежде чем мы закончим эту главу, мы вернемся к концепции мо­
делирования программно-информационного обеспечения вокруг домена, благодаря
чему я смогу поделиться некоторыми идеями о доменно-обусловленном дизайне —
идеями, которые формируют наше представление об архитектуре на основе микро­
служб.

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

|

25

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

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

Как уже обсуждалось в предыдущем разделе, мы хотим рассматривать наши служ­
бы как сквозные ’’куски” бизнес-функциональности, которые в соответствующих
случаях инкапсулируют UI, прикладную логику и хранение данных. Это обуслов­
лено желанием уменьшить усилия, необходимые для изменения бизнес-функ­
циональности и всего, что с ней связано. Инкапсуляция данных и поведения таким
образом дает нам высокую связность бизнес-функциональности. Скрывая базу дан­
ных, которая поддерживается нашей службой, мы также обеспечиваем снижение
сопряженности. Мы еще вернемся к сопряженности и связности чуть позже.
Это бывает трудно понять, в особенности, когда вы имеете существующую моно­
литную систему с гигантской базой данных, с которой вам приходится работать.
К счастью, глава 4 полностью посвящена отказу от монолитных баз данных.

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

Однако важно отметить, что ни одно из этих преимуществ не дается бесплатно.
Существует много подходов к декомпозиции системы, и изначально преследуемая
вами цель будет вести эту декомпозицию в разных направлениях. Следовательно,
становится важным понимание вопроса о том, что вы пытаетесь получить от архи­
тектуры на основе микрослужб.
26

|

Гпава 1

Какие проблемы они создают?
Ориентированная на службы архитектура вошла в моду отчасти потому, что ком­
пьютеры стали дешевле, и поэтому их стало больше. Вместо того чтобы разверты­
вать системы на одном гигантском мэйнфрейме, разумнее использовать несколько
более дешевых машин. Архитектура, ориентированная на службы, была попыткой
выработать наилучший способ строительства приложений, охватывающих много­
численные машины. Одна из главных трудностей во всем этом заключается в тех
способах, которыми указанные компьютеры "разговаривают” друг с другом: сетях.

Коммуникация между компьютерами по сетям не является мгновенной (это оче­
видным образом следует из физики). Отсюда ясно, что мы должны беспокоиться
о латентностях — ив частности, о латентностях, намного превышающих те, кото­
рые мы видим у локальных, внутрипроцессных операций. Ситуация ухудшается,
когда мы учтем, что эти латентности варьируются, делая поведение системы не­
предсказуемым. И мы также должны учитывать тот факт, что сети иногда выходят
из строя — пакеты теряются; сетевые кабели отсоединяются.

Эти препятствия намного затрудняют действия, которые относительно просты
с однопроцессным монолитом. И затрудняют настолько, что по мере усложнения
системы вам, скорее всего, придется избавиться от транзакций и безопасности, ко­
торую они приносят, в обмен на другие виды методов (которые, к сожалению,
имеют очень разные компромиссы).
Осознание того факта, что любой сетевой вызов может быть и будет безуспешным,
становится головной болью, как и тот факт, что службы, с которыми вы обменивае­
тесь, по какой-либо причине могут отключиться или же начать вести себя странно.
Вдобавок ко всему этому, вам также придется приступить к попыткам выработать
способ получения согласованного представления данных на многочисленных ма­
шинах.
И потом, конечно же, у нас есть огромный массив новых, дружественных для мик­
рослужб технологий, которые следует принять в расчет. Если их использовать не­
умело, то они помогут вам совершать ошибки гораздо быстрее и более интересны­
ми, дорогостоящими способами. Честно говоря, микрослужбы выглядят ужасной
идеей, если не считать всего хорошего.
Стоит отметить, что практически все системы, которые мы относим к категории
’’монолитов”, также являются распределенными системами. Однопроцессное при­
ложение, скорее всего, считывает данные из базы данных, работающей на другой
машине, и далее передает данные в веб-браузер. Это, по крайней мере, смесь из
трех компьютеров с коммуникацией между ними по сети. Разница состоит в степе­
ни, в которой монолитные системы ’’распределены" по сравнению с архитектурами
на основе микрослужб. Чем больше будет компьютеров, которые общаются по
большему количеству сетей, тем с большей вероятностью вы столкнетесь с непри­
ятными проблемами, ассоциированными с распределенными системами. Эти крат­
ко описанные мной проблемы, возможно, не появятся изначально, но со временем,
по мере роста вашей системы, вы, вероятно, столкнетесь с большинством, если не
со всеми из них.

Основные сведения о микрослужбах

|

27

Как сказал мой старый коллега, друг и эксперт по микрослужбам Джеймс Льюис
(James Lewis) ’’микрослужбы покупают вам варианты”. Когда Джеймс высказал эту
мысль, он знал, что говорит — они покупают вам варианты, У них есть стоимость,
и вы должны решить, сопоставима ли стоимость с ценой вариантов, за которые вы
хотите ухватиться. Мы разведаем эту тему подробнее в главе 2.

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

Технология
Иногда возникает заманчивое искушение — ухватиться за целую связку новых тех­
нологий, движущихся в фарватере вашей совершенно новой архитектуры на основе
микрослужб, но я настоятельно призываю вас не поддаваться этому искушению.
Внедрение любой новой технологии будет иметь свою цену — оно создаст некий
беспорядок. Надо надеяться, что оно будет стоить того (если вы выбрали правиль­
ную технологию, конечно!), но при первичном принятии архитектуры на основе
микрослужб у вас будет происходить немало других вещей.
Выработка способа правильного эволюционного развития и управления архитекту­
рой на основе микрослужб предусматривает обуздание целого ряда трудностей,
связанных с распределенными системами, трудностей, с которыми вы, возможно,
не сталкивались раньше. Думаю, что гораздо полезнее сначала разобраться в этих
вопросах, по мере того как вы с ними сталкиваетесь, используя стек технологий,
с которым вы знакомы, а затем подумать о том, поможет ли изменение сущест­
вующей технологии решить эти проблемы по мере их обнаружения.

Как мы уже говорили, микрослужбы по своей сути нейтральны к технологиям. По­
ка ваши службы способны общаться друг с другом через сеть, все остальное можно
’’хватать и уносить”. И в этом огромное преимущество, т. к. вы, если захотите, смо­
жете смешивать и сочетать стеки технологий.

От вас не требуется использовать Kubemetes, Docker, контейнеры или публичное
облако. От вас не требуется кодировать на Go или Rust или чем-то еще. На самом
деле подбор языка программирования совершенно не важен в том, что касается ар­
хитектур на основе микрослужб, помимо того что некоторые языки имеют более
богатую экосистему поддерживающих библиотек и вычислительных каркасов.
Если вы знаете РНР лучше всего, то начните строить службы с РНР!2 По отноше­

2 Для получения дополнительной информации по этой теме я рекомендую книгу Лорны Джейн Мит­
челл "Веб-службы РНР" (РНР Web Services, Loma Jane Mitchell, O’Reilly).

28

|

Гnaea 1

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

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

Как измерять размер? Строками кода? Для меня это не имеет особого смысла. То,
для чего на Java потребуется 25 строк кода, возможно, будет написано в 10 строках
на Clojure. Это не значит, что Clojure лучше или хуже Java, скорее, некоторые язы­
ки выразительнее других.
По моему мнению, ближе всего к определению ’’размера”, имеющего какой-то
смысл с точки зрения микрослужб, были слова, однажды высказанные экспертом
по микрослужбам Крисом Ричардсоном (Chris Richardson), заявившим, что цель
микрослужб— иметь ’’минимально возможный интерфейс”. Это определение со­
гласуется с концепцией сокрытия информации (о которой мы поговорим чуть поз­
же), но представляет собой попытку найти смысл постфактум. Когда мы впервые
говорили об этих вещах, в центре нашего внимания, по крайней мере, изначально
было то обстоятельство, что эти вещи действительно легко заменяются.

В конечном счете, понятие ’’размер” является весьма контекстуальным. Поговорите
с человеком, который работал над системой в течение 15 лет, и по его ощущениям
их система из 100К строк кода действительно будет простой для понимания. Спро­
сите мнение кого-то, кто для этого проекта является абсолютным новичком, и по
его ощущениям проект будет, скажем так, просто огромным. Точно так же спроси­
те компанию, которая только что приступила к транзиту на микрослужбы, возмож­
но, с десятью микрослужбами или меньше того, и вы получите другой ответ, чем от
компании аналогичного размера, в которой микрослужбы были нормой в течение
многих лет, а теперь они имеют их сотни.
Я призываю людей не беспокоиться о размере. Когда вы только начинаете, гораздо
важнее сосредоточиться на двух ключевых вещах. Прежде всего, со сколькими
микрослужбами вы справитесь? По мере того как у вас будет служб все больше и
больше, сложность вашей системы будет увеличиваться, и вам придется усваивать
новые навыки (и, возможно, внедрять новые технологии), для того чтобы с ней
справляться. Именно по этой причине я решительно выступаю за поступательную

3 Прочитав блог-пост Ауринн Шоу (Aurynn Shaw) "Культура презрения" (Contempt Culture, http://
bit.ly/2oeICgL), я осознал, что в прошлом был виноват, проявляя некоторую степень презрения к раз­
ным технологиям и, соответственно, к сообществам вокруг них.

Основные сведения о микрослужбах

|

29

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

История термина "микрослужбы"
В 2011 году, когда я еще работал в консалтинговой компании Thoughtworks, мой друг,
а затем коллега Джеймс Льюис (James Lewis) заинтересовался тем, что он называл
"микроприложениями". Он заметил, что этот шаблон применяется несколькими компа­
ниями, которые использовали ориентированную на службы архитектуру, — они зани­
мались оптимизацией этой архитектуры с целью сделать службы легко заменяемыми.
Компании, о которых идет речь, были заинтересованы в быстром развертывании кон­
кретной функциональности, но с тем расчетом, что ее можно будет переписать в дру­
гих стеках технологий, когда это понадобится для масштабирования.
В то время особняком стоял вопрос, насколько эти службы были малы по объему. Не­
которые из служб можно было написать (или переписать) в течение нескольких дней.
Джеймс продолжал повторять, что "службы должны быть не больше, чем моя голова",
причем идея заключалась в том, что объем функциональности должен быть таким,
чтобы ее было легко понимать и, следовательно, легко изменять.
Позже, в 2012 году, Джеймс поделился этими идеями на архитектурном саммите, где
присутствовали некоторые из разработчиков. На том семинаре мы обсуждали тот
факт, что на самом деле эти приложения не были самодостаточными, поэтому назва­
ние "микроприложения" было не совсем правильным. Вместо него более подходящим
выглядел термин "микрослужбы"4.

И владение
С помощью микрослужб, смоделированных вокруг бизнес-домена, мы видим вы­
равнивание между нашими ИТ-артефактами (нашими независимо развертываемы­
ми микрослужбами) и нашим бизнес-доменом. Эта идея хорошо резонирует, когда
мы учитываем сдвиг в сторону разрушения разделяющих границ между ’’Бизнесом”
и ”ИТ” в технологических компаниях. В традиционных ИТ-организациях процесс
разработки софта часто осуществляется частью организации, совершенно отличной
от той, которая фактически определяет требования и имеет связь с клиентом, как
показано на рис. 1.4. Дисфункции этих видов организаций многочисленны и разно­
образны и, вероятно, не нуждаются в дальнейшем рассмотрении.
Вместо этого мы видим, как истинные технологические организации тотально объ­
единяют эти предыдущие разрозненные организационные структуры, как показано
на рис. 1.5. Владельцы продуктов теперь работают непосредственно в рамках групп
доставки, причем эти группы выравниваются не вокруг произвольных технических
группировок, а вокруг ориентированных на клиента продуктовых линий. Теперь
нормой являются не централизованные ИТ-функции, а, наоборот, существование

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

30

|

Гпава 1

Рис. 1.4. Организационный вид традиционного деления на ИТ и Бизнес

Рис. 1.5. Пример того, как истинные технологические компании

интегрируют программно-информационные продукты

Основные сведения о микрослужбах

|

31

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

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

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

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

Рис. 1.6. Однопроцессный монолит: весь код упакован в один единственный процесс

32

|

Гпава 1

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

И модульный монолит
Модульный монолит является вариацией как подмножество однопроцессного
монолита: один процесс состоит из отдельных модулей, над каждым из которых
можно работать независимо, но все они по-прежнему должны объединяться для
развертывания, как показано на рис. 1.7. Концепция разбиения софта на модули не
является чем-то новым, мы вернемся к некоторым историческим моментам вокруг
нее позже в этой главе.

Рис. 1.7. Модульный монолит: код внутри процесса разбивается на модули

Для многих организаций модульный монолит— отличный вариант выбора. Если
контуры модулей четко определены, то он обеспечивает высокую степень парал­
лельности работы, но обходит трудности более распределенной архитектуры, осно­
ванной на микрослужбах, наряду с гораздо более простыми вопросами развертыва­
ния. Компания Shopify представляет собой отличный пример организации, которая
использовала этот метод в качестве альтернативы декомпозиции на микрослужбы,
и, похоже, для этой компании он действительно работает хорошо5.
Одна из преград модульного монолита заключается в том, что база данных имеет
тенденцию к нехватке декомпозиции, которую мы находим на уровне кода, приво­
дя к значительным трудностям, с которыми можно столкнуться, если вы захотите
затащить монолит в будущее. Я видел, как некоторые группы пытались продвинуть
идею модульного монолита дальше, разложив базу данных по тем же линиям, что и
модули, как показано на рис. 1.8. По существу дела, внести такое изменение в су­

5 Выступление Кристен Уестейнд (Kirsten Westeinde) на YouTube (http://bitly/2oauZ29) дает глубокое
понимание образа мыслей, принятого в Shopify, лежащего в основе привлечения модульного моноли­
та вместо микрослужб.

Основные сведения о микрослужбах

|

33

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

Рис. 1.8. Модульный монолит с разложенной базой данных

Распределенный монолит
’’Распределенная система — это система, в которой отказ компьютера, о сущест­
вовании которого вы даже не подозревали, сделает ваш собственный компьютер
непригодным для использования”6.
- Лесли Лэмпорт (Leslie Lamport)

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

6 Сообщение электронной почты, отправленное на доску объявлений DEC SRC в 12:23:29 тихоокеан­
ского летнего времени (PDT) 28 мая 1987 года (подробности см. по адресу
https://www.microsoftcom/en-us/research/publication/distribution/).

34

|

Гпава 1

Сторонние черно-ящичные системы
В качестве монолитов, которые можно ’’разложить” в рамках усилий по миграции,
можно также рассматривать некий сторонний софт. Сюда входят такие вещи, как
платежные системы, CRM-системы и HR-системы. Общим фактором здесь являет­
ся то, что этот софт разработан другими людьми, и у вас нет возможности изменить
код. Указанный софт может быть серийным, развернутым на собственной инфра­
структуре, либо используемым вами продуктом SaaS (программно-информа­
ционное обеспечение как служба). Многие методы декомпозиции, которые мы рас­
смотрим в этой книге, могут применяться даже в системах, в которых невозможно
изменить лежащий в основании код.

Трудности монолитов
Монолит, будь то однопроцессный или распределенный, часто бывает уязвимее
к опасностям сопряженности, в частности, имплементационной сопряженности и
сопряженности развертывания, темы, которые вскоре мы разведаем подробнее.

По мере того как в одном и том же месте работает все больше и больше людей, они
начинают вставать друг у друга на пути. Разные разработчики хотят изменить один
и тот же фрагмент кода, разные группы хотят вывести функциональность в прямой
эфир в разное время (или задержать развертывание). Возникает путаница вокруг
того, кто чем владеет и кто принимает решения. Многочисленные исследования
выявляют трудности, связанные с запутанными ’’линиями владения”7. Я называю
эту проблему конкуренцией за доставку (delivery contention).
Наличие монолита не означает, что вы обязательно столкнетесь с проблемами кон­
куренции за доставку, так же как наличие архитектуры на основе микрослужб не
означает, что вы никогда не столкнетесь с этой проблемой. Но архитектура на ос­
нове микрослужб дает вам более конкретные контуры в системе, вокруг которых
могут быть проведены ’’линии владения”, что дает вам гораздо больше гибкости
в отношении того, как уменьшить эту проблему.

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

7 Microsoft Research провела исследования в этом пространстве, и я рекомендую их все. В качестве
отправной точки я предлагаю статью "Не трогай мой код! Обследование влияния владения на качест­
во программно-информационного обеспечения" (Don’t Touch Му Code! Examining the Effects of Own­
ership on Software Quality, http://bit.ly/2p5RlTl) Кристиана Берда (Christian Bird) и др.

Основные сведения о микрослужбах

|

35

Монолиты также упрощают многоразовое использование кода в самом монолите.
Если мы хотим задействовать код в распределенной системе повторно, то мы
должны решить, хотим ли мы копировать код, извлечь библиотеки или заложить
совместную функциональность в службу. С монолитом наши варианты выбора на­
много проще, и многим людям нравится эта простота — весь код тут, просто поль­
зуйся им!
К сожалению, люди стали рассматривать монолит как нечто, чего следует избегать,
что по своей сути несет в себе проблемы. Я встречал многих, для которых термин
’’монолит” является синонимом унаследованной системы. И в этом проблема. Мо­
нолитная архитектура — это вариант, причем допустимый. Она не будет правиль­
ным вариантом выбора во всех обстоятельствах, так же как и микрослужбы, но, тем
не менее, это вариант. Если мы попадем в ловушку систематического очернения
монолита как жизнеспособного варианта для доставки нашего софта, то существует
риск того, что мы сами либо наши пользователи поступим неправильно. В главе 3
мы продолжим разведывание компромиссов между монолитами и микрослужбами
и обсудим некоторые инструменты, которые помогут вам лучше оценить по досто­
инству то, что из существующего подходит для вашего собственного контекста.

О сопряженности и связности
Понимание балансирующих сил между сопряженностью и связностью имеет боль­
шое значение во время определения контуров микрослужб. Сопряженность
(coupling) говорит о том, как изменение в одной вещи требует изменения в другой;
связность (cohesion) говорит о том, как мы группируем родственный код. Эти поня­
тия непосредственно связаны между собой.

Закон Константина хорошо формулирует эту связь8:

’’Структура является стабильной, если связность высокая, а сопряженность
низкая”.

- Ларри Константин (Larry Constantine)

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

8 Связность (cohesion, синонимы — когезия, спайка) — это показатель отношений внутри модуля и
является внутримодульным понятием. Сопряженность (coupling, синонимы — сцепление, сцепка,
стыковка)— это показатель отношений между модулями и является межмодульным понятием.
См.

https://www.geeksforgeeks.org/software-engineering-differences-between-coupling-and-cohesion/ —

Пер.

36

|

Гпава 1

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

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

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

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

Краткая история сопряженности и связности
Понятия связности и сопряженности существуют в вычислительном процессе уже
давно, причем эти понятия впервые были изложены Ларри Константином в 1968 году.
Сдвоенные идеи сопряженности и связности легли в основу многих наших представ­
лений о строительстве компьютерных программ. Такие книги, как "Структурный ди­
зайн" (Structured Design) Ларри Константина и Эдварда Йордона (Edward Yourdon)
(Prentice Hall, 1979) впоследствии повлияли на поколения программистов (для моей
собственной университетской степени она была обязательным чтением, почти через
20 лет после ее первой публикации).
Ларри впервые изложил свои концепции связности и сопряженности в 1968 году (этот
год был в особенности выдающимся для вычислительной техники) на Национальном
симпозиуме по модульному программированию, той самой конференции, где закон
Конвея впервые получил свое название. Этот год также дал нам две нашумевшие
спонсируемые НАТО конференции, во время которых понятие инженерии программно­
информационного обеспечения также получило свою известность (данный термин ра­
нее был придуман Маргарет X. Гамильтон).

Основные сведения о микрослужбах

|

37

Связность
Одно из самых лаконичных определений, в котором дается описание связности, из
всех, что я слышал, таково: ’’код, который изменяется вместе, остается вместе”. Для
наших целей это определение является довольно хорошим. Как мы уже обсуждали,
мы оптимизируем нашу архитектуру, основанную на микрослужбах, вокруг про­
стоты внесения изменений в бизнес-функциональность, поэтому мы хотим, чтобы
функциональность была сгруппирована так, чтобы мы могли вносить изменения
как можно в меньшем количестве мест.

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

Сопряженность
’’Сокрытие информации, как и диету, несколько легче описать, чем ее придер­
живаться”.
-Дэвид Парнас (David Parnas),
Тайная история сокрытия информации (The Secret History Of Information Hiding)

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

Сокрытие информации
Концепция под названием "сокрытие информации" возвращается вновь и вновь в том,
что касается дискуссий вокруг сопряженности. Указанная концепция, впервые изло­
женная Дэвидом Парнасом в 1971 году, появилась в его работе, посвященной опреде­
лению границ модулей9.
Стержневая идея скрытия информации заключается в том, чтобы отделять части кода,
которые меняются часто, от тех, которые являются статическими. Мы хотим, чтобы

9 Хотя в качестве источника часто цитируется известная работа Парнаса 1972 года "О критериях, ис­
пользуемых при декомпозиции систем на модули" (On the Criteria to be Used in Decomposing Systems
into Modules), он впервые поделился этой концепцией в работе "Информационные аспекты методоло­
гии дизайна" (Information Distributions Aspects of Design Methodology), труды съезда IFIP ‘71, 1971.

38

|

Гпава 1

граница модуля была стабильной, и она должна скрывать те части имплементации
модуля, которые мы ожидаем изменять чаще. Идеязаключается в том, что внутрен­
ние изменения могут вноситься безопасно до тех пор, пока поддерживается совмес­
тимость модуля.
Лично я принимаю подход, заключающийся в том, чтобы как можно меньше выстав­
лять наружу за пределы границы модуля (или контура микрослужбы). Как только нечто
становится частью интерфейса модуля, трудно вернуться назад. Но если вы спрячете
это сейчас, то вы всегда сможете решить поделиться этим позже.
Инкапсуляция как понятие в объектно-ориентированном программно-информацион­
ном обеспечении является родственным термином, но в зависимости от того, чьего
определения вы придерживаетесь, бывает не совсем тем же самым. Инкапсуляция
в программировании стала означать упаковывание вместе одной или нескольких ве­
щей в контейнер — подумайте о классе, содержащем как поля, так и методы, которые
действуют на этих полях. Затем вы можете использовать видимость в определении
класса для сокрытия части имплементации.
Для более детального знакомства с историей сокрытия информации я рекомендую
книгу Парнаса "Тайная история сокрытия информации"10.

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

Трудность здесь в том, что детали имплементации часто произвольно выбраны раз­
работчиками. Существует много способов решить некую проблему; мы выбираем
один, но можем передумать. Когда мы решаем изменить свое мнение, мы не хотим,
чтобы это ударило по потребителям (независимая развертываемость, помните?).
Классический и распространенный пример имплементационной сопряженности —
использование совместной базы данных. На рис. 1.9 наша служба ’’Заказ” регистри­
рует все заказы, размещаемые в нашей системе. Служба ’’Рекомендации” предлага­
ет нашим клиентам записи, которые они, возможно, захотят приобрести на основе
предыдущих покупок. В настоящее время служба ’’Рекомендации” напрямую обра­
щается к этим данным из базы данных.

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

10 См. Парнас, Дэвид, "Тайная история сокрытия информации" (The Secret History of Information Hid­
ing). Опубликовано в журнале Software Pioneer, ред. M. Брой и Э. Денерт (Berlin Heidelberg: Springer,
2002).

Основные сведения о микрослужбах

|

39

Логический контур службы "Заказ"
Рис. 1.9. Служба "Рекомендации" напрямую обращается к данным, хранящимся в службе "Заказ"

извлекает эту информацию. Лучше скрыть эту деталь имплементации, как показано
на рис. 1.10, теперь служба ’’Рекомендации” получает доступ к необходимой ин­
формации через вызов API.
Мы также можем сделать так, чтобы служба ’’Заказ” публиковала набор данных
в форме базы данных, которую предполагается использовать для массового доступа
потребителей, как показано на рис. 1.11. До тех пор пока служба ’’Заказ” публикует
данные соответствующим образом, любые изменения, вносимые внутрь службы
’’Заказ”, невидимы для клиентов, поскольку она поддерживает публичный кон­
тракт. Она также открывает возможность улучшить модель данных, выставленную
наружу для клиентов, подстраиваясь под их нужды. Мы разведаем подобные шаб­
лоны подробнее в главах 3 и 4.

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

40

|

Гпава 1

Рис. 1.10. Служба "Рекомендации" теперь обращается к информации о заказе через API,

скрывая внутренние детали имплементации

Рис. 1.11. Служба "Рекомендации" теперь обращается к информации о заказе через выставленную

наружу базу данных, которая структурирована по-другому в отличие от внутренней базы данных

Основные сведения о микрослужбах

|

41

ный подход (который, по моим наблюдениям, к сожалению, слишком часто встре­
чается) заключается в выполнении обратного. Группа, работающая над службой,
берет модель данных или еще одну деталь внутренней имплементации, а затем
думает о том, чтобы выставить ее наружу внешнему миру.
Думая ’’извне-вовнутрь”, вы вместо этого сначала спрашиваете: ’’Что нужно потре­
бителям моей службы?” И я не имею в виду, что вы спрашиваете себя. что нужно
вашим потребителям; на самом деле я имею в виду, что вы спрашиваете у людей,
которые будут вызывать вашу службу!

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

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

Рис. 1.12. Можно сказать, что три службы, которые используют синхронные вызовы

для выполнения операции, сопряжены во времени

Здесь мы видим синхронный HTTP-вызов, выполненный из нашей службы ’’Склад”
в нижестоящую службу ’’Заказ” для получения требуемой информации о заказе.
Для удовлетворения запроса служба ’’Заказ”, в свою очередь, должна получить ин­
формацию от клиента, опять же через синхронный HTTP-вызов. Для завершения
этой совокупной операции службы ’’Склад”, ’’Заказ” и "Клиент” должны быть ак­
тивными и доступными для контакта. Они сопряжены во времени.

Мы можем уменьшить эту проблему различными способами. Мы можем подумать
о кэшировании: если служба ’’Заказ” кэширует информацию, необходимую ей от
42

|

Гпава 1

службы ’’Клиент”, то в некоторых случаях служба ’’Заказ” сможет избежать вре­
менной сопряженности с нижестоящей службой. Мы также можем подумать об
асинхронном транспорте для отправки запросов, возможно, используя что-то вроде
брокера сообщений. Это позволит отправлять сообщение в нижестоящую службу и
обрабатывать его после того, как будет доступна нижестоящая служба.

Полное изложение коммуникации типа ’’служба-служба” выходит за рамки данной
книги, но подробнее рассматривается в главе 4 книги ’’Создание микросервисов”.

Сопряженность развертывания
Возьмем отдельный процесс, состоящий из нескольких статически связанных мо­
дулей. Изменение вносится в одну строку кода в одном из модулей, и мы хотим
развернуть это изменение. Для этого мы должны развернуть весь монолит — даже
включая те модули, которые остаются неизменными. Все должно быть развернуто
вместе, поэтому мы имеем сопряженность развертывания.
Сопряженность развертывания бывает принудительной, как в примере нашего ста­
тически связанного процесса, но и бывает вопросом выбора, обусловленным таки­
ми практиками, как релизная серия (release train). В случае релизной серии предва­
рительно запланированные графики релизов составляются заранее, в типичной си­
туации с периодическим графиком. Когда релиз готов к выпуску, все изменения,
внесенные с момента последнего релиза в релизной серии, будут развернуты. Для
некоторых людей релизная серия является полезным методом, но я решительно
предпочитаю смотреть на нее не как на конечную цель, а как на переходный шаг
к правильной методике релиза по требованию. Я даже работал в организациях, ко­
торые развертывали все службы в системе одновременно в рамках таких процессов
релизных серий, не задумываясь о том, нужно ли менять эти службы.
Развертывание чего-либо несет в себе риск. Существует много путей снизить риск
развертывания, и один из них — изменять только то, что должно быть изменено.
Если мы сможем уменьшить число развертываний, возможно, путем декомпозиции
более крупных процессов на независимо развертываемые микрослужбы, то мы
сможем уменьшить риск каждого развертывания, сократив объем развертывания.
Меньшие релизы способствуют меньшему риску. Существует меньше того, что
пойдет не так. Если все-таки что-то пошло не так, то выяснить то, что пошло не так
и как это исправить, становится легче, потому что мы внесли меньше изменений.
Поиск путей уменьшения размера релиза лежит в основе непрерывной доставки,
которая поддерживает важность методов быстрой обратной связи и релиза по тре­
бованию11. Чем меньше объем релиза, тем проще и безопаснее его инициировать,
и тем быстрее мы получим обратную связь. Мой собственный интерес к микро­
службам проистекает из предыдущей заинтересованности в непрерывной до-11

11 Более подробную информацию см. в Jez Humble (Джез Хамбл) и David Farley (Дэвид Фарли) "Не­
прерывная доставка: надежные релизы программно-информационного обеспечения посредством
сборки, тестирования и автоматизации развертывания" (Continuous Delivery: Reliable Software Releases
through Build, Test, and Deployment Automation, Upper Saddle River: Addison Wesley, 2010).

Основные сведения о микрослужбах

|

43

ставке — я искал архитектуры, которые облегчали бы адаптацию непрерывной дос­
тавки.

Уменьшение сопряженности развертывания, конечно же, не требует наличия мик­
рослужб. Среды выполнения, такие, как Erlang, обеспечивают ’’горячее” разверты­
вание новых версий модулей прямо в работающем процессе. В конце концов, по­
жалуй, многие из нас имеют доступ к таким возможностям в технологических сте­
ках, которые мы используем ежедневно12.

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

В качестве конкретного примера возьмем Music Corp. У нас есть склад, который
хранит товары. Когда клиенты размещают заказы на компакт-диски, люди, рабо­
тающие на складе, должны понимать, какие товарные позиции нужно взять и упа­
ковать и куда нужно отправить пакет. Поэтому информация о заказе должна быть
передана людям, работающим на складе.
На рис. 1.13 показан соответствующий пример: служба ’’Обработка заказа” отправ­
ляет все детали заказа в службу ’’Склад”, которая затем запускает процесс упаковки
номенклатурной товарной позиции. В рамках этой операции служба ’’Склад” ис­
пользует ИД клиента для получения информации о клиенте из отдельной службы
’’Клиент”, благодаря которой мы знаем, как уведомить его во время отправки за­
каза.
В этой ситуации мы делимся всем заказом со складом, что не имеет смысла, т. к.
складу нужна информация только о том, что упаковать и куда отправить. Им не
нужно знать, сколько товарная позиция стоит (если им нужно включить счетфактуру в пакет, то это передается как предварительно отрисованный PDF-файл).
У нас также были бы проблемы с информацией, доступ к которой мы должны кон­
тролировать, поскольку она распространяется слишком широко, например, если мы
делимся полным заказом, то в итоге мы выставим наружу данные кредитной карты
службам, которые в этом не нуждаются.

Поэтому вместо варианта, приведенного выше, мы можем предложить новое до­
менное понятие под названием ’’Инструкция по комплектации”, содержащее только

12 10-е правило Гринспена (Greenspun) гласит: "Любая достаточно сложная программа на С или
Fortran содержит нерегламентированную, неформально заданную, изобилующую дефектами, медлен­
ную имплементацию половины языка Common Lisp". Оно превратилось в новую шутку: "Каждая ар­
хитектура на основе микрослужб содержит наполовину сломанную реимплементацию на Erlang". Я
думаю, что в этом есть много правды.

44

|

Гпава 1

Рис. 1.13. Заказ отправляется на склад, для того чтобы начать его упаковку

ту информацию, которая необходима службе ’’Склад”, как показано на рис. 1.14.
Это еще один пример сокрытия информации.
Сопряженность можно уменьшить еще больше, удалив необходимость в том, чтобы
служба ’’Склад” даже знала о клиенте, если мы этого захотим — вместо этого мы
можем предоставить все надлежащие детали через ’’Инструкцию по комплектации”,
как показано на рис. 1.15.

Для того чтобы указанный подход работал как надо, это, вероятно, означает, что
в какой-то момент ’’Обработка заказа” должна обратиться к службе ’’Клиент”, что­
бы иметь возможность сперва сгенерировать эту ’’Инструкцию по комплектации”,
но вполне вероятно, что ’’Обработка заказа” должна будет обратиться к информа­
ции о клиентах по другим причинам, так что это вряд ли будет большой проблемой.
Из указанного процесса ’’отправки” ’’Инструкции по комплектации” следует вызов
API из службы ’’Обработка заказа” в службу ’’Склад”.
Альтернативой могло бы быть эмитирование ’’Обработкой заказа” некоего события,
которое ’’Склад” потребляет, как показано на рис. 1.16. Путем эмитирования собы-

Основные сведения о микрослужбах

|

45

Рис. 1.14. Использование "Инструкции по комплектации" для уменьшения количества информации,

которую мы отправляем в службу "Склад"

Рис. 1.15. Ввод дополнительной информации в "Инструкцию по комплектации"

поможет избежать необходимости вызова службы "Клиент"

46

|

Гпава 1

Рис. 1.16. Запуск события, которое способна получать служба "Склад", с информацией в объеме,
достаточном для упаковки и отправки заказа

тия, которое ’’Склад” потребляет, мы фактически переворачиваем зависимости. Мы
переходим от ’’Обработки заказа” в зависимости от службы ’’Склад”, чтобы быть
в состоянии обеспечить отправку заказа, к прослушиванию "Складом” событий из
службы ’’Обработка заказа”. Оба подхода имеют свои достоинства, и мой выбор,
скорее всего, будет зависеть от более широкого понимания взаимодействий между
логикой ’’Обработки заказа" и инкапсуляцией функциональности в службе
"Склад” — это то, с чем помогает доменное моделирование, тема, которую мы раз­
ведаем далее.

По существу дела, для выполнения любой работы службой "Склад” все равно тре­
буется некоторая информация о заказе. Мы не можем избежать этого уровня
доменной сопряженности. Но, тщательно обдумывая то, какими понятиями мы
делимся и как мы ими делимся, мы по-прежнему нацелены на снижение уровня ис­
пользуемой сопряженности.

Доменно-обусловленный дизайн
Как мы уже говорили, моделирование наших служб вокруг бизнес-домена имеет
значительные преимущества для нашей архитектуры, основанной на микрослуж­
бах. Вопрос в том, как сформулировать эту модель — и именно здесь выходит на
сцену доменно-обусловленный дизайн (domain-driven design, DDD, дизайн, обу­
словленный областью деятельности).

Основные сведения о микрослужбах

|

47

Стремление к тому, чтобы наши программы лучше представляли реальный мир,
в котором будут работать сами программы, не ново. Объектно-ориентированные
языки программирования, такие, как Simula, были разработаны, для того чтобы
дать нам возможность моделировать реальные области деятельности (реальные до­
мены). Но чтобы эта идея действительно обрела форму, требуется нечто большее,
чем возможности языка программирования.

В книге ’’Доменно-обусловленный дизайн” Эрика Эванса (Eric Evans)13 изложен
ряд важных идей, которые помогли нам лучше представлять проблемную область
в наших программах. Полное исследование этих идей выходит за рамки данной
книги, но я дам краткий обзор наиболее важных идей, возникающих при рассмот­
рении архитектур, основанных на микрослужбах.

Агрегат
В доменно-обусловленном дизайне агрегат представляет собой несколько запутан­
ное понятие, имеющее массу разных определений. Не является ли он просто произ­
вольной коллекцией объектов? Самой малой единицей, которую я должен взять из
базы данных? Для меня всегда работала ментальная модель сначала рассматривать
агрегат, взятый как представление понятия реальной области деятельности — по­
думайте о чем-то вроде ’’Заказа”, ’’Счета-фактуры”, ’’Номенклатурной товарной
позиции” и т. д. В типичной ситуации с агрегатами связан жизненный цикл, что
открывает их для имплементации в качестве ’’машины состояний”. Мы хотим рас­
сматривать агрегаты как самодостаточные единицы, мы хотим обеспечить, чтобы
код, обрабатывающий переходы агрегата из состояния в состояние, группировался
вместе с самим состоянием.

Размышляя об агрегатах и микрослужбах, можно сказать, что одна микрослужба
будет обрабатывать жизненный цикл и хранение данных одного или нескольких
разных типов агрегатов. Если функциональность в другой службе хочет изменить
один из этих агрегатов, то она должна либо непосредственно запросить изменение
в этом агрегате, либо заставить сам агрегат реагировать на другие вещи в системе
с целью инициировать свои собственные переходы из состояния в состояние —
примеры мы видим на рис. 1.17.
Здесь нужно понять главное — если внешняя сторона запрашивает в агрегате пере­
ход из одного состояния в другое, то агрегат может сказать ’’нет”. В идеале вы хо­
тите имплементировать свои агрегаты таким образом, чтобы незаконные переходы
из состояния в состояние были невозможными.

Агрегаты могут иметь связи с другими агрегатами. На рис. 1.18 мы имеем агрегат
’’Клиент”, который ассоциирован с одним или несколькими ’’Заказами”. Мы решили
моделировать ’’Клиента” и ’’Заказ” как отдельные агрегаты, которыми занимаются
разные службы.
13 Доменно-обусловленный дизайн: пути решения сложности в центре программно-информационного
обеспечения (Domain-Driven Design: Tackling Complexity in the Heart of Software, Eric Evans, Boston:
Addison-Wesley, 2004).

48

|

Гпава 1

Рис. 1.17. Разные пути, которыми служба "Платеж" инициирует переход "Оплачено"

в агрегате "Счет-фактура"

Рис. 1.18. Один агрегат "Клиент" может быть ассоциирован

с одним или несколькими агрегатами "Заказ"

Существует масса способов разобрать систему на агрегаты, причем некоторые ва­
рианты весьма субъективны. Вы можете, по соображениям производительности
или простоты имплементации, решить реформировать агрегаты через какое-то вре­
мя. В самом начале, однако, я рассматриваю вопросы имплементации как второсте­
пенные, исходно позволяя ментальной модели пользователей системы быть моим
путеводным светом при первичном дизайне до тех пор, пока другие факторы не
вступят в игру. В главе 2 я представлю ’’Событийный штурм” как коллаборативное
усилие в том, чтобы помочь сформировать эти доменные модели с помощью ваших
коллег-неразработчиков.
Основные сведения о микрослужбах

|

49

Ограниченный контекст
Ограниченный контекст в типичной ситуации представляет собой более крупный
организационный контур внутри организации. Внутри объема этого контура долж­
ны выполняться четкие обязанности. Это все немного запутано, поэтому давайте
рассмотрим еще один конкретный пример.
В Music Corp наш склад представляет собой ’’кипучий муравейник”: управление
заказами, доставляемыми адресатам (и нерегулярным возвратом), поставка новых
запасов, гонки на вилочных погрузчиках и т. д. В других местах финансовый отдел,
возможно, менее веселый, но все же имеет важную функцию внутри нашей органи­
зации, обрабатывая платежную ведомость, оплачивая поставки и тому подобное.

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

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

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

Хитрость здесь заключается в том, что даже если вы решите позже разложить
службу, моделирующую весь ограниченный контекст, на меньшие службы, то вы
все равно скроете это решение от внешнего мира, возможно, представив потреби­
телям более грубо гранулированный API. Решение выполнить декомпозицию
службы на меньшие по гранулярности части, возможно, является имплементацион­
50

|

Гпава 1

ным решением, поэтому с таким же успехом мы могли бы скрыть и его, если смо­
жем!

Дальнейшее чтение
Тщательное изучение доменно-обусловленного дизайна будет полезно, но это вы­
ходит за рамки данной книги. Если вы хотите следовать ему дальше, то я предла­
гаю прочитать либо оригинальную книгу ’’Доменно-обусловленный дизайн” Эрика
Эванса либо ’’Основы доменно-обусловленного дизайна” Вона Вернона14.

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

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

14 См. Основы доменно-обусловленного дизайна (Domain-Driven Design Distilled, Vaughn Vernon, Boston:
Addison-Wesley, 2014).

Основные сведения о микрослужбах

|

51

ГЛАВА 2

Планирование миграции

Слишком легко погрузиться сразу в мельчайшие технические стороны декомпози­
ции монолита — и это будет в центре внимания остальной части книги! Но сначала
нам действительно нужно разведать несколько менее технических вопросов. С чего
начинать миграцию? Как управлять изменениями? Как брать с собой других в это
путешествие? И важный вопрос, который необходимо задать на ранней стадии, —
использовать ли микрослужбы вообще?

Понимание цели
Микрослужбы не являются самоцелью. Вы не ’’выигрываете”, если имеете микро­
службы. Решение внедрить архитектуру на основе микрослужб должно быть осоз­
нанным, основанным на принятии рациональных решений. Рассуждать о миграции
на архитектуру, основанную на микрослужбах, следует для достижения чего-то,
чего вы в настоящее время не способны достичь с помощью архитектуры сущест­
вующей системы.

Если вы не будете понимать то, чего вы пытаетесь достичь, то каким образом вы
собираетесь информировать свой процесс принятия решений о том, какие варианты
вы должны принять? Внедряя микрослужбы, вы пытаетесь достичь состояния, ко­
торое значительно изменит то, на чем вы сосредоточиваете свое время и как вы
расставляете приоритеты своих усилий.
Понимание цели также поможет вам не стать жертвой ’’аналитического парали­
ча” — быть подавленным вариантами выбора. Вы также рискуете впасть в каргокультную ментальность, просто исходя из того, что ’’если микрослужбы хороши
для Netflix, то они хороши и для нас!”.

Часто встречающееся непонимание
Несколько лет назад я вел семинар по микрослужбам на конференции. Как и на всех
моих занятиях, мне нравится вникать в то, почему люди туда приходят и что они на­
деются получить от семинара. На этом конкретном занятии несколько человек пришли
из одной компании, и мне было любопытно узнать, почему компания их послала.
— В чем причина вашего посещения семинара? Почему у вас возник интерес к ис­
пользованию микрослужб? — спросил я одного из них. И ответ был:
— Мы не знаем, наш босс велел нам прийти! — Заинтригованный, я продолжил рас­
следование.
— Так, а как вы предполагаете, почему ваш босс захотел, чтобы вы были здесь?
— Ну, это вы у него спросите — он сидит позади нас, — ответил посетитель.

53

Я переключил свою серию вопросов на их босса, задав тот же вопрос:
— Итак, почему вы хотите использовать микрослужбы? — Ответ босса был таким:
— Наш технический директор сказал, что мы принимаемся за микрослужбы, поэтому я
подумал, что мы должны узнать, что это такое!
Эта правдивая история, хотя с одной стороны и смешная, к сожалению, встречается
слишком часто. Я сталкиваюсь со многими группами, которые приняли решение вне­
дрить архитектуру на основе микрослужб, не понимая, почему или чего они надеются
достичь.

Проблемы с отсутствием четкого видения относительно того, почему вы исполь­
зуете микрослужбы, носят разнообразный характер. Могут потребоваться значи­
тельные инвестиции непосредственно с точки зрения увеличения числа людей или
количества денег, либо с точки зрения ’’приоритизации”1 работы по транзиту, по­
мимо добавления функций. Это осложняется еще более тем фактом, что потребует­
ся некоторое время на то, чтобы увидеть выгоды от такого транзита. Иногда это
приводит к ситуации, когда люди год или больше специализируются на транзите,
но вообще не могут вспомнить, почему они его начали. Это не просто вопрос эф­
фекта понесенных расходов, сотрудники буквально не знают, зачем они делают эту
работу.
В то же время люди просят меня поделиться информацией о возвратности инвести­
ций (ROI) в переход на архитектуру, основанную на микрослужбах. Некоторые хо­
тят иметь твердые факты и цифры, подтверждающие причину, почему они вообще
должны рассматривать этот подход. Реальность такова, что детальные исследова­
ния такого рода вещей исчисляются единицами и встречаются редко, даже когда
они существуют, наблюдения из такого рода исследований редко годятся для пере­
носа на свою почву из-за разных контекстов, в которых люди могут оказаться.
И что же нам остается, угадайте? Ну, уж нет. Убежден, что мы можем и должны
иметь более широкие исследования эффективности наших решений в области раз­
работки, технологий и архитектуры. С этой целью уже проводится некоторая рабо­
та, например, в виде таких вещей, как ’’Отчет о состоянии дел в области DevOps”
(The State of DevOps Report, http://bit.ly/2ojVq5o)1
2, но там архитектура исследуется
лишь мимоходом. Вместо этих скрупулезных исследований мы должны, по край­
ней мере, стремиться применять к нашему принятию решений критическое мыш­
ление и в то же время осваивать более экспериментальный настрой мыслей.
Вам потребуется четкое понимание того, чего вы надеетесь достичь. Ни один рас­
чет показателя ROI не будет выполнен без правильной оценки того, какой возврат
от инвестиций вы ищете. Нам нужно сосредоточиться на результатах, которых мы
надеемся достичь, а не рабски и догматически придерживаться единого подхода.

1 Здесь и далее оставлен перевод авторского термина — Ред.

2 DevOps (разработка и операции) — это тесная связь между разработчиками приложений и людьми,
которые их тестируют и развертывают. Считается, что DevOps является пересечением разработки
программно-информационного обеспечения, проведения контроля его качества и его эксплуатации
и сопровождения. Она призвана улучшить сотрудничество между этими группами.
См. https://encyclopedia2.thefreedictionary.com/devops — Пер.

54

|

Гпава 2

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

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

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

Подумали ли вы об альтернативах использованию микрослужб?
Как мы увидим далее, часто существует масса других способов достижения неко­
торых из тех же выгод, которые приносят микрослужбы. Анализировали ли вы эти
вещи? Если нет, то почему? Довольно часто вы получите то, что вам нужно, ис­
пользуя гораздо более простой и ’’скучный” метод.

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

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

Почему вы, возможно,
выберете микрослужбы?
Я не могу определить цели, которые существуют в вашей компании. Вы лучше
знаете цели своей компании и стоящие перед ней трудности. То, что я могу изло­
жить, — это причины, которые часто упоминают, говоря о внедрении микрослужб
компаниями по всему миру. В духе честности я также опишу другие способы, ко­
торыми вы могли бы потенциально достичь тех же результатов, используя другие
подходы.

Повысить автономию групп
”В какой бы индустрии вы ни работали, все дело в ваших людях, в том, чтобы
ловить их на правильных поступках и обеспечивать им уверенность, мотивацию,
свободу и желание достичь своего истинного потенциала”.
-Джон Тимпсон (John Timpson)
Многие организации продемонстрировали выгоды от создания автономных групп.
Поддержание малого размера организационных групп, разрешение им создавать

Планирование миграции

|

55

тесные связи и эффективно работать вместе, не привлекая слишком много бюро­
кратии, помогло многим организациям в росте и масштабировании эффективнее,
чем у некоторых из их коллег. Гор (Gore) добился большого успеха, ограничив
численность работающих в каждой структурной единице пределом в 150 человек,
ради того чтобы все друг друга знали. Для того чтобы эти меньшие структурные
единицы могли функционировать, им необходимо предоставлять полномочия и от­
ветственность для работы в качестве автономных единиц.
Очень успешный британский ритейлер Timpsons добился огромных масштабов,
расширяя полномочия своей рабочей силы, уменьшая потребность в центральных
функциях и позволяя местным магазинам принимать решения самим, например,
предоставляя им полномочия в том, сколько возвращать недовольным клиентам.
Теперь председатель компании Джон Тимпсон (John Timpson) прославился тем, что
отказался от внутренних правил и заменил их всего двумя:

Выгляди, как подобает, и можешь класть деньги в кассу.
Ты можешь сделать что-то еще ради более качественного обслуживания клиентов.

Автономия также работает и в меньшем масштабе, и большинство современных
организаций, с которыми я сотрудничаю, стремятся создавать в своих организациях
более автономные группы, часто пытаясь копировать модели из других организа­
ций, таких, как модель двухпиццевых групп Amazon или модель Spotify3.

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

Как еще это сделать?
Автономия — распределение ответственности — проявляется по-разному. Выясне­
ние того, как заложить больше ответственности в группу, не требует сдвига в архи­
тектуре. По сути, это процесс выявления конкретных обязанностей, которые могут
быть переданы группам, и он сыграет свою роль во многих отношениях. Давая вла­
деть частью кодовой базы разным группам, вы получите один из ответов (модуль­
ный монолит здесь по-прежнему принесет вам выгоду): это можно сделать путем
выявления людей, уполномоченных принимать решения в отношении частей кодо­
вой базы по функциональным основаниям (например, Райан умеет лучше показы­
вать рекламу, поэтому он несет ответственность за это; Джейн знает больше всего
о тонкой настройке производительности наших запросов, поэтому сначала пропус­
кайте все в этой области через нее).
Улучшение автономии также играет свою роль в том, что просто не приходится
больше ждать, пока другие люди сделают что-то для вас, поэтому принятие самообслуживаемых подходов к обеспечению работы машин или сред является огром­

3 Которую, как известно, даже Spotify больше не использует.

56

|

Гпава 2

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

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

Как еще это сделать?
И с чего же начать? В игру вступает так много переменных, когда рассматриваешь
вопрос о том, как быстрее поставлять софт. Я всегда предлагаю вам выполнить
какое-то упражнение по моделированию пути к производству, т. к. оно помогает
продемонстрировать, что самым большим блокирующим игроком может оказаться
совсем не то, что вы думаете.
Помню, как много лет назад в одном крупном инвестиционном банке нас привлек­
ли для того, чтобы помочь ускорить доставку софта. Нам сказали: ’’Разработчикам
требуется слишком много времени на то, чтобы запускать все в производство!”.
Один из моих коллег, Киф Моррис (Kief Morris), нашел время, чтобы составить
карту всех этапов, связанных с доставкой софта, рассматривая процесс с момента,
когда владелец продукта придумывает идею, до момента, когда эта идея фактиче­
ски попадает в производство.

Он быстро выяснил, что с того времени, когда разработчик приступал к выполне­
нию части работы, до ее развертывания в производственной среде уходило в сред­
нем около шести недель. Мы чувствовали, что могли бы скинуть с этого процесса
пару недель за счет использования подходящей автоматизации, поскольку были
задействованы ручные процессы. Но Киф обнаружил гораздо более серьезную про­
блему на пути к производству — часто требовалось более 40 недель на то, чтобы
идеи от владельца продукта доходили до точки, где разработчики могли хоть как-то
начать работу. Сосредоточив наши усилия на улучшении этой части процесса, мы
помогли клиенту в уменьшении времени выхода на рынок новой функционально­
сти значительно больше.
Поэтому подумайте обо всех шагах, связанных с доставкой софта. Посмотрите,
сколько времени они занимают, продолжительность (как прошедшее время, так и
занятое время) по каждому шагу и выделите ’’болевые” точки на этом пути. После
всего этого вы вполне можете обнаружить, что микрослужбы будут частью реше­
ния, но вы, вероятно, найдете много другого, что можно попробовать параллельно.

Выполнить эффективное по стоимости масштабирование
с учетом нагрузки
Разбив нашу обработку на отдельные микрослужбы, мы получаем возможность
масштабировать эти процессы независимо. Это означает, что мы также можем на­

Планирование миграции

|

57

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

Как еще это сделать?
Здесь мы можем рассмотреть огромное число альтернатив, с большинством из ко­
торых легче проводить эксперименты, прежде чем связывать себя подходом, ори­
ентированным на микрослужбы. Для начала мы могли бы просто взять ’’коробку”
побольше — если вы находитесь в публичном облаке или другом типе виртуальных
платформ, то вы могли бы обеспечить, чтобы в вашем процессе работали более
крупные машины. Это ’’вертикальное" масштабирование, очевидно, имеет свои ог­
раничения, но для быстрого краткосрочного улучшения его не следует сразу отбра­
сывать.

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

Повысить робастность
Переход от однопользовательского софта к мультитенантным SaaS-приложениям
означает, что влияние перебоев в работе системы будет гораздо более распростра­
ненным. Ожидания наших клиентов в отношении доступности их софта, а также
его важность в их жизни, возросли. Раскладывая наше приложение на отдельные,

58

|

Гпава 2

независимо развертываемые процессы, мы открываем массу механизмов повыше­
ния робастности наших приложений.

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

Отказоустойчивость против робастности
Обычно, когда мы хотим улучшить способность системы избегать перебоев в работе,
плавно обрабатывать сбои, когда они происходят, и быстро ее восстанавливать, когда
возникают проблемы, мы часто говорим об отказоустойчивости. В области того, что
сейчас известно как инженерия отказоустойчивости была проделана большая работа,
которая рассматривала данную тему в целом, поскольку она применима ко всем об­
ластям, а не только к вычислительной технике. Модель отказоустойчивости, впервые
предложенная Дэвидом Вудсом (David Woods), рассматривает концепцию отказо­
устойчивости шире и указывает на тот факт, что быть отказоустойчивым не так про­
сто, как мы могли бы подумать, разграничивая нашу способность иметь дело с из­
вестными и неизвестными источниками сбоев среди прочего4.
Джон Оллспоу (John Allspaw), коллега Дэвида Вудса, помогает различать понятия ро­
бастности и отказоустойчивости. Робастность — это способность иметь систему, ко­
торая может реагировать на ожидаемые вариации. Отказоустойчивость — это нали­
чие организации, способной адаптироваться к тому, что не было продумано заранее,
вполне включая в себя создание культуры экспериментирования посредством таких
вещей, как инженерия хаоса. Например, мы отдаем себе отчет в том, что конкретная
машина может заглохнуть, поэтому мы вносим в нашу систему избыточность путем
балансировки экземпляра по нагрузке. Это пример обращения с робастностью. Отка­
зоустойчивость есть процесс подготовки организации самой себя к тому факту, что
она не в состоянии предвосхитить все потенциальные проблемы.
Важным соображением здесь является то, что микрослужбы не обязательно дают
вам робастность бесплатно. Скорее, они открывают возможности для дизайна сис­
темы таким образом, чтобы она была терпимее к сетевым разделениям, перебоям
в работе служб и т. п. Простое распределение функциональности между несколь­
кими отдельными процессами и отдельными машинами не гарантирует улучшен­
ной робастности; скорее наоборот— это просто увеличит "суммарную площадь"
сбоя.

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

4 См. Дэвид Вудс, "Четыре концепции отказоустойчивости и последствия для будущего инженерии
отказоустойчивости" (David Woods, “Four Concepts for Resilience and the Implications for the Future of
Resilience Engineering.” Reliability Engineering & System Safety 141 (2015) 5-9).
5 См. шаблон конкурирующего потребителя для одного такого примера в книге "Шаблоны интеграции
предприятия" Грегора Хоп и Бобби Вулфа, стр. 502 (Enterprise Integration Patterns by Gregor Hohpe,
Bobby Woolf).

Планирование миграции

|

59

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

Инвестиции в более надежное аппаратное и программно-информационное обеспе­
чение также принесут выгоду, как и тщательное исследование существующих при­
чин перебоев в работе системы. Например, я видел немало производственных про­
блем, вызванных чрезмерной зависимостью от ручных процессов, или людей, кото­
рые "не следуют протоколу". Это часто означает, что невинная ошибка человека
может иметь значительные последствия. Авиакомпания British Airways пережила
массовый отток в 2017 году, в результате чего все ее рейсы в лондонский Хитроу и
Гатвик были отменены. Эта проблема, по всей видимости, была непреднамеренно
вызвана скачком напряжения в результате действий одного человека. Если робаст­
ность вашего приложения опирается на допущение, что люди никогда не ошибают­
ся, то вы движетесь по ухабистой дороге.

Промасштабировать число разработчиков
Мы все, вероятно, встречались с проблемой, когда проект "закидывали" разработ­
чиками в попытках его ускорить — это очень часто приводит к обратному эффекту.
Но для решения некоторых проблем все-таки нужно больше людей. Как отмечает
Фредерик Брукс (Frederick Brooks)6 в своей ставшей теперь основополагающей
книге "Мифический человеко-месяц", добавление большего числа людей продол­
жит улучшать быстроту осуществления доставки, если сама работа будет подразде­
лена на отдельные части с ограниченным взаимодействием между ними. Он приво­
дит пример уборки урожая в поле — простой задачи, в которой несколько человек
работают параллельно, т. к. работа, выполняемая каждым сборщиком, не требует
взаимодействия с другими людьми. Софт редко работает подобным образом, по­
скольку выполняемая работа не всегда одинакова, и часто выход из одной части
работы необходим в качестве входа для другой.

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

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

6 См. Фредерик Брукс "Мифический человеко-месяц" (Frederick Р. Brooks, The Mythical Man-Month,
20th Anniversary Edition, Boston: Addison-Wesley, 1995).

60

|

Гпава 2

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

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

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

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

Как еще это сделать?
Если мы по-прежнему продолжим поставлять наш софт как единый процесс, у нас
действительно будут ограничения на то, какие технологии мы можем использовать.
Конечно, мы могли бы безопасно внедрить новые языки в одной и той же среде вы­
полнения — в качестве одного примера JVM способна с радостью разместить код,
написанный на нескольких языках, в одном и том же работающем процессе. Одна­
ко новые типы баз данных становятся все более проблемными, поскольку из этого
вытекает некоторая декомпозиция ранее монолитной модели данных для обеспече­
ния поступательной (инкрементной) миграции, если только вы не собираетесь пол­
ностью и немедленно переключиться на новую технологию баз данных, что сделать
сложно и рискованно.
Если текущий стек технологий считается ’’выгорающей платформой”, то у вас не
будет иного выбора, кроме как заменить его на новый, лучше поддерживаемый

Планирование миграции

|

61

стек технологий7. Конечно же, вам ничто не мешает постепенно поменять ваш су­
ществующий монолит на новый — шаблоны, наподобие подхода на основе фикусаудавки, описанного в главе 3, хорошо для этого работают.

Многоразовое использование?
Многоразовое использование — одна из наиболее часто заявляемых целей миграции
на микрослужбы, и, по-моему, это слабая цель. По сути, многоразовое использова­
ние — это не тот прямой результат, который люди хотят. Люди надеются, что много­
разовое использование приведет к другим выгодам. Мы надеемся, что благодаря ему
мы сможем поставлять функции быстрее или, возможно, снизить затраты, но если эти
вещи являются вашей целью, то просто отслеживайте их, а иначе вы в итоге будете
оптимизировать совсем не то.
Поясню, что я имею в виду. Давайте повнимательнее приглядимся к одной из обычных
причин, по которой многоразовое использование выбирается в качестве цели. Мы хо­
тим поставлять функции быстрее. Мы думаем, что, оптимизируя наш процесс разра­
ботки вокруг многоразового использования существующего кода, нам не придется пи­
сать очень много кода — и мы с меньшей работой и быстрее доведем наш софт до
выходной двери, так? Но давайте возьмем простой пример. Группа обслуживания
клиентов в Music Corp должна форматировать PDF для обеспечения клиентских сче­
тов-фактур. Еще одна часть системы уже занимается генерацией PDF-файлов: мы
производим PDF-файлы на складе для распечатки упаковочных листов, прилагаемых
к заказам, поставляемым клиентам, и для отправки поставщикам заявок на размеще­
ние заказов.
Следуя цели многоразового использования, наша группа будет ориентирована на су­
ществующую возможность генерации PDF. Но эта функциональность в настоящее
время выполняется другой группой в другой части организации. Поэтому теперь мы
должны координировать работу с ними в части внесения необходимых изменений для
поддержки наших функций. Это будет означать, что мы должны просить их делать
работу за нас или, возможно, должны будем вносить изменения сами и отправлять
запрос на включение модифицированного кода (при условии, что наша компания ра­
ботает таким образом). В любом случае, мы должны координировать свои действия
с другой частью организации при внесения изменения.
Мы будем тратить время на координирование с другими людьми и обеспечивать вне­
сение изменений, и все это ради того, чтобы мы могли внедрить наши изменения. Но
мы выяснили, что на самом деле мы могли бы намного скорее написать свою собст­
венную имплементацию и отправить функцию клиенту быстрее, чем потратив время
на адаптацию существующего кода. Если ваша фактическая цель — меньшее время
выхода на рынок, то это будет правильным выбором. Но если вы выполняете оптими­
зацию с целью многократного использования, надеясь на то, что вы получите более
короткое время выхода на рынок, то в итоге вы придете к тому, что будете делать ве­
щи, которые вашу работу замедляют.
Измерять многократное использование в сложных системах трудно, и, как я уже отме­
чал, оно, как правило, привлекается для достижения чего-то другого. Вместо этого
потратьте свое время, сосредоточившись на реальной цели, и признайте, что много­
разовое использование не всегда бывает правильным ответом.
7 Термин ’’выгорающая платформа" (burning platform), как правило, используется для обозначения
технологии, которая, по общему мнению, находится в конце своего срока эксплуатации. Получить
поддержку со стороны технологии может оказаться слишком тяжело или дорого, а нанять людей
с соответствующим опытом — слишком трудно. Распространенный пример технологии, которая, по
общему мнению большинства организаций, считается выгорающей платформой, — мейнфреймовое
приложение на COBOL.

62

|

Гпава 2

Когда микрослужбы будут плохой идеей?
Мы потратили годы на разведывание потенциальных выгод от архитектур на осно­
ве микрослужб. Но в некоторых ситуациях я рекомендую вам не использовать мик­
рослужбы вообще. Давайте теперь рассмотрим несколько таких ситуаций.

Неясный домен
Неправильное понимание контуров служб приводит к дорогостоящим результатам.
Оно приводит к большему числу изменений между службами, чрезмерно сопря­
женным компонентам и в целом будет хуже, чем просто иметь единую монолитную
систему. В книге ’’Создание микросервисов” я поделился опытом работы коллекти­
ва SnapCI в ThoughtWorks. Несмотря на то что они очень хорошо знали домен (об­
ласть) непрерывной интеграции, их первоначальная попытка в создании контуров
служб для их технического решения по непрерывной интеграции на хосте (hostedCI) была не совсем правильной. Она привела к высокой стоимости изменений и вы­
сокой стоимости владения. После нескольких месяцев борьбы с этой проблемой
указанная группа решила снова объединить службы в одно большое приложение.
Позже, когда функциональный набор приложения несколько стабилизировался
и группа получила более четкое представление о домене, отыскать эти стабильные
контуры стало легче.
SnapCI был инструментом непрерывной интеграции и непрерывной доставки, раз­
мещаемым на хосте. Ранее данная группа работала над другим подобным инстру­
ментом, Go-CD, который теперь служит средством непрерывной доставки с откры­
тым исходным кодом и разворачивается локально, а не в облаке. Хотя между про­
ектами SnapCI и Go-CD было некоторое повторное использование кода, в конце
концов, SnapCI оказался совершенно новой кодовой базой. Тем не менее предыду­
щий опыт группы в домене обеспечения инструментарием для непрерывной дос­
тавки (CD) вдохновил их двигаться быстрее в определении контуров и создании
своей системы в виде набора микрослужб.
Однако через несколько месяцев стало ясно, что варианты использования SnapCI
тонко отличались настолько, что первоначальный подход к контурам служб был не
совсем правильным. Он приводил к большому числу изменений, вносимых во всех
службах, и ассоциированной высокой стоимости изменений. В конце концов, груп­
па объединила службы обратно в одну монолитную систему, что дало им время по­
лучше разобраться в том, где должны проходить контуры. Через год группе уда­
лось разложить монолитную систему на микрослужбы, контуры которых оказались
гораздо стабильнее. Это далеко не единственный пример такой ситуации, который
я видел. Бывает, что преждевременная декомпозиция системы на микрослужбы
становится дорогостоящей, в особенности если вы являетесь новичком в затраги­
ваемом домене. Во многих отношениях иметь существующую кодовую базу, кото­
рую вы хотите разложить на микрослужбы, намного проще, чем пытаться перейти
к микрослужбам с самого начала.

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

|

63

темы. (Еще одна причина для того, чтобы заняться доменным моделированием!
Вскоре мы обсудим его подробнее.)

Стартапы
Эта ситуация покажется немного спорной, т. к. многие организации, известные
своим использованием микрослужб, считаются стартапами, но на самом деле мно­
гие из этих компаний, включая Netflix, Airbnb и т. п., перешли на архитектуру,
основанную на микрослужбах, позже в ходе своей эволюции. Микрослужбы явля­
ются отличным вариантом для ’’масштабирования вверх” — стартапных компаний,
которые до этого утвердили, по крайней мере, основы соответствия продукта рын­
ку8 и теперь занимаются масштабированием с целью увеличения (или, скорее всего,
просто достижения) прибыльности.
Стартапы, в отличие от масштабирования вверх, часто экспериментируют с раз­
личными идеями в попытке отыскать степень соответствия с клиентами. Это при­
водит к огромным сдвигам в первоначальном видении продукта, по мере разведы­
вания пространства, в результате давая огромные сдвиги в домене продукта.

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

Гораздо проще подразделить существующую ’’браунфилдовскую”9 систему, чем
сделать это непосредственно с новой ’’гринфилдовской” системой, которую создал
бы стартап. У вас есть еще над чем поработать. У вас есть код, который вы можете
проэкзаменовать, и вы можете поговорить с людьми, которые используют и сопро­
вождают систему. Вы также знаете, как выглядит хорошее, — у вас есть рабочая
система, готовая к изменению, облегчая вам понимание того, когда вы допустили
ошибку или были слишком агрессивны в процессе принятия решений.
У вас также есть система, которая выполняет работу фактически. Вы понимаете,
как она работает и как она ведет себя в производстве. Декомпозиция на микро­
службы, например, вызывает некоторые неприятные проблемы с производительно ­

8 Соответствие продукта рынку (product/market fit) — это степень, в которой продукт удовлетворяет
сильный рыночный спрос. Определяется как первый шаг к созданию успешного бизнеса, на котором
компания встречается с ранними последователями, собирает обратную связь и измеряет интерес
к своему продукту(ам). См. https://en.wikipedia.org/wiki/Product/market_fit, а также https://medium.com/
Iean-digital/чтo-тaкoe-market-fit-или-пoчeмy-нeт-пpoдaж-27efad0b0d9 — Пер.
9 "Браунфилдовская" система (brownfield system) — это система, имплементируемая на основе суще­
ствующей рабочей системы и каких-либо ее объектов — Пер.

64

|

Гпава 2

стью, но с "браунфилдовской” системой у вас есть шанс утвердить здоровый базо­
вый уровень, прежде чем вносить изменения, потенциально влияющие на произво­
дительность.

Я, конечно, не говорю никогда не заниматься микрослужбами для стартапов;
я лишь хочу донести до вас следующее: смысл этих факторов в том, что вы должны
быть осторожными. Проводите раздел только вокруг тех контуров, которые ясны
изначально, и держите остальные на более монолитной стороне. Это также даст вам
время оценить пределы того, насколько вы являетесь зрелыми с операционной точ­
ки зрения, — если вы с трудом справляетесь с управлением двумя службами, то
управление десятью обязательно будет трудным.

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

В типичной ситуации с софтом, устанавливаемым клиентом, вы ориентируетесь на
определенную платформу. Например, вы можете сказать "требуется сервер
Windows 2016" или "требуется macOS 10.12 или выше". Это четко определенные
целевые среды развертывания, и вы, вполне возможно, упаковываете свой моно­
литный софт с использованием механизмов, хорошо понятных людям, которые
управляют этими системами (например, доставка служб Windows, укомплектован­
ных в пакет установщика Windows Installer). Ваши клиенты, наверняка, знакомы
с покупкой и запуском софта таким образом.

Представьте себе, какие у вас будут проблемы, если вместо передачи им одного
выполняемого и управляемого ими процесса вы станете передавать им 10 или 20?
Или, возможно, еще агрессивнее, ожидая, что они будут выполнять ваш софт на
кластере Kubemetes или на чем-то аналогичном?

Реальность такова, что нельзя ожидать, что у ваших клиентов будут иметься навы­
ки или платформы для управления архитектурой на основе микрослужб. Даже если
они их будут иметь, то у них не будет тех навыков или платформ, которые вам
нужны. Например, существует большая разница между версиями инсталляций
Kubemetes.

Отсутствует веская причина!
И, наконец, категорически не следует внедрять микрослужбы, если у вас нет четко­
го представления о том, что именно вы пытаетесь достичь. Как мы увидим, резуль­
тат, который вы ищете от внедрения вами микрослужб, будет определять, где вы
Планирование миграции

|

65

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

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

Все начинается достаточно невинно. Нам нужно выполнить перепланировку архи­
тектуры нашего приложения, чтобы справляться с существенным ростом трафика,
и мы решаем, что микрослужбы — это путь вперед. Кто-то другой подходит и го­
ворит: "Ну, если мы беремся за микрослужбы, то одновременно с этим мы могли
бы сделать наши группы автономнее!". Еще один вмешивается и говорит: "И это
дает нам отличный шанс попробовать Kotlin в качестве языка программирования!".
Прежде чем вы придете в себя, у вас уже будет масштабная инициатива по измене­
нию, которая пытается внедрить автономию групп, масштабировать приложение и
одновременно внедрить новую технологию, а также другие вещи, которые люди
накинули к программе работы "для верности".

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

Следовательно, важно отделить мотивирующий стержневой мотив от любых вто­
ростепенных выгод, которые вы также хотели бы получить. В этом случае умение
обращаться с улучшенным масштабом приложения — самый важный мотив. Рабо­
ты, проделываемые для достижения прогресса по другим второстепенным целям
(например, улучшение автономии групп), будут полезными, но если они мешают
или отвлекают от ключевого целевого критерия, то они должны отойти на задний
план.
Здесь важно осознать, что некоторые вещи важнее других. В противном случае вы
не сможете надлежаще расставить приоритеты. Одно из усилий, которое мне здесь
нравится, — это думать о каждом вашем желаемом результате, как о ползунковом
регуляторе. Каждый ползунок начинается в середине. Когда вы придаете одной ве­
щи большую важность, должны опустить приоритет у другой — данный пример
можно увидеть на рис. 2.1. Этим четко артикулируется то, например, что, хотя вы
хотели бы упростить полиглотное программирование, оно не столь же важно, как
обеспечение отказоустойчивости приложения. Что касается выяснения способа ва66

|

Гпава 2

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

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

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

Приглашение людей в "путешествие"
Меня часто спрашивают: ’’Как продать микрослужбы своему боссу?”. Этот вопрос,
как правило, исходит от разработчика — того, кто увидел потенциал архитектуры,
основанной на микрослужбах, и убежден, что этот путь ведет вперед.
Нередко, когда люди расходятся во мнениях по поводу того или иного подхода, это
происходит потому, что у них разные взгляды на то, чего вы пытаетесь достичь.
Важно, чтобы вы и другие люди, которых вам нужно взять с собой в ’’путешест­
вие”, имели общее понимание того, чего вы пытаетесь достичь. Если ваши взгляды
в этом совпадают, то, по крайней мере, вы знаете, что вы не согласны только в том,
как туда добраться. Поэтому все снова возвращается к цели — если другие люди
в организации разделяют общую цель, то они с гораздо большей вероятностью
будут готовы к внесению изменений.

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

Планирование миграции

|

67

Изменение организаций
Восьмиступенчатый процесс д-ра Джона Коттера (John Kotter) по имплементированию изменений в организации лежит в основе работы менеджеров по изменениям
по всему миру, отчасти потому, что он хорошо справляется с перегонкой требуе­
мых действий в дискретные, понятные шаги. Эта модель далеко не единственная,
но она является именно той, которую я нахожу наиболее полезной.
Этот процесс, очерченный на рис. 2.2, описывается огромным объемом информа­
ционного материала, поэтому я не буду здесь останавливаться на указанном про­
цессе слишком много10. Тем не менее, стоит кратко описать шаги и подумать о том,
как они нам помогут, если мы подумываем о принятии на вооружение архитектуры,
основанной на микрослужбах.

Рис. 2.2. Восьмиступенчатый процесс Коттера для осуществления организационных изменений

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

Закрепление чувства насущной необходимости
Возможно, люди посчитают вашу идею перехода на микрослужбы хорошей. Про­
блема в том, что ваша идея — всего лишь одна из многих хороших идей, которые,
10 Модель изменений Джона Коттера подробно изложена в его книге "Во главе перемен" (Leading
Change, Harvard Business Review Press, 1996).

68

|

Гпава 2

вероятно, витают в окружении организации. Хитрость заключается в том, чтобы
помочь людям понять, что сейчас наступило самое время осуществить это конкрет­
ное изменение.
Здесь поможет поиск моментов ’’открытости к обучению”. Иногда самое подходя­
щее время, для того чтобы запереть дверь конюшни, наступает после того, как ло­
шадь была заперта, потому что люди вдруг начинают осознавать, что именно о бег­
стве лошадей должны быть все их мысли, и теперь они начинают осознавать, что
у них даже есть дверь, и ’’Вон, смотрите, ее можно закрыть и все такое!”. В моменты
после преодоления кризиса у вас есть краткий миг в сознании людей, где срабаты­
вает толчок к изменениям. Прождете слишком долго, и боль — и причины этой бо­
ли — спадут.

Помните, что своими действиями вы не пытаетесь сказать: ’’Нам прямо сейчас сле­
дует заняться микрослужбами!”. Вы стараетесь поделиться чувством насущной не­
обходимости в том, чего вы хотите достичь, — и, как я уже сказал, микрослужбы
не являются целью!

Создание направляющей коалиции
Вам не обязательно интегрировать всех, но их должно быть достаточно, для того
чтобы это произошло. Вам нужно выявить людей из вашей организации, которые
помогут вам продвигать это изменение вперед. Если вы являетесь разработчиком,
то первые из них, вероятно, будут среди ваших ближайших коллег в вашей группе
и, возможно, кто-то более старший по должности — это будет технический руко­
водитель, архитектор или менеджер по доставке. В зависимости от масштаба изме­
нения участие большого числа людей может не понадобиться. Если вы меняете
просто то, как ваша группа что-то делает, то соответствующего ’’прикрытия с воз­
духа” может хватить. Если вы пытаетесь изменить способ разработки софта в ва­
шей компании, то для обеспечения поддержки вам понадобится кто-то на уровне
сотрудников исполнительного звена (возможно, директор по информационным
технологиям (СЮ) или технический директор (СТО).
Интегрирование людей с целью помочь осуществить это изменение не будет про­
ходить гладко. Независимо от того, насколько хороша эта идея, если человек нико­
гда о вас не слышал или никогда с вами не работал, то почему он должен поддер­
живать вашу идею? Доверие завоевывается. Кто-то с гораздо большей вероятно­
стью поддержит вашу большую идею, если он уже работал с вами и достиг
меньших, быстрых побед.
Здесь важно, чтобы у вас были вовлечены люди, не связанные с доставкой софта.
Если вы уже работаете в организации, где барьеры между ”ИТ” и "Бизнесом” были
разрушены, то все, вероятно, будет ОК. С другой стороны, если обособленность
подразделений все еще существует, то вам, возможно, придется протянуть руку
через проход, для того чтобы найти сторонника в другом месте. Конечно, если ва­
ша архитектура на основе микрослужб ориентирована на решение проблем, с кото­
рыми организация сталкивается в своей деятельности, то продать ее будет намного
проще.
Планирование миграции

|

69

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

Развитие видения и стратегии
Это важно там, где вы собираете своих людей вместе и договариваетесь о том, ка­
кие изменения вы надеетесь принести (видение) и как вы собираетесь туда попасть
(стратегия). Видение изменений — скользкая штука. Оно должно быть реалистич­
ным, но в то же время желательным, и ключом является отыскание баланса между
этим. Чем шире видение распространено, тем больше работы пойдет на его упаков­
ку для интегрирования людей. Но видение может быть расплывчатым и все равно
работать с меньшими группами (’’нам нужно уменьшить количество багов!”).

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

Коммуницирование видения перемен
Вероятно, здорово иметь большое видение перемен, но не делайте его настолько
большим, что люди не поверят в их осуществление. Недавно я увидел заявление
генерального директора (СЕО) крупной организации, в котором говорилось (не­
сколько перефразируя) следующее:

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

70

|

Гпава 2

трат, поскольку вам придется привлечь новые навыки, и вы будете испытывать не­
гативное влияние на продуктивность до тех пор, пока новые навыки не будут зало­
жены в основу. Другой вопрос — это упомянутые здесь временные рамки. В дан­
ной конкретной организации скорость изменений была достаточно малой, чтобы
считать 12-месячную цель смехотворной. Поэтому любое видение, которое вы раз­
деляете, должно быть в какой-то степени правдоподобным.
Что касается распространения своего видения, то следует начинать с малого. Много
лет назад я работал в рамках программы под названием ’’Легионеры тестирования”
(Test Mercenaries), чтобы оказать помощь во внедрении практики автоматизации
тестирования в Google. Причиной запуска этой программы явились предыдущие
попытки со стороны тех, кого мы сейчас называем сообществом практиков (”групплетов” в номенклатуре Google), с целью помочь распространить понимание важ­
ности автоматизированного тестирования. Одной из первых попыток программы по
распространению информации о тестировании была инициатива под названием
’’Тестирование на унитазе”. Она состояла из коротких одностраничных статей, при­
калываемых к дверям туалета, с тем чтобы люди могли читать их ”на досуге”! Я не
предлагаю, что эта технология будет работать везде, но она хорошо работала
в Google— и это был действительно эффективный способ распространения не­
больших действенных советов11.

И последнее замечание. Наблюдается тенденция все большего ухода от общения
’’лицом к лицу” в пользу таких систем, как Slack. В том что касается обмена важ­
ными сообщениями такого рода, то общение ’’лицом к лицу” (в идеале лично, но,
возможно, через видеосвязь) будет значительно эффективнее. Оно облегчает пони­
мание реакции людей на эти идеи, а также помогает калибровать ваше сообщение и
избегать недоразумений. Даже если для транслирования своего видения через более
крупную организацию вам понадобятся другие формы коммуникации, сначала по­
общайтесь как можно больше лицом к лицу. Это поможет вам гораздо эффективнее
улучшить свой ’’месседж”.

Расширение полномочий сотрудников
по широкому кругу действий
’’Расширение полномочий сотрудников” — это призыв со стороны консалтинга по
менеджменту поспособствовать им в выполнении своей работы. Чаще всего он
означает нечто довольно простое — удаление ’’дорожных пробок”.

Вы поделились своим видением и подняли воодушевление — и что затем происхо­
дит? На пути начинают вставать всяческие помехи. Одна из наиболее распростра­
ненных проблем кроется в том, что люди слишком заняты тем, что они делают сей­
час, а тут еще надо иметь пропускную способность для осуществления перемен —11

11 Более подробная история инициативы по внесению изменений с целью внедрения тестирования
в Google изложена в отличной тематической подборке Майка Блэнда (http://bit.ly/2omkxVy), которую
стоит прочитать. Майк также подробно описал историю "тестирования на унитазе" (http://bit.ly/
2ojpWwm).

Планирование миграции

|

71

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

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

В рамках программы ’’Легионеры тестирования” в Google мы изготовили каркасы,
облегчающие создание и управление тестовыми наборами, повысили степень ви­
димости тестов в рамках системы ревизии кода и даже в итоге поспособствовали
созданию нового общекорпоративного инструмента CI, упрощающего выполнение
тестов. Но мы делали все это не сразу. Мы работали с несколькими группами, ви­
дели болевые точки, учились на них, а затем вкладывали время в привлечение но­
вых инструментов. Мы также начали с малого — процесс изготовления тестового
набора был довольно простым, но работа по изменению системы ревизии кода
в масштабах всей компании была гораздо крупнее. Мы не пытались решать его до
тех пор, пока не добились некоторых успехов в других местах.

Генерирование краткосрочных выигрышей
Если людям потребуется слишком много времени на то, чтобы увидеть прогресс, то
они потеряют веру в видение перемен. Поэтому идите на несколько быстрых побед.
Концентрация с самого начала на малых, легких, ’’низко висящих фруктах” помо­
жет создать импульс. В том что касается декомпозиции на микрослужбы, то функ­
циональность, которую можно легко извлечь из нашего монолита, должна нахо­
диться в вашем списке высоко. Но, как мы уже установили, сами по себе микро­
службы не являются целью, поэтому вам нужно будет уравновешивать легкость
извлечения некоторой части функциональности относительно выгоды, которую она
принесет. Мы вернемся к этой идее позже в данной главе.

Разумеется, если вы выберете нечто, что считаете легким, и в итоге столкнетесь
с огромными трудностями, то это станет источником ценного понимания вашей
стратегии и заставит вас пересмотреть то, что вы делаете. Это совершенно нор­
72

|

Гпава 2

мально! Главное сначала сосредоточиться на чем-то легком, и тогда, скорее всего,
понимание будет получено раньше. Нам свойственно ошибаться, мы способны
лишь структурировать вещи, благодаря чему обеспечиваем свое максимально ско­
рое обучение на этих ошибках.

Консолидация выигрышей
и порождение новых изменений
Как только у вас есть некий успех, важно не почивать на лаврах. Быстрые выигры­
ши останутся единственными, если вы не будете продолжать настаивать на своем.
После успехов (и неудач) важно делать паузы и обдумывать их в плане того, как
продолжать осуществлять изменения. Возможно, когда вы достигнете разных час­
тей организации, вам придется поменять свой подход.

Во время транзита на микрослужбы по мере того как вы будете вгрызаться все
глубже и глубже, вы обнаружите, что продвигаться становиться все труднее. Воз­
можно, вопрос улаживания декомпозиции базы данных вы откладывали с самого
начала, но его не получится откладывать вечно. Как мы разведаем в главе 4. в ва­
шем распоряжении имеется целый ряд методов, но, для того чтобы выяснить, какой
подход является правильным, потребуется тщательный анализ. Просто помните,
что метод декомпозиции, который работал для вас в одной области вашего моноли­
та, может не работать где-то еще — вам нужно будет постоянно пробовать новые
способы продвижения вперед.

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

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

Планирование миграции

|

73

Важность поступательной миграции
’’Если вы переписываете методом “Большого взрыва”, то единственное, что вам
гарантировано, — это большой взрыв”.
— Мартин Фаулер (Martin Fowler)

Если вы уже готовы решить, что декомпозиция существующей монолитной систе­
мы является правильным поступком, то я настоятельно рекомендую вам ’’откалы­
вать” от этих монолитов, вынимая каждый раз по ’’кусочку”. Поступательный под­
ход поможет вам усваивать знания о микрослужбах по мере продвижения работы, а
также ограничит влияние ошибок (и, поверьте, они у вас будут!). Думайте о моно­
лите как о ’’мраморной глыбе”. Можно было бы просто взорвать всю глыбу цели­
ком, но это редко заканчивается хорошо. Гораздо больше смысла в откалывании от
нее постепенно, поступательно, по кусочку.
Трудность в том, что стоимость эксперимента по переходу с нетривиальной моно­
литной системы на архитектуру, основанную на микрослужбах, будет большой,
и если вы делаете все сразу, то бывает непросто получить хорошую обратную связь
о том, что работает (или не работает) хорошо. Гораздо легче разбить такое ’’путе­
шествие” на более мелкие этапы; каждый из них можно проанализировать и из
каждого извлечь уроки. Именно по этой причине я был большим поклонником ите­
ративной доставки софта еще до появления концепции маневренности agile, т. е.
принятия того факта, что я буду делать ошибки и поэтому мне нужен способ
уменьшить размер этих ошибок.
Любой транзит на архитектуру, основанную на микрослужбах, должен учитывать
эти принципы. Разбейте большое путешествие на множество малых шагов. Каждый
шаг можно выполнить и усвоить. Если этот шаг окажется ретроградным, то совсем
небольшим. В любом случае вы на нем научитесь, и следующий шаг, который вы
сделаете, будет проинформирован теми шагами, которые были сделаны раньше.
Как мы уже говорили ранее, разбиение вещей на более мелкие кусочки также по­
зволяет выявлять быстрые выигрыши и на них обучаться. Это поможет упростить
следующий шаг и накопить импульс. Выделяя микрослужбы по одной, вы также
выводите наружу запертую в них ценность, приносимую ими поступательно, вме­
сто ожидания какого-то развертывания методом ’’Большого взрыва”.

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

Главное — производство
Действительно, важно отметить, что извлечение микрослужбы не может считаться
завершенным до тех пор, пока та не находится в производстве и активно не исполь­
зуется. Одна из целей поступательного извлечения состоит в том, чтобы дать нам
74

|

Гпава 2

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

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

Обратимые и необратимые решения
Джефф Безос (Jeff Bezos), генеральный директор Amazon, в своих ежегодных
письмах акционерам дает интересное представление о том, как работает Amazon.
Письмо за 2015 год содержало следующий пассаж:

"Некоторые решения являются последовательными и необратимыми или почти
необратимыми — однопутные двери— и эти решения должны приниматься
методично, тщательно, медленно, с большим обдумыванием и консультацией.
Если вы проходите через них и вам не нравится то, что вы видите на другой сто­
роне, то вы не сможете вернуться туда, где вы были раньше. Назовем эти реше­
ния решениями 1-го рода. Но большинство решений не таковы — они изменчи­
вы, обратимы — они являются “двупутными дверьми”. Если вы приняли субоп­
тимальное решение 2-го рода, то вам не придется жить с последствиями так
долго. Вы можете снова открыть дверь и пройти обратно. Решения 2-го рода мо­
гут и должны приниматься быстро людьми с высоким уровнем суждений или
малыми группами".
-Джефф Безос, Письмо акционерам Amazon (2015)
Безос продолжает: "Люди, которые не принимают решения, часто попадают в ло­
вушку, рассматривая решения 2-го рода как решения 1-го рода. Все становится во­
просом жизни или смерти, все становится важнейшим мероприятием. Проблема
в том, что внедрение архитектуры, основанной на микрослужбах, приносит с собой
массу вариантов относительно того, как вы делаете вещи, а это означает, что вам
Планирование миграции

|

75

потребуется принимать гораздо больше решений, чем раньше. И если вы (или ваша
организация) к этому не привыкли, то вы окажетесь в этой ловушке, и прогресс за­
стопорится”.
Указанные термины не особо описательны, и бывает трудно вспомнить, что на са­
мом деле означает решение 1-го или 2-го рода, поэтому я предпочитаю имена ’’не­
обратимое” (для решения 1-го рода) или ’’обратимое” (для решения 2-го рода)12.
Хотя эта концепция мне нравится, я не думаю, что решения всегда аккуратно попа­
дают в одну из этих двух корзин; данный вопрос видится немного тоньше, чем тут.
Я бы предпочел думать в терминах необратимости и обратимости как находящихся
на двух концах спектра, как показано на рис. 2.3.

Рис. 2.3. Спектр различий между необратимыми и обратимыми решениями с примерами

Оценить то, где вы находитесь в этом спектре, с самого начала будет трудно, но
в сущности все это возвращается к пониманию влияния, в случае если позже вы
решите изменить свое мнение. Чем большее влияние окажет последующее исправ­
ление курса, тем больше это решение начинает выглядеть как необратимое.

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

Необратимые решения потребуют большей вовлеченности, тщательного обдумы­
вания и учета всех ”за” и ’’против”, и вам следует (должным образом) уделять этому
больше времени. Чем дальше мы продвигаемся по этому спектру к нашим обрати­
мым решениям, тем больше мы можем просто положиться на наших коллег, кото­
рые близки к затрагиваемой проблеме, и принять верное решение, зная, что если
они принимают неправильное решение, то позже его будет легко исправить.

12 Чаевые в шляпу Мартину Фаулеру в благодарность за имена!

76

|

Гпава 2

Более легкие места для эксперимента
Стоимость, связанная с переносом кода в пределах кодовой базы, довольно мала.
Нас поддерживает большое число инструментов, и если мы создаем проблему, то
исправление наступает в общем-то быстро. Однако разложение базы данных требу­
ет гораздо большей работы, и откат изменения базы данных так же сложен. Схо­
жим образом распутывание чрезмерно сопряженной интеграции между службами
или необходимость полностью переписывать API, используемый многочисленными
потребителями, становится значительным мероприятием. Высокая стоимость изме­
нений означает, что эти операции становятся все более рискованными. Как управ­
лять этим риском? Мой подход— пытаться совершать ошибки там, где влияние
будет наименьшим.
Я склонен посвящать большую часть своих мыслей тому месту, где стоимость из­
менения и ошибок настолько низкие, насколько это возможно: на доске. Набросай­
те предлагаемый вами дизайн. Посмотрите, что произойдет при прогоне вариантов
использования через то, что, по вашему мнению, будет контуром службы. В случае
нашего музыкального магазина, например, представьте, что произойдет, когда кли­
ент ищет запись, регистрируется на веб-сайте или покупает альбом. Какие вызовы
делаются? Появляются ли у вас странные циклические ссылки? Не замечаете ли вы
две чрезмерно ’’болтливые” службы, что может сигнализировать о том, что они
должны быть единым целым?

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

Доменно-обусловленный дизайн
В главе 1 я представил доменно-обусловленный дизайн, как важную концепцию,
помогающую задавать контуры наших служб. Разработка доменной модели также
помогает нам в том, что касается выработки способа приоритизации нашей деком­
позиции. На рис. 2.4 приведен пример высокоуровневой доменной модели компа­
нии Music Corp. Вы видите ряд ограниченных контекстов, выявленных в результате
доменного моделирования. Мы ясно видим связи между этими ограниченными
контекстами, которые, как мы предполагаем, будут представлять взаимодействия
внутри самой организации.

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

Планирование миграции

|

77

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

Рис. 2.4. Ограниченные контексты и связи между ними в Music Corp

Я рассматриваю создание доменной модели как почти необходимый шаг, который
является частью структурирования транзита на микрослужбы. Нередко вызывает
опасение то, что многие люди не имеют прямого опыта в создании такого пред­
ставления. Они также очень обеспокоены объемом предстоящей работы. Реаль­
ность такова, что, хотя в создании логической модели подобного рода наличие
опыта значительно помогает, даже небольшой объем усилий приносит некоторые
по-настоящему полезные выгоды.

Как далеко заходить?
По мере приближения к декомпозиции существующей системы, ее перспектива вы­
глядит пугающей. Многие люди, вероятно, строили и продолжают строить эту сис­
тему, и, по всей вероятности, гораздо более крупная группа людей фактически
использует ее изо дня в день. Учитывая масштаб, попытка придумать подробную
доменную модель для всей системы выглядит устрашающей.
Важно понимать, что от доменной модели нам нужна лишь информация, представ­
ленная в достаточном объеме для принятия разумного решения о том, с чего начи­
нать декомпозицию. Вероятно, у вас уже есть некоторые идеи в отношении тех час­
тей вашей системы, которые нуждаются во внимании больше всего, и, следова­
тельно, для монолита достаточно придумать обобщенную модель с точки зрения
высокоуровневых группировок функциональности и выбрать те части, в которые
вы хотите погрузиться глубже. Всегда есть опасность, что если смотреть только на
часть системы, то можно пропустить более крупные системные вопросы, которые
требуют решения. Но я бы не стал на этом зацикливаться — вовсе не требуется де­
лать это правильно с первого раза, вам просто нужна информация в достаточном

78

|

Гпава 2

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

Событийный штурм
Событийный штурм (event storming), метод, созданный Альберто Брандолини
(Alberto Brandolini), представляет собой коллаборативное усилие с участием техни­
ческих и нетехнических заинтересованных сторон, которые вместе определяют со­
вместную доменную модель. Событийный штурм работает снизу вверх. Участники
начинают с определения ’’доменных событий" — вещей, которые происходят в сис­
теме. Затем эти события группируются в агрегаты, а далее агрегаты группируются
в ограниченные контексты.
Важно отметить, что событийный штурм не означает, что вы должны затем строить
событийно-обусловленную систему. Вместо этого он фокусируется на понимании
того, какие (логические) события происходят в системе, — выявлении фактов, ко­
торые вас интересуют как участника системы. Эти доменные события отображают­
ся в события, активируемые в рамках событийно-обусловленной системы, но они
представляются разными способами.

Одна из вещей, на которых Альберто действительно концентрирует внимание с по­
мощью этого метода, — это идея коллективного определения модели. Результатом
данного усилия является не только сама модель, но и совместное понимание моде­
ли. Для того чтобы этот процесс работал как надо, необходимо собрать в вашей
комнате правильные заинтересованные стороны— и часто в этом состоит самая
большая трудность.
Более подробное разведывание темы событийного штурма выходит за рамки этой
книги, но указанный метод я использовал, и он мне очень нравится. Если вы хотите
узнать больше, то прочитайте статью Альберто "Введение в событийный штурм"
(в настоящее время статья пополняется)13.

Использование доменной модели для приоритизации
Мы можем получить некоторые полезные сведения из диаграмм, таких, как на
рис. 2.4. Основываясь на числе вышестоящих или нижестоящих зависимостей, мы
можем экстраполировать представление о том, какую функциональность, скорее
всего, будет легче или труднее извлечь. Например, если взять извлечение функцио­
нальности "Уведомление", то можно ясно увидеть ряд вышестоящих зависимостей,
как показано на рис. 2.5 — многие части нашей системы требуют использования
этого поведения. Если мы хотим извлечь нашу новую службу "Уведомление", то
нам придется проделать большую работу с существующим кодом, изменив вызовы

13 См. https://leanpub.com/introducing_eventstorming.

Планирование миграции

|

79

Рис. 2.5. С точки зрения нашей доменной модели функциональность "Уведомления"

выглядит логически сопряженной, поэтому извлечь ее будет сложнее

с локальных вызовов существующей уведомительной функциональности и вместо
этого сделав их вызовами службы. В главе 3 мы рассмотрим несколько методов,
касающихся такого рода изменений.
Поэтому ’’Уведомление” не будет хорошим местом для старта. С другой стороны,
как показано на рис. 2.6, ’’Выписка счетов-фактур” вполне может представлять го­
раздо более простую часть поведения системы, пригодную для извлечения; она не
имеет входящих зависимостей, уменьшая необходимые изменения, которые нам
нужно внести в существующий монолит. В этих случаях эффективным будет шаб­
лон типа ’’Фикус-удавка”, поскольку мы можем легко перенаправлять входящие
вызовы, прежде чем они дойдут до монолита. Мы рассмотрим этот и многие другие
шаблоны в следующей главе.

Рис. 2.6. "Выписка счетов-фактур", по всей видимости, извлекается легче

80

|

Гпава 2

Во время оценивания вероятной сложности извлечения эти связи являются хоро­
шим местом для старта, но мы должны понимать, что доменная модель представля­
ет собой логическую точку зрения на существующую систему. Нет никакой гаран­
тии, что лежащая в основании кодовая структура нашего монолита структурирова­
на именно таким образом. Это означает, что наша логическая модель поможет
направлять нас с точки зрения функций, которые, вероятно, будут более (или ме­
нее) сопряженными, но для получения более точной оценки степени запутанности
текущей функциональности нам все равно потребуется взглянуть на сам код. До­
менная модель такого рода не покажет нам, какие именно ограниченные контексты
хранят данные в базе данных. Мы, возможно, обнаружим, что ’’Выписка счетовфактур” управляет большим объемом данных, и, следовательно, нам придется учи­
тывать влияние работы по декомпозиции базы данных. Как мы обсудим в главе 7,
мы можем и должны пытаться разбирать монолитные хранилища данных на части,
но эта работа будет совсем не той, с которой мы хотим начать, извлекая нашу пер­
вую пару микрослужб.
Таким образом, мы смотрим на вещи через призму того, что выглядит легко и что
выглядит трудно, и это занятие будет стоящим — в конце концов мы хотим оты­
скать несколько быстрых выигрышей! Однако мы должны помнить, что рассматри­
ваем микрослужбы как способ достижения чего-то конкретного. Возможно, мы вы­
ясним, что ’’Выписка счетов-фактур”, на самом деле, представляет собой простой
первый шаг, но если наша цель — помочь сократить время до рынка, а функцио­
нальность ’’Выписка счетов-фактур” едва ли изменится, то это не будет хорошим
использованием нашего времени.

Следовательно, нам нужно объединить наше представление о том, что легко и что
трудно, вместе с нашим представлением о том, какие выгоды принесет декомпози­
ция на микрослужбы.

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

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

Планирование миграции

|

81

Рис. 2.7. Простая двухосевая модель для приоритизации декомпозиции на службы

Рис. 2.8. Пример использования квадранта приоритизации

82

|

Гпава 2

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

Когда вы начнете вносить изменения, вы научитесь большему. Некоторые вещи,
которые вы считали легкими, окажутся трудными, а некоторые, казалось бы, труд­
ные, будут легкими. И это естественно! Но это еще означает необходимость воз­
вращаться к указанному усилию по приоритизации и заново составлять план, по
мере того как вы учитесь все больше. Возможно, откалывая по кусочку, вы начи­
наете осознавать, что "Уведомление" на самом деле легче извлечь, чем вы думали
раньше.

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

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

Сдвиг в структуре
Исторически ИТ-организации структурировались вокруг стержневых компетенций.
Разработчики на Java работали в одной группе с другими разработчиками на Java.
Тестировщики находились в одной группе с другими тестировщиками. Все адми­
нистраторы БД были в своей группе. Во время создания софта специалисты из та­
ких групп назначались для работы над этими часто недолговечными инициативами.

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

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

Планирование миграции

|

83

зации: чем больше групп необходимо вовлечь в создание или изменение части соф­
та, тем больше времени это займет.

Эти обособленные подразделения разрушаются. Во многих организациях выделен­
ные группы тестирования теперь ушли в прошлое. Вместо этого специалисты по
тестированию становятся неотъемлемой частью групп доставки, позволяя разра­
ботчикам и тестировщикам работать теснее вместе. Движение DevOps также час­
тично привело к тому, что многие организации отошли от централизованных опе­
рационных групп, вместо этого возлагая большую ответственность за операцион­
ные аспекты на группы доставки.
В ситуациях, когда роли этих выделенных групп были перенесены в группы дос­
тавки, роли централизованных групп сместились. От выполнения работы самостоя­
тельно они перешли к помощи группам доставки в выполнении работы. Сюда вхо­
дит встраивание специалистов в группы, создание самообслуживаемого инстру­
ментария, повышение квалификации или целый ряд других мероприятий. Их
ответственность сместилась с делания к созданию возможностей.

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

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

Ранее мы очень кратко коснулись модели Spotify. Возрос интерес к тому, как
Spotify выстроила свою организацию в известной статье 2012 года ’’Масштабирова­
ние Agile @ Spotify” (Scaling Agile @ Spotify)14 Хенрика Книберга (Henrik Kniberg)
и Андерса Иварссона (Anders Ivarsson). В той статье популяризировались понятия
отрядов, орденов и гильдий, терминов, которые в нашей отрасли сейчас являются
обычными (хотя и неправильно понятыми). В конечном счете, это привело к тому,
что люди окрестили это ’’моделью Spotify”, хотя данный термин никогда не исполь­
зовался в Spotify.

14 См. http://bit.ly/2ogAz3d.

84

|

Гпава 2

Впоследствии, компании поспешно стали перенимать эту структуру. Но, как и
в случае с микрослужбами, многие организации тяготели к модели Spotify, не заду­
мываясь о контексте, в котором работает Spotify, об их бизнес-модели, задачах,
с которыми они сталкиваются, или культуре компании. Оказывается, что организа­
ционная структура, которая хорошо работала для шведской музыкальной стримин­
говой компании, может не работать для инвестиционного банка. Кроме того, в ори­
гинальной статье был показан снимок того, как Spotify работала в 2012 году, а с тех
пор все изменилось. Оказывается, даже Spotify не использует ’’модель Spotify”.
То же самое должно относиться и к вам. Черпайте вдохновение из того, что сделали
другие организации, и никак иначе, но не исходите из того, что если что-то работа­
ло у кого-то другого, то оно будет работать и в вашем контексте. Как однажды вы­
разилась Джессика Керр (Jessica Kerr) по поводу модели Spotify ’’Копируйте вопро­
сы, а не ответы”15. Снимок организационной структуры Spotify отражает измене­
ния, которые она провела для решения своих проблем. Копируйте это гибкое,
вопрошающее отношение в том, как вы делаете вещи, и пробуйте новые вещи, но
обеспечьте, чтобы изменения, которые вы применяете, коренились в понимании
вашей компании, ее потребностей, ее людей и ее культуры.

Приводя конкретный пример, я вижу, как многие компании говорят своим группам
доставки "Так, теперь вы должны разворачивать софт и обеспечивать поддержку
24/7”. Такой подход является невероятно разрушительным и бесполезным. Иногда,
большие, смелые заявления бывают отличным способом побудить все завертеться,
но будьте готовы к хаосу, который он принесет. Если вы работаете в среде, где раз­
работчики привыкли работать с 9 до 5, не будучи на связи, никогда не работали
в среде технической поддержки или операций и не отличат SSH от своего локтя, то
это отличный способ оттолкнуть свой персонал и потерять много людей. Если вы
считаете, что для вашей организации такой шаг будет правильным, то отлично! Но
говорите об этом как о стремлении, цели, которую вы хотите достичь, и объясните
причину. Затем работайте со своими людьми, организуя путешествие к этой цели.
Если вы действительно хотите сделать сдвиг в сторону групп, более полно вла­
деющих всем жизненным циклом своего софта, то вам следует понять, что навыки
этих групп должны измениться. Вы можете предоставить помощь и обучение, до­
бавить в группу новых людей (возможно, путем встраивания в группы доставки
людей из текущей операционной группы). Независимо от того, какие изменения вы
хотите внести, как и с нашим софтом, вы можете это осуществить в поступатель­
ном режиме.

DevOps не означает NoOps!
Существует широко распространенная путаница вокруг термина DevOps, причем не­
которые люди считают, что указанный термин означает, что разработчики выполняют
все операции и что люди со стороны операций не нужны. Это далеко не так. По сути,
DevOps — это культурное движение, основанное на концепции разрушения барьеров
между разработкой и операциями (по тестированию, развертыванию и сопровожде­
нию — Пер.). Вы, возможно, и не хотите, чтобы специалисты по-прежнему выступали
15 См. http://bit.ly/2AKTaXP.

Планирование миграции

|

85

в этих ролях, но независимо от того, что вы хотите сделать, вы хотите содействовать
общему выравниванию и пониманию между людьми, которые участвуют в доставке
вашего софта, независимо от их конкретных обязанностей.
Для получения дополнительной информации я рекомендую книгу "Топологии групп"
(Team Topologies)16, в которой исследуются организационные структуры DevOps. Еще
один отличный ресурс по этой теме, хотя и более широкий по охвату, — "Справочник
по Devops" (The Devops Handbook)17.

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

Рис. 2.9. Подмножество обязанностей по доставке и их увязка с существующими группами

16 Мануэль Паис (Manuel Pais) и Мэтью Скелтон (Matthew Skelton), Team Topologies (IT Revolution
Press, 2019).
17 Джин Ким (Gene Kim), Джез Хамбл (Jez Humble) и Патрик Дебуа (Patrick Debois), The DevOps
Handbook (IT Revolution Press, 2016).

86

|

Гпава 2

Очень важно иметь такое понимание текущего реального (как есть) состояния, по­
скольку оно поможет дать каждому совместное понимание всей связанной с этим
работы. Природа обособленной организации состоит в том, что вы с трудом пони­
маете, что делает одно обособленное подразделение, когда вы находитесь в другом
обособленном подразделении. Я считаю, что это действительно помогает организа­
циям быть честными перед самими собой относительно того, как быстро все может
измениться. Скорее всего, вы также обнаружите, что не все группы равны — неко­
торые уже умеют многое делать сами по себе, а другие будут полностью зависеть
от других групп во всем — от тестирования до развертывания.

Если вы обнаружите, что ваши группы доставки уже самостоятельно развертывают
софт для тестов и тестирования со стороны пользователей, то шаг к развертыванию
в производстве будет не таким большим. С другой стороны, вам все еще нужно
учитывать влияние взятия на себя нижнеярусной технической поддержки (нося с
собой пейджер), диагностики производственных вопросов и т. д. Эти навыки нака­
пливаются людьми в течение многих лет работы, и ожидать, что разработчики бы­
стро справятся с этим за одну ночь, совершенно нереально.
После того как у вас есть реальная картина, перерисуйте ваше видение того, как все
должно быть в будущем, в течение некоторой разумной временной шкалы.
Я нахожу, что вы захотите разведать подробно не более чем на шесть месяцев и до
года вперед. Какие обязанности переходят из рук в руки? Как вы собираетесь осу­
ществить этот транзит? Что нужно, чтобы сделать этот сдвиг? Какие новые навыки
понадобятся группам? Каковы приоритеты различных изменений, которые вы хо­
тите осуществить?
Если взять наш предыдущий пример, то на рис. 2.10 видно, что мы решили объеди­
нить обязанности групп по фронтэнду и бэкэнду. Мы также хотим, чтобы группы
могли обеспечивать работу своих собственных тестовых сред. Но для этого опера­
ционная группа должна предоставить самообслуживаемую платформу, которую
группа доставки будет использовать. Мы хотим, чтобы в конечном счете группа
доставки брала на себя полную поддержку своего софта, и поэтому мы желаем,
чтобы группы начали чувствовать себя более удовлетворенными от связанной
с этим работы. Наличие собственных тестовых развертываний во владении групп
доставки — хороший первый шаг. Мы также решили, что они будут обрабатывать
все инциденты в течение рабочего дня, давая им возможность ускорить этот про­
цесс в безопасной среде, где существующая операционная группа находится под
рукой и будет их направлять и тренировать.

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

Планирование миграции

|

87

Рис. 2.10. Один из примеров того, как можно переназначить обязанности в нашей организации

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

Конкретным примером этой идеи в действии является проект, в котором я участво­
вал во время моего пребывания в ThoughtWorks. Мы были наняты помочь газете
Guardian восстановить свое онлайновое присутствие (к этому мы вернемся в сле­
дующей главе). В рамках этого проекта они должны были быстро освоить новый
язык программирования и связанные с ним технологии.
В начале проекта наши объединенные группы составили список стержневых навы­
ков, которые были важны для разработчиков Guardian. Затем каждый разработчик
оценивал себя по этим критериям, ранжируя себя от 1 (’’для меня это ничего не зна­
чит!”) до 5 (”я мог бы написать об этом книгу”). Балл каждого разработчика был
приватным, он был доступен только тому, кто их наставлял. Цель состояла не
в том, чтобы каждый разработчик доводил каждый навык до ”5”, а наоборот в том,
чтобы они сами устанавливали достигаемые ими цели.

Моя работа, как тренера, состояла в том, чтобы в случае если один из разработчи­
ков, которых я тренировал, хотел улучшить свои навыки в Oracle, то я способство­
вал тому, чтобы у него была возможность этого добиться. Сюда входит обеспече­
ние того, чтобы он работал над вариантами, в которых эта технология применялась,

88

|

Гпава 2

рекомендации видео для просмотра, возможность участия в учебном курсе или
конференции и т. д.

Вы можете использовать этот процесс для раскручивания визуального представле­
ния областей, где человек, возможно, захочет сосредоточить свое время и усилия.
На рис. 2.11 мы видим такой пример, который показывает, что я действительно хо­
чу сосредоточить свое время и энергию на развитии своего опыта в Kubemetes и
Lambda, что, возможно, свидетельствует о том, что теперь я собираюсь управлять
развертыванием своего собственного софта. Так же важно выделить те области,
которыми вы довольны — в данном примере я чувствую, что мое кодирование на
Go не является тем, на чем мне нужно сосредотачиваться прямо сейчас.

Рис. 2.11. Пример диаграммы навыков, показывающий те области,

которые я хочу улучшить

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

Хотя каждый балл является приватным, вы все равно можете его использовать для
составления картины группы в целом. Возьмите анонимизированные рейтинги са­

Планирование миграции

|

89

мооценки и разработайте матрицу навыков для всей группы. Это поможет выявить
пробелы, которые, возможно, потребуется устранить на более системном уровне.
На рис. 2.12 показано, что хотя я могу быть доволен своим уровнем овладения
платформой РАСТ, в целом группа желает улучшить свои навыки в этой области
больше, в то время как Kafka и Kubemetes — еще одно место, которое потребует
интенсивного внимания. Это, возможно, подчеркнет необходимость некоего груп­
пового обучения и оправдает более крупные вложения, такие, как проведение внут­
реннего учебного курса. Распространение этой совокупной картины среди вашей
группы также поможет людям понять, как им принять участие в оказании помощи
группе в целом с целью отыскания необходимого баланса.

Рис. 2.12. Если смотреть в целом, то у группы есть потребность
улучшить свои навыки в Kafka и Kubernetes и тестирования в РАСТ

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

90

|

Гпава 2

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

Как узнать, что транзит работает?
Мы все совершаем ошибки. Даже если вы начинаете путешествие к микрослужбам
с самыми лучшими намерениями, вы должны принять как данность, что невозмож­
но знать все и что когда-нибудь по ходу дела вы, возможно, осознаете, что все это
не работает. Вопросы таковы: знаете ли вы, что он работает? Совершили ли вы
ошибку?

Основываясь на желаемых целевых результатах, вы должны попытаться опреде­
лить некоторые показатели, которые можно отслеживать и которые помогут вам
ответить на эти вопросы. Вскоре мы разведаем некоторые примеры показателей, но
я хочу воспользоваться этой возможностью, чтобы подчеркнуть тот факт, что мы
говорим не только о количественных показателях. Также необходимо учитывать
качественную обратную связь от людей на передовой.
Эти количественные и качественные показатели должны служить основой для про­
должающегося процесса ревизии. Вам нужно установить контрольные точки, кото­
рые дадут вашей группе время на то, чтобы отрефлексировать вашу работу и уяс­
нить, двигаетесь ли вы в правильном направлении или нет. Во время этих кон­
трольных точек следует задавать себе вопрос не просто о том, ’’работает ли нечто
вообще?”, а о том "а не попробовать ли вместо этого что-нибудь еще?”

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

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

Независимо от того, как часто вы предпринимаете эти усилия, и независимо от
того, насколько формально (или неформально) вы их выполняете, я предлагаю
обеспечить охват следующих тем:

Планирование миграции

|

91

1. Вновь подтвердить, чего вы ожидаете от транзита на микрослужбы. Если бизнес
изменил направление так, что направление, в котором вы движетесь, больше не
имеет смысла, тогда остановиться!
2. Просмотреть все количественные показатели, которые у вас есть, чтобы убе­
диться, что вы продвигаетесь вперед.

3. Запросить качественную обратную связь— считают лилюди, что все попрежнему получается, как и планировалось?
4. Принять решение о том, что вы собираетесь изменить в будущем, если вообще
будете это делать.

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

Стоит отметить, что метрики могут оказаться опасными из-за старой пословицы
’’получаешь то, что измеряешь”. Метрики могут быть подстроены без всякого
умысла или преднамеренно. Я помню, как моя жена рассказывала мне о компании,
в которой она работала, где внешний поставщик отслеживался на основе числа на­
рядов-заказов, которые они закрывали, и оплачивался на основе этих результатов.
И что случилось? Поставщик закрывал наряды-заказы, даже если задача не была
решена, приводя к тому, что вместо них люди открывали новые наряды-заказы.
Другие показатели бывает трудно изменить в течение короткого периода времени.
Я был бы удивлен, если вы увидели значительное улучшение времени цикла в рам­
ках миграции на микрослужбы в первые несколько месяцев; на самом деле, я, веро­
ятно, ожидал бы, что оно вообще ухудшится. Внесение изменений в порядок рабо­
ты часто негативно сказывается на производительности в краткосрочной перспек­
тиве, пока группа быстро осваивает новый способ работы. Это еще одна причина,
почему так важно делать небольшие поступательные шаги: чем меньше изменение,
тем меньше будут потенциальные негативные последствия, которые вы увидите,
и тем быстрее вы их устраните, когда они произойдут.

Качественные показатели
’’...Программно-информационное обеспечение состоит из чувств".
- Астрид Аткинсон (@shinynew_oz) (Astrid Atkinson)
Что бы ни показывали нам наши данные, именно люди строят софт, и важно, чтобы
обратная связь с их стороны была включена в измерение успеха. Получают ли они
удовольствие от этого процесса? Чувствуют ли они, что у них стало больше сил?
Или они чувствуют себя подавленными? Получают ли они поддержку, необходи­
мую для того, чтобы взять на себя новые обязанности или освоить новые навыки?

92

|

Гпава 2

Когда вы докладываете о каких-либо перечнях показателей высшему руководству
для такого рода транзитов18, вы должны включать проверку настроений, исходящих
из вашей группы. Если транзит им нравится, то все отлично! Если же это не так, то
вам, возможно, придется что-то с этим делать. Игнорирование мнения людей
в пользу количественных показателей — отличный способ попасть в большую беду.

Избегать эффекта понесенных расходов
Вы должны отдавать себе полный отчет об эффекте понесенных расходов, и нали­
чие ревизионного процесса отчасти подстегивает к тому, чтобы оставаться честным
и, надо надеяться, помогать вам избегать этого явления. Эффект понесенных рас­
ходов возникает, когда люди настолько вкладываются в предыдущий подход к че­
му-то, что, даже если факты показывают, что этот подход не работает, они все рав­
но продолжают работать в том же направлении. Иногда мы оправдываемся перед
собой, говоря, что "в любую минуту все может измениться!” В других случаях
внутри нашей организации мы, возможно, приложили столько политического капи­
тала на осуществление перемен, что сейчас просто не можем дать задний ход. В
любом случае, можно, без всякого сомнения, утверждать, что эффект понесенных
расходов связан с эмоциональными вложениями: мы настолько ’’купились” на ста­
рый способ мышления, что просто не можем от него отказаться.
По моему опыту, чем выше ставка и громче сопровождающие ее ’’фанфары”, тем
труднее отступить, когда все идет не так. Эффект понесенных расходов19 также
именуемый когнитивным искажением Конкорд, названным в честь провалившегося
проекта, поддержанного британским и французским правительствами, строитель­
ства сверхзвукового пассажирского самолета с огромными расходами. Несмотря на
все факты, свидетельствующие о том, что указанный проект никогда не принесет
финансовой отдачи, в него закачивалось все больше и больше денег. Какими бы ни
были инженерные успехи, которые, возможно, пришли из Конкорда, он никогда не
работал как самолет, подходящий для коммерческих пассажирских рейсов.

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

18 Да, это действительно произошло. С Kubemetes не все веселье и игры....
19 Эффект понесенных расходов (sunk cost fallacy) — это широко известное когнитивное искажение,
дословно переводимое как ’’ошибочность утопленных затрат", когда психика человека отказывается
признать и зафиксировать понесенные затраты, "списать" их и двигаться дальше, вместо этого побуж­
дая "вбухивать" все больше и больше — Пер.

Планирование миграции

|

93

Оставаясь открытым для новых подходов
Как я надеюсь, для вас не будет сюрпризом, если вы дошли до этой части главы,
что в процесс разбиения монолитной системы на куски задействованы многочис­
ленные переменные и многочисленные пути, которые мы могли бы выбрать. Уве­
ренным можно быть только в одном — не все пойдет гладко, и вам нужно оста­
ваться открытым для отката внесенных вами изменений, пробуя новые вещи или
иногда просто давая вещам немного утрястись, чтобы увидеть, какое влияние они
оказывают.
Если вы пытаетесь освоить культуру постоянного совершенствования, всегда апро­
бируя что-то новое, тогда смена направления, когда это необходимо, становится
гораздо естественнее. Если вы концентрируете концепцию изменений или улучше­
ний процесса в отдельных трудовых потоках, вместо того чтобы встраивать ее во
все, что вы делаете, то вы рискуете увидеть изменения как разовые транзакционные
мероприятия. Как только работа будет сделана, на этом все! Для нас больше ника­
ких перемен! При таком образе мыслей через несколько лет вы окажетесь позади
всех своих конкурентов и с другой горой, на которую еще предстоит подняться.

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

♦ Чего вы надеетесь достичь?
♦ Думали ли вы об альтернативах использованию микрослужб?
♦ Как узнать, что транзит работает?

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

Большинство из нас также работают над системами, которые имеют реальных кли­
ентов. Мы не можем позволить себе тратить месяцы или годы на переписывание
нашего приложения методом ’’Большого взрыва", позволяя существующему при­
ложению, которым пользуются наши клиенты, "простаивать под паром". Целью
должно быть поступательное создание новых микрослужб и их развертывание
в рамках вашего производственного решения, благодаря чему вы сможете начать
учиться на опыте и получать выгоды как можно раньше.
Я предельно ясен по поводу идеи о том, что во время извлечения функциональ­
ности в новую службу работа не будет завершена до тех пор, пока она не окажется

94

|

Гпава 2

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

Планирование миграции

|

95

ГЛАВА 3

Разложение монолита

В главе 2 мы провели разведывательный анализ того, как продумать миграцию на
архитектуру, основанную на микрослужбах. Если конкретнее, мы разведали во­
прос, была ли вообще эта идея хорошей, и если да, то как нужно поступать с точки
зрения внедрения своей новой архитектуры и обеспечения движения в правильном
направлении.
Мы обсудили вопрос о том, как выглядит хорошая служба и почему меньшие по
объему службы будут для нас лучше. Но как справиться с тем фактом, что у нас
уже имеется большое число приложений, которые не следуют этим шаблонам? Как
выполнить декомпозицию этих монолитных приложений, не прибегая к переписы­
ванию методом ’’Большого взрыва”?

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

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

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

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

В одной памятной ситуации я работал с несколькими коллегами, помогая им про­
масштабировать вычислительно тяжелую систему. Опорные вычисления выполня­
лись с помощью библиотеки С, которую нам дали. Наша задача состояла в том,
чтобы собрать различные входные данные, передать их в библиотеку, а также
получить и сохранить результаты. Сама библиотека была полна проблем. Утечки
памяти и ужасно неэффективный дизайн API были лишь двумя главенствующими
причинами проблем. В течение многих месяцев мы просили дать нам исходный код
библиотеки, чтобы иметь возможность исправить эти проблемы, но нам отказали.
Много лет спустя я встретился со спонсором проекта и спросил, почему он тогда не
дал нам изменить базовую библиотеку. Именно в этот момент спонсор, наконецтаки, признался, что он потерял исходный код, но был слишком смущен, и поэтому
ничего нам не сказал! Не давайте этому случиться с вами.

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

Вырезать, скопировать или реимплементировать?
Даже если в самом начале миграции функциональности на новые микрослужбы
у вас есть доступ к существующему коду в монолите, не всегда ясно, что делать
с этим кодом. Следует ли нам перенести код как есть или же реимплементировать
функциональность?
Если существующая монолитная кодовая база достаточно хорошо факторизована,
то вы сэкономите значительное время, перенеся сам код. Главное здесь— понять,
что мы хотим именно скопировать код из монолита и, по крайней мере, на данном
этапе не хотим удалять эту функциональность из самого монолита. Почему? Пото­
му что, оставляя функциональность в монолите на некоторое время, вы получаете
больше возможностей. Это даст нам точку отката или же возможность выполнять
обе имплементации параллельно. И дальше по ходу дела, как только вы будете до­
вольны тем, что миграция прошла успешно, вы удалите эту функциональность из
монолита.

98

|

Гпава 3

Рефакторизация монолита
Я заметил, что часто самым большим препятствием для использования сущест­
вующего кода из монолита в ваших новых микрослужбах является то, что сущест­
вующие кодовые базы традиционно не организованы вокруг понятий бизнесдомена— более заметны технические категоризации (например, подумайте обо
всех пакетных именах "Модель-Вид-Контроллер", которые вы встречали). Когда вы
пытаетесь перенести функциональность, относящуюся к бизнес-домену, это бывает
трудно сделать: существующая кодовая база не соответствует этой категоризации,
поэтому даже отыскать код, который вы пытаетесь перенести, бывает проблема­
тично!

Если вы действительно встали на путь реорганизации существующего монолита
вдоль контуров бизнес-домена, то я настоятельно рекомендую книгу ’’Эффективная
работа с унаследованным кодом” Майкла Фитерса (Michael Feathers)1. В своей кни­
ге Майкл определяет понятие стыка (seam, шов), т. е. места, где можно изменить
программу без необходимости редактировать существующее поведение. По сути,
вы определяете стык вокруг фрагмента кода, который хотите изменить, работаете
над новой имплементацией стыка и подставляете ее после внесения изменений. Ав­
тор показывает методику безопасной работы со стыками как способ очистки кодо­
вых баз.

Хотя в целом концепция стыков Майкла Фитерса применима во многих областях,
она очень хорошо вписывается в ограниченные контексты, которых мы касались
в главе 1. Поэтому, хотя книга ’’Эффективная работа с унаследованным кодом” не
ссылается непосредственно на концепции доменно-обусловленного дизайна, вы
можете воспользоваться методологией, описанной в той книге, для организации
своего кода в соответствии с этими принципами.

Модульный монолит?
После того как ваша существующая кодовая база начала обретать смысл, стоит по­
думать о следующем очевидном шаге — взять ваши только что выявленные стыки
и начать извлекать их как отдельные модули, превращая ваш монолит в модульный
монолит. У вас по-прежнему одна единица развертывания, но эта развернутая еди­
ница состоит из многочисленных статически связанных модулей. Точная природа
этих модулей зависит от вашего опорного стека технологий — для Java мой мо­
дульный монолит будет состоять из нескольких файлов JAR; для приложения Ruby
это будет коллекция из gem-ов языка Ruby.

Как мы кратко упомянули в начале книги, наличие монолита, разложенного на мо­
дули, которые развиваются независимо, приносит много выгод при одновременном
обходе многих трудностей архитектуры, основанной на микрослужбах, и является
наиболее благоприятной зоной для многих организаций. Я беседовал с нескольки­
ми группами, начавшими дезинтегрировать свой монолит на модульный монолит,
1 См. Эффективная работа с унаследованным кодом (Working Effectively with Legacy Code, Michael
Feathers, Prentice Hall, 2004).

Разложение монолита

|

99

о перспективе в конечном счете перейти на архитектуру, основанную на микро­
службах, и выяснил лишь то, что модульный монолит решил большинство их про­
блем!

Поступательные переписывания
Мое общее стремление — всегда сначала пытаться спасти существующую кодовую
базу, прежде чем прибегнуть к простой реимплементации функциональности, и со­
вет, который я дал в своей предыдущей книге ’’Создание микросервисов”, был
именно в этом плане. Иногда группы считают, что они получают от этой работы
выгоды, достаточные для того, чтобы вообще не нуждаться в микрослужбах!
Однако должен признаться, на практике я нахожу, что очень немногие группы ис­
пользуют подход, предусматривающий рефакторизацию своего монолита, в качест­
ве предшественника транзита на микрослужбы. Вместо этого более общепринятый
подход, похоже, состоит в том, чтобы, после того как группы выявили обязанности
только что созданной микрослужбы, они выполняли новую имплементацию этой
функциональности в ’’чистой комнате”.
Но разве мы не рискуем повторить проблемы, ассоциированные с переписывания­
ми методом ’’Большого взрыва”, если начнем реимплементировать нашу функцио­
нальность? Ключ находится в обеспечении переписывания только малых кусков
функциональности за один раз и доставке этой переработанной функциональности
своим клиентам на регулярной основе. Если работа по реимплементации поведения
службы занимает несколько дней или недель, то это, вероятно, будет нормально.
Если же временные рамки начнут выглядеть более похожими на несколько меся­
цев, то я подвергну свой подход переэкзаменовке.

Шаблоны миграции
Я встречал применение многих методов, которые использовались в рамках мигра­
ции на микрослужбы. В оставшейся части главы мы разведаем эти шаблоны, рас­
смотрев, где они могут быть полезны и как их можно имплементировать. Помните,
что, как и все шаблоны, они не являются универсально ’’хорошими” идеями. По каж­
дому из них я попытался привести информацию в достаточной мере, для того что­
бы помочь вам понять, имеют ли они смысл в вашем контексте.
Убедитесь, что вы понимаете плюсы и минусы каждого из этих шаблонов. Они не
всегда являются "правильным" способом делать вещи.

Мы начнем с рассмотрения методов, позволяющих вам мигрировать и интегриро­
ваться с монолитом; в первую очередь мы займемся вопросом о том, где располага­
ется прикладной код. Для начала, однако, мы рассмотрим один из самых полезных
и часто применяемых методов: приложение ’’Фикус-удавка”.

100

|

Гпава 3

Шаблон: приложение "Фикус-удавка"
Метод, который часто используется при переписывании системы, называется при­
ложением ’’Фикус-удавка” (strangler fig арр). Мартин Фаулер был первым, кто вы­
явил этот шаблон, находясь под впечатлением особого вида фикуса, который посе­
ляется на верхних ветвях деревьев. Со временем фикус опускается к земле и пуска­
ет корни, постепенно обволакивая первоначальное дерево. Существующее дерево
первоначально становится опорной структурой для нового фикуса, и если он дой­
дет до заключительных стадий, то вы увидите, как первоначальное дерево умирает
и трухлявеет, оставляя на своем месте лишь новый, теперь уже самоподдерживающийся фикус.
В контексте софта параллель здесь состоит в том, чтобы наша новая система изна­
чально поддерживалась существующей системой и обертывала ее. Идея состоит
в том, что старое и новое могут сосуществовать, давая новой системе время вырас­
ти и потенциально полностью заменить собой старую систему. Ключевая выгода от
этого шаблона, как мы вскоре увидим, заключается в том, что он поддерживает на­
шу цель обеспечения поступательной миграции на новую систему. Более того, он
дает нам возможность ставить на паузу и даже полностью останавливать миграцию,
по-прежнему используя преимущества новой системы, поставленной к этому вре­
мени.

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

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

Имплементация шаблона ’’Фикус-удавка” основана на трех шагах, как показано на
рис. 3.1. Прежде всего, определить части существующей системы, которые вы хо­
тите мигрировать. Вам необходимо будет принять решение о том, какими частями
системы следует заняться в первую очередь, используя что-то вроде компромисс­
ных мероприятий, которые мы обсуждали в главе 2, Затем вам нужно имплементи­
ровать эту функциональность в своей новой микрослужбе. Когда ваша новая им­
плементация будет готова, вы должны иметь возможность перенаправлять вызовы
из монолита в вашу совершенно новую микрослужбу.
Разложение монолита

|

101

Рис. 3.1. Общий вид шаблона "Фикус-удавка'

Стоит отметить, что, до тех пор пока вызов перенесенной функциональности не
будет перенаправлен, новая функциональность технически не будет находиться
"в прямом эфире” — даже если она развернута в рабочей среде. Это означает, что
вы можете не торопиться с приведением данной функциональности в соответст­
вующий вид, работая с имплементацией этой функциональности в течение некото­
рого периода времени. Вы можете вложить эти изменения в производственную
среду с осознанием того, что она еще не используется, позволяя нам получать
удовлетворение от развертывания вашей новой службы и управления ею. После
того, как ваша новая служба будет имплементировать ту же самую эквивалентную
функциональность, что и в вашем монолите, вы сможете подумать о применении
такого шаблона, как ’’Параллельное выполнение” (который мы вскоре рассмотрим),
который даст вам уверенность в том, что новая функциональность работает так, как
задумано.

С

Важно разделять понятия развертывания и релиза. Просто потому что программ­
но-информационное обеспечение развертывается в заданной среде, не означает,
что оно используется клиентами фактически. Рассматривая эти две вещи как от­
дельные понятия, вы даете возможность проверить свой софт в конечной произ­
водственной среде до его использования, что позволяет избежать риска разверты­
вания нового софта. Шаблоны, подобные "Фикусу-удавке", "Параллельному вы­
полнению" и "Канареечному релизу", относятся к числу тех шаблонов, которые
учитывают тот факт, что развертывание и релиз представляют собой отдельные
мероприятия.

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

102

|

Гпава 3

Где его использовать
Шаблон ’’Фикус-удавка’’ позволяет переносить функциональность на новую архи­
тектуру, основанную на службах, не касаясь и не внося никаких изменений в суще­
ствующую систему. Он выгоден, когда над существующим монолитом как таковым
работают другие люди, т. к. он помогает уменьшить конкуренцию. Он также очень
полезен, когда монолит фактически является черно-ящичной системой— такой,
как сторонний софт или служба SaaS.
От случая к случаю можно извлекать весь сквозной кусок функциональности цели­
ком, как показано на рис. 3.2. Это значительно упрощает извлечение, не считая во­
просов, связанных с данными, которые мы рассмотрим в этой книге позже.

Рис. 3.2. Прямолинейная сквозная абстракция функциональности "Управления запасами"

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

Если же вы хотите откусить кусок поменьше, то, возможно, вам придется подумать
о более ’’мелких” извлечениях, как показано на рис. 3.3. Здесь мы извлекаем функ­
циональность ’’Расчета заработной платы”, несмотря на то что она использует еще
одну функциональность, которая остается внутри монолита, — в данном примере
это возможность отправки ’’Уведомлений пользователям”.
Вместо того чтобы также реимплементировать функциональность ’’Уведомлений
пользователей”, мы выставляем эту функциональность наружу из монолита нашей
новой микрослужбе, что, очевидно, потребует изменений в самом монолите.

Однако, для того чтобы ’’удавка” работала как надо, необходимо, чтобы у вас была
возможность четко отображать входящий вызов интересующей вас функциональ­
ности на актив, который вы хотите перенести. Например, на рис. 3.4 в идеале мы
хотели бы вынести возможность отправки ’’Уведомлений пользователю” в новую
службу. Однако уведомления запускаются в результате многочисленных входящих

Разложение монолита

|

103

вызовов существующего монолита. Следовательно, мы не можем четко перена­
правлять вызовы извне самой системы. Вместо этого нам нужно бы рассмотреть
метод, подобный описанному в разделе ’’Шаблон: ветвление по абстракции”.

Рис. 3.3. Извлечение функциональности,
которая по-прежнему нуждается в использовании монолита

Рис. 3.4. Шаблон "Фикус-удавка" работает не слишком хорошо, когда функциональность, которую нужно

перенести, находится глубже внутри существующей системы

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

Несмотря на эти ограничения, приложение ’’Фикус-удавка” снова и снова доказы­
вает, что это очень полезный метод миграции. Учитывая легкое прикосновение и
104

|

Глава 3

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

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

На рис. 3.5 мы видим существующую монолитную систему, которая выставляет
наружу HTTP-интерфейс. Это приложение может быть ’’безголовым”, или же
HTTP-интерфейс может фактически вызываться вышестоящим пользовательским
интерфейсом. В любом случае, цель одинакова: вставить обратный прокси-селек­
тор HTTP2 между вышестоящими вызовами и нижестоящим монолитом.

Рис. 3.5. Простой общий вид HTTP-обусловленного монолита до имплементации "удавки"

Шаг 1: вставить прокси-селектор
Если у вас еще нет подходящего прокси-селектора HTTP, который вы можете ис­
пользовать много раз, то я предлагаю сначала установить его на свое место, как
показано на рис. 3.6. На этом первом шаге прокси-селектор просто позволит любым
вызовам проходить насквозь без изменений.

Этот шаг позволит вам оценить влияние вставки дополнительного сетевого ’’прыж­
ка” между вышестоящими вызовами и нисходящим монолитом, выстроить любой

2 Для справки: обратный прокси-селектор (reverse proxy) — это селектор, который находится перед
веб-серверами и перенаправляет запросы клиента (например, веб-браузера) на эти веб-серверы. Об­
ратные прокси обычно реализуются для повышения безопасности, производительности и надежно­
сти — Пер.

Разложение монолита

|

105

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

Рис. 3.6. Шаг 1: вставка прокси-селектора между монолитом и вышестоящей системой

Если перед вашим монолитом уже есть существующий прокси-селектор, то вы мо­
жете пропустить этот шаг — хотя убедитесь, что вы понимаете, как этот прокси­
селектор можно реконфигурировать для перенаправления вызовов впоследствии.
Я предлагаю, по крайней мере, поэкспериментировать с перенаправлением, убе­
диться, что все работает, как задумано, а не откладывать данный шаг на более
поздний срок. Было бы неприятным сюрпризом обнаружить, что это невозможно,
прямо перед тем как вы запланировали отправить свою новую службу в ’’прямой
эфир”!

Шаг 2: мигрировать функциональность
После установки нашего прокси-селектора на свое место можно начать извлечение
новой микрослужбы, как показано на рис. 3.7.

Сам этот шаг можно разбить на несколько этапов. Прежде всего, привести базовую
службу в рабочее состояние без имплементации какой-либо функциональности.
Ваша служба должна будет принимать вызовы соответствующей функционально­
сти, НО на ЭТОМ этапе МОЖНО просто возвращать КОД ошибки 501 Not Implemented (Не
имплементировано). Даже на этом шаге я бы развернул службу в производственной
среде. Это позволит вам освоиться с процессом развертывания в производстве и
протестировать службу прямо на месте. В этой точке ваша новая служба не выпус­
106

|

Гпава 3

кается в производственную среду, т. к. вы еще не перенаправили существующие
вышестоящие вызовы. Фактически, мы отделяем шаг развертывания софта от рели­
за софта — распространенный метод релиза, к которому мы вернемся позже.

Рис. 3.7. Шаг 2: поступательная имплементация переносимой функциональности

Шаг 3: перенаправить вызовы
Только после завершения переноса всей функциональности, вы переконфигурируе­
те прокси-селектор с целью перенаправления вызовов, как мы видим на рис. 3.8.
Если по какой-либо причине это не получается, то вы можете выставить перена­
правление в прежнее состояние — для большинства прокси-селекторов это очень
быстрый и легкий процесс, дающий вам быстрый откат.

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

Данные?
Мы до сих пор еще не говорили о данных. Глядя на рис. 3.8, представьте, что про­
изойдет, если нашей новой службе "Расчета заработной платы" потребуется обра-

Разложение монолита

|

107

Рис. 3.8. Шаг 3: перенаправление вызова функциональности "Расчета заработной платы"
в завершение миграции

титься к данным, которые в настоящее время хранятся в базе данных монолита?
В главе 4 мы разведаем варианты этого полнее.

Варианты прокси-селектора
Имплементация прокси-селектора частично будет зависеть от протокола, исполь­
зуемого монолитом. Если существующий монолит применяет HTTP, то у нас вели­
колепное начало. HTTP — это такой широко поддерживаемый протокол, что у вас
есть масса вариантов управления перенаправлением. Я бы, вероятно, выбрал выде­
ленный прокси-селектор, например NGINX, который был создан с учетом именно
таких вариантов использования и поддерживает целый ряд механизмов пере­
направления, которые опробованы и протестированы и, вероятно, будут работать
довольно хорошо.

Некоторые перенаправления будут проще, чем другие. Возьмем перенаправление
URI-путей, возможно, как оно демонстрируется с использованием ресурсов REST.
На рис. 3.9 мы переносим весь ресурс ’’Выписка счетов-фактур” в нашу новую
службу, и его легко извлечь из URI-пути.

Если, однако, существующая система ’’закапывает” информацию о природе вызы­
ваемой функциональности где-то в теле запроса (возможно, в параметре формы), то
наше правило перенаправления должно будет иметь возможность активировать па­
раметр в методе POST, что сложнее имплементировать. Конечно, стоит проверить
имеющиеся у вас варианты прокси-селекторов, чтобы убедиться, что они в состоя­
нии справиться с такой ситуацией, если вы в ней окажетесь.
108

|

Глава 3

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

Рис. 3.9. Перенаправление в зависимости от ресурсов

Разложение монолита

|

109

Поступательное внедрение
Как видно из рис. 3.10, этот метод позволяет вносить архитектурные изменения
с помощью серии малых шагов, каждый из которых предпринимается наряду с дру­
гими работами над системой.

Рис. 3.10. Пошаговая имплементация "удавки" на основе HTTP

Вы, возможно, посчитаете, что новая имплементация функциональности ’’Расчета
заработной платы”, на которую вы переключились, по-прежнему остается слишком
большой, и решите брать куски функциональности поменьше. Например, вы поду­
маете о мигрировании только части функционала "Расчета заработной платы” и пе­

110

|

Гпава 3

реадресации вызовов соответствующим образом, имея часть поведения, имплемен­
тированным в монолите, и часть— в микрослужбе, как показано на рис. 3.11. Это
вызовет затруднения, если функциональность, как в монолите, так и в микрослуж­
бе, должна ’’видеть" один и тот же набор данных, поскольку для этого, вероятно,
потребуется совместная база данных и все проблемы, которые она может принести.

Рис. 3.11. Общий вид имплементации "удавки" на основе HTTP

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

Смена протоколов
Прокси-селектор также используется для трансформирования протокола. Напри­
мер, вы, возможно, в настоящее время выставляете наружу SOAP-ориентированный HTTP-интерфейс, но вместо него ваша новая микрослужба собирается под­
3 Переплатформирование (re-platforming) — это процесс, с помощью которого онлайновый бренд
переходит с одной платформы на другую — Пер.

Разложение монолита

|

111

держивать gRPC-интерфейс. Тогда вы могли бы соответствующим образом скон­
фигурировать прокси-селектор для трансформирования запросов и откликов, как
показано на рис. 3.12.

Рис. 3.12. Использование прокси-селектора для смены коммуникационного протокола
в рамках миграции на основе "удавки”

У меня есть опасения по поводу этого подхода, в первую очередь из-за сложности и
логики, которая начинает нарастать в самом прокси-селекторе. Для одной службы
это выглядит не так уж и плохо, но если вы начнете трансформировать протокол
для многочисленных служб, то работа, выполняемая в прокси-селекторе, будет на­
растать и нарастать. Как правило, мы выполняем оптимизацию в сторону незави­
симого развертывания наших служб, но если у нас совместный прокси-слой, кото­
рый должен редактироваться несколькими группами, то он замедлит процесс вне­
сения и развертывания изменений. Мы должны быть осторожными в том, чтобы не
добавлять новый источник конкуренции. Когда мы обсуждаем архитектуру на ос­
нове микрослужб, часто звучит мантра ’’держите каналы безмозглыми, а конечные
точки умными”. Мы хотим уменьшить объем функциональности, заталкиваемый
в совместные слои промежуточного софта, т. к. это по-настоящему замедлит разра­
ботку функций.

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

|

Глава 3

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

Рис. 3.13. Если вы хотите сменить тип протокола, то подумайте о выставлении службой
своих возможностей наружу по нескольким типам протокола

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

И сетки для служб
В компании Square был принят гибридный подход к решению этой проблемы4. Они
решили отказаться от своего собственного доморощенного RPC-механизма двух­
сторонней коммуникации между службами в пользу принятия gRPC, хорошо
поддерживаемого каркаса RPC с открытым исходным кодом с очень широкой эко­
системой. Для того чтобы сделать это как можно безболезненнее, они хотели
уменьшить число изменений, необходимых в каждой службе. Для этого они ис­
пользовали сетку для служб5.
С помощью сетки для служб, показанной на рис. 3.14, каждый экземпляр службы
осуществляет коммуникацию с другими экземплярами службы через свой собст­
4 Более подробное объяснение дано в статье Сноу Петтерсена (Snow Pettersen) "Дорога к сетке для
служб в Envoy" (The Road to an Envoy Service Mesh, https://squ.re/2ntslGc) в блоге для разработчиков
на веб-сайте Square.
5 Сетка для служб (service mesh) — это выделенный инфраструктурный слой для облегчения сквозно­
го обмена данными между микрослужбами, часто использующий прицепной (sidecar) прокси­
селектор — Пер.

Разложение монолита

|

113

венный выделенный локальный прокси-селектор. Каждыйэкземпляр прокси­
селектора можно сконфигурировать специально для экземпляра службы, с которым
он сотрудничает. Вы также можете обеспечить централизованное управление и мо­
ниторинг этих прокси-селекторов с помощью плоскости управления. Поскольку
центрального прокси-слоя нет, вы избегаете ловушек, связанных с наличием совме­
стного "умного” канала. Если это необходимо, то каждая служба практически спо­
собна владеть своей собственной частью канала службы. Стоит отметить, что по
мере развития архитектуры компания Square в итоге вынуждена была создать свою
собственную сетку для служб, специфичную для ее потребностей, хотя и с прокси­
селектором с открытым исходным кодом Envoy вместо устоявшегося решения, та­
кого, как Linkerd или Istio.
Популярность сетки для служб растет, и концептуально, как мне думается, эта идея
попала в точку. Это отличный способ решения общих вопросов двухсторонней
коммуникации между службами. Беспокоит то, что, несмотря на большую работу
ряда очень умных людей, потребовалось продолжительное время для стабилизации
инструментария в этом пространстве. Istio, похоже, явный лидер, но он далеко не
единственный вариант в этом пространстве, и существуют новые инструменты, ко­
торые появляются еженедельно. Мой общий совет состоит в том, чтобы, если мож­
но, дать идее сетки для служб немного больше времени на то, чтобы устояться,
прежде чем сделать свой выбор.

Рис. 3.14. Общий вид сетки для служб

114

|

Глава 3

Пример: FTP
Хотя я уже подробно рассказывал об использовании шаблона ’’Удавка” для систем
на основе HTTP, вам ничто не мешает перехватывать и перенаправлять другие
формы коммуникационных протоколов. Швейцарская риэлторская компания
Homegate с помощью вариации этого шаблона изменила способ закачки клиентами
новых листингов недвижимости.
Клиенты Homegate закачивали листинги по FTP, при этом существующая монолит­
ная система занималась закачанными файлами. Указанная компания стремилась
перейти на микрослужбы, а также хотела начать поддерживать новый механизм
закачки, который вместо пакетной закачки по FTP собирался использовать REST
API, соответствующий стандарту, ратификация которого ожидалась в ближайшем
будущем.

Риэлторская компания не собиралась ничего менять с точки зрения клиента — она
хотела сделать любые изменения бесстыковыми. Это означает, что механизм FTP
по-прежнему оставался востребованным; с помощью него клиенты взаимодейство­
вали с системой, по крайней мере на текущий момент. В конце компания перехва­
тывала FTP-закачки (обнаруживая изменения в журнале FTP-сервера) и направляла
только что закачанные файлы в адаптер, который преобразовывал закачанные фай­
лы в запросы к новому REST API, как показано на рис. 3.15.

Рис. 3.15. Перехватывание FTP-закачки
и переадресация ее на службу новых листингов для Homegate

С точки зрения клиента, сам процесс закачки не изменился. Выгода заключалась
в том, что новая служба, которая занималась клиентской закачкой, публиковала
обновленные данные существенно быстрее, помогая клиентам выводить их рекла­
му в прямой эфир намного скорее. В дальнейшем планировалось выставить наружу
новый REST API клиентам напрямую. Интересно, что в этот период задействова­
лись оба механизма закачки листингов. Это позволило группе обеспечить условие,
чтобы оба механизма закачки работали надлежащим образом. Указанный при­
мер — отличная демонстрация шаблона, который мы рассмотрим далее в разделе
’’Шаблон: параллельное выполнение”.

Разложение монолита

|

115

Пример: перехват сообщений
До сих пор мы рассматривали перехват синхронных вызовов, но что если ваш мо­
нолит управляется из какой-то другой формы протокола, возможно, получая сооб­
щения через брокера сообщений? Фундаментальный шаблон тот же — нам нужен
метод перехвата вызовов и перенаправления их в нашу новую микрослужбу. Глав­
ное различие заключается в природе самого протокола.

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

Рис. 3.16. Монолит, принимающий вызовы через очередь

Простой подход состоит в перехвате всех сообщений, предназначенных для ниже­
стоящего монолита, и фильтрации сообщений в надлежащее место, как показано на
рис. 3.17. Это, в сущности, имплементация шаблона маршрутизатора, основанного
на содержимом (content-based router), как описано в книге Бобби Вульфа и Грегора
Хопа ’’Шаблоны интеграции предприятия”6.

Рис. 3.17. Использование маршрутизатора, основанного на содержимом,
для перехвата вызовов, связанных с обменом сообщениями

6 См. "Шаблоны интеграции предприятия" (Enterprise Integration Patterns, Bobby Woolf, Gregor Hohpe,
Addison-Wesley, 2003).

116

|

Глава 3

Такой метод позволяет оставить монолит нетронутым, но мы помещаем на наш
путь запросов еще одну очередь, что вносит добавочную задержку, и это еще одна
вещь, которой нам нужно управлять. Другая озабоченность заключается в том,
сколько ’’мозгов” мы помещаем в слой обмена сообщениями. В главе 4 книги
’’Создание микросервисов” я говорил о трудностях, связанных с использованием
системой излишних ’’мозгов” в сетях между вашими службами, поскольку это за­
труднит понимание систем и затруднит их изменение.

Вместо этого я призвал вас принять мантру ’’умные конечные точки, безмозглые
каналы”, на чем я по-прежнему настаиваю. Здесь можно поспорить, что маршрути­
затор на основе содержимого означает, что мы имплементируем ’’умный канал”,
добавляя сложность с точки зрения того, как вызовы маршрутизируются между
нашими системами. В некоторых ситуациях этот метод очень полезен, но решать
вам, где находится золотая середина.

Селективное потребление
Альтернативой было бы изменить монолит и побудить его игнорировать отправ­
ляемые сообщения, которые должны быть получены нашей новой службой, как мы
видим на рис. 3.18. Здесь и наша новая служба, и наш монолит делят между собой
одну и ту же очередь, и локально они используют процесс своего рода сопоставле­
ния с шаблоном для прослушивания сообщений, в которых они заинтересованы.
Этот вид фильтрации является довольно распространенным требованием в систе­
мах на основе сообщений и имплементируется с использованием чего-то вроде
’’Селектора сообщений” в JMS или эквивалентной технологии на других платфор­
мах.

Рис. 3.18. Вариант использования маршрутизатора, основанного на содержимом,
для перехвата вызовов, связанных с обменом сообщениями

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

Разложение монолита

|

117

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

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

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

Другие протоколы
Как я надеюсь, вы поняли из рассмотренного примера, есть много способов пере­
хвата вызовов в существующем монолите, даже если вы используете разные типы
протоколов. Что делать, если ваш монолит управляется пакетной закачкой файлов?
Перехватить пакетный файл, извлечь вызовы, которые вы хотите перехватить,
и удалить их из файла перед его пересылкой дальше. Правда, некоторые механизмы
еще более усложняют этот процесс, и будет намного проще, если использовать чтото вроде HTTP, но при некотором творческом подходе шаблон "Фикус-удавка" мо­
жет применяться в очень многих ситуациях.

Другие примеры шаблона "Фикус-удавка"
Шаблон "Фикус-удавка" очень полезен в любом контексте, где вы хотите поступа­
тельно переплатформировать существующую систему, и его применение не огра­
ничивается группами, имплементирующими архитектуры на основе микрослужб.
Указанный шаблон использовался уже в течение длительного времени, прежде чем
Мартин Фаулер описал его в 2004 году. У моего предыдущего работодателя,
Thought Works, мы часто с помощью данного шаблона перестраивали монолитные
приложения. Пол Хаммант (Paul Hammant) — автор неисчерпаемого списка проек­
тов7, где мы использовали этот шаблон в его блоге. Проекты включают в себя ор­
7 См. http://bit.ly/2paBpyP.

118

|

Глава 3

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

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

Представьте себе, например, что мы собираемся использовать шаблон ’’Фикусудавка”, для того чтобы перенести нашу существующую функциональность ’’Расче­
та заработной платы” из монолита. Шаблон ’’Фикус-удавка” дает нам возможность
делать это в несколько шагов, причем каждый шаг теоретически позволяет нам от­
катиться назад. Если бы мы развернули новую службу ’’Расчет заработной платы”
для наших клиентов и обнаружили с ней проблему, то мы могли бы перенаправить
вызовы функциональности ’’Расчета заработной платы” обратно в старую систему.
Это хорошо работает, если функциональность ’’Расчета заработной платы” у моно­
лита и микрослужбы является функционально эквивалентной, но что если мы из­
менили поведение "Расчета заработной платы” в рамках миграции?

Если в микрослужбе ’’Расчет заработной платы” было устранено несколько дефек­
тов, причем их устранение коснулось того, как она работает, и эти изменения не
были перенесены назад в эквивалентную функциональность в монолите, то откат
снова привел бы к появлению этих дефектов в системе. Все было бы еще проблема­
тичнее, если в микрослужбу "Расчет заработной платы” вы добавили новую функ­
циональность — откат тогда потребовал бы удаления функций из ваших клиентов.
Здесь нет простого решения. Если вы допускаете изменения в функциональности,
которую вы переносите до завершения миграции, то должны смириться с тем, что
затрудняете любой откат. Проще, если вы не допускаете никаких изменений до за­
вершения миграции. Чем дольше длится миграция, тем сложнее обеспечить "замо­
розку функции” в этой части системы — если есть спрос на изменение части вашей
системы, то этот спрос вряд ли исчезнет. Чем дольше вы будете завершать мигра­
цию, тем больше давления вы будете испытывать в том, чтобы "вставить эту функ­
цию, пока мы тут". Чем меньше длится каждая ваша миграция, тем меньше давле­
ние, которое вы будете испытывать в том, чтобы изменить функциональность,
переносимую до завершения миграции.

Ж

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

|

119

Шаблон:
"Композиция пользовательского интерфейса"
С помощью методов, рассматриваемых до сих пор, мы в первую очередь ’’заталки­
вали” работу по поступательной миграции на сервер, однако пользовательский ин­
терфейс предоставляет нам некоторые полезные возможности для склеивания
функциональности, раздаваемой частично из существующего монолита или новой
архитектуры, основанной на микрослужбах.
Много лет назад я принимал участие в помощи, оказываемой газете Guardian в он­
лайновом переходе с существующей системы управления контентом на новую
заказную платформу на базе Java. Это должно было совпасть с развертыванием
совершенно нового внешнего вида и ощущения от онлайновой газеты в связке
с перезапуском печатного издания. Поскольку мы хотели принять поступательный
подход, пробежка от существующей CMS к новому веб-сайту раздаваемому совер­
шенно по-новому, была фазирована по частям, ориентируясь на конкретные тема­
тические вертикали (путешествия, новости, культура и т. д.). Даже внутри этих вер­
тикалей мы также искали возможности разложить миграцию на меньшие ’’куски”.

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

Пример: страничная композиция
Хотя в случае с Guardian мы начали с развертывания отдельного виджета (что мы
вскоре обсудим), план всегда состоял в том, чтобы для вывода в прямой эфир со­
вершенно нового внешнего вида и ощущения использовать главным образом одно­
страничную миграцию. Это было сделано на вертикальной основе, причем верти­
каль ’’Путешествия” была первой, которую мы отправили в ’’прямой эфир”. Посети­
телям веб-сайта в течение этого транзитного периода показывались другие
варианты внешнего вида и ощущения, когда они заходили на новые части веб­
сайта. Кроме того, были предприняты большие усилия, для того чтобы все старые
ссылки на страницы были перенаправлены на новые места (там, где URL-адреса
поменялись).
Когда Guardian внесла еще одно изменение в технологии, несколько лет спустя
отойдя от монолита на базе Java, они снова воспользовались аналогичным методом
миграции по одной вертикали за один раз. На этом этапе для имплементации новых
правил маршрутизации они использовали сеть быстрой доставки контента (CDN),
эффективно задействуя CDN так же, как вы бы применяли межкорпоративный про­
кси-селектор8.

8 Было приятно услышать от Грэма Тэкли (Graham Tackley) из Guardian, что "новая" система, помощь
в имплементации которой я оказывал с самого начала, действовала почти 10 лет, прежде чем ее пол­
ностью заменили на текущую архитектуру. Как читатель их веб-сайта, я поймал себя на мысли, что за
этот период я ни разу не заметил никаких изменений!

120

|

Гпава 3

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

Пример: виджетная композиция
В Guardian вертикаль ’’Путешествия” была первой, которая была выявлена для ми­
грации на новую платформу. Отчасти это объяснялось тем, что у нее были некото­
рые трудности с разбиением на категории, но также и тем, что эта часть веб-сайта
была не самой ’’громкой”. В принципе, мы хотели вывести хоть что-то в ’’прямой
эфир”, научиться на этом опыте, а также обеспечить бесперебойную работу прай­
мовых частей веб-сайта, если что-то пойдет не так.

Вместо того чтобы выводить в ’’прямой эфир” всю туристическую часть веб-сайта
с изобилием подробных репортажей о гламурных направлениях по всему миру, мы
хотели сделать гораздо более сдержанный релиз с целью тестирования системы.
Вместо этого мы развернули отдельный виджет, показывающий 10 лучших тури­
стических направлений, определяемых с помощью новой системы. Этот виджет
был вклеен в старые страницы газеты о путешествиях, как показано на рис. 3.19.
В нашем случае мы использовали метод, именуемый боковыми вставками (EdgeSide Includes, ESI), используя Apache. С помощью ESI вы определяете на своей веб­
странице шаблон, и веб-сервер ’’вклеивает” этот контент.

Рис. 3.19. Использование боковых вставок ESI для вклеивания контента
из новой CMS газеты Guardian

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

|

121

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

Хотя в Guardian мы, в конце концов, использовали главным образом странично­
ориентированную композицию, многие другие компании активно применяют виджетно-ориентированную композицию с поддержкой бэкэндовых служб. Orbitz
(теперь часть Expedia), например, создала выделенные службы для раздачи лишь
одного виджета9. До перехода на микрослужбы веб-сайт Orbitz уже был разбит на
отдельные ’’модули” UI (в номенклатуре Orbitz). Эти модули UI представляют фор­
му поиска, форму бронирования, карту и т. д. Они первоначально раздавались не­
посредственно из службы оркестровки контента, как показано на рис. 3.20.

Рис. 3.20. До миграции на микрослужбы служба оркестровки контента Orbitz
раздавала все модули

Служба ’’Оркестровка контента” фактически была крупным монолитом. Группы,
которые владели этими модулями, должны были координировать изменения, вно­
симые внутри монолита, что приводило к значительным задержкам во внедрении
изменений. Это классический пример проблемы конкуренции за доставку, которую
я высветил в главе 7: всякий раз, когда группам приходится координировать вне­
9 См. Стив Хоффман (Steve Hoffman) и Рик Фаст (Rick Fast). "Задействование микрослужб в Orbitz"
(Enabling Microservices at Orbitz, http://bit.ly/2nGNgnI), YouTube, 11 августа 2016.

122

|

Глава 3

дрение изменений, стоимость изменений растет. В рамках стремления к более
быстрым релизным циклам, когда Orbitz решила попробовать микрослужбы, они
сосредоточили свою декомпозицию на этих модулях, начиная с редакционного
модуля. Служба ’’Оркестровка контента’’ была изменена, делегируя ответствен­
ность за транзитные модули нижестоящим службам, как мы видим на рис. 3.21.

Рис. 3.21. Модули мигрировались по одному, при этом служба оркестровки контента
делегировалась новым поддерживающим службам

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

И мобильные приложения
Хотя мы главным образом говорили о веб-интерфейсе пользователя, некоторые из
этих методов могут хорошо работать и для мобильных клиентов. Например, как
Android, так и iOS предоставляют возможность компонентизации частей своих
пользовательских интерфейсов, облегчая работу над этими частями пользователь­
ского интерфейса в изоляции или рекомбинированными различными способами.
Одна из трудностей развертывания изменений с помощью нативных мобильных
приложений заключается в том, что как магазин Apple Арр Store, так и магазин

Разложение монолита

|

123

Google Play требуют, чтобы приложения были предъявлены на рассмотрение и под­
тверждены до появления новых версий. Хотя за последние несколько лет время,
в течение которого магазины приложений подписывают соглашения, в целом зна­
чительно сократилось, это все же по-прежнему увеличивает время, прежде чем но­
вые релизы программно-информационного обеспечения могут быть развернуты.

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

Многие организации решали эту проблему, позволяя вносить динамические изме­
нения в существующее нативное мобильное приложение, не прибегая к разверты­
ванию новой версии нативного приложения. При развертывании изменений на сто­
роне сервера клиентские устройства сразу же видят новую функциональность без
необходимости развертывания новой версии нативного мобильного приложения.
Это достигается просто с помощью таких вещей, как компоненты WebView, позво­
ляющие встраивать веб-страницы в приложения, хотя некоторые компании исполь­
зуют более изощренные методы.
Пользовательский интерфейс Spotify на всех платформах сильно ориентирован на
компоненты, включая ее приложения для iOS и Android. Практически все, что вы
видите, — это отдельный компонент, от простого текстового заголовка до обложки
альбома или списка воспроизведения10. Некоторые из этих модулей, в свою оче­
редь, поддерживаются одной или несколькими микрослужбами. Конфигурация и
расположение этих компонентов UI определяются декларативно на стороне серве­
ра; инженеры Spotify способны быстро изменять изображения, которые видят поль­
зователи, и откатывать их, не требуя отправки новых версий своего приложения
в магазин приложений. Это позволяет им гораздо быстрее экспериментировать и
апробировать новые функции.

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

10 См. статью Джона Санделла (John Sundell) "Строительство компонентно-обусловленных UI в Spotify"
(Building Component-Driven UIs at Spotify, http://bit.ly/2nDpJUP), опубликованную 25 августа
2016 года.

124

|

Гпава 3

кто работал с ’’толстыми” SDK пользовательского интерфейса, такими, как Swing
на Java.

Поставляя весь интерфейс на одной странице, мы, очевидно, не можем рассматри­
вать страничную композицию, поэтому нам придется подумать о некой форме
виджетной композиции. Были предприняты попытки кодифицировать общеприня­
тые форматы виджетов для веб. В последнее время спецификация веб-компонентов
пытается определить стандартную компонентную модель, поддерживаемую всеми
браузерами. Однако потребовалось много времени на то, чтобы этот стандарт на­
брал обороты в условиях, когда браузерная поддержка (среди прочего) была значи­
тельным камнем преткновения.
Люди, пользующиеся каркасами одностраничных приложений, такими, как Vue,
Angular или React, не сидят и не ждут, пока веб-компоненты решат их проблемы.
Вместо этого многие из них пытались разобраться с вопросом, как модуляризировать пользовательские интерфейсы, построенные с помощью SDK-инструментариев, которые изначально были спланированы так, чтобы владеть всей браузер­
ной панелью. Это привело к толчку в сторону того, что некоторые окрестили как
микрофронтэнды.

На первый взгляд, микрофронтэнды на самом деле просто разбивают пользователь­
ский интерфейс на разные компоненты, над которыми можно работать независимо.
В этом нет ничего нового, ведь компонентно-ориентированный софт предшествует
моему появлению на свет на несколько лет! Гораздо интереснее, что люди выраба­
тывают способы побудить веб-браузеры, SDK SPA и компонентизацию работать
вместе. Как именно создать отдельный пользовательский интерфейс из кусков Vue
и React, не сталкивая их зависимости друг с другом, но все же позволяя им потен­
циально обмениваться информацией?

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

Где его использовать
Композиция пользовательского интерфейса как метод, позволяющий переплатформировать системы, очень эффективна, поскольку позволяет переносить целые
вертикальные куски функциональности. Однако, чтобы он работал как надо, необ­
ходима возможность изменять существующий пользовательский интерфейс для
обеспечения безопасной вставки новой функциональности. Мы рассмотрим компо­
зиционные методы далее в этой книге, но стоит отметить, что используемые вами
методы часто зависят от природы технологии, задействуемой для имплементации
пользовательского интерфейса. Хороший старомодный веб-сайт упрощает компо­
зицию пользовательского интерфейса, в то время как технология одностраничных
приложений добавляет некоторую сложность и часто препятствует различным под­
ходам к имплементации!
Разложение монолита

|

125

Шаблон: "Ветвление по абстракции"
Для того чтобы полезный шаблон ’’Фикус-удавка” работал как надо, необходима
способность перехватывать вызовы по периметру нашего монолита. Однако, что
произойдет, если функциональность, которую мы хотим извлечь, находится глубже
внутри нашей существующей системы? Возвращаясь к предыдущему примеру,
возьмем желание извлечь функциональность ’’Уведомления”, как показано на
рис. 3.4.

Для того чтобы выполнить такое извлечение, нам нужно будет внести изменения
в существующую систему. Эти изменения бывают значительными и препятствую­
щими для других разработчиков, работающих над кодовой базой в одно и то же
время. Здесь у нас возникает конкурирующая напряженность. С одной стороны, мы
хотим вносить изменения поступательными шагами. С другой стороны, мы хотим
уменьшить помехи для других людей, работающих в других областях кодовой
базы. Это естественным образом приведет нас к желанию завершить работу быстро.

Часто во время переработки частей существующей кодовой базы люди будут де­
лать эту работу на отдельной ветви исходного кода. Это позволяет вносить измене­
ния, не нарушая работу других разработчиков. Проблема заключается в том, что
как только изменение в какой-либо ветви завершено, эти изменения должны быть
слиты обратно, что часто вызывает значительные трудности. Чем дольше сущест­
вует ветвь, тем больше эти проблемы. Я не буду сейчас подробно останавливаться
на проблемах, связанных с долгоживущими ветвями исходного кода, скажу лишь,
что они противоречат принципам непрерывной интеграции. Данные, взятые из
’’Отчета о состоянии DevOps за 2017 год”11, также показывают, что внедрение раз­
работки на основе главной ветви исходного кода (где изменения вносятся непо­
средственно на магистральной линии и ветвление избегается) и использование ко­
роткоживущих ветвей способствует более высокой производительности ИТ-групп.
Скажем так, я не поклонник долгоживущих ветвей, и я не одинок.
Таким образом, мы хотим иметь возможность вносить изменения в кодовую базу
поступательным образом, но при этом держать на минимуме нарушение работы
у разработчиков, работающих над другими частями кодовой базы. Существует еще
один шаблон, позволяющий вносить изменения в наш монолит поступательно, не
прибегая к ветвлению исходного кода. Шаблон ’’Ветвление по абстракции” (branch
by abstraction) вместо этого полагается на внесение изменений в существующую
кодовую базу, допуская безопасное сосуществование имплементаций друг с другом
в одной и той же версии кода, не вызывая слишком большого нарушения работы.

Как он работает
Ветвление по абстракции состоит из пяти шагов:

1. Создать абстракцию для заменяемой функциональности.

2. Изменить клиентов существующей функциональности так, чтобы они использо­
вали новую абстракцию.11
11 См. http://bit.ly/2pctNfn.

126

|

Глава 3

3. Создать новую имплементацию абстракции с переработанной функциональ­
ностью. В нашем случае эта новая имплементация будет вызывать новую мик­
рослужбу.

4. Переключиться на абстракцию, для того чтобы использовать новую имплемен­
тацию.
5. Очистить абстракцию и удалить старую имплементацию.

Давайте рассмотрим эти шаги по переносу функциональности ’’Уведомлений"
в службу, как было показано на рис. 3.4.

Шаг 1: создать абстракцию
Первая часть работы состоит в создании абстракции, представляющей взаимодей­
ствия между изменяемым кодом и элементами, вызывающими этот код, как пока­
зано на рис. 3.22. Если существующая функциональность "Уведомлений" доста­
точно хорошо факторизована, то эта работа просто сводится к применению рефак­
торизации с извлечением интерфейса в нашей среде IDE. Если нет, то вам
потребуется извлечь стык, как упоминалось ранее. Это заставит вас просканировать
свою кодовую базу на предмет вызовов, выполняемых к API-интерфейсам, которые
отправляют электронные письма, SMS-сообщения
или любой другой механизм уведомлений, кото­
рый у вас есть. Отыскание этого кода и создание
абстракции, которую другой код использует, яв­
ляется обязательным шагом.

Рис. 3.22. Шаг 1: создание абстракции

Шаг 2: использовать абстракцию
Теперь, когда наша абстракция создана, нам нужно рефакторизовать существую­
щих клиентов функциональности "Уведомления", для того чтобы использовать эту
новую точку абстракции, как мы видим на рис. 3.23. Возможно, что рефакториза­
ция с извлечением интерфейса уже сделала это за нас автоматически — но, по мо­
ему опыту, чаще всего этот процесс должен быть поступательным, включающий
ручное отслеживание входящих вызовов затрагиваемой функциональности. Самое
приятное здесь то, что эти изменения являются малыми и поступательными; их
легко делать малыми шагами, не оказывая слишком большого влияния на сущест­
вующий код. В этой точке не должно быть никаких функциональных изменений
в поведении системы.

Разложение монолита

|

127

Рис. 3.23. Шаг 2: изменить существующих клиентов так,
чтобы они использовали новую абстракцию

Шаг 3: создать новую имплементацию
Когда новая абстракция находится на своем месте, можно начать работу над новой
имплементацией вызова службы. Внутри монолита имплементация функциональ­
ности ’’Уведомления” будет представлять собой главным образом просто клиента,
который вызывает внешнюю службу, как показано на рис. 3.24. Подавляющая часть
функциональности будет находиться в самой службе.

Ключевая вещь в этой точке состоит в том, что, хотя мы имеем две имплементации
абстракции в кодовой базе одновременно, только одна имплементация в настоящее
время активна в системе. До тех пор пока мы не будем довольны тем, что наша но­
вая имплементация вызова службы готова к отправке в ’’прямой эфир”, она практи­
чески находится в спячке. В то время как мы работаем над имплементацией всей
эквивалентной функциональности в нашей новой службе, наша новая имплемента-

Рис. 3.24. Шаг 3: Создать новую имплементацию абстракции

128

|

Гпава 3

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

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

Бывает, что эта фаза длится достаточно долго. Джез Хамбл (Jez Humble) подробно
описывает применение шаблона "Ветвление по абстракции"12 для мигрирования
слоя постоянства базы данных, используемого в приложении GoCD по непрерыв­
ной доставке (в то время именуемом Cruise). Переход от iBatis к Hibernate продол­
жался несколько месяцев, в течение которых приложение по-прежнему продолжало
поставляться клиентам дважды в неделю.

Шаг 4: переключить имплементацию
Как только мы будем довольны тем, что наша новая имплементация работает пра­
вильно, мы переключим нашу точку абстракции так, чтобы новая имплементация
стала активной, а старая функциональность больше не использовалась, как показа­
но на рис. 3.25.

Рис. 3.25. Шаг 4: переключиться на активную имплементацию для использования новой микрослужбы

12 См. http://bit.ly/2p95lv7.

Разложение монолита

|

129

В идеале, как и в случае с ’’фикусом-удавкой”, мы хотели бы использовать пере­
ключающий механизм, который легко принимает одно из двух состояний. Это по­
зволило бы быстро переключаться назад на старую функциональность при возник­
новении проблем. Общепринятое решение — использование реле с двумя состоя­
ниями (флажка). На рис. 3.26 мы видим, что указанные реле имплементируются
с помощью конфигурационного файла, позволяя нам менять действующую импле­
ментацию без необходимости изменять код. Если вы хотите узнать о реле функций

Рис. 3.26. Шаг 5: использование реле функций для переключения между имплементациями

130

|

Гпава 3

больше и о том, как их имплементировать, то у Пита Ходжсона (Pete Hodgson) есть
отличная тематическая подборка.

На данном этапе мы имеем две имплементации одной и той же абстракции, кото­
рые, как мы надеемся, должны быть функционально эквивалентными. Для верифи­
кации эквивалентности можно задействовать тесты, но как вариант, мы можем
применить обе имплементации в производстве, тем самым обеспечивая дополни­
тельную верификацию. Эта идея рассматривается далее в разделе ’’Шаблон: парал­
лельное выполнение”.

Шаг 5: очистка
Теперь, когда наша новая микрослужба обеспечивает пользователям все уведомле­
ния, мы можем обратиться к очистке после себя. В этой точке наша старая функ­
циональность ’’Уведомлений пользователя” больше не используется, поэтому оче-

Рис. 3.27. Шаг 6: удалить старую имплементацию

Разложение монолита

|

131

видным шагом будет ее удалить, как показано на рис. 3.27. Мы начинаем сжимать
монолит!

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

Рис. 3.28. Шаг 7: (необязательный) удалить точку абстракции

132

|

Гпава 3

В качестве механизма отката
Возможность переключаться назад к предыдущей имплементации, если новая
служба не ведет себя как надо, полезна, но есть ли способ делать это автоматиче­
ски? Стив Смит (Steve Smith) подробно описывает вариацию шаблона ’’Ветвление
по абстракции”, именуемую верификацией ветвления по абстракции (verify branch
by abstraction)13, которая также имплементирует шаг верификации в ’’прямом эфи­
ре”; мы видим пример этого шаблона на рис. 3.29. Идея состоит в том, что если вы­
зовы новой имплементации не срабатывают, то вместо нее можно использовать
старую имплементацию.

Рис. 3.29. Верификация ветвления по абстракции

Указанная вариация явно добавляет некоторую сложность не только с точки зрения
кода, но и с точки зрения рассуждений о системе. В практическом плане обе им­
плементации в любой момент времени могут быть активными, что затрудняет по­
нимание поведения системы. Если две имплементации так или иначе поддержива­
ют внутреннее состояние, то нам также придется подумать о согласованности дан­
ных14. Хотя согласованность данных является проблемой в любой ситуации, когда
мы переключаемся между имплементациями, шаблон ’’Верификация ветвления по
абстракции" позволяет переключаться туда-сюда между имплементациями, опира­
ясь на запрос по запросу (request-by-request). Это означает, что вам понадобится

13 См. http://bit.ly/2mLVevz.

14 Для справки: согласованность данных (data consistency), также консистентность, когерентность,
означает, что значения данных одинаковы для всех экземпляров приложения — Пер.

Разложение монолита

|

133

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

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

Для миграции на архитектуру, основанную на микрослужбах, я почти всегда сперва
обращаюсь к использованию шаблона ’’Фикус-удавка”, т. к. он проще во многих
отношениях. Однако существует несколько ситуаций, как здесь было с уведомле­
ниями, где это просто невозможно.
Описанный шаблон также исходит из того, что вы можете изменить код сущест­
вующей системы. Если же по какой-либо причине это сделать невозможно, то вам
придется рассмотреть другие варианты, некоторые из которых мы рассмотрим
в остальной части этой главы.

Шаблон: "Параллельное выполнение"
Прежде чем развернуть свою новую имплементацию, предстоит выполнить огром­
ный массив работы по ее тестированию. Вы будете делать все возможное для того,
чтобы предрелизная верификация вашей новой микрослужбы была выполнена
в обстановке, максимально приближенной к производственной, в рамках обычного
процесса тестирования, но мы все понимаем, что не всегда возможно продумать
каждый сценарий, который может произойти в производственной среде. Однако
у нас имеются и другие методы.
И шаблон ’’Фикус-удавка”, и шаблон ’’Ветвление по абстракции” позволяют старым
и новым имплементациям одной и гой же функциональности одновременно сосу­
ществовать в производстве. В типичной ситуации оба этих метода позволяют нам
исполнять либо старую имплементацию в монолите, либо новое решение на основе
микрослужб. Для снижения риска переключения на новую имплементацию, осно­
ванную на службах, эти методы дают возможность быстро переключаться назад
к предыдущей имплементации.

Во время использования параллельного выполнения (parallel run) вместо вызова
старой или новой имплементации мы вызываем обе. что позволяет нам сравнивать
результаты с целью обеспечения их эквивалентности. Несмотря на вызов обеих им­
плементаций, в любой момент времени только одна из них считается источником
истины. В типичной ситуации старая имплементация считается источником исти­
134

|

Глава 3

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

Пример: сравнение ценообразования
кредитных деривативов
Много лет назад я участвовал в проекте по изменению платформы, используемой
для расчетов типа финансового продукта, именуемого кредитными деривативами.
Банк, в котором я работал, должен был обеспечивать, чтобы различные деривати­
вы, которые он предлагал, были для них разумной сделкой. Заработаем ли мы день­
ги на этой сделке? Не является ли эта сделка слишком рискованной? К тому же,
после выпуска дериватива рыночные условия изменяются. Поэтому им также нуж­
но было оценивать стоимость текущих сделок для обеспечения неуязвимости перед
огромными убытками из-за изменившихся рыночных условий15.

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

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

Оказалось, что у нас было несколько проблем, которые нам пришлось исправить,
но мы также обнаружили большее число несоответствий, вызванных дефектами
15 Оказалось, что как отрасль мы были ужасны. Рекомендую книгу Мартина Льюиса (Martin Lewis)
"Большая шишка" (The Big Short, W. W. Norton & Company, 2010) как отличный обзор роли кредит­
ных деривативов в мировом финансовом кризисе 2007-2008 годов. Я часто с огромным сожалением
оглядываюсь назад на ту небольшую роль, которую я сыграл в этой индустрии. Оказывается, незнание
того, что вы делаете, и продолжение этой работы может иметь некоторые довольно катастрофические
последствия.

Разложение монолита

|

135

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

Рис. 3.30. Пример параллельного выполнения — активируются обе системы ценообразования,
а результаты сравниваются в оффлайновом режиме

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

Пример: листинги компании Homegate
Как мы обсуждали ранее в разделе ’’Пример: FTP”, компания Homegate параллель­
но выполняла обе свои системы импорта листингов, при этом новая микрослужба
занималась импортом листингов, которые затем сравнивались с существующим
монолитом. Отдельная закачка по FTP со стороны клиента приводила к запуску
обеих систем. После того как они получили подтверждение о том, что новая микро­
служба ведет себя эквивалентно, импорт по FTP в старом монолите был деактиви­
рован.
136

|

Гпава 3

N-вариантное программирование
Можно утверждать, что вариация параллельного выполнения существует в некоторых
системах управления с особыми требованиями к безопасности, таких, как воздушные
судна с электродистанционным управлением. Вместо того чтобы полагаться на меха­
ническое управление, авиалайнеры все больше опираются на цифровые системы
управления. Когда для управления рулем направления вместо натягивания троса пи­
лот использует элементы управления, воздушное судно с электродистанционным
управлением посылает входные данные в системы управления, которые решают, на­
сколько следует повернуть руль направления. В обязанностях этих систем управления
находится интерпретация сигналов, которые им посылают, и выполнение надлежащих
действий.
Очевидно, что дефект в этих системах управления чрезвычайно опасен. Для компен­
сации влияния дефектов в некоторых ситуациях параллельно используются несколько
имплементаций одной и той же функциональности. Сигналы посылаются всем импле­
ментациям одной и той же подсистемы, которые затем посылают свой отклик. Эти ре­
зультаты сравниваются, и "правильный" отбирается, как правило, путем поиска квору­
ма среди участников. Это метод носит название "N-вариантное программирование"16.
Конечная цель такого подхода не в том, чтобы заменить одну из имплементаций, в от­
личие от других шаблонов, которые мы рассмотрели в этой главе, а, наоборот, аль­
тернативные имплементации будут продолжать существовать рядом друг с другом,
в надежде, что альтернативные имплементации уменьшат влияние дефекта в любой
данной подсистеме.

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

Использование "шпионов"
В предыдущем примере с ’’Уведомлениями” мы не хотели бы отправлять электрон­
ное письмо клиенту дважды. В такой ситуации ’’шпион” (spy) окажется весьма
кстати. Взятый из модульного тестирования указанный структурный шаблон под­
меняет часть функциональности и позволяет нам выполнять верификацию после

16 См. Лайминг Чен (Liming Chen) и Альгирдас Авициенс (Algirdas Avizienis) "N-вариантное програм­
мирование: отказоустойчивый подход к надежности операций на основе программно-информа­
ционного обеспечения (N-Version Programming: A Fault-Tolerance Approach to reliability of Software
Operation), опубликованный в сборнике 25-го Международного симпозиума по отказоустойчивому
программированию (the Twenty-Fifth International Symposium on Fault-Tolerant Computing, 1995).

Разложение монолита

|

137

того, как некоторые вещи были сделаны. ’’Шпион” встает и заменяет часть функ­
циональности, заглушая ее.
Таким образом, для нашей функциональности ’’Уведомлений” мы могли бы с по­
мощью ’’шпиона” заменить низкоуровневый код, который служит для фактической
отправки электронной почты, как показано на рис. 3.31. Наша новая служба ’’Уве­
домления” будет использовать этого ’’шпиона” во время фазы параллельного вы­
полнения, позволяя нам проверять, что этот побочный эффект (отправка электрон­
ной почты) будет вызван, когда вызов sendNotification будет получен службой.

Рис. 3.31. Использование "шпиона" для проверки отправки электронных писем

во время параллельного выполнения

Обратите внимание, что мы могли бы решить использовать ’’шпиона” внутри моно­
лита И вообще избежать вызова службы нашим КОДОМ RemoteNotification. Однако,
скорее всего, вы на самом деле хотите учесть влияние дистанционных (удаленных,
remote) вызовов — для понимания того, не являются ли причиной проблем тайм­
ауты, сбои или общая задержка в нашей новой службе ’’Уведомлений”.

Дополнительная сложность здесь заключается в том, что ’’шпион” работает в от­
дельном процессе, который усложнится, когда выполняется верификационный
процесс. Если бы мы хотели, чтобы это происходило в ’’прямом эфире”, в рамках
исходного запроса, то нам, вероятно, нужно было бы выставить наружу методы,
определенные на службе ’’Уведомления”, чтобы разрешить выполнять верифика­
цию после отправки первоначального вызова в нашу службу ’’Уведомления”. Это
будет представлять значительный объем работы, и во многих случаях верификация
в ’’прямом эфире” не требуется. Более вероятной моделью верификации внепроцессных ’’шпионов” будет регистрация взаимодействий, которая позволяет прово­
дить верификацию внеполосно, возможно, на ежедневной основе. Очевидно, что
если бы мы все-таки задействовали ’’шпиона” для замены вызова службы "Уведом­
лений”, то проверка стала бы проще, но зато тестировать придется меньше! Чем
больше функциональности вы заменяете ’’шпионом”, тем меньше функционально­
сти тестируется фактически.
138

|

Гпава 3

Библиотека Scientist хостинга GitHub
Библиотека Scientist17 хостинга GitHub — это примечательная библиотека, которая
помогает имплементировать этот шаблон на уровне кода. Написанная на Ruby ука­
занная библиотека позволяет выполнять имплементации бок о бок и собирать ин­
формацию о новой имплементации, помогая вам понять, насколько правильно она
работает. Я не использовал ее сам, но вижу, как наличие подобного рода библиоте­
ки действительно поможет в верификации вашей новой функциональности, осно­
ванной на микрослужбах, относительно существующей системы. Теперь указанная
библиотека портирована на многочисленные языки, включая Java, .NET, Python,
Node.JS и многие другие, помимо упомянутых.

"Темный" запуск и выпуск "канареечных" релизов
Стоит отметить, что параллельное выполнение отличается от того, что традицион­
но именуется как выпуск ’’канареечного” релиза. ’’Канареечный” релиз (canary
release) связан с направлением некоторого подмножества ваших пользователей
к новой функциональности, при этом подавляющая часть пользователей видит ста­
рую имплементацию. Идея состоит в том, что если новая система имеет проблему,
то только подмножество запросов подвержено влиянию этой проблемы. При па­
раллельном выполнении мы вызываем обе имплементации.

Еще один родственный метод называется ’’темным” запуском (dark launching). При
’’темном” запуске вы развертываете новую функциональность и ее тестируете, но
новая функциональность для ваших пользователей невидима. Поэтому параллель­
ное выполнение является способом имплементации ’’темного” запуска, поскольку
’’новая” функциональность практически невидима для ваших пользователей до тех
пор, пока вы не переключитесь на систему, которая работает в ’’прямом эфире”.
’’Темный” запуск, параллельные выполнения и выпуск ’’канареечных” релизов —
все эти методы можно использовать для верификации того, что наша новая функ­
циональность работает правильно, и для уменьшения влияния, если окажется, что
это не так. Все эти методы попадают под так называемое знамя ’’прогрессивной
доставки”— зонтичного термина, придуманного Джеймсом Тавернером (James
Governor)18 для описания методов, помогающих контролировать то, как софт раз­
вертывается для ваших пользователей более нюансированным способом, позволяя
вам выпускать софт быстрее, при этом верифицируя его эффективность и уменьшая
влияние проблем, если они возникают.

Где его использовать
Имплементация параллельного выполнения редко оказывается тривиальным делом
и обычно зарезервирована для тех случаев, когда считается, что изменяемая функ­
циональность находится под высокой степенью риска. В главе 4 мы рассмотрим

17 См. https://github.com/github/scientist.
18 См. http://bit.ly/2IZjrxK.

Разложение монолита

|

139

пример использования этого шаблона для медицинской документации. Я бы опре­
деленно был достаточно избирательным в отношении того, где применять этот
шаблон — работа по его имплементации должна обмениваться на выгоды, которые
вы получаете. Я сам пользовался этим шаблоном всего один-два раза, но в этих си­
туациях он был чрезвычайно полезен.

Шаблон: "Сотрудник-декоратор"
Что произойдет, если вы захотите вызвать какое-то поведение, основываясь на том,
что происходит внутри монолита, но вы не способны изменить сам монолит? Шаб­
лон ’’Сотрудник-декоратор” (decorating collaborator) окажет здесь большую помощь.
Широко известный структурный шаблон ’’Декоратор” позволяет прикреплять но­
вую функциональность к чему-либо без того, чтобы лежащая в основании вещь
что-то об этом ’’знала”. Мы собираемся использовать декоратор, для того чтобы
сделать вид, что наш монолит делает вызовы нашей службы напрямую, даже если
мы на самом деле не изменили лежащий в основании монолит.
Вместо перехвата этих вызовов до того, как они достигнут монолита, мы даем вы­
зову выполняться как обычно. Затем, основываясь на результате этого вызова, мы
обращаемся к нашим внешним микрослужбам через любой механизм сотрудниче­
ства, который мы выберем. Давайте подробно рассмотрим эту идею на примере
компании Music Corp.

Пример: программа лояльности
Music Corp всецело строится на заботе о наших клиентах! Мы хотим добавить им
возможность зарабатывать баллы на основе размещаемых ими заказов, но наша те­
кущая функциональность размещения заказов достаточно сложна, и мы предпочли
бы не менять ее прямо сейчас. Поэтому функциональность размещения заказов
останется в существующем монолите, но мы будем использовать прокси-селектор
для перехвата этих вызовов и на основе результата решать, сколько баллов выстав­
лять, как показано на рис. 3.32.

Рис. 3.32. Когда заказ успешно размещен, наш прокси-селектор обращается к службе "Лояльности"
для начисления баллов клиенту

140

|

Глава 3

С шаблоном ’’Фикус-удавка” прокси-селектор был довольно упрощенным. Теперь
наш прокси-селектор имеет возможность воплотить еще несколько ’’умов”. Он
должен делать свои собственные вызовы новой микрослужбы и туннелировать от­
клики назад клиенту. Как и прежде, приглядывайте за сложностью, которая ’’сидит”
в прокси-селекторе. Чем больше кода вы начинаете здесь добавлять, тем больше он
становится микрослужбой сам по себе, хотя и в техническом плане, со всеми труд­
ностями, которые мы обсуждали ранее.
Еще одна потенциальная трудность заключается в том, что для обеспечения воз­
можности делать вызов микрослужбы нам нужен достаточный объем информации
из входящего запроса. Например, если мы хотим присудить баллы, основываясь на
стоимости заказа, но стоимость заказа не ясна ни из запроса в ’’Размещении заказа”,
ни из отклика оттуда, то нам потребуется поиск дополнительной информации, воз­
можно, обратный вызов в монолит для извлечения нужной информации, как пока­
зано на рис. 3.33.

Рис. 3.33. Наша служба ’’Лояльности" должна загрузить дополнительные детали заказа
для выяснения того, сколько баллов присуждать

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

Где его использовать
При сохранении простоты этот подход является наиболее элегантным и наименее
сопряженным, чем захват изменений в данных. Описанный шаблон лучше всего
работает там, где требуемая информация извлекается из входящего запроса или от­
клика из монолита. Там, где для выполнения правильных вызовов вашей новой
службы требуется больше информации, его имплементация становится сложнее и
запутаннее. По моим внутренним ощущениям, если запрос в монолит и отклик из
Разложение монолита

|

141

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

Шаблон: "Захват изменений в данных"
В рамках шаблона ’’Захват изменений в данных” (change data capture), вместо того
чтобы пытаться перехватывать и действовать по вызовам в монолит, мы реагируем
на изменения, вносимые в хранилище данных. Для правильной работы шаб­
лона необходимо, чтобы опорная система захвата была сопряжена с хранилищем
данных монолита. В этом по-настоящему неизбежная трудность с указанным шаб­
лоном.

Пример: выпуск карточек лояльности
Мы хотим интегрировать немного функциональности с целью распечатки карточек
лояльности для наших пользователей, когда они регистрируются. В настоящее вре­
мя учетная запись лояльности создается при регистрации клиента. Как мы видим на
рис. 3.34, когда регистрация возвращается из монолита, мы знаем только, что кли­
ент был успешно зарегистрирован. Чтобы мы могли напечатать карточку, нам нуж­
но больше сведений о клиенте, что затрудняет вставку этого поведения выше по
течению, возможно, с помощью ’’сотрудника-декоратора”. В точке, где вызов воз­
вращается, нам нужно будет сделать дополнительные запросы в монолит, чтобы
извлечь другую необходимую нам информацию, и эта информация может и не быть
выставлена наружу через API.

Рис. 3.34. Наш монолит делится не очень большой информацией,
когда клиент зарегистрирован

Вместо этого мы решили использовать захват изменений в данных. Мы засекаем
любые вставки в таблицу Loyalty Accounts (Учетные записи лояльности), и при
наступлении вставки вызываем нашу новую службу "Печати карточек лояльности”,
как показано на рис. 3.35. В этой конкретной ситуации мы решаем запустить собы­
тие ’’Учетная запись создана”. Наш процесс печати лучше всего работает в пакет­
ном режиме, позволяя накапливать список печатных заданий, которые будут вы­
полнены в нашем брокере сообщений.

142

|

Глава 3

Рис. 3.35. Применение захвата изменений в данных для вызова новой службы печати

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

Триггеры базы данных
Большинство реляционных баз данных позволяют инициировать настраиваемое
под свои нужды поведение во время изменения данных. То, как именно эти тригге­
ры определены и что они могут вызывать, варьируется от системы к системе, но все
современные реляционные базы данных так или иначе их поддерживают.
В примере на рис. 3.36 наша служба вызывается всякий раз, когда выполняется
вставка в таблицу Loyalty Accounts.

Рис. 3.36. Использование триггера базы данных для вызова микрослужбы во время вставки данных

Разложение монолита

|

143

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

На первый взгляд, может показаться, что сделать это довольно просто. Нет необхо­
димости иметь какой-либо другой софт, не нужно вводить какие-либо новые тех­
нологии. Однако, как и хранимые процедуры, бывает, что триггеры становятся
"скользким склоном".
Мой друг, Рэнди Шоуп (Randy Shoup) однажды высказался как-то так: "Не страшно
иметь один-два триггера базы данных. Ужасно, когда из них строится целая систе­
ма". И нередко данная проблема сопряжена именно с триггерами баз данных. Чем
их у вас больше, тем труднее понять, как ваша система на самом деле работает. Эта
трудность часто связана с инструментарием и контролем со стороны триггеров за
изменениями — стоит задействовать их слишком много, и ваше приложение при­
мет вид сооружения в стиле барокко.
Поэтому, если вы собираетесь их использовать, то делайте это очень экономно.

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

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

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

|

Глава 3

Рис. 3.37. Система захвата изменений в данных, использующая опорный журнал транзакций

Пакетный копировальщик дельты
Вероятно, наиболее упрощенный подход — написание программы, которая на ре­
гулярной основе сканирует затрагиваемую базу данных на предмет того, какие
данные изменились, и копирует эти данные в место назначения. Эти задания часто
выполняются с помощью таких инструментов, как cron или аналогичных инстру­
ментов пакетного планирования.

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

Где его использовать
’’Захват изменений в данных” — полезный шаблон общего назначения, в особенно­
сти, если вам необходимо реплицировать данные (что мы рассмотрим подробнее
в главе 4). В случае миграции на микрослужбы наиболее благоприятная зона нахо­
дится там, где вам нужно реагировать на изменение в данных в вашем монолите, но
Разложение монолита

|

145

вы не способны перехватить это ни по периметру системы с помощью ’’удавки” или
"декоратора”, ни изменить лежащую в основании кодовую базу.
В общем случае я стараюсь свести использование этого шаблона к минимуму из-за
трудностей, связанных с некоторыми имплементациями указанного шаблона. Триг­
геры базы данных обладают своими недостатками, и полномасштабные инструмен­
ты захвата изменений в данных, работающие с журналами транзакций, значительно
усложняют решение. Тем не менее, если вы понимаете эти потенциальные пробле­
мы, то описанный шаблон будет полезным инструментом в вашем распоряжении.

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

Мы пока замалчиваем одну из самых больших трудностей в мигрировании на архи­
тектуру, основанную на микрослужбах, — данные. Мы не можем это больше от­
кладывать! В главе 4 мы разведаем способы мигрирования данных и разложения
баз данных.

146

|

Глава 3

ГЛАВА 4

Декомпозиция
базы данных
Как мы уже выяснили, существует масса способов извлечения функциональности
из монолита в микрослужбы. Однако нам нужно обратиться к вопросу о ’’слоне
в комнате”1: а именно, что делать с нашими данными? Микрослужбы работают луч­
ше всего, когда мы практикуем сокрытие информации, что, в свою очередь, обычно
приводит нас к микрослужбам, которые полностью инкапсулируют свои собствен­
ные механизмы хранения и извлечения данных. Отсюда следует вывод, что во вре­
мя мигрирования на архитектуру, основанную на микрослужбах, нужно разложить
базу данных нашего монолита, если мы хотим извлечь из транзита максимум.
Однако разложение базы данных — далеко не простая задача. Нам нужно учесть
вопросы синхронизации данных во время транзита, логической и физической
декомпозиции схемы данных, транзакционной целостности, соединений, задержки
и многое другое. В этой главе мы рассмотрим эти вопросы и разведаем шаблоны,
которые нам помогут.

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

Шаблон: "Совместная база данных"
Как уже обсуждалось в главе 7, мы можем думать о сопряженности в терминах до­
менной, временной или имплементационной сопряженности. Из трех упомянутых
имплементационная сопряженность занимает нас больше всего при рассмотрении
баз данных, поскольку люди часто используют одну и ту же базу данных в не­
скольких схемах, как показано на рис. 4.1.
На первый взгляд, существует ряд проблем, связанных с совместным использова­
нием одной базы данных многочисленными службами. Главенствующая проблема
заключается в том, что мы отказываем себе в возможности решать, что является
совместным, а что скрытым — что противоречит нашему стремлению к сокрытию
информации. Это означает, что будет трудно понять, какие части схемы можно из­
менять безопасным образом. Знать, что внешняя сторона может обращаться к ва­
шей базе данных, — это одно, но не знать, какую часть вашей схемы она использу-

1 То есть к очевидной проблеме, которая ставит в тупик — Пер.

147

ет, — это другое. Проблему можно смягчить с помощью проекций, которые мы об­
судим в ближайшее время, но это решение не тотальное.
Еще одна трудность состоит в том, что становится неясным, кто ’’контролирует”
данные. Где находится бизнес-логика, которая оперирует этими данными? Не ’’раз­
мазана” ли она теперь по всем службам? Из этого, в свою очередь, вытекает отсут­
ствие связности бизнес-логики, как мы уже обсуждали ранее, рассматривая микро­
службу как комбинацию поведения и состояния, инкапсулирующую одну или не­
сколько машин состояний. Если поведение, изменяющее это состояние, теперь
"размазано” по всей системе, то обеспечение правильной имплементации машины
состояний окажется запутанной задачей.

Если, как показано на рис. 4.1, три службы непосредственно изменяют информа­
цию о заказе, что произойдет при отсутствии согласованного поведения между
службами? Что произойдет, когда поведение нужно изменить — придется ли мне
применить эти изменения ко всем этим службам? Как уже упоминалось ранее, мы
стремимся к высокой связности бизнес-функциональности, и слишком часто из со­
вместной базы данных следует обратное.

Рис. 4.1. Несколько служб напрямую обращаются к одной базе данных

Шаблоны преодоления
Хотя это мероприятие бывает трудным, разложение базы данных, для того чтобы
позволить каждой микрослужбе владеть своими собственными данными, почти
всегда является предпочтительным. Если это невозможно, то поможет использова­
ние шаблона ’’Проекция базы данных” (см. раздел "Шаблон: проекция базы дан­
ных'") или же принятие на вооружение шаблона ’’Служба обертывания базы дан­
ных” (см. раздел "Шаблон: служба обертывания базы данных").
148

|

Глава 4

Где его использовать
По моему мнению, прямое совместное использование базы данных подходит для
архитектуры на основе микрослужб только в двух ситуациях. Первая — при рас­
смотрении статических справочных данных, допускающих только чтение. Вскоре
мы разведаем эту тему подробнее, но давайте возьмем схему, содержащую инфор­
мацию о коде валюты страны, просмотровые таблицы с почтовыми кодами или ин­
дексами и тому подобное. Здесь структура данных остается очень стабильной,
и контроль за изменениями в них в типичной ситуации регулируется в рамках ра­
боты по администрированию.
Второе место, где, по моему мнению, подошло бы непосредственное обращение
многочисленных служб к одной и той же базе данных — там, где служба непосред­
ственно выставляет базу данных наружу как определенную конечную точку, кото­
рая спланирована и управляется для обслуживания многочисленных потребителей.
Мы рассмотрим эту идею подробнее, когда будем обсуждать шаблон ’’Интерфейс
база-данных-как-служба” (см. раздел "Шаблон: интерфейс база-данных-как-служба").

Но это невозможно сделать!
Итак, в идеале, мы хотим, чтобы наши новые службы имели свои собственные не­
зависимые схемы. Но это не то место, где мы начинаем работу с существующей
монолитной системой. Означает ли это, что мы всегда должны разбивать эти схе­
мы? Я убежден в том, что это уместно делать в большинстве ситуаций, но не всегда
целесообразно делать изначально.
Иногда, как мы вскоре увидим, работа занимает слишком много времени или со­
пряжена с изменением особенно чувствительных частей системы. В таких случаях
полезны различные шаблоны преодоления, которые, по крайней мере, остановят
ухудшение ситуации, а в лучшем случае станут разумными шагами к чему-то более
оптимальному в будущем.

Схемы и базы данных
В прошлом я был виновен в том, что использовал термины "база данных" и "схема"
взаимозаменяемо. Это иногда приводит к путанице, поскольку в этих терминах есть
некоторая двусмысленность. В техническом плане мы можем рассматривать схему как
логически разделенное множество таблиц, содержащих данные, как показано на
рис. 4.2. Тогда на одном ядре системы управления базами данных (СУБД, database
engine) можно разместить несколько схем. В зависимости от контекста, когда люди го­
ворят "база данных", они могут ссылаться на схему либо ядро СУБД ("база данных не
работает!").
Поскольку в центре данной главы будут главным образом логические понятия баз
данных, и поскольку термин "база данных" обычно используется в этом контексте,
практически ссылаясь на логически изолированную схему, в этой главе я буду при­
держиваться этого употребления. Поэтому, когда я говорю "база данных", думайте
о "логически изолированной схеме". Для краткости я опущу из наших диаграмм поня­
тие ядра СУБД, если явно не указано иное.
Декомпозиция базы данных

|

149

Стоит отметить, что разнообразные базы данных NoSQL могут и не иметь одинаково­
го понятия логического разделения, в особенности при работе с базами данных, пре­
доставляемыми облачными провайдерами. Например, на AWS база данных DynamoDB
имеет только понятие таблицы, а управление ролевым доступом используется для
ограничения тех, кто может видеть или изменять данные. Это вызывает трудности
в том, как мы думаем о логическом разделении в таких ситуациях.

Рис. 4.2. Один экземпляр ядра СУБД вмещает многочисленные схемы,
каждая из которых обеспечивает логическую изоляцию

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

Шаблон: "Проекция базы данных"
В ситуации, когда нам нужен один источник данных для нескольких служб, проек­
ция (view)2 способна смягчить трудности, касающиеся сопряженности. При нали­
чии проекции служба представляется схемой, которая является ограниченной про­
екцией из опорной схемы. Эта проекция ограничивает данные, видимые службе,
скрывая информацию, к которой она не должна иметь доступа.

2 Для справки: проекция (view), или ракурс — это набор данных, получаемый в результате сохранен­
ного в базе данных запроса к данным, который пользователи могут выполнять точно так же, как они
это делают к хранимому в базе данных объекту-коллекции. В русскоязычной литературе распростра­
нены термины "представление” и "вид”, которые выглядят крайне неудачными (попробуйте перевести
на русский "present a view", используя первый вариант или "a kind of view", используя второй). Во
французском языке применяется термин "проекция" — Пер.

150

|

Гпава 4

База данных как публичный контракт
Еще в главе 3 я поделился своим опытом по оказанию помощи по переплатформированию существующей системы кредитных деривативов для ныне несуществую­
щего инвестиционного банка. Мы ударили по проблеме сопряженности базы дан­
ных с размаху: нам нужно было увеличить пропускную способность системы, что­
бы ускорить обратную связь с трейдерами, которые использовали систему. После
небольшого анализа мы обнаружили, что узким местом в обработке были операц;.
записи в нашу базу данных. После быстрой атаки первым темпом мы осознали, что
сможем резко увеличить производительность операции записи в нашей системе,
если реструктурируем схему.
Именно в этот момент мы обнаружили, что многочисленные приложения вне наше
го контроля имели доступ на чтение к нашей базе данных, а в некоторых случаях
доступ на чтение/запись. К сожалению, мы установили, что все эти внешние систе­
мы имели одинаковые имена пользователей и пароли, поэтому было невозможно
понять, что это за пользователи и к чему они обращались. Мы подсчитали, что
в этом участвовало ’’примерно 20” приложений, но данный результат был получен
из базового анализа входящих сетевых вызовов3.

Если каждый актор (например, человек или внешняя система) имеет разный набор
учетных данных, то становится намного проще ограничивать доступ к определен­
ным сторонам, уменьшать влияние отзыва и ротации учетных данных и лучше по­
нимать, что делает каждый актор. Управление разными наборами учетных данных
бывает болезненным, в особенности в системе на основе микрослужб, которая
управляет многочисленными наборами учетных данных в расчете на одну службу.
Для решения этой проблемы мне нравится применять выделенные секретные хра­
нилища. Vault компании HashiCorp4— отличный инструмент в этом пространстве,
поскольку он генерирует учетные данные для каждого актора для таких вещей, как
базы данных, которые кратковременны и ограничены по объему.

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

3 Когда для определения тех, кто использует вашу базу данных, вы опираетесь на анализ сети, ждите
неприятностей.
4 См. https://www.vaultproject.io/.
5 Ходили слухи, что одна из систем, использующая нашу базу данных, была нейронной сетью на ос­
нове Python, которую никто не понимал, но "просто юзал".

Декомпозиция базы данных

|

151

Представляемые проекции
Наше решение состояло в том, чтобы сначала уладить те ситуации, когда внешние
системы писали в нашу схему. К счастью, в нашем случае их было легко уладить.
Однако для всех тех клиентов, которые хотели данные читать, мы создали выде­
ленную схему, содержащую проекции, которые выглядели как старая схема, и вме­
сто этого побуждали клиентов указывать на эту схему, как показано на рис. 4.3.
В результате мы смогли вносить изменения в нашу собственную схему, при усло­
вии, что поддерживали указанную проекцию. Скажем просто, была задействована
масса хранимых процедур.

Рис. 4.3. Использование проекций дает возможность изменять базовую схему

В нашем примере инвестиционного банкинга проекция и лежащая в основе схема
в итоге изрядно отличались. Разумеется, проекцию можно использовать гораздо
проще, возможно, с целью скрыть фрагменты информации, которые вы не хотите
делать видимыми для внешних сторон. Как простой пример на рис. 4.4, наша служ­
ба лояльности была просто списком карточек лояльности в нашей системе.
В настоящее время эта информация хранится в нашей таблице клиентов в форме
столбца. Поэтому мы определяем проекцию, которая выставляет наружу только
отображение ИД клиента в ИД лояльности в одной единственной таблице без вы­
ставления наружу какой-либо другой информации из таблицы клиентов. Точно так
же любые другие таблицы, которые находятся в базе данных монолита, полностью
скрыты от службы лояльности.

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

152

|

Гпава 4

что чтение из проекции не должно генерировать чтение на опорной схеме, что по­
вышает производительность. Компромисс тогда вертится вокруг того, как эта предвычисленная проекция обновляется. Может случиться так, что вы будете читать из
проекции ’’устаревший” набор данных.

Рис. 4.4. Проекция базы данных, берущая подмножество опорной схемы

Ограничения
Способы имплементации проекций отличаются, но в типичной ситуации они явля­
ются результатом запроса. Это означает, что сама проекция доступна только для
чтения. Этот факт сразу же ограничивает их полезность. Хотя проекции присущи
реляционным базам данных и многие более зрелые базы данных NoSQL их под­
держивают (например, Cassandra и Mongo), это делают не все. Даже если ваше ядро
СУБД поддерживает проекции, скорее всего, существуют и другие ограничения,
например, необходимость, чтобы исходная схема и проекция находились на одном
и том же ядре СУБД. Это увеличивает сопряженность вашего физического развер­
тывания, приводя к потенциальной единой точке сбоя.

Владение
Стоит отметить, что изменения в базовой исходной схеме требуют обновления про­
екции, поэтому особое внимание должно быть уделено тому, кто этой проекцией
’’владеет”. Я предлагаю рассматривать любые опубликованные проекции базы дан­
ных как равносильные любому другому интерфейсу службы и, следовательно, как
то, что должно постоянно обновляться группой, присматривающей за исходной
схемой.

Где его использовать
Я использую проекцию базы данных преимущественно в ситуациях, когда считаю
нецелесообразным осуществлять декомпозицию существующей монолитной схе­
Декомпозиция базы данных

|

153

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

Шаблон: "Служба обертывания базы данных"
Когда с чем-то слишком трудно справиться, имеет смысл скрыть беспорядок. С по­
мощью шаблона ’’Служба обертывания базы данных” (database wrapping service) мы
делаем именно это: скрываем базу данных заслужбой, которая действует как тон­
кая "обертка”, перенося зависимости базы данных, которые становятся зависимо­
стями службы, как показано на рис. 4.5.

Рис. 4.5. Использование службы для "обертывания" базы данных

Несколько лет назад я работал в крупном банке в Австралии над небольшим пору­
чением — помочь одной части организации имплементировать усовершенствован­
ный путь к производству. В первый день мы провели несколько собеседований
с ключевыми людьми, чтобы понять проблемы, с которыми они сталкиваются,
и составить общий вид текущего процесса. В перерыве между собеседованиями
подошел один человек и представился администратором БД этой части компании.
’’Пожалуйста, — сказал он, — сделайте так, чтобы они перестали помещать вещи
в базу данных!”.
Мы схватили по чашечке кофе, и администратор БД выложил нам проблемы. В те­
чение примерно 30-летнего периода сформировалась система расчетно-кассового
обслуживания — одна из главных ’’жемчужин” организации. Одна из наиболее
важных частей этой системы — управление тем, что они называли "допусками”.
В расчетно-кассовом обслуживании управление тем, какие люди получают доступ
к каким счетам, и выяснение того, что им разрешено делать с этими счетами, были

154

|

Гпава 4

очень сложными. Чтобы дать вам понять, как выглядят эти допуски, возьмем бух­
галтера, которому разрешено просматривать счета компаний Л, Б и С. По компании
В он может переводить до $500 между счетами, а по компании С он может делать
неограниченные переводы между счетами, но также снимать со счета до $250. Под­
держание и применение этих допусков осуществлялось почти исключительно
в рамках хранимых процедур базы данных. Весь доступ к данным был ограничен
с помощью этой логики допусков.

По мере того как банк расширялся, а количество логики и внутреннего состояния
росло, база данных начала ’’прогибаться” под нагрузкой. "Мы отдали в Oracle все
деньги, какие только можно, но их все равно недостаточно”. Опасение состояло
в том, что с учетом спроецированного роста и даже в расчете на улучшение произ­
водительности аппаратного обеспечения они в итоге достигнут такого уровня,
когда потребности организации превысят возможности базы данных.
По мере дальнейшего разведывания проблемы мы обсудили идею выделения час­
тей схемы для уменьшения нагрузки. Затруднение заключалось в том, что запутан­
ным ’’пучком” в середине всего была та самая система допусков. Был бы просто
кошмар, если бы мы попытались его распутать, и риски, связанные с ошибками на
этом участке, были огромными: сделаешь неправильный шаг, и кто-то будет забло­
кирован от доступа к своим счетам, или, что еще хуже, кто-то, кто не должен, по­
лучит доступ к вашим деньгам.
Мы придумали план в попытке разрешить описанную ситуацию. Мы согласились
с тем, что в ближайшее время не сможем внести изменения в систему допусков,
поэтому было крайне важно, чтобы мы, по меньшей мере, не усугубили проблему.
Нам нужно было сделать так, чтобы люди прекратили размещать большой объем
данных и поведения в схему допусков. Как только это встало бы на свое место, мы
могли подумать об удалении тех частей схемы допусков, которые было легче из­
влечь, как мы надеялись, сократив нагрузку настолько, что опасения по поводу
долгосрочной жизнеспособности будут уменьшены. В результате появилась бы не­
которая передышка, для того чтобы подумать о следующих шагах.

Мы обсудили введение новой службы ’’Допуски”, которая позволит нам ’’скрыть”
проблемную схему. Эта служба сначала будет иметь очень мало поведения, т. к.
в текущей базе данных уже имплементировано много поведения в качестве храни­
мых процедур. Но цель состояла в том, чтобы побудить группы, пишущие другие
приложения, думать о схеме допусков как о чьей-то другой и побуждать их хранить
свои собственные данные локально, как мы видим на рис. 4.6.
Как и проекции базы данных, служба ’’обертывания” позволяет контролировать то,
что является совместным, а что скрытым. Она предоставляет потребителям интер­
фейс, который можно исправить, тогда как изменения вносятся ’’под капотом” для
улучшения ситуации.

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

|

155

Рис. 4.6. Уменьшение зависимости от центральной базы данных
с помощью шаблона "Служба обертывания базы данных"

данные будут доступны только через эту схему, вы, по меньшей мере, затормажи­
ваете дальнейшее развитие базы данных. Указанный шаблон четко определяет, что
является ’’вашим”, по сравнению с тем, что является "чужим”. Думаю, что этот
подход также работает лучше всего, когда вы выравниваете владение как базовой
схемой, так и слоем службы по одной и той же группе. API службы должен надле­
жаще восприниматься как управляемый интерфейс с соответствующим надзором за
тем, как изменяется слой API. Подобный подход также выгоден для вышестоящих
приложений, поскольку они легче ’’понимают”, как они используют нижестоящую
схему. Он делает такие мероприятия, как установка заглушек для целей тестирова­
ния, гораздо более управляемыми.

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

В идеале, применение этого шаблона будет отправной точкой для более фундамен­
тальных изменений, давая вам время на то, чтобы разложить схему под вашим сло­
ем API. Можно утверждать, что мы просто накладываем ’’повязку” на проблему,
вместо того чтобы обратиться к решению первичного затруднения. Тем не менее,
в духе поступательного улучшения, я думаю, что указанный шаблон имеет много
возможностей для этого.
156

|

Гпава 4

Шаблон: "Интерфейс база-да нных-как-служба"
Иногда клиентам нужна база данных только для запросов. Это бывает обусловлено
тем, что им нужно запрашивать или извлекать большие объемы данных, или, воз­
можно, потому, что внешние стороны уже используют цепочки инструментов, для
работы с которыми требуется конечная точка на базе SQL (подумайте о таких ин­
струментах, как Tableau, которые часто применяются для получения информации
о бизнес-метриках). В этих ситуациях имеет смысл давать клиентам возможность
просматривать данные, которыми ваша служба управляет в базе данных, но мы
должны позаботиться об отделении базы данных, которую мы выставляем наружу,
от базы данных, которую мы используем внутри контура нашей службы.

Один из подходов, который на моем опыте работает хорошо, состоит в создании
выделенной базы данных, предназначенной для выставления наружу в качестве ко­
нечной точки с доступом только для чтения, и заполнении этой базы данных, когда
данные в опорной базе данных изменяются. Практически, служба выставляет базу
данных наружу внешним потребителям, точно так же, как она выставляет наружу
поток событий в качестве единой конечной точки, и синхронный API — в качестве
другой конечной точки. На рис. 4.7 мы видим пример службы ’’Заказ”, которая вы­
ставляет наружу конечную точку с чтением/записью через API и базу данных в ка­
честве интерфейса с доступом только для чтения. Механизм отображения берет
изменения во внутренней базе данных и выясняет, какие изменения необходимо
внести во внешнюю базу данных.

Рис. 4.7. Выставление выделенной базы данных в качестве конечной точки

позволяет внутренней базе данных оставаться скрытой

Шаблон базы отчетных данных
Мартин Фаулер уже задокументировал этот подход в шаблоне базы отчетных данных
(reporting database)6, тогда почему я здесь применил другое название? Чем больше
людей я опрашивал, тем больше я понимал, что, хотя распространенным применени­

6 См. http://bit.ly/2kWW9Ir.

Декомпозиция базы данных

|

157

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

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

Имплементация механизма отображения
Тонкость здесь кроется в выработке ответа на вопрос, как обновлять, а именно, как
имплементировать механизм отображения. Мы уже рассмотрели систему захвата
изменений в данных, которая здесь была бы отличным вариантом выбора. На са­
мом деле, она, вероятно, будет самым надежным решением, а также обеспечит наи­
более актуальную проекцию. Еще один вариант— простое копирование данных
пакетным процессом, хотя это бывает проблематичным, поскольку приводит к бо­
лее длительному отставанию между внутренней и внешней базами данных, и с не­
которыми схемами трудно определять то, какие данные должны быть скопированы.
Третьим вариантом может быть прослушивание событий, запущенных из затраги­
ваемой службы, и использование его для обновления внешней базы данных.
В прошлом для улаживания этого вопроса я бы использовал пакетное задание. Се­
годня же я бы, вероятно, задействовал выделенную систему захвата изменений
в данных, возможно, что-то вроде Debezium7. Я слишком часто попадал в ситуации,
когда пакетные процессы не работали или же работали слишком долго. Поскольку
мир уходит от пакетных заданий и хочет получать данные быстрее, пакетная обра­
ботка уступает место реальному времени. Установка системы захвата изменений
в данных на свое место для улаживания этого вопроса имеет смысл, в особенности,
если вы подумываете о ее применении для выставления событий наружу за преде­
лы контура службы.

7 См. https://github.com/debezium/debezium.

158

|

Гпава 4

Сравнение с проекциями базы данных
Этот шаблон выглядит более изощренным, чем простая проекция базы данных.
Проекции базы данных обычно привязаны к тому или иному стеку технологий:
если я хочу представить проекцию базы данных Oracle, то как лежащая в основе
база данных, так и схема, в которой размещаются проекции, работают в Oracle. При
таком подходе база данных, которую мы выставляем наружу, может иметь совер­
шенно другой стек технологий. Внутри нашей службы можно было бы задейство­
вать Cassandra, но представлять традиционную базу данных на базе SQL в качестве
конечной точки, обращенной в публичное пространство.
Этот шаблон обеспечивает более высокую гибкость, чем проекции базы данных, но
с добавленной стоимостью. Если потребности ваших потребителей могут быть
удовлетворены с помощью простой проекции базы данных, то в первую очередь
имплементация, скорее всего, обойдется в меньший объем работы. Просто учтите,
что шаблон накладывает ограничения на то, как этот интерфейс будет эволюциони­
ровать. Вы можете начать с использования проекции базы данных и подумать
о смещении в сторону выделенной базы отчетных данных в дальнейшем.

Где его использовать
Очевидно, что, поскольку база данных, выставляемая наружу в качестве конечной
точки, доступна только для чтения, указанный шаблон полезен лишь для клиентов,
которым требуется доступ только для чтения. Он очень хорошо укладывается в ва­
рианты использования, связанные с отчетностью, — ситуации, когда вашим клиен­
там требуется соединять большие объемы данных, хранящихся в той или иной
службе. Эта идея может быть расширена за счет дальнейшего импортирования дан­
ных этой базы данных в более крупное хранилище данных, обеспечивая возмож­
ность опрашивать данные из нескольких служб. Я рассказываю об этом подробнее
в главе 5 книги ’’Создание микросервисов”.

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

Передача владения
До сих пор мы на самом деле не решали проблему, которая лежит в основании. Мы
просто накладывали самые разные ’’повязки” на большую совместную базу данных.
Прежде чем мы начнем думать о запутанной работе по вытаскиванию данных из
гигантской монолитной базы данных, нам нужно подумать о том, где затрагивае­
мые данные фактически располагаются. Когда вы выделяете службы из монолита,
некоторые данные должны уходить вместе с вами, а некоторые из них должны
оставаться там, где они есть.
Если мы внедряем идею, в которой микрослужбы инкапсулируют логику, ассоции­
рованную с одним или несколькими агрегатами, то нам также необходимо перенеДекомпозиция базы данных

|

159

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

Шаблон:
"Монолит с выставлением агрегата наружу"
На рис. 4.8 показано, что нашей новой службе ’’Выписка счетов-фактур” нужно об­
ращаться к разнообразной информации, которая не имеет прямого отношения
к управлению выпиской счетов. По крайней мере, ей нужна информация по нашим
текущим ’’Сотрудникам” в целях управления трудовыми потоками по утверждению
счетов-фактур. В настоящее время все эти данные находятся в базе данных моно­
лита. Выставляя информацию о наших ’’Сотрудниках” наружу через конечную точ­
ку службы (это может быть API или поток событий) на самом монолите, мы четко
указываем, какая информация требуется службе ’’Счет-фактура".

Рис. 4.8. Выставление информации из монолита наружу через надлежащий интерфейс микрослужбы
позволяет нашей новой микрослужбе обращаться к этой информации

Мы хотим думать о наших микрослужбах как о комбинациях поведения и состоя­
ния; я уже обсуждал идею о микрослужбах как содержащих одну или несколько
машин состояний, которые управляют доменными агрегатами. При выставлении
агрегата наружу из монолита, мы хотим рассуждать в тех же понятиях. Монолит
по-прежнему ’’владеет” понятием того, что является и не является допустимым
160

|

Глава 4

Рис. 4.9. Использование объема существующей конечной точки
для приведения в действие извлечения новой службы "Сотрудник"

Декомпозиция базы данных

161

изменением состояния; мы не хотим трактовать это просто как "обертку” вокруг
базы данных.

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

В качестве пути к большему числу служб
Определяя потребности службы ’’Выписка счетов-фактур” и в явной форме выстав­
ляя наружу информацию, необходимую в четко определенном интерфейсе, мы
встаем на путь потенциального обнаружения контуров будущих служб. В этом
примере очевидный шаг — далее извлечь службу ’’Сотрудники”, как мы видим на
рис. 4.9. Выставив наружу API для данных, связанных с сотрудниками, мы уже
прошли долгий путь к пониманию того, каковы потребности пользователей новой
службы "Сотрудники”.

Разумеется, если мы извлекаем сотрудников из монолита и монолит нуждается
в данных об этих сотрудниках, то его, возможно, потребуется изменить так, чтобы
он использовал новую службу!

Где его использовать
Когда данные, к которым вы хотите обратиться, по-прежнему находятся ”во владе­
нии” базы данных, указанный шаблон хорошо работает, предоставляя вашим но­
вым службам необходимый доступ. При извлечении служб необходимость в том,
чтобы новая служба обращалась обратно в монолит для получения доступа к необ­
ходимым данным, скорее всего, будет оборачиваться немного большим объемом
работы, чем прямой доступ к монолитной базе данных — но в долгосрочной пер­
спективе эта идея гораздо лучше. Я бы подумал об использовании проекции базы
данных вместо этого подхода только в том случае, если затрагиваемый монолит
нельзя изменить с целью выставить наружу новые конечные точки. В таких случаях
смогла бы работать проекция, взятая на базе данных монолита, как и ранее обсуж­
давшийся шаблон ’’Захват изменений в данных” (см. раздел "Шаблон: захват изме­
нений в данных"), или создание шаблона выделенной службы обертывания базы
данных (см. раздел "Шаблон: служба обертывания базы данных'") поверх схемы
монолита, выставляя наружу информацию о ’’Сотруднике”, которую мы хотим.

Шаблон: "Смена владельца данных"
Мы рассмотрели, что происходит, когда нашей новой службе ’’Счет-фактура” тре­
буется обратиться к данным, которые принадлежат другой функциональности, как
в предыдущем разделе, где нам нужно было обратиться к данным ’’Сотрудник”.

162

|

Глава 4

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

На рис. 4.10 мы описываем изменение, которое должно произойти. Нужно перене­
сти наши счет-фактурные данные из монолита в новую ’’Счет-фактуру”, поскольку
как раз там находится контроль над жизненным циклом данных. Затем нам нужно
изменить монолит так, чтобы трактовать службу ’’Счет-фактура” как источник ис­
тины для счет-фактурных данных, и изменить его таким образом, чтобы он вызы­
вал конечную точку службы ’’Счет-фактура” для чтения данных или выполнения
запроса об изменениях.

Рис. 4.10. Наша новая служба "Счет-фактура"
берет на себя владение соответствующими данными

Бывает, что распутывание счет-фактурных данных существующей монолитной ба­
зы данных превращается в сложную проблему. Нам, возможно, придется рассмот­
реть влияние нарушения ограничений внешнего ключа, нарушения границ транзак­
ций и многое другое — ко всем этим темам мы вернемся позже в этой главе. Если
монолит будет изменен таким образом, что ему потребуется доступ к счет-фактурным данным лишь для чтения, то можно подумать о том, чтобы взять проекцию
из базы данных службы ’’Счет-фактура”, как показано на рис. 4.11. Однако при та­
ком способе будут присутствовать все ограничения проекций базы данных. Гораздо
предпочтительнее внести изменения в монолит так, чтобы он совершал вызовы
новой службы ’’Счет-фактура” напрямую.

Декомпозиция базы данных

|

163

Рис. 4.11. Отображение счет-фактурных данных обратно в монолит в качестве проекции

Где его использовать
Указанный шаблон выглядит немного более четко очерченным. Если только что
извлеченная служба инкапсулирует бизнес-логику и указанная логика изменяет не­
кие данные, то эти данные должны находиться под контролем новой службы. Дан­
ные должны быть перенесены оттуда, где они находятся сейчас, в новую службу.
Конечно, процесс перенесения данных из существующей базы данных далеко не
простой. Собственно, на этом и будет сосредоточена остальная часть этой главы.

Синхронизация данных
Как мы обсуждали в главе 3, одна из выгод шаблона, подобного ’’Фикусу-удавке”
состоит в том, что при переключении на новую службу мы затем можем переклю­
читься обратно, если появляется затруднение. Проблема возникает, когда затраги­
ваемая служба управляет данными, которые должны поддерживаться в синхрони­
зированном состоянии между монолитом и новой службой.
На рис. 4.12 мы видим такой пример. Мы находимся в процессе переключения на
новую службу ’’Счет-фактура”. Но новая служба и существующий эквивалентный
программный код в монолите также управляют этими данными. Для поддержания
возможности переключаться между имплементациями мы должны обеспечить,
чтобы оба набора программного кода ’’видели” одни и те же данные и чтобы эти
данные поддерживались согласованным образом.

Итак, какие тут у нас варианты? Ну, во-первых, нам нужно подумать о степени,
в которой данные должны быть согласованы между двумя проекциями. Если какойлибо набор программного кода должен всегда видеть тотально согласованную про­
екцию счет-фактурных данных, то одним из наиболее простых подходов было бы
обеспечить хранение данных в одном месте. Это, вероятно, приведет нас к тому,
164

|

Гпава 4

что наша новая служба ’’Счет-фактура” будет считывать свои данные непосредст­
венно из монолита в течение короткого промежутка времени, возможно, используя
проекцию, как мы разведали в разделе ’’Шаблон: проекция базы данных”. После
успешного переключения мы можем мигрировать данные, как обсуждалось ранее
в разделе ’’Шаблон: смена владельца данных”. Однако опасения по поводу исполь­
зования совместной базы данных невозможно преувеличить: вам следует ее рас­
сматривать только как очень краткосрочную меру, как часть более полного извле­
чения. Если совместная база данных слишком долго остается на своем месте, то это
приведет к значительной головной боли в долгосрочной перспективе.

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

Если бы мы выполняли переключение методом ’’Большого взрыва” (чего я бы ста­
рался избегать), мигрируя одновременно код приложения и данные, то могли бы
использовать пакетный процесс для копирования данных перед переключением на
новую микрослужбу. Как только счет-фатурные данные будут скопированы в нашу
новую микрослужбу, она сможет начать обслуживать трафик. Однако, что про­
изойдет, если нам нужно будет вернуться к использованию функциональности
существующей монолитной системы? Данные, измененные в схеме микрослужб, не
будут отражены в состоянии монолитной базы данных, поэтому мы в итоге потеря­
ем внутреннее состояние.
Еще один подход — подумать о поддержании двух баз данных в синхронизирован­
ном состоянии с помощью нашего кода. В этом случае операции записи в обе базы
данных у нас будет выполнять либо монолит, либо новая служба ’’Счет-фактура”.
Это решение требует тщательного обдумывания.

Декомпозиция базы данных

|

165

Шаблон: "Синхронизировать данные
в приложении"
Переключать данные с одного места на другое — мероприятие сложное в самые
лучшие времена, но оно тем больше чревато последствиями, чем более ценными
являются данные. Когда вы начинаете думать о присмотре за медицинской доку­
ментацией, тщательное обдумывание того, как вы мигрируете данные, становится
еще важнее.

Несколько лет назад консалтинговая компания Trifork участвовала в проекте, при­
званном помочь в хранении консолидированного представления медицинской
документации датских граждан8. Первоначальная версия этой системы хранила
данные в базе данных MySQL, но со временем стало ясно, что она, возможно, не
подойдет для задач, с которыми система столкнется. Было принято решение ис­
пользовать альтернативную базу данных, Riak. Надежда состояла в том, что Riak
даст системе возможность лучше масштабироваться, для того чтобы справляться
с ожидаемой нагрузкой, но также предложит улучшенные характеристики отказо­
устойчивости.

Существующая система хранила данные в одной базе данных, но при этом сущест­
вовали лимиты на то, как долго система может находиться в оффлайновом режиме,
и было чрезвычайно важно, чтобы данные не были потеряны. Поэтому требовалось
решение, которое позволило бы компании не только перенести данные в новую
базу данных, но и построить механизмы, которые верифицировали бы миграцию,
а также в рабочем порядке имели быстрые механизмы отката.
Было принято решение, что приложение само будет выполнять синхронизацию ме­
жду двумя источниками данных. Идея заключалась в том, что изначально сущест­
вующая база данных MySQL останется источником истины, но в течение опреде­
ленного периода времени приложение будет обеспечивать синхронизацию данных
в MySQL и Riak. Через некоторое время Riak станет источником истины для при­
ложения, и только после этого MySQL будет выведена из эксплуатации. Давайте
рассмотрим этот процесс немного подробнее.

Шаг 1: массово синхронизировать данные
Первый шаг — добраться до точки, где у вас есть копия данных в новой базе дан­
ных. Для проекта медицинской документации это включало выполнение пакетной
миграции данных из старой системы в новую базу данных Riak. Пока продолжался
пакетный импорт, существующая система продолжала работать, поэтому источни­
ком данных для импорта был снимок данных, взятый из существующей системы
MySQL (рис. 4.13). Это вызывает трудность в том плане, что после завершения
пакетного импорта данные в исходной системе вполне могли измениться. В этом

8 Подробную презентацию по этой теме можно увидеть в записи выступления Крестена Краба Тору па
(Kresten Krab Thorup) "Riak на таблетках (и наоборот)" (Riak on Drugs (and the Other Way Around),
http://bit.ly/2inlCvLP).

166

|

Глава 4

Рис. 4.13. Подготовка нового хранилища данных для синхронизации на основе приложения

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

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

Шаг 2: синхронизировать при записи,
читать из старой схемы
Теперь, когда обе базы данных были синхронизированы, мы развернули новую
версию приложения, которая будет записывать все данные в обе базы данных, как
показано на рис. 4.14. Цель на данном этапе — обеспечить, чтобы приложение пра-

Рис. 4.14. Приложение поддерживает обе базы данных в синхронизированном состоянии,

но одну использует только для чтения

Декомпозиция базы данных

|

167

вильно писало в оба источника и чтобы Riak вела себя в пределах приемлемых до­
пусков. Тот факт, что все данные по-прежнему читались из MySQL, обеспечивал
возможность извлечения данных из существующей базы данных MySQL даже
в случае, если бы Riak ’’рухнула”.

Только после того, как укрепилась достаточная уверенность в новой системе Riak,
они перешли к следующему шагу.

Шаг 3: синхронизировать при записи,
читать из новой схемы
На этом этапе было верифицировано, что чтение в Riak осуществляется нормально.
Последний шаг — убедиться, что запись тоже работает. Простое изменение в при­
ложении— и теперь Riak становится источником истины, как мы видим на
рис. 4.15. Обратите внимание, что мы по-прежнему пишем в обе базы данных, по­
этому при возникновении каких-либо затруднений у вас есть возможность откатить
назад.

Рис. 4.15. Новая база данных теперь является источником истины,
но старая база данных по-прежнему поддерживается в синхронизированном состоянии

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

Зачем использовать этот шаблон
В случае с датской системой медицинской документации мы занимались одним
приложением. Но мы говорим о ситуациях, когда хотим извлекать микрослужбы.
Тогда действительно ли этот шаблон помогает? Первым делом следует учесть то,
что этот шаблон имеет большой смысл, если вы хотите разложить схему перед вы­
делением кода приложения. На рис. 4.16 мы видим именно такую ситуацию, когда
сначала мы дублируем счет-фактурные данные.
При правильной имплементации оба источника данных всегда должны находиться
в синхронизованном состоянии, что дает нам значительные выгоды в ситуациях,

168

|

Глава 4

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

Рис. 4.16. Пример монолита, поддерживающего две схемы в синхронизованном состоянии

Где его использовать
Теперь, когда у вас есть как монолит, так и микрослужба, которая обращается
к данным, вы можете подумать об использовании этого шаблона, но это чрезвы­
чайно усложняется. На рис. 4.17 мы имеем такую ситуацию. Для того чтобы этот
шаблон работал как надо, необходимо, чтобы и монолит, и микрослужба обеспечи­
вали надлежащую синхронизацию во всех базах данных. Если одно из них ошибет­
ся, то у вас будут неприятности. Эта сложность значительно смягчается, если вы
уверены в том, что в любой момент времени либо служба ’’Счет-фактура” выполня­
ет операции записи, либо это делает счет-фактурная функциональность монолита.

Рис. 4.17. Пример, когда и монолит, и микрослужба пытаются поддерживать две одинаковые схемы

в синхронизованном состоянии

Декомпозиция базы данных

|

169

Это будет хорошо работать, если применить простой метод переключения, как мы
обсуждали на примере шаблона ’’Фикус-удавка”. Если, однако, запросы могут за­
трагивать либо монолитную счет-фактурную функциональность либо новую счетфактурную функциональность, возможно, в рамках ’’канареечного” релиза, то вы,
возможно, не захотите использовать этот шаблон, т. к. результирующая синхрони­
зация будет запутанной.

Шаблон: "Трассировочная запись"
Шаблон ’’Трассировочная запись” (tracer write), очерченный на рис. 4.18, можно
назвать вариацией шаблона ’’Синхронизовать данные в приложении” (см. раздел
"Шаблон: синхронизовать данные в приложении"). С помощью трассировочной
записи мы переносим источник истины для данных в поступательном режиме, до­
пуская во время миграции наличие двух источников истины. Вы определяете но­
вую службу, которая будет содержать перенесенные данные. Текущая система попрежнему ведет регистрацию этих данных локально, но во время внесения измене­
ний также обеспечивает, чтобы эти данные записывались в новую службу через ее
интерфейс. Существующий код можно изменить так, чтобы начать обращаться
к новой службе, и как только вся функциональность будет использовать новую
службу в качестве источника истины, старый источник истины можно вывести из
эксплуатации. Следует уделять тщательное внимание тому, как данные синхрони­
зируются между двумя источниками истины.

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

из одной системы в другую, обустраивая два источника истины во время миграции

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

|

Гпава 4

Рис. 4.19. Поступательный перенос счет-фактурной информации из монолита
в нашу службу "Счет-фактура"

Декомпозиция базы данных

I

171

истины служит монолит. После релиза источник истины — наша новая микро­
служба. Трудность в том, что во время этого обмена самые разные вещи могут пой­
ти не так. Шаблон, подобный ’’Трассировочной записи”, позволяет осуществлять
фазированное переключение, уменьшая влияние каждого релиза в обмен на более
терпимое отношение к наличию более одного источника истины.

Причина, почему этот шаблон называется трассировочной записью, заключается
в том, что вы начинаете с небольшого набора синхронизируемых данных и с тече­
нием времени увеличиваете их объем, одновременно увеличивая число потребите­
лей нового источника данных. Если взять пример, описанный на рис. 4.12, где счетфактурные данные переносились из монолита в нашу новую микрослужбу ’’Счетфактура”, то мы могли бы сначала синхронизировать базовые счет-фактурные дан­
ные, затем мигрировать контактную информацию счета-фактуры и, наконец, син­
хронизировать платежные данные, как показано на рис. 4.19.
Другие службы, которые хотели бы получать счет-фактурную информацию, будут
выбирать источник этой информации либо из монолита, либо из самой новой служ­
бы, в зависимости от того, какая информация им нужна. Если им по-прежнему тре­
буется информация, имеющаяся только в монолите, то им придется подождать до
тех пор, пока эти данные и вспомогательная функциональность не будут перенесе-

Рис. 4.20. Вывод из эксплуатации старого источника истины с помощью трассировочной записи

172

|

Гпава 4

ны. Как только данные и функциональность будут иметься в новой микрослужбе,
потребители смогут переключиться на новый источник истины.
Цель нашего примера — мигрировать всех потребителей на использование службы
’’Счет-фактура”, включая сам монолит. На рис. 4.20 мы видим пример двух этапов
миграции. Первоначально мы пишем только базовую счет-фактурную информацию
для обоих источников истины. Как только мы подтвердим, что эта информация
надлежаще синхронизирована, монолит может начать читать свои данные из новой
службы. По мере того как синхронизируется все больше данных, монолит исполь­
зует новую службу в качестве источника истины для все большего объема данных.
Как только все данные синхронизированы и последний потребитель старого источ­
ника истины был переключен, мы можем прекратить синхронизацию данных.

Синхронизация данных
Самая большая задача, которую необходимо решить при использовании шаблона
’’Трассировочная запись”, связана с проблемой, возникающей в любой ситуации,
когда данные дублируются, — несогласованность. Для ее решения у вас есть не­
сколько вариантов:

♦ Писать в один источник — все записи отправляются в один из источников ис­
тины. После осуществления записи данные синхронизируются с другим источ­
ником истины.

♦ Отправлять записи в оба источника — все запросы на запись со стороны вы­
шестоящих клиентов отправляются в оба источника истины. Это происходит,
убедившись, что клиент обращается к каждому источнику истины сам или пола­
гаясь на посредника в том, что он протранслирует запрос в каждую нижестоя­
щую службу.
♦ "Высеивать" записи в любой из двух источников — клиенты могут отправлять
запросы на запись в любой источник истины, и за кулисами данные синхронизи­
руются в двустороннем режиме между системами.
Два отдельных варианта отправки операций записи в оба источника истины или
отправки в один источник истины и опора на некоторую форму фоновой синхрони­
зации выглядят работоспособными решениями, и пример, который мы вскоре рас­
смотрим, использует оба этих метода. Однако, хотя эта ситуация технически воз­
можна, ее — когда записи выполняются либо в один источник истины, либо в дру­
гой — следует избегать, поскольку она требует двусторонней синхронизации (что
бывает очень трудно достичь).

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

Декомпозиция базы данных

|

173

зуя систему захвата изменений в данных, то окна несогласованности могут изме­
ряться в секундах или меньше.

Как бы долго ни длилось это окно несогласованности, такая синхронизация дает
нам то, что называется конечной согласованностью9 — в результате оба источника
истины будут иметь одни и те же данные. Вам нужно будет понять, какой период
несогласованности подходит в вашем случае, и учесть его при выборе способа им­
плементации синхронизации.
Важно, чтобы при поддержании такого рода двух источников истины у вас был ка­
кой-то процесс согласования для обеспечения работы синхронизации как задума­
но. Это может быть что-то простое, например, несколько SQL-запросов, которые
вы выполняете к каждой базе данных. Но без проверки того, что синхронизация
работает как задумано, вы можете столкнуться с несогласованностью между двумя
системами и не понять этого, пока не станет слишком поздно. Очень разумно вы­
полнять ваш новый источник истины в течение периода времени, когда у него нет
потребителей, до тех пор пока вы не будете удовлетворены тем, как все работа­
ет— что, как мы разведаем в следующем разделе, как раз и сделали, например, в
Square.

Пример: заказы в Square
Первоначально этим шаблоном со мной поделился Дерек Хаммер (Derek Hammer),
разработчик из Square, и с тех пор в общей практике я нашел другие примеры его
использования10. Дерек подробно описал его применение, помогая распутать часть
домена компании Square, связанного с заказом доставки еды на вынос. В первона­
чальной системе концепция единого ’’Заказа” управляла несколькими трудовыми
потоками: один для клиентов, заказывающих еду, другой для ресторана, готовяще­
го еду, и третий управляемый трудовой поток состоял в том, что водители доставки
забирали еду и отправляли ее клиентам. Потребности трех заинтересованных сто­
рон различаются, и, хотя все эти стороны работают с одним и тем же ’’Заказом”,
значение этого ’’Заказа” для каждого из них различно. Клиенту важно то, что он
выбрал для доставки, и то, за что ему нужно заплатить. Ресторану требуется знать,
что нужно приготовить и укомплектовать. И какой заказ водителю нужно своевре­
менно доставить из ресторана клиенту. Несмотря на эти разные потребности, код и
ассоциированные с ’’Заказом” данные связаны между собой.

Наличие всех этих трудовых потоков, объединенных в единую концепцию ’’Заказа”,
было источником уже упоминавшейся ’’конкуренции за доставку” — разные разра­
ботчики, которые пытаются внести изменения, соответствующие разным вариантам
9 Для справки: конечная согласованность (eventual consistency)— это модель согласованности, ис­
пользуемая в распределенных вычислениях для достижения высокой доступности, которая неофици­
ально гарантирует, что если в отдельно взятый элемент данных не будет внесено никаких новых об­
новлений, то в конечном итоге все обращения к этому элементу вернут последнее обновленное значе­
ние — Пер.
10 Сандита Ханда (Sangeeta Handa) поделилась тем, как Netflix использовал этот шаблон в рамках
своих миграций данных на конференции QCon SF, и Даниэль Брайант (Daniel Bryant) впоследствии
составил о нем хорошую тематическую подборку (http://bit.ly/2mlEwHT).

174

|

Гпава 4

использования, будут мешать друг другу, поскольку всем им нужно вносить изме­
нения в одну и ту же часть кодовой базы. Square хотела разложить ’’Заказ” так, что­
бы изменения в каждом трудовом потоке могли делаться изолированно, а также
активировать разные потребности в масштабировании и робастности.

Создание новой службы
Первым шагом было создание новой службы ’’Исполнения”, как показано на
рис. 4.21, которая будет управлять данными ’’Заказа”, ассоциированными с ресто­
раном и водителями доставки. Эта служба в будущем должна была стать новым
источником истины для подмножества данных ’’Заказа”. Первоначально эта служба
просто выставляла наружу функциональность, позволяющую создавать сущности,
связанные с ’’Исполнением”. После того как новая служба была выпущена в ’’пря­
мой эфир”, у компании имелся фоновой работник, который копировал данные, свя­
занные с ’’Исполнением”, из существующей системы в новую службу ’’Исполне­
ния”. Этот фоновый работник просто использовал API, выставляемый наружу
службой ’’Исполнения”, вместо прямой вставки в базу данных, избегая необходи­
мости прямого обращения к базе данных.

Рис. 4.21. Новая служба "Исполнения" использовалась для репликации данных,
связанных с исполнением заказов, из существующей системы

Фоновый работник контролировался посредством флажка функции, которыймож­
но было включить или выключить для остановки процесса копирования. Это по­
зволило легко отключать указанный процесс, если работник становился причиной
каких-либо проблем в производстве. Они прогнали эту систему в производстве
в течение достаточного объема времени, для того чтобы получить уверенность
в том, что синхронизация работала правильно. Как только они были довольны
тем, что фоновый работник работал так, как ожидалось, этот флажок функции был
удален.
Декомпозиция базы данных

|

175

Синхронизировать данные
Одна из трудностей с такого рода синхронизацией заключается в том, что она явля­
ется односторонней. Изменения, внесенные в существующую систему, привели
к тому, что данные, связанные с исполнением заказов, записывались в новую служ­
бу ’’Исполнения” через ее API. Square решила эту проблему, обеспечив внесение
всех обновлений в обеих системах, как показано на рис. 4.22. Однако не все обнов­
ления нужно было делать в обеих системах. Как объяснил Дерек, теперь, когда
служба ’’Исполнения” представляла собой только подмножество концепции ’’За­
каз”, нужно было копировать только те изменения, внесенные в заказ, которые ин­
тересовали клиентов доставки или ресторана.

Рис. 4.22. Последующие обновления синхронизировались путем обеспечения того,

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

Любой код, который изменял информацию, ориентированную на ресторан или дос­
тавку, следовало модифицировать так, чтобы делались два набора вызовов API:
один— в сторону существующей системы, другой— в сторону той же микро­
службы. Эти вышестоящие клиенты также должны были улаживать любые условия
возникновения ошибок, если запись в одну из них работала, а в другую — нет. Из­
менения в двух нижестоящих системах (существующая система заказов и новая
служба ’’Исполнения”) не делались атомарно. Это означает, что существовало ко­
роткое окно, в котором изменение видно в одной системе, но еще не видно в дру­
гой. До тех пор пока оба изменения не будут применены, вы видите несогласован­
ность между двумя системами. Это одна из форм конечной согласованности, о ко­
торой мы говорили ранее.
С точки зрения возможной последовательной природы информации о ’’Заказе”, это
не было проблемой для указанного конкретного варианта использования. Данные
синхронизировались между двумя системами достаточно быстро, что не влияло на
пользователей системы.
Если бы для управления обновлениями "Заказов” вместо вызовов API в компании
Square использовалась событийно-обусловленная система, то они могли бы поду­

176

|

Гпава 4

мать об альтернативной имплементации. На рис. 4.23 представлен единый поток
сообщений, который активирует изменения в состоянии ’’Заказа”. И существующая
система, и новая служба ’’Исполнения” получают одни и те же сообщения. Выше­
стоящим клиентам не нужно знать о том, что для этих сообщений существуют мно­
гочисленные клиенты; это то, что может быть урегулировано с помощью брокера
в стиле ’’публикация-подписка ”.

Рис. 4.23. Альтернативный подход к синхронизации может заключаться в том,
чтобы оба источника истины подписывались на одинаковые события

Донастройка архитектуры Square под событийную обусловленность только для
удовлетворения такого рода варианта использования выльется в большую работу.
Но если вы уже используете систему на основе событий, то вам будет проще
управлять процессом синхронизации. Также стоит отметить, что такая архитектура
все равно в итоге будет демонстрировать согласованное поведение, поскольку вы
не можете гарантировать, что и существующая система, и служба ’’Исполнения”
будут обрабатывать одно и то же событие в то же самое время.

Мигрирование потребителей
Теперь, когда новая служба ’’Исполнения” содержит всю необходимую информа­
цию для трудовых потоков ресторана и водителя доставки, код, управлявший этими
трудовыми потоками, может начать переключаться на использование новой служ­
бы. Во время этой миграции может привноситься дополнительная функциональ­
ность для поддержки потребностей этих потребителей. Первоначально служба
’’Исполнения” требовалась только для имплементации API, который позволял соз­
давать новые записи для фонового работника. По мере миграции новых потребите­
лей оцениваются их потребности, и в службу добавляется новая функциональность
с целью их поддержки.

Эта поступательная миграция данных, а также изменение потребителей, чтобы они
использовали новый источник истины, в случае Square оказались весьма эффективДекомпозиция базы данных

|

177

ними. По словам Дерека, достижение той точки, где все потребители переключи­
лись, в значительной степени оказалось разочарованием. Это было просто еще
одним крохотным изменением, сделанным во время рутинного релиза (еще одна
причина, по которой в этой книге я так сильно ратую за поступательную ми­
грацию!).
С точки зрения доменно-обусловленного дизайна вы, конечно, можете утверждать,
что вся функциональность, связанная с водителями доставки, клиентами и рестора­
нами, представляла разные ограниченные контексты. С этой точки зрения Дерек
предположил, что он в идеале мог бы подумать о дальнейшем разбиении этой
службы ’’Исполнения” на две службы: одну — для ресторанов, а другую — для во­
дителей доставки. Тем не менее, несмотря на наличие возможностей для дальней­
шей декомпозиции, эта миграция оказалась весьма успешной.
В случае с Square продублированные данные было решено оставить. Благодаря то­
му, что информация о заказах, связанных с рестораном и доставкой, осталась в су­
ществующей системе, компания обеспечила видимость этой информации в случае
недоступности службы "Исполнения”. Разумеется, при этом синхронизация тоже
должна остаться на своем месте. Интересно, будет ли это со временем подвергнуто
ревизии. Как только появится достаточная уверенность в работоспособности служ­
бы ’’Исполнения”, удаление фонового работника и необходимости в том, чтобы по­
требители делали два набора вызовов на обновление, вполне помогут оптимизиро­
вать указанную архитектуру.

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

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

Разбиение базы данных
Мы уже подробно обсуждали проблемы использования баз данных в качестве ме­
тода интеграции многочисленных служб. Как уже должно быть совершенно ясно,
я не поклонник этого! А значит, нам нужно найти стыки в базах данных тоже, для
того чтобы аккуратно их выделить. Вместе с тем базы данных— звери хитрые.
Прежде чем перейти к нескольким примерам подходов, мы должны кратко обсу­
178

|

Глава 4

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

Физическое и логическое разделение баз данных
Когда мы говорим о разложении наших баз данных в этом контексте, мы в первую
очередь пытаемся достичь логического разделения, или сегментации. Одно ядро
СУБД способно идеально разместить более одной логически разделенной схемы,
как показано на рис. 4.24.

Рис. 4.24. Две службы с отдельными логическими схемами,

работающими на одном физическом ядре СУБД

Мы могли бы пойти дальше и разместить каждую логическую схему также на от­
дельных ядрах СУБД, получая и физическое разделение тоже, как мы видим на
рис. 4.25.

Почему возникает желание разложить свои схемы логически, но все-таки иметь их
на одном ядре СУБД? Дело в том, что в своей основе логическая и физическая
декомпозиция преследуют разные цели. Логическая декомпозиция обеспечивает
более простое независимое изменение и сокрытие информации, в то время как фи­
зическая декомпозиция потенциально повышает робастность системы и помогает
устранять конкуренцию за ресурсы, позволяя повышать пропускную способность
или уменьшать задержку.
Когда мы разбиваем наши схемы баз данных логически, но сохраняем их на том же
физическом ядре СУБД, как показано на рис. 4.24, мы имеем потенциальную един­
ственную точку сбоя. Если ядро СУБД выходит из строя, то затрагиваются обе

Декомпозиция базы данных

|

179

службы. Однако мир не так прост. Многие ядра СУБД имеют механизмы, позво­
ляющие избегать единственных точек сбоя, такие, как мультипримарные режимы
баз данных, механизмы ’’теплой” отработки отказа и тому подобное. Собственно,
в вашей организации, возможно, были приложены значительные усилия, для того
чтобы создать высокоотказоустойчивый кластер базы данных, и будет трудно
оправдать наличие нескольких кластеров из-за связанных с этим времени, усилий и
стоимости (а досадные лицензионные сборы пойдут в нагрузку!).

Рис. 4.25. Две службы, использующие отдельные логические схемы,
каждая из которых работает на своем собственном физическом ядре СУБД

Еще одно соображение состоит в том, что, если вы захотите выставлять наружу
проекции своей базы данных, то потребуется, чтобы многочисленные схемы совме­
стно использовали одно и то же ядро СУБД. Возникнет необходимость распо­
ложить на одном и том же ядре СУБД как исходную базу данных, так и схемы, на
которых размещаются проекции.
Конечно, для того чтобы у вас была даже возможность выполнять отдельные служ­
бы на разных физических ядрах СУБД, вам нужно уже разложить их схемы логи­
чески!

Что выделять сначала: базу данных или код?
До сих пор мы говорили о шаблонах, которые помогают работать с совместными
базами данных и, надо надеяться, переходить к менее сопряженным моделям.
В данный момент нам нужно осмотреть со всех сторон шаблоны декомпозиции ба­
зы данных. Однако, прежде чем мы это сделаем, нам необходимо обсудить вопрос
установления последовательности. Извлечение микрослужбы не ’’делается” до тех
пор, пока код приложения не будет работать в его собственной службе, а данные,
которыми он управляет, не будут извлечены в его собственную логически изолиро­
180

|

Гпава 4

ванную базу данных. Но поскольку эта книга в основном посвящена поступатель­
ным изменениям, мы должны немного разведать вопрос, в какой последовательно­
сти это извлечение должно выполняться. У нас есть несколько вариантов:
♦ Сначала выделить базу данных, а затем код.
♦ Сначала выделить код, а затем базу данных.
♦ Выделить и то, и другое сразу.
У каждого варианта есть свои плюсы и минусы. Давайте сейчас рассмотрим эти
варианты, а также некоторые шаблоны, которые помогут в зависимости от подхода,
который вы принимаете.

Сначала выделить базу данных
С помощью отдельной схемы мы будем потенциально увеличивать число вызовов
базы данных для выполнения одного-единственного действия. Если раньше, у нас,
возможно, были все необходимые данные в одной инструкции select, то теперь
нам, возможно, потребуется вытаскивать данные из двух мест и соединять их в па­
мяти. Кроме того, мы в итоге нарушаем транзакционную целостность, когда пере­
ходим к двум схемам, что окажет значительное влияние на наши приложения; мы
обсудим эти проблемы позже в этой главе, когда рассмотрим такие темы, как рас­
пределенные транзакции и саги, и то, как они помогают. Выделяя схемы, но держа
код приложения вместе, как показано на рис. 4.26, мы даем себе возможность отка­
тывать наши изменения назад или продолжать корректировать вещи, не влияя на
каких-либо потребителей нашей службы, если мы понимаем, что идем по непра­
вильному пути. Как только мы убедимся, что выделение БД имеет смысл, то можем
подумать о разделении кода приложения на две службы.

Рис. 4.26. Выделение сначала схемы позволяет раньше обнаружить проблемы с производительностью
и транзакционной целостностью

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

|

181

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

Примечание по инструментарию
Вносить изменения в базы данных трудно по многим причинам. Одна из них— огра­
ниченность набора инструментов, которые позволяли бы легко вносить изменения.
В случае с кодом мы имеем инструменты рефакторизации, которые встроены в наши
IDE, и у нас есть дополнительная выгода в том, что в своей основе системы, которые
мы изменяем, не имеют состояния. В случае с базой данных изменяемые нами вещи
имеют состояние, но нам также не хватает хорошего инструмента рефакторизации.
Много лет назад этот пробел в инструментах заставил меня и двух моих коллег, Ника
Эшли (Nick Ashley) и Грэма Тэкли (Graham Tackley), создать инструмент с открытым
исходным кодом под названием DBDeploy. Теперь несуществующий (создание инст­
румента с открытым исходным кодом очень отличается от его сопровождения!), он ра­
ботал, позволяя улавливать изменения в SQL-скриптах, которые можно было выпол­
нять детерминированным образом на схемах. В каждой схеме была специальная таб­
лица, которая использовалась для отслеживания того, какие сценарии схемы были
применены.
Цель DBDeploy состояла в том, чтобы позволить вам вносить поступательные изме­
нения в схему, контролировать каждую версию изменений и разрешать исполнение
изменений на нескольких схемах в разное время (подумайте о схемах этапов разра­
ботки, тестирования и производства).
В настоящее время я направляю людей к FlywayDB11 или чему-то, что обеспечивает
аналогичные возможности, но, какой бы инструмент вы ни выбрали, я настоятельно
призываю вас убедиться, что он позволяет вам улавливать каждое изменение в дель­
та-скрипте, управляемом системой контроля версий.

Шаблон: "Один репозиторий
на один ограниченный контекст"
В обычной практике принято иметь репозиторный слой, поддерживаемый какимнибудь каркасом, таким, как Hibernate, для привязки вашего кода к базе данных,
что упрощает отображение объектов или структур данных в базу данных и из нее.
Вместо того чтобы иметь один репозиторный слой для всех наших задач доступа
к данным, есть смысл подразделить эти репозитории по линиям ограниченных кон­
текстов, как показано на рис. 4.27.
Наличие программного кода отображения базы данных, расположенного внутри
кода для заданного контекста, помогает нам понять, какие части базы данных ис­
пользуются и какими фрагментами кода. Например, Hibernate делает это очень ясно,
если у вас есть что-то вроде одного файла отображения на один ограниченный 11

11 См. https://flywaydb.org/.

182

|

Гпава 4

Рис. 4.27. Разбиение наших репозиторных слоев

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

Однако это не дает нам всей картины. Например, можно понять, что финансовый
код использует таблицу ’’Приходно-расходный регистр” и каталожный код — таб­
лицу ’’Товарные позиции”, но далеко не всегда ясно, что база данных обеспечивает
соблюдение связи по внешнему ключу из таблицы ’’Приходно-расходный регистр”
в таблицу ’’Товарные позиции”. Для того чтобы увидеть эти ограничения уровня
базы данных, что бывает камнем преткновения, нам нужен еще один инструмент
для визуализации данных. Отличное место для старта — использовать инструмент,
подобный свободно доступному SchemaSpy12, который генерирует графические
представления связей между таблицами.
Все это помогает вам понять сопряженность между таблицами, которая охватывает
то, что в итоге станет контурами служб. Но как оборвать эти связи? А как насчет
случаев, когда одни и те же таблицы используются из нескольких ограниченных
контекстов? Мы подробно рассмотрим эту тему далее в этой главе.

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

12 См. http://schemaspy.sourceforge.net/.

Декомпозиция базы данных

|

183

Шаблон: "Одна база данных
на один ограниченный контекст"
После того как вы четко изолировали доступ к данным с точки зрения приложения,
имеет смысл продолжить этот подход в схеме. Центральное место в идее независи­
мой развертываемости микрослужб занимает тот факт, что они должны владеть
своими собственными данными. Прежде чем приступить к выделению кода прило­
жения, мы можем начать эту декомпозицию, четко отделяя наши базы данных во­
круг линий выявленных ограниченных контекстов.

В ThoughtWorks мы занимались имплементацией нескольких новых механизмом
для расчета и прогнозирования валового дохода компании. В рамках этой работы
мы выявили три широкие области функциональности, которые нужно было вопло­
тить в коде. Я обсудил эту проблему с руководителем данного проекта Питером
Гиллардом-Моссом (Peter Gillard-Moss). Питер объяснил, что функциональность
ощущается совершенно отдельной, но у него есть опасения относительно лишней
работы, которую принесет наличие этой функциональности, если она будет поме­
щена в отдельные микрослужбы. В то время его группа была небольшой (всего три
человека), и чувствовалось, что группа не могла оправдать выделение этих новых
служб. В конце концов, они остановились на модели, в которой новая функцио­
нальность валового дохода была практически развернута как единая служба, со­
держащая три изолированных ограниченных контекста (каждый из которых ока­
зался отдельным файлом JAR), как показано на рис. 4.28.

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

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

|

Гпава 4

лового дохода остается такой, как есть, монолитом с многочисленными ассоцииро­
ванными базами данных — отличным примером модульного монолита.

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

Именно этот шаблон я почти всегда рекомендую людям, строящим совершенно но­
вые системы (в отличие от реимплементации существующей системы). Я не по­
клонник имплементации микрослужб для новых продуктов или стартапов. Ваше
понимание домена вряд ли будет достаточно зрелым, для того чтобы знать, как вы­
являть стабильные границы домена. В случае стартапов, в особенности, поскольку
природа вещи, которую вы строите, может резко измениться. Вместе с тем этот
шаблон будет хорошей промежуточной точкой. Держите выделение схемы там, где,
по вашему мнению, у вас в будущем будет выделение службы. Благодаря этому вы
получаете некоторые выгоды от размежевания этих идей, одновременно снижая
сложность системы.

Сначала выделить код
В общем случае я нахожу, что большинство групп сначала выделяют код, а затем
базу данных, как показано на рис. 4.29. Они получают краткосрочное улучшение
(надо надеяться) от новой службы, что дает им уверенность в завершении декомпо­
зиции путем выделения базы данных.

Рис. 4.29. Выделение сначала прикладного яруса оставляет нас с одной совместной схемой

Декомпозиция базы данных

|

185

В результате выделения прикладного яруса намного проще понять, какие данные
необходимы новой службе. Вы также раньше получаете выгоду от наличия незави­
симо развертываемого программного артефакта. Трудности, которые я всегда ис­
пытывал с этим подходом, заключаются в том, что группы нередко доходят до это­
го места и останавливаются, оставляя совместную базу данных в игре на постоян­
ной основе. Если вы идете в этом направлении, то должны понимать, что если вы
не доведете выделение до яруса данных, то вы накапливаете неприятности на бу­
дущее. Я видел группы, которые попадались в такую ловушку, но с радостью могу
сообщить об организациях, которые здесь поступили правильно. JustSocial — одна
из таких организаций, которая использовала описанный подход в рамках своей соб­
ственной миграции на микрослужбы. Другая потенциальная трудность здесь за­
ключается в том, что вы, возможно, будете откладывать обнаружение неприятных
сюрпризов, вызываемых ’’заталкиванием” операций соединения вверх в прикладной
ярус.

Если вы идете в этом направлении, то будьте перед собой честны: уверены ли вы
в том, что сможете обеспечить выделение любых данных, принадлежащих микро­
службе, в рамках следующего шага?

Шаблон: "Монолит как слой доступа к данным"
Вместо прямого доступа к данным из монолита мы можем просто перейти к моде­
ли, в которой мы создаем API в самом монолите. На рис. 4.30 службе ’’Счетфактура” требуется информация о сотрудниках в нашей службе ’’Клиенты”, поэто­
му мы создаем API ’’Сотрудники”, позволяющий службе ’’Счет-фактура” к ним об­
ращаться. Сюзанна Кайзер (Susanne Kaiser) из JustSocial поделилась со мной ука­
занным шаблоном, т. к. эта компания успешно использовала его в рамках миграции

Рис. 4.30. Выставление API наружу на монолите позволяет службе избегать прямой привязки данных

186

|

Гпава 4

До: Данные и функциональность о сотрудниках размещены в монолите, доступ к ним через API

После: Данные и функциональность о сотрудниках извлечены из монолита в новую микрослужбу

Рис. 4.31. Использование API "Сотрудники" для выявления контура службы "Сотрудники",
которая должна быть выделена из монолита

Декомпозиция базы данных

|

187

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

Одна из причин, почему указанный шаблон не применяется шире, вероятно, кроет­
ся в том, что у людей как бы застряла в голове мысль о том, что монолит мертв и
бесполезен. Они хотят отойти от него. Они не думают о том, чтобы сделать его по­
лезнее! Но плюсы здесь очевидны: нам (пока) не нужно заниматься декомпозицией
данных, а необходимо заняться сокрытием информации, облегчая изолирование
нашей новой службы от монолита. Я был бы более склонен принять эту модель,
если бы чувствовал, что данные в монолите останутся там. Но этот шаблон хорошо
работает, в особенности если вы думаете, что ваша новая служба практически не
будет иметь состояния.
Не так уж сложно смотреть на этот шаблон как на способ выявления других кандидатных служб. Развивая эту идею, мы могли увидеть, что API ’’Сотрудники" выде­
ляется из монолита, становясь микрослужбой самой по себе, как показано на
рис. 4.31.

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

Если данные, к которым вы пытаетесь обратиться в базе данных монолита, на са­
мом деле должны быть "во владении" микрослужбы, то я больше склонен предло­
жить пропустить этот шаблон и вместо него выделить данные.

Шаблон: "Мультисхемное хранение"
Как мы уже обсуждали, полезная идея — не усугублять плохую ситуацию. Если вы
по-прежнему используете данные в базе данных напрямую, то это не означает, что
новые данные, хранящиеся в микрослужбе, должны туда входить тоже. На рис. 4.32
приведен пример нашей службы "Счет-фактура". Стержневые счет-фактурные дан­
ные по-прежнему располагаются в монолите, откуда мы (в настоящее время) к ним
обращаемся. Мы добавили возможность добавлять в счета-фактуры пересмотры.
Это совершенно новая функциональность, находящаяся вне монолита. Для ее под­
держки нам нужно хранить таблицу перепроверяющих лиц, отображая сотрудников
в идентификаторы счетов-фактур. Если мы поместим эту новую таблицу в моно­
лит, то будем помогать базе данных расти! Вместо этого мы поместили эти новые
данные в нашу собственную схему.
188

|

Гпава 4

Рис. 4.32. Служба "Счет-фактура" помещает новые данные в свою собственную схему,

но по-прежнему обращается к старым данным в монолите напрямую

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

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

Если данные, к которым вы обращаетесь в схеме монолита, никогда не планируется
переносить в свою схему, то я настоятельно рекомендую использовать шаблон
"Монолит как слой доступа к данным" (см. раздел "Шаблон: монолит как слой
доступа к данным") в сочетании с описанным здесь шаблоном.

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

Декомпозиция базы данных

|

189

Рис. 4.33. Выделение кода и данных за один шаг

Здесь меня беспокоит то, что этот шаг гораздо обширнее, и пройдет больше време­
ни, прежде чем вы сможете оценить влияние вашего решения в результате. Я на­
стоятельно рекомендую избегать этого подхода и вместо него сначала выделять
либо схему, либо прикладной ярус.

Так что же мне выделять сначала?
Понимаю: вы, наверное, устали от всех этих оговорок, дескать, ’’все зависит от кон­
кретных условий”, верно? И я не могу вас винить. Проблема в том, что у каждого
своя ситуация, поэтому я пытаюсь вооружить вас достаточным контекстом и обсу­
дить различные плюсы и минусы, чтобы помочь вам принять свое собственное ре­
шение. Тем не менее я знаю, что иногда люди хотят самую малость ’’горячего”
взгляда на эти вещи, так что вот он.

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

Примеры выделения схемы
До сих пор мы рассматривали выделение схемы на довольно высоком уровне, но
есть ряд сложных проблем, связанных с декомпозицией базы данных, и несколько
запутанных вопросов, которые требуется прояснить. Теперь мы рассмотрим не­
сколько более низкоуровневых шаблонов декомпозиции данных и разведаем влия­
ние, которое они оказывают.

Реляционные базы данных против NoSQL
Во многих примерах рефакторизаций, подробно описанных в этой главе, разведыва­
ются трудности, возникающие во время работы с реляционными схемами. Природа
этих типов баз данных создает дополнительные трудности с точки зрения выделения
190

|

Гпава 4

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

Шаблон: "Разложить таблицу"
Иногда вы будете находить данные в одной таблице, которые нуждаются в разде­
лении вдоль двух или более контуров служб, и этот вопрос представляет интерес.
На рис. 4.34 мы видим одну совместную таблицу ’’Товарная позиция”, в которой
хранится информация не только о продаваемой товарной позиции, но и об уровнях
ее запасов.

Рис. 4.34. Одна таблица, соединяющая в себе два выделяемых ограниченных контекста

В рассматриваемом примере мы хотим выделить каталог и склад как новые служ­
бы, но данные для них перемешаны в одной таблице. Поэтому нам нужно разло­
жить эти данные на две отдельные таблицы, как показано на рис. 4.34. В духе по­
ступательной миграции, возможно, следует отделить таблицы друг от друга в су­
ществующей схеме перед выделением схем. Если эти таблицы существовали
в одной схеме, то имеет смысл объявить связь по внешнему ключу из столбца ’’Ар­
тикул инвентарной товарной позиции” (SKU) в таблицу ’’Каталожная товарная по­
зиция”. Однако, поскольку в итоге мы планируем перенести эти таблицы в отдель­
ные базы данных, мы, возможно, не извлечем из этого большой выгоды, поскольку
у нас не будет единой базы данных, обеспечивающей согласованность данных
(вскоре мы рассмотрим эту идею подробнее).

Этот пример довольно прямолинейный, отделить владение данными, один столбец
за другим, было легко. Но что произойдет, когда несколько частей кода обновляют
один и тот же столбец? На рис. 4.35 мы имеем таблицу ’’Клиент”, которая содержит
столбец ’’Статус”.
Декомпозиция базы данных

|

191

Рис. 4.35. И код "Управления клиентами", и код "Финансов" могут изменять статус в таблице "Клиент"

Этот столбец обновляется во время регистрации клиента, указывая на то, что дан­
ное лицо подтвердило (или не подтвердило) свою электронную почту, при этом
значение переходит из НЕВЕРИФИЦЦРОВАНО в ВЕРИФИЦИРОВАНО. После
того как клиент ВЕРИФИЦИРОВАН, он может делать покупки. Наш финансовый
код занимается приостановкой клиентов, если их счета не оплачены, поэтому они
иногда меняют статус клиента на ПРИОСТАНОВЛЕН. В этом случае ’’Статус” кли­
ента по-прежнему выглядит так, как будто он должен быть частью доменной моде­
ли клиента, и как таковой он должен управляться службой ’’Клиенты”, которая
вскоре будет создана. Помните, что мы хотим, где это возможно, держать машины
состояний для сущностей нашего домена внутри контура одной службы, и обнов­
ление ’’Статуса”, безусловно, ощущается для клиента как часть машины состояний!
Это означает, что после выделения служб наша новая служба ’’Финансы” будет нуж­
даться в вызове службы для обновления этого статуса, как мы видим на рис. 4.36.

Рис. 4.36. Новая служба "Финансы" должна совершать вызовы службы для приостановки клиента

192

|

Гпава 4

Большая проблема с таким разложением таблиц заключается в том, что мы теряем
безопасность, предоставляемую нам транзакциями базы данных. Мы разведаем эту
тему подробнее в конце этой главы, когда в соответствующих разделах рассмотрим
’’Транзакции” и ’’Саги".

Где его использовать
На первый взгляд указанный шаблон кажется довольно простым. Если таблица
принадлежит двум или более ограниченным контекстам в текущем монолите, то
вам нужно разложить таблицу по этим линиям. Если вы находите конкретные
столбцы в таблице, которые, по-видимому, обновляются многочисленными частя­
ми вашей кодовой базы, то вам нужно принять решение на свое усмотрение в от­
ношении того, кто должен "владеть” этими данными. Находится ли в центре вашего
внимания существующее доменное понятие? Ответ на этот вопрос поможет опре­
делить, куда эти данные должны пойти.

Шаблон:
"Перенести связь по внешнему ключу в код"
Мы решили извлечь нашу службу "Каталог", которая может управлять и предос­
тавлять информацию об исполнителях, треках и альбомах. В настоящее время наш
каталожный программный код внутри монолита хранит информацию о компактдисках, которые у нас имеются для продажи в таблице "Альбомы". Эти альбомы
в итоге будут упомянуты в нашей таблице "Приходно-расходный регистр", где мы
отслеживаем все продажи. Вы видите это на рис. 4.37. Строки в таблице "Приход­
но-расходный регистр" просто регистрируют сумму, которую мы получаем за ком­
пакт-диск, вместе с идентификатором, который ссылается на проданную товарную
позицию. Идентификатор в нашем примере называется SKU13 — распространенная
практика в розничных системах.

В конце каждого месяца мы должны составлять отчет с описанием наших самых
продаваемых компакт-дисков. Таблица "Приходно-расходный регистр" помогает
нам понять, копий какого артикула продано больше всего, но информация об этом
артикуле находится в таблице "Альбомы". Мы хотим, чтобы отчеты были прият­
ными и удобными для чтения, поэтому вместо утверждения: "Мы продали 400 ко­
пий артикула 123 и заработали 1596 долларов", мы хотели бы видеть более инфор­
мативную фразу: "Мы продали 400 копий Bom То Run Брюса Спрингстина и зара­
ботали 1596 долларов". Для этого запрос к базе данных, инициированный нашим
финансовым кодом, должен присоединить информацию из таблицы "Приходнорасходный регистр" к таблице "Альбомы", как показано на рис. 4.37.
Мы определили связь по внешнему ключу в нашей схеме так, что строка в таблице
"Приходно-расходный регистр" идентифицируется как имеющая связь со строкой
13 SKU (stock keeping unit) — это артикул, или единица складского учета, инвентарной позиции —
Пер.

Декомпозиция базы данных

|

193

Рис. 4.37. Связь по внешнему ключу

в таблице ’’Альбомы”. Определяя такую связь, опорное ядро СУБД способно обес­
печивать согласованность данных: если строка в таблице ’’Приходно-расходный
регистр” ссылается на строку в таблице ’’Альбомы”, то мы знаем, что эта строка
существует. В нашей ситуации это означает, что мы всегда можем получить ин­
формацию о проданном альбоме. Такие связи по внешнему ключу также позволяют
ядру СУБД выполнять оптимизацию производительности для обеспечения макси­
мально быстрого выполнения операции соединения.
Мы хотим выделить каталожный и финансовый код в собственные соответствую­
щие им службы, и это означает, что данные должны идти тоже. Если таблицы
’’Альбомы” и ’’Приходно-расходный регистр” в итоге будут располагаться в разных
схемах, то что произойдет с нашей связью по внешнему ключу? Скажем так, нам
придется подумать о двух ключевых проблемах. Во-первых, когда наша новая
служба ’’Финансы” захочет сгенерировать этот отчет в будущем, то как она будет
извлекать каталожную информацию, если не сможет этого сделать через сущест­
вующую в базе данных операцию соединения? Во-вторых, что мы сделаем с тем
фактом, что в нашем новом мире теперь будет существовать несогласованность
данных?

Перенос операции соединения
Давайте сначала рассмотрим замену соединения (операции join). В случае моно­
литной системы для присоединения строки таблицы ’’Альбомы” к информации
о продажах в ’’Приходно-расходном регистре” база данных выполнила бы соедине­
ние за нас. Нам потребовался бы один-единственный запрос select, и мы бы при­
соединились к таблице ’’Альбомы”. Для исполнения запроса и извлечения всех не­
обходимых данных необходим всего один вызов базы данных.
В нашем мире, основанном на микрослужбах, новая служба ’’Финансы” несет от­
ветственность за генерирование отчета о бестселлерах, но не имеет данных об аль­
бомах локально. Поэтому она должна будет извлечь их из новой службы "Каталог”,

194

|

Глава 4

как мы видим на рис. 4.38. Во время генерирования отчета служба ’’Финансы” сна­
чала запрашивает таблицу ’’Приходно-расходный регистр”, извлекая список наибо­
лее продаваемых артикулов за последний месяц. В этой точке у нас есть только
список артикулов и число проданных копий по каждому; это единственная инфор­
мация, которую мы имеем локально.

Рис. 4.38. Замена операции соединения базы данных вызовами служб

Далее нам нужно вызвать службу ’’Каталог”, запросив информацию по каждому из
этих артикулов. Этот запрос, в свою очередь, побудит службу ’’Каталог” сделать
свой локальный запрос select в своей собственной базе данных.
Логически операция соединения по-прежнему происходит, но теперь она выполня­
ется внутри службы "Финансы”, а не в базе данных. К сожалению, она не будет та­
кой же эффективной, как раньше. Мы перешли из мира, где у нас есть одна инст­
рукция select, в новый мир, где у нас есть запрос select к таблице ’’Приходнорасходный регистр”, за которым следует вызов службы ’’Каталог”, которая, в свою
очередь, запускает инструкцию select в отношении таблицы ’’Альбомы”, как мы
видим на рис. 4.38.

В этой ситуации я был бы очень удивлен, если совокупная задержка этой операции
не увеличилась. Она не является существенной проблемой в данном конкретном
случае, поскольку отчет генерируется ежемесячно и поэтому может агрессивно кэ­
широваться. Но если эта операция выполняется часто, то задержка станет пробле­
мой. Мы можем смягчить вероятное влияние этого увеличения задержки, разрешив
массовый поиск артикулов в службе ’’Каталог” или, возможно, даже локально
кэшируя требуемую информацию об альбомах.
В конечном счете, является ли увеличение задержки проблемой — решать только
вам. Вам нужно иметь представление о допустимой задержке для ключевых опера­
ций и уметь измерять текущую задержку. Распределенные системы, такие, как
Jaeger, действительно здесь помогают, поскольку они предоставляют возможность
Декомпозиция базы данных

|

195

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

Согласованность данных
Более запутанное соображение — возможность столкнуться с несогласованностью
данных в случае отдельных служб ’’Каталог” и ’’Финансы” с отдельными схемами.
С одной схемой я бы не смог удалить строку в таблице ’’Альбомы”, если бы в таб­
лице ’’Приходно-расходный регистр” была ссылка на эту строку. Моя схема обес­
печила бы согласованность данных. В нашем новом мире такого соблюдения не
существует. Какие у нас тут варианты?

Проверять перед удалением
Наш первый вариант заключается в том, чтобы при удалении записи из таблицы
’’Альбомы” сверяться со службой ’’Финансы”, чтобы убедиться, что она еще не
имеет ссылки на запись. Проблема здесь в том, что трудно гарантировать, что мы
сможем сделать это правильно. Скажем, мы хотим удалить артикул 683. Мы посы­
лаем вызов в ’’Финансы”, говоря ”Вы действительно используете 683?” Оттуда при­
ходит ответ, что эта запись не используется. Затем мы удаляем запись, но пока мы
это делаем, в системе ’’Финансы” создается новая ссылка на 683. Для того чтобы
этого не произошло, нам нужно остановить создание новых ссылок на запись 683
до тех пор, пока не произошло удаление — что, вероятно, потребует установления
замков и всех трудностей, которые следуют из распределенной системы.

Еще одна проблема с проверкой того, не используется ли уже та или иная запись,
состоит в том, что она создает де-факто обратную зависимость от службы ’’Ката­
лог”. Теперь нам нужно будет сверяться с любой другой службой, которая исполь­
зует наши записи. Уже плохо, если у нас информация необходима лишьоднойдругой службе, но ситуация значительно ухудшается по мере того, как у нас стано­
вится больше потребителей.

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

Улаживать удаление изящно
Более приемлемый вариант— предоставить службе ’’Финансы” возможность раз­
бираться с тем фактом, что служба ’’Каталог” может не иметь информации об аль­
боме, делая это изящным способом. Это так же просто, как показать в нашем отчете
сообщение ’’Информация об альбоме отсутствует”, если мы не можем найти дан­
ный артикул.
В этой ситуации служба ’’Каталог” могла бы выдать нам сообщение, когда мы за­
прашиваем артикул, который раньше существовал. Например, здесь хорошо подо­
шел бы код отклика под номером 410 GONE (Перестал существовать) при исполь­
196

|

Гпава 4

зовании HTTP. Код отклика 410 отличается от обычного 404. 404 означает, что за­
прошенный ресурс не найден, тогда как 410 означает, что запрошенный ресурс был
по указанному адресу, но больше недоступен. Это различие может быть важным,
в особенности во время отслеживания проблем несогласованности данных! Даже
если вы не применяете протокол на базе HTTP, подумайте о том, получите ли вы
выгоду от поддержки такого отклика.

Если бы мы действительно хотели продвинуться, то могли бы обеспечить, чтобы
наша служба ’’Финансы” информировалась, когда товарная позиция ’’Каталога”
удаляется, возможно, путем подписки на события. Когда мы подхватываем событие
удаления из ’’Каталога”, мы могли бы решить скопировать информацию о теперь
удаленном ’’Альбоме” в нашу локальную базу данных. В данной конкретной ситуа­
ции указанная мера кажется излишней, но будет полезной в других сценариях,
в особенности если вы хотели бы имплементировать распределенную машину со­
стояний для выполнения чего-то вроде каскадного удаления через контуры служб.

Не разрешать удаление
Один из способов уменьшения несогласованности в системе мог бы заключаться
в том, чтобы просто не позволять удалять записи в службе ’’Каталог”. Если в суще­
ствующей системе удаление товарной позиции было сродни обеспечению недос­
тупности товара для продажи или чему-то подобному, то мы могли бы просто им­
плементировать возможность ’’мягкого” удаления. Это можно сделать, например,
с помощью столбца статуса, помечая данную строку как недоступную или, воз­
можно, даже перенося строку в выделенную ’’кладбищенскую” таблицу14. В такой
ситуации запись об альбоме по-прежнему может запрашиваться службой ’’Финансы”.

И как же тогда обрабатывать удаление?
В сущности, мы создали режим сбоя, который не мог существовать в нашей моно­
литной системе. Разглядывая пути решения этого вопроса, мы должны учитывать
потребности наших пользователей, поскольку разные решения могут влиять на на­
ших пользователей по-разному. Выбор правильного решения здесь требует пони­
мания вашего конкретного контекста.
Лично я бы в этой конкретной ситуации, скорее всего, решил это двумя путями: не
позволяя удалять информацию об ’’Альбоме” в ’’Каталоге” и обеспечивая, чтобы
службы ’’Финансы” занималась недостающей записью. Вы можете утверждать, что
если запись нельзя удалить из службы ’’Каталог”, то поиск из ’’Финансов” никогда
не был бы безуспешным. Однако существует вероятность того, что в результате
повреждения служба ’’Каталог” будет восстановлена в более раннее состояние,
означающее, что запись, которую мы ищем, больше не существует. В этой ситуа­
ции я бы не хотел, чтобы служба ’’Финансы” рухнула. Этот набор обстоятельств

14 Поддержка "исторических" данных в реляционной базе данных, такой, как эта, усложняется, в осо­
бенности если вам нужно программно воссоздавать старые версии ваших сущностей. Если у вас стро­
гие требования в этой области, то было бы полезным разведывание источников событий как альтерна­
тивного способа поддержания состояния.

Декомпозиция базы данных

|

197

выглядит маловероятным, но я всегда ищу возможности усиления отказоустойчи­
вости, и подумайте о том, что произойдет, если вызов не сработает; изящное ула­
живание этой ситуации в службе ’’Финансы” выглядит довольно легким исправле­
нием.

Где его использовать
Когда вы начинаете думать об эффективном разрыве связей по внешнему ключу,
одна из первых мер, которую вам нужно обеспечить, — это не разъединить две ве­
щи, которые на самом деле хотят быть единым целым. Если вы беспокоитесь о том,
что разъединяете агрегат, то сделайте паузу и пересмотрите свое решение. В случае
’’Приходно-расходного регистра” и ’’Альбомов” здесь кажется ясно, что у нас два
отдельных агрегата со связью между ними. Но возьмем другой случай: таблицу
’’Заказ” и много ассоциированных строк в таблице "Строки заказа”, содержащих
сведения о заказанных товарных позициях. Если мы выделим ’’Строки заказа” в от­
дельную службу, то нам придется подумать о вопросах целостности данных. На
самом деле строки заказа являются частью самого заказа. Следовательно, нам сле­
дует видеть их как единое целое, и если мы хотим перенести их из монолита, то их
необходимо переносить вместе.
Иногда, беря более крупный ’’кусок” из монолитной схемы, вы будете в состоянии
перенести с собой обе стороны связи по внешнему ключу, что намного упрощает
вашу жизнь!

Пример: совместные статические данные
Статические справочные данные (которые меняются нечасто, но, как правило,
имеют критически важный характер) приводят к некоторым интересным трудно­
стям, и я видел несколько подходов к управлению ими. Чаще всего, они проявляют
себя в базах данных. Я встречал, возможно, столько же кодов стран, которые хра­
нятся в базах данных (показано на рис. 4.39), сколько я написал своих собственных
классов string utils для проектов на Java.

Рис. 4.39. Коды стран в базе данных

198

|

Глава 4

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

Шаблон:
"Дублировать статические справочные данные"
Почему бы просто не предоставить каждой службе свою собственную копию дан­
ных, как показано на рис. 4.40? Вероятно, у многих из вас от неожиданности это
вызовет резкий вдох. Дублировать данные? Я сошел с ума? Послушайте! Все не так
безумно, как вы думаете.

Рис. 4.40. Каждая служба имеет свою собственную схему "Коды стран"

Обеспокоенности, связанные с дублированием данных, как правило, сводятся
к двум вещам. Во-первых, каждый раз, когда мне нужно изменить данные, я дол­
жен делать это в нескольких местах. Но как часто в описываемой ситуации данные
меняются? Последний раз, когда страна была создана и официально признана, было
в 2011 году, с появлением Южного Судана (короткий код которого, SSD). Поэтому
я не думаю, что тут есть, о чем волноваться, верно? Больше беспокоит то, что про­
изойдет, если данные будут несогласованными? Например, служба ’’Финансы” зна­
ет, что Южный Судан— это страна, но необъяснимым образом служба ’’Склад”
живет в прошлом и ничего о нем не знает.
Вопрос о том, вызывает или нет несогласованность затруднения, сводится к вари­
анту использования данных. В рассматриваемом примере учтите, что ’’Склад” ис­
пользует данные кодов стран для регистрации места производства наших компактдисков. Оказывается, что у нас на складе нет компакт-дисков производства Южно­
го Судана, поэтому тот факт, что мы не располагаем этими данными, не влечет ни­

Декомпозиция базы данных

|

199

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

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

Где его использовать
Указанный шаблон следует использовать лишь изредка, и вы должны предпочесть
ему некоторые варианты, которые мы рассмотрим позже. Он иногда полезен для
крупных объемов данных, когда не обязательно, чтобы все службы видели один и
тот же набор данных. Хорошим вариантом будет что-то вроде файлов почтовых
индексов в Великобритании, где вы периодически получаете обновления отобра­
жений из почтовых индексов в адреса. Это довольно крупный набор данных,
управлять которым в кодовой форме, вероятно, будет болезненно. Если вы хотите
присоединиться к этим данным напрямую, то целесообразно выбрать указанный
вариант, но я буду честен и скажу, что не помню, чтобы я когда-либо делал это сам!

Шаблон:
"Выделенная схема справочных данных"
Если вам действительно нужен один источник истины для кодов стран, то вы мо­
жете перенести эти данные в выделенную схему, возможно, отложенную в сторону
для всех статических справочных данных, как мы видим на рис. 4.41.

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

|

Гпава 4

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

Рис. 4.41. Использование выделенной совместной схемы для справочных данных

Наличие данных в схеме открывает возможность их использования службами
в рамках запросов на соединение к своим собственным локальным данным. Однако
для этого вам, вероятно, потребуется обеспечить, чтобы схемы были расположены
на одном и том же опорном ядре СУБД. Это добавляет некоторую сложность с точ­
ки зрения отображения логического ’’мира” в физический, игнорируя потенциаль­
ные проблемы с единственной точкой сбоя.

Где его использовать
Указанный вариант имеет много достоинств. Мы избегаем опасений, связанных
с дублированием, и формат данных вряд ли изменится, поэтому некоторые из наших
возможных опасений смягчаются. Этот подход допустим для крупных объемов
данных или для варианта перекрестно-схемных соединений. Просто помните, что
любые изменения формата схемы, скорее всего, значительно повлияют на много­
численные службы.

Шаблон:
"Библиотека статических справочных данных"
Если присмотреться, то в наших данных кодов стран не так много записей. Из
стандартного ISO-листинга мы видим, что в нем представлено только 249 стран15.

15 Для вас, поклонников ISO, речь идет об ISO 3166-1!.

Декомпозиция базы данных

|

201

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

Конечно, мы бы предпочли не дублировать данные, если нам это не нужно, а это
приводит нас к тому, чтобы подумать о размещении данных в библиотеке, которая
будет статически связана с любыми службами, желающими получить эти данные.
Stitch Fix, американский ритейлер модной одежды, часто использует такие совме­
стные библиотеки для хранения статических справочных данных.
Рэнди Шоуп (Randy Shoup), бывший вице-президент по инженерным вопросам в
Stitch Fix, высказался о том, что наиболее благоприятной зоной для этого метода
были малые по объему типы данных, которые изменялись нечасто или вообще не
менялись (и если они изменялись, то у вас было много предварительных предупре­
ждений об изменении). Наглядный пример — классические обозначения размеров
одежды: XS, S, М, L, XL для универсальных размеров или измерений внутреннего
шва для брюк.
В нашем случае мы определяем отображения кодов стран в перечислимом типе
Country и укомплектовываем их в библиотеку для использования в наших службах,
как показано на рис. 4.42.

Рис. 4.42. Хранение справочных данных в библиотеке,
которую можно использовать между службами совместно

Это решение является изящным, но оно не лишено недостатков. Очевидно, что если
у нас есть смесь стеков технологий, то мы не сможем использовать одну совмест­
ную библиотеку. Кроме того, помните ’’золотое” правило микрослужб? Мы должны
обеспечивать, чтобы наши микрослужбы развертывались независимо. Если бы нам
потребовалось обновить библиотеку кодов стран и все службы должны были не­
медленно получить новые данные, то нам пришлось бы переразвернуть все службы
в момент, когда новая библиотека будет доступна. Это классический командно­

202

|

Гпава 4

строевой релиз16, и именно такой ситуации мы пытаемся избежать с помощью
архитектур на основе микрослужб.
На практике, если нам нужно, чтобы одни и те же данные были доступны везде, то
поможет надлежащее уведомление об изменении. Примером, который привел Рэн­
ди, была потребность добавить новый цвет в один из наборов данных Stitch Fix.
Это изменение необходимо было развернуть для всех служб, которые использовали
этот тип данных, но они имели значительное упредительное время на то, чтобы все
группы забрали последнюю версию. Если вы возьмете пример кодов стран, опятьтаки, у нас, вероятно, будет много предварительных сведений о необходимости до­
бавить новую страну. Например, Южный Судан стал независимым государством
в июле 2011 года после референдума, проведенного шестью месяцами ранее, давая
нам много времени на то, чтобы осуществить наши изменения. Новые страны редко
создаются по прихоти!
Если ваши микрослужбы используют совместные библиотеки, то помните, что вы
должны смириться с тем, что у вас в производстве могут быть развернуты разные
версии библиотеки!

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

Рис. 4.43. Различия между совместными библиотеками справочных данных могут вызвать затруднения

16 Командно-строевой релиз (lock-step release) в сфере программно-информационного обеспечения
означает строительство отказоустойчивых систем путем обеспечения избыточности, когда выполня­
ется один и тот же набор операций в одно и то же время параллельно. Образно обозначает стандарт­
ный метод или процедуру, которой придерживаются бездумно или которая сводит к минимуму инди­
видуальность. Термин lock-step взят из армейского лексикона, где он означает движение строевым
шагом, слаженно в ногу — Пер.

Декомпозиция базы данных

|

203

В простом варианте этого шаблона затрагиваемые данные хранятся в конфигураци­
онном файле, возможно, в стандартном файле свойств или, если требуется, в более
структурированном формате JSON.

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

Шаблон:
"Служба статических справочных данных"
У меня есть подозрения, что вы понимаете, куда это все клонится. Эта книга по­
священа созданию микрослужб, так почему бы не подумать о создании выделенной
службы только для кодов стран, как показано на рис. 4.44?

Рис. 4.44. Раздача кодов стран из выделенной службы

Я прокручивал такой сценарий с группами по всему миру, и он имеет тенденцию
делить аудиторию пополам. Некоторые люди сразу же думают: "Он сработает!".
Однако большая часть группы, как правило, начинает качать головой и говорить
что-то вроде: "Он выглядит безумно!". Копая глубже, мы добираемся до сути их
беспокойства: работа и потенциальная сложность им кажется значительной, а вы­
года— небольшой. При этом слово "перебор" возникает совсем нередко!
Поэтому давайте разведаем шаблон чуть-чуть поглубже. Когда я беседую с людьми
и пытаюсь понять, почему некоторые относятся к этой идее хорошо, а другие —
нет, то в типичной ситуации это сводится к нескольким вещам. Сотрудники, кото­
рые работают в среде, где создание и управление микрослужбами находится на
низком уровне, этот вариант рассматривают гораздо чаще. С другой стороны, если
для создания новой службы, даже такой простой, как эта, требуются дни или даже
недели работы, то люди, понятно, будут от создания такой службы отнекиваться.

204

|

Гпава 4

Бывший мой коллега и соавтор в издательстве O’Reilly Киф Моррис (Kief Morris)17
рассказал мне о своем опыте в проекте для крупного международного банка, бази­
рующегося в Великобритании, где потребовался почти год на то, чтобы получить
одобрение на первый релиз программно-информационного обеспечения. Прежде
чем что-либо могло выйти в ’’прямой эфир”, необходимо было провести консульта­
ции более чем с 10 группами внутри банка, причем по всем вопросам, начиная
с получения подписанных проектов и заканчивая подготовкой машин к работе по
развертыванию. К сожалению, такой опыт далеко не редкость в крупных организа­
циях.
В организациях, где развертывание нового софта требует много ручной работы,
одобрений и, возможно, даже необходимости приобретения и настройки нового
аппаратного обеспечения, стоимость создания служб велика. Следовательно, в та­
кой среде мне следует быть очень избирательным в создании новых служб — они
должны приносить большую добавочную ценность, оправдывая дополнительную
работу. При этом создание чего-то вроде кодов стран может оказаться неоправдан­
ным. С другой стороны, если бы я мог раскручивать ’’заготовку” службы и пускать
ее в производство в течение дня или меньше, а все остальное она делала бы за меня,
то я бы с большей вероятностью рассматривал этот вариант как жизнеспособный.
Или даже лучше, служба ’’Кодов стран” будет отлично подходить для чего-то вроде
платформы ”функция-как-служба”, такой, как облачные функции Azure или AWS
Lambda. Более низкая операционная стоимость для функций привлекательна, и они
отлично подходят для простых служб, таких, как служба ’’Кодов стран”.

Еще одна упомянутая обеспокоенность заключается в том, что, добавляя службу
для кодов стран, мы будем привносить еще одну сетевую зависимость, которая по­
влияет на задержку. Я считаю, что этот подход не будет хуже, а, может, окажется
даже быстрее, чем наличие выделенной базы данных для этой информации. Поче­
му? Дело в том, что, как мы уже установили, в этом наборе данных всего 249 запи­
сей. Служба ’’Кодов стран” сможет легко хранить их в памяти и раздавать напря­
мую. Наша служба ’’Кодов стран”, скорее всего, будет просто хранить эти записи
в коде, без ’’выпечки” хранилища данных.

Эти данные, конечно, также могут агрессивно кэшироваться на стороне клиента.
В конце концов, мы не часто добавляем сюда новые записи! Мы могли бы также
подумать об использовании событий для информирования пользователей об изме­
нении этих данных, как показано на рис. 4.45. Когда данные изменяются, заинтере­
сованные потребители предупреждаются с помощью событий и обновляют свои
локальные кэши. Я подозреваю, что в этом сценарии традиционный клиентский
кэш на основе TTL, вероятно, будет достаточно хорош, учитывая низкую частоту
изменений, и я много лет назад с большим эффектом применил аналогичный под­
ход для службы общего назначения ’’Справочных данных”.

17 Киф написал книгу "Инфраструктура как код: управление серверами в облаке (Infrastructure as Code:
Managing Servers in the Cloud, Sebastopol: O'Reilly, 2016).

Декомпозиция базы данных

|

205

Рис. 4.45. Запуск событий обновления, позволяющих потребителям обновлять локальные кэши

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

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

Что бы я сделал?
Я снова надавал вам кучу вариантов. И как же поступить? Наверное, я не могу веч­
но ’’сидеть на заборе”, так что говорю, как есть. Если считать, что нам не нужно
постоянно обеспечивать согласованность кодов стран во всех службах, то я, скорее
всего, сохраню эту информацию в совместной библиотеке. Для такого рода данных
это, по-видимому, имеет гораздо больший смысл, чем дублирование этих данных
в схемах локальных служб, поскольку данные просты по своей природе и невелики
по объему (коды стран, размеры одежды и т. п.). Более сложные справочные дан­
ные или более крупные их объемы, возможно, подсказали бы мне о том, что следу­
ет поместить их в базу данных, локальную для каждой службы.
Если данные должны быть согласованными между службами, я захотел бы создать
выделенную службу (или, возможно, раздавать эти данные в рамках более мас­
штабной статической справочной службы).

206

|

Гпава 4

Я, скорее всего, прибегну к выделенной схеме для такого рода данных только в том
случае, если будет сложно оправдать работу по созданию новой службы.
В предыдущих примерах мы рассмотрели несколько рефакторизаций баз данных,
которые помогают выделять ваши схемы. Для более детального обсуждения дан­
ного вопроса вы, возможно, захотите взглянуть на книгу "Рефакторизация баз дан­
ных Скотта Дж. Амблера и Прамод Ж. Садаладжа (Refactoring Databases, Scott
J. Ambler, Pramod J. Sadalage, Addison-Wesley).

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

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

Прежде чем мы разведаем пути решения этой проблемы, давайте кратко взглянем
на то, что дает нам обычная транзакция в базах данных.

ACID-транзакции
В типичной ситуации, когда упоминают транзакции в базах данных, обычно говорят
о транзакциях ACID. ACID — это аббревиатура, обозначающая ключевые свойства
транзакций в базах данных, которые приводят к созданию системы, на которую мы
можем положиться в обеспечении долговечности и согласованности хранения на­
ших данных. ACID означает атомарность (atomicity), согласованность (consistency),
изоляцию (isolation) и долговечность (durability), и вот что эти свойства нам дают:
♦ Атомарность— обеспечивает, чтобы все операции, завершаемые в рамках
транзакции, либо все завершались успешно, либо все завершались безуспешно.
Если какое-либо из изменений, которые мы пытаемся внести, по какой-то при­
чине не срабатывает, то вся операция прерывается, и возникает ситуация, будто
никаких изменений никогда не было сделано.
♦ Согласованность — при внесении изменений в базу данных мы обеспечиваем,
чтобы она оставалась в допустимом, согласованном состоянии.

♦ Изоляция — позволяет нескольким транзакциям работать одновременно без ка­
кого-либо вмешательства. Это достигается путем обеспечения ’’невидимости”
любых промежуточных изменений состояния, произведенных в ходе одной
транзакции, для других транзакций.
Декомпозиция базы данных

|

207

♦ Долговечность — обеспечивает, чтобы после завершения транзакции мы были
уверены, что данные не будут потеряны в случае системного сбоя.

Стоит отметить, что не все базы данных предоставляют транзакции ACID. Все ре­
ляционные системы баз данных, которые я когда-либо использовал, их предостав­
ляют, как и многие из новых баз данных NoSQL, таких, как Neo4j. MongoDB в те­
чение многих лет поддерживала транзакции ACID только относительно одного до­
кумента, что создает трудности, если вы хотите выполнить атомарное обновление
более чем одного документа18.
Эта книга не предназначена для подробного, глубокого погружения в упомянутые
понятия, и ради краткости я, конечно же, упростил некоторые из этих описаний.
Для тех из вас, кто хотел бы разведать эти концепции глубже, я рекомендую книгу
’’Дизайн приложений с интенсивным использованием данных” (Designing DataIntensive Applications)19. В дальнейшем мы будем в основном касаться атомарности.
Это не значит, что другие свойства нам не важны, но атомарность тяготеет к тому,
чтобы быть первой трудностью, с которой мы сталкиваемся при разложении тран­
закционных границ.

По-прежнему ACID, но не хватает атомарности?
Я хочу сразу прояснить, что мы по-прежнему можем использовать транзакции
в стиле ACID, когда разбиваем базы данных, но объем этих транзакций уменьшает­
ся, как и их полезность. Рассмотрим рис. 4.46. Предположим, мы отслеживаем про­
цесс, связанный с подключением нового клиента к нашей системе. Мы подошли
к концу процесса, который предусматривает изменение статуса клиента с ОЖИДА­
ЮЩЕГО на ВЕРИФИЦИРОВАННЫЙ. Поскольку регистрация теперь завершена,
мы также хотим удалить соответствующую строку из таблицы ’’Ожидающие реги­
страции”. С одной базой данных это делается в рамках одной транзакции ACID —
либо обе новые строки записываются, либо ни одна из них не записывается.
Сравните это с рис. 4.47. Мы делаем точно такие же изменения, но теперь каждое
из них вносится в разную базу данных. Это означает, что существует две транзак­
ции, каждая из которых может сработать либо не сработать независимо от другой.

Конечно, мы могли бы задать последовательность этих двух транзакций, удаляя
строку из таблицы ’’Ожидающие регистрации”, только если есть возможность из­
менить строку в таблице ’’Клиенты”. Но нам все равно придется рассуждать о том,
что делать, если затем удаление из таблицы ’’Ожидающие регистрации” не сработа­
ло — всю логику нам пришлось бы имплементировать самостоятельно. Обеспече­
ние возможности переупорядочить шаги для учета этих вариантов — действитель­
но полезная идея (к которой мы вернемся, когда займемся разведыванием саг). Но

18 Теперь с поддержкой мультидокументных транзакций ACID, которая была выпущена в рамках
Mongo 4.0, ситуация изменилась. Я сам эту особенность Mongo не использовал; я просто знаю, что
она существует!

19 См. Мартин Клеппманн "Дизайн приложений с интенсивным использованием данных" (Martin Kleppmann, Designing Data-Intensive Applications, Sebastopol, O'Reilly Media, Inc., 2017).

208

|

Глава 4

Рис. 4.46. Обновление двух таблиц в области действия одной транзакции ACID

Рис. 4.47. Изменения, вносимые как в "Счет-фактуру", так и в "Заказ",

теперь делаются в рамках двух разных транзакций

Декомпозиция базы данных

|

209

в принципе, разложив эту операцию на две отдельные транзакции, мы должны при­
знать, что гарантированная атомарность операции в целом потеряна.

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

Двухфазные фиксации
Алгоритм двухфазной фиксации (иногда сокращенно 2РС от англ, two-phase
commit) часто предоставляет нам возможность вносить транзакционные изменения
в распределенную систему, где несколько отдельных процессов нуждаются в об­
новлении в рамках совокупной операции. Я хочу, чтобы вы знали заранее, что
двухфазная фиксация имеет ограничения, которые мы в дальнейшем рассмотрим.
Распределенные транзакции и, в частности, двухфазные фиксации часто выдвига­
ются группами, переходящими на архитектуры, основанные на микрослужбах, как
способ решения трудностей, с которыми они сталкиваются. Но, как мы увидим, они
не решат ваши проблемы и принесут еще больше путаницы в вашу систему.
Указанный алгоритм разбит на две фазы (отсюда и название ’’двухфазная фикса­
ция”): фаза голосования и фаза фиксации. Во время фазы голосования центральный
координатор контактирует со всеми работниками, которые участвуют в транзакции,
и запрашивает подтверждение относительно того, можно или нет сделать какоелибо изменение состояния. На рис. 4.48 мы видим два запроса: один на изменение
статуса клиента на ВЕРИФИЦИРОВАНО, другой на удаление строки из нашей
таблицы ’’Ожидающие регистрации”. Если все работники согласны с тем, что изме­
нение состояния, которое они запрашивают, может произойти, то алгоритм перехо­
дит к следующей фазе. Если кто-либо из работников говорит, что изменение про­
изойти не может, возможно, потому, что запрошенное изменение состояния нару­
шает какое-то локальное условие, то вся операция прерывается.

Важно подчеркнуть, что изменение не вступает в силу сразу после того, как работ­
ник сообщает, что он может внести изменения. Вместо этого работник гарантирует,
что он сможет сделать это изменение в какой-то момент в будущем. Как работник
может дать такую гарантию? Например, на рис. 4.48 работник А сказал, что он бу­
дет способен изменить состояние строки в таблице ’’Клиенты” для обновления ста­
туса конкретного клиента до ВЕРИФИЦИРОВАНО. Что делать, если другая опера­
ция в какой-то более поздний момент удаляет строку или вносит другое меньшее
изменение, которое, тем не менее, означает, что изменение на ВЕРИФИЦИРОВАНО
позже является недопустимым? Для того чтобы гарантировать возможность после­
дующего изменения, работнику Л, вероятно, придется поставить эту запись ”на за­
мок”, чтобы такое изменение не могло произойти.
210

|

Глава 4

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

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

Рис. 4.49. В фазе фиксации двухфазной фиксации изменения применяются фактически

Декомпозиция базы данных

|

211

Важно отметить, что в такой системе мы никоим образом не можем гарантировать,
что эти фиксации будут происходить в одно и то же время. Координатор должен
направить запрос на фиксацию всем участникам, и это сообщение может быть по­
лучено и обработано в разное время. Это означает, что мы будем видеть изменения,
внесенные в работнике Л, но еще не видеть изменения в работнике В, если обеспе­
чим возможность просматривать состояния этих работников вне координатора
транзакции. Чем больше задержка между координатором и чем медленнее работни­
ки обрабатывают отклик, тем шире будет это окно несогласованности. Возвращаясь
к нашему определению термина ACID, изоляция обеспечивает, чтобы мы не видели
промежуточных состояний во время транзакции. Но при двухфазной фиксации мы
ее потеряли.
Когда работают двухфазные фиксации, в своей основе они очень часто просто ко­
ординируют распределенные ’’замки”. Работникам нужно ’’запереть” доступ к ло­
кальным ресурсам для обеспечения возможности фиксации во второй фазе. Управ­
лять ’’замками” и предотвращать ’’тупики” в однопроцессной системе — работа не
из веселых. Теперь представьте себе трудности координирования ’’замков” между
многочисленными участниками. Это не очень приятно.

С двухфазными фиксациями ассоциирована масса режимов сбоя, которые у нас нет
времени разведывать. Возьмем проблему, когда работник голосует за продолжение
транзакции, но затем не откликается на запрос о фиксации. Что тогда нам делать?
Одни из режимов сбоя будут улажены автоматически, но другие оставят систему
в таком состоянии, что придется расшивать вещи вручную.
Чем больше участников и чем значительнее задержка у вас в системе, тем больше
затруднений будет иметь двухфазная фиксация. Они будут очевидным способом
’’вбрызнуть” в вашу систему огромные объемы задержек, в особенности если мас­
штаб запирания на ’’замок” большой или длительность транзакции велика. Именно
по этой причине двухфазные фиксации в типичной ситуации используются только
для очень короткоживущих операций. Чем дольше длится операция, тем дольше
у вас ресурсы заперты!

Распределенные транзакции — просто скажи "нет"
По всем изложенным ранее причинам я настоятельно рекомендую избегать распре­
деленных транзакций, таких, как двухфазная фиксация, для координации измене­
ний состояния в ваших микрослужбах. Тогда что еще вы можете сделать?
Скажем так, первый вариант — вообще не разбивать данные. Если у вас есть фраг­
менты состояния, которыми вы хотите управлять по-настоящему атомарным и со­
гласованным способом, и вы не можете решить вопрос, как разумно получить эти
характеристики без транзакции в стиле ACID, то оставьте это состояние в одной
базе данных и сохраните функциональность, которая управляет этим состоянием
в одной службе (или в вашем монолите). Если вы находитесь в процессе выяснения
того, где разбить ваш монолит, и определения того, какие декомпозиции являются
легкими (или трудными), то вы вполне можете решить, что заниматься разбиением
данных, которые в настоящее время управляются в транзакции, просто слишком

212

|

Глава 4

сложно прямо сейчас. Поработайте над каким-нибудь другим участком системы и
вернитесь к этому вопросу позже.
Но что произойдет, если вам действительно нужно разбить данные, но вы не хотите
иметь все тяготы управления распределенными транзакциями? Как выполнять опе­
рации в многочисленных службах, но избежать запирания на ’’замок”? Что, если
операция займет минуты, дни или даже месяцы? В подобных случаях мы можем
подумать об альтернативном подходе: о сагах.

Саги
В отличие от двухфазной фиксации, сага (saga) по своему дизайну представляет
собой алгоритм, который координирует многочисленные изменения в состоянии,
но позволяет избегать необходимости запирания ресурсов на ’’замок” в течение
длительного периода времени. Мы делаем это путем моделирования шагов, при­
влекаемых в качестве дискретных действий, которые исполняются независимо. Это
сопровождается добавочной выгодой, заставляя нас явно моделировать наши бизнес-процессы, что может дать значительные выгоды.
Стержневая идея, впервые изложенная Гектором Гарсиа-Молиной (Hector GarciaMolina) и Кеннетом Салемом (Kenneth Salem)20, отражала трудности, связанные
с тем, как лучше всего регулировать операции, которые они называли долгоживу­
щими транзакциями (long lived transaction, LLT). Подобные транзакции могут за­
нимать много времени (минуты, часы или, возможно, даже дни) и в рамках этого
процесса требуют, чтобы в базу данных вносились изменения.
Если бы вы непосредственно отображали долгоживущую транзакцию (LLT)
в обычную транзакцию базы данных, то одна транзакция охватывала бы весь жиз­
ненный цикл LLT. Это привело бы к запиранию нескольких строк или даже полных
таблиц на длительные сроки во время выполнения LLT, вызывая значительные за­
труднения, если другие процессы пытаются прочитать или модифицировать запер­
тые ресурсы.
Вместо этого авторы статьи предлагают разбить LLT на последовательность тран­
закций, каждая из которых регулируется независимо. Идея заключается в том, что
продолжительность каждой ”под-транзакции” будет меньшей и будет модифициро­
вана только часть данных, затронутых всей LLT-транзакцией. Как результат,
в опорной базе данных окажется гораздо меньше конкуренции, т. к. объем и про­
должительность ’’замков” значительно уменьшаются.

Первоначально саги предусматривались в качестве механизма, помогающего LLTтранзакциям действовать в отношении одной базы данных, однако указанная мо­
дель работает так же хорошо для координирования изменений в многочисленных
службах. Мы можем разбить один бизнес-процесс на множество вызовов сотруд­
ничающих служб в рамках одной саги.
20 См. Гектор Гарсия-Молина и Кеннет Салем "Саги” (Sagas, Hector Garcia-Molina, Kenneth Salem,
в АСМ Sigmod Record 16, № 3 (1987): 249-259.

Декомпозиция базы данных

|

213

Прежде чем мы пойдем дальше, вы должны понять, что сага не дает нам атомар­
ности в терминах АСЮ, к которой мы привыкли с обычной транзакцией базы дан­
ных. Поскольку мы разбиваем LLT на отдельные транзакции, у нас нет атомарно­
сти на уровне самой саги. У нас есть атомарность для каждой "под-транзакции"
внутри LLT, поскольку каждая из них может относиться к АСЮ-транзакционному
изменению, если это необходимо. Но вот что сага нам дает, так это достаточно
информации для выяснения состояния, в котором она находится. Ответ на вопрос,
как обращаться с последствиями этого, находится полностью в наших руках.

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

Рис. 4.50. Пример потока исполнения заказа наряду со службами,
ответственными за проведение операции

Здесь процесс исполнения заказа представлен как одна сага, причем каждый шаг
в этом потоке представляет собой операцию, которая выполняется другой службой.
В каждой службе любое изменение состояния регулируется в рамках локальной
ACID-транзакции. Например, когда мы проверяем и резервируем запасы с помо­
щью службы ’’Склад”, эта служба, возможно, создаст строку внутри своей локаль­
ной таблицы ’’Резервирование”, регистрирующую резервирование, и это изменение
будет регулироваться внутри обычной транзакции.
214

|

Глава 4

Режимы сбоя саги
Когда сага разбивается на отдельные транзакции, нам нужно подумать о том, как
работать со сбоем или, конкретнее, как восстанавливаться, когда происходит сбой.
В оригинальной статье "Сага" описаны два типа: обратное и прямое восстанов­
ление.

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

Откаты в саге
В случае ACID-транзакции откат происходит перед фиксацией. После отката си­
туация такова, будто ничего и не произошло: изменение, которое мы пытались вне­
сти, не состоялось. Однако с сагой у нас вовлечены многочисленные транзакции,
и некоторые из них, возможно, уже зафиксированы до того, как мы решим откатить
всю операцию. Как же откатить транзакции после того, как они уже были зафикси­
рованы?
Давайте вернемся к нашему примеру с обработкой заказа, как показано на рис. 4.50.
Возьмем потенциальный режим сбоя. Мы дошли до попытки упаковать товарную
позицию и обнаружили, что указанная товарная позиция на складе не найдена, как
показано на рис. 4.51. Наша система думает, что товарная позиция существует, но
ее просто нет на полке!

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

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

|

215

Рис. 4.51. Мы попытались упаковать нашу товарную позицию, но не можем найти ее на складе

Стоит отметить тот факт, что компенсирующие транзакции не обладают точно та­
ким же поведением, как и обычный откат базы данных. Откат базы данных проис­
ходит перед фиксацией; и после отката возникает состояние, будто бы транзакция
никогда не происходила. В этой ситуации, конечно, такие транзакции действитель­
но имели место. Мы создаем новую транзакцию, которая отменяет изменения, вне­
сенные исходной транзакцией, но мы не можем откатить назад время и сделать так,
как будто исходная транзакция не произошла.
Поскольку не всегда есть возможность откатывать транзакцию назад ’’чисто”, мы
говорим, что компенсирующие транзакции являются семантическими откатами.
Мы не можем все всегда подчищать, но мы делаем достаточно для контекста нашей
саги. Например, один из наших шагов, возможно, предусматривал отправку элек­
тронной почты клиенту с сообщением о том, что его заказ уже в пути. Если мы ре­
шим откатить его назад, то вы не сможете вернуть отправленное электронное
письмо!21 Вместо этого ваша компенсирующая транзакция может активировать от­
правку клиенту второго электронного письма с сообщением о том, что возникла
проблема с заказом и он был отменен.

21 Вы действительно не сможете. Я пытался!

216

|

Глава 4

Рис. 4.52. Запуск отката всей саги

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

Переупорядочивание шагов для уменьшения откатов
На рис. 4.52 мы могли бы сделать наши вероятные сценарии отката несколько про­
ще, переупорядочив шаги. Пример несложного изменения — присуждение баллов
только тогда, когда заказ был фактически отправлен, как показано на рис. 4.53.
И нам не придется беспокоиться о том, чтобы этот этап был откатан назад, если
у нас возникнут проблемы при попытке упаковать и отправить заказ. Иногда вы
можете упростить операции отката, просто подрегулировав то, как этот процесс
выполняется. Проталкивая вперед те шаги, которые с наибольшей вероятностью не
сработают, и приводя процесс к неуспеху раньше, вы избегаете необходимости
запускать более поздние компенсирующие транзакции, поскольку эти шаги даже
вообще не были инициированы.
Если разместить подобные изменения, то ваша жизнь станет намного проще, даже
отпадет необходимость создавать компенсирующие транзакции для некоторых ша­
гов. Это будет особенно важно, если имплементация компенсирующей транзакции

Декомпозиция базы данных

|

217

Рис. 4.53. Перенос шагов на более поздние участки в саге
уменьшает объемы отката назад в случае сбоя

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

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

218

|

Глава 4

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

Оркестрированные саги
Оркестрированные саги (orchestrated saga) используют центрального координатора
(то, что мы далее будем называть оркестровщиком) для определения порядка ис­
полнения и активации любого необходимого компенсирующего действия. Вы мо­
жете думать об оркестрированных сагах как о командно-контрольном подходе:
центральный оркестровщик контролирует, что происходит и когда, и в результате
возникает хорошая степень видимости того, что происходит с любой данной сагой.
Взяв процесс исполнения заказа, показанный на рис. 4.50, давайте посмотрим, как
этот процесс центральной координации будет работать в виде набора сотрудни­
чающих служб, как показано на рис. 4.54.

Здесь наш центральный ’’Обработчик заказов”, играя роль оркестровщика, коорди­
нирует процесс исполнения. Он знает, какие службы необходимы для выполнения

Рис. 4.54. Пример того, как оркестрированная сага используется

для имплементации нашего процесса исполнения заказа

Декомпозиция базы данных

|

219

операции, и решает, когда следует вызывать эти службы. Если вызовы не срабаты­
вают, то он решает, что делать в результате. Эти оркестрированные обработчики,
как правило, интенсивно используют вызовы ’’запрос-отклик” между службами:
’’Обработчик заказов” отправляет запрос в службы (например, ’’Платежный шлюз”)
и ожидает отклика, сообщающего ему об успешности или неуспешности запроса и
предоставляющего результаты запроса.

Чрезвычайно полезно, чтобы наш бизнес-процесс был однозначно смоделирован
внутри ’’Обработчика заказов”. Это позволяет взглянуть на одно место в нашей сис­
теме и понять, как этот процесс предположительно должен работать. В результате
облегчается интеграция новых сотрудников и обмен знаниями о стержневых частях
системы.

Тем не менее здесь следует учесть несколько недостатков. Прежде всего, по своей
природе этот подход является несколько сопряженным. Наш ’’Обработчик заказов”
должен знать обо всех ассоциированных службах, что приводит к более высокой
степени доменной сопряженности (см. главу 7). Хотя она не так уж и плоха, мы все
равно хотели бы свести доменную сопряженность к минимуму, если это возможно.
Здесь нашему ’’Обработчику заказов” нужно знать и контролировать так много ве­
щей, что этой формы сопряженности трудно избежать.
Другая, более тонкая, трудность заключается в том, что логика, которая в иных
случаях должна быть ’’втиснута” в службы, вместо этого может начать поглощаться
оркестровщиком. Если подобное начнет происходить, то вы обнаружите, что ваши
службы становятся ’’анемичными", с малым собственным поведением, просто при­
нимая заказы от оркестровщиков, таких, как ’’Обработчик заказов”. Важно, чтобы
вы по-прежнему рассматривали службы, составляющие эти оркестрированные по­
токи, как сущности, имеющие свое собственное локальное состояние и поведение.
Они отвечают за свои собственные локальные машины состояний.

Если у логики есть место, где она может быть централизована, то она станет цен­
трализованной!

Один из способов избежать чрезмерной централизации с оркестрированными пото­
ками состоит в обеспечении наличия разных служб, выполняющих роль оркестровщика для разных потоков. У вас может быть служба "Обработка заказов”, кото­
рая улаживает размещение заказа, служба "Возвраты” для обеспечения процесса
возврата товаров и уплаченных денег, служба "Прием товаров”, которая улаживает
поступление на склад новых товаров и расстановку их на полках, и т. д. Что-то вро­
де нашей службы "Склад" может использоваться всеми этими оркестровщиками.
Такая модель упрощает поддержание функциональности в самой службе "Склад”,
обеспечивая функциональность во всех этих потоках повторно.

Инструменты моделирования бизнес-процессов?
Инструменты моделирования бизнес-процессов (business process modeling, BPM) су­
ществуют уже много лет. По большому счету, они предназначены для обеспечения
неразработанное возможностью определять потоки бизнес-процессов, часто через ви­
220

|

Гпава 4

зуальные инструменты перетаскивания. Идея заключается в том, что разработчики
создают строительные блоки этих процессов, а затем неразработчики связывают эти
строительные блоки вместе в более крупные процессные потоки. Применение таких
инструментов, похоже, очень хорошо выстраивается как способ имплементации оркестрированных саг, и, действительно, процессная оркестровка — это в значительной
степени главный вариант работы с инструментами ВРМ (или, наоборот, использова­
ние инструментов ВРМ приводит к тому, что вам требуется оркестровка).
С течением времени инструменты ВРМ мне, в конце концов, сильно перестали нра­
виться. Главная причина в том, что центральная высокомерная идея — о том, что не­
разработчики будут определять бизнес-процесс, — на моем опыте почти никогда не
была верной. Инструментарий, предназначенный для неразработчиков, в конечном
итоге используется разработчиками, и у них возникает масса затруднений. Они часто
требуют применения GUI-интерфейсов для изменения потоков, потоки, которые они
создают, с трудом (или вообще не) поддаются версионному контролю, сами потоки
оказываются спланированы без учета тестирования и многое другое.
Если ваши разработчики собираются имплементировать ваши бизнес-процессы, то
пускай они задействуют инструментарий, который они знают и понимают и который
пригоден для их трудовых потоков. В общем случае, это означает просто дать им воз­
можность имплементации этих вещей непосредственно в коде! Если вам нужна
наглядность того, как был имплементирован бизнес-процесс или как он работает, то
гораздо проще спроецировать визуальное представление трудового потока из кода,
чем описывать с помощью визуального представления, как должен работать ваш код.
Предпринимаются меры по созданию более удобных для разработчиков инструментов
ВРМ. Отзывы об этих инструментах от разработчиков различны, но в ряде случаев
они хорошо себя проявили, и приятно видеть, что люди пытаются усовершенствовать
эти каркасы. Если вы чувствуете необходимость разведать эти инструменты дальше,
взгляните на Camunda22 и Zeebe23, оба из которых являются оркестровочными карка­
сами с открытым исходным кодом, предназначенными для разработчиков микрослужб.

Хореографированные саги
Хореографированные саги (choreographed saga) призваны распределять ответствен­
ность за функционирование саги среди нескольких сотрудничающих служб. Если
оркестровка является командно-контрольной, то хореографированные саги пред­
ставляют собой архитектуру по принципу ’’доверяй, но проверяй”. Как мы увидим
в нашем примере на рис. 4.55, хореографированные саги интенсивно используют
события для сотрудничества между службами.
Здесь происходит довольно много, и поэтому стоит разведать тему подробнее.
Прежде всего, эти службы реагируют на получаемые ими события. Концептуально
события транслируются в системе, и заинтересованные стороны могут их получать.
Вы не отправляете события в некую службу; вы просто их запускаете, и службы,
которые заинтересованы в этих событиях, получают их и действуют соответст­
вующим образом. В нашем примере, когда служба ’’Склад” получает первое собы­
тие ’’Заказ размещен”, она знает свою работу, резервируя соответствующий товар и
запуская событие, как только резервирование будет сделано. Если товар не может

22 См. https://camunda.com/.

23 См. https://zeebe.io/.

Декомпозиция базы данных

|

221

Рис. 4.55. Пример хореографированной саги для имплементации исполнения заказа

быть получен, то ’’Складу” потребуется вызвать соответствующее событие (воз­
можно, событие ’’Нехватка товара”), что может привести к прерыванию заказа.
Как правило, для управления надежной трансляцией и доставкой событий вы за­
действуете своего рода брокера сообщений. Существует возможность, что несколь­
ко служб будут реагировать на одно и то же событие, и именно там вы будете ис­
пользовать тему. Стороны, заинтересованные в определенном типе событий, будут
подписываться на определенную тему, не беспокоясь о том, откуда эти события
пришли, и брокер обеспечивает долговечность темы и то, что события на ней
успешно доставляются подписчикам. Например, у нас может быть служба ’’Реко­
мендации”, которая также прослушивает события ’’Заказ размещен” и использует
его для построения базы данных вариантов музыки, которые вам могут понравиться.
В приведенной ранее архитектуре ни одна служба не знает ни о какой другой служ­
бе. Им нужно только знать, что делать, когда получено определенное событие. По
сути, это приводит к гораздо менее сопряженной архитектуре. Поскольку импле­
ментация процесса здесь разлагается и распределяется между четырьмя службами,
мы также избегаем опасений по поводу централизации логики (если у вас нет мес­
та, где логика может быть централизована, то она не будет централизована!).

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

|

Гпава 4

эту картину в своей голове — далеко не прямолинейный процесс, даже с таким
простым бизнес-процессом, как в нашем примере.

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

Один из самых простых способов сделать это — взять проекцию о состоянии саги
из существующей системы, потребляя эмитируемые события. Если мы сгенерируем
уникальный ИД для саги, то сможем поместить его во все события, которые эмити­
руются в рамках этой саги, — это называется ИД корреляции. Тогда мы могли бы
иметь службу, работа которой состоит в том, чтобы просто вакуумировать все эти
события и представлять проекцию о том, в каком состоянии находится каждый за­
каз, и, возможно, программно выполнять действия по урегулированию трудностей
в рамках процесса его исполнения, если другие службы не могут это сделать сами.

Смешивание стилей
Хотя может показаться, что оркестрированные и хореографированные саги диамет­
рально противоположны по виду имплементации, вы можете легко подумать
о смешивании и сочетании указанных моделей. В вашей системе могут иметься не­
кие бизнес-процессы, которые естественнее вписываются в ту или иную модель.
Вы также можете иметь единую сагу, которая сочетает смесь стилей. В варианте
с исполнением заказов, например, внутри контура службы ’’Склад”, во время
управления упаковкой и отправкой пакета мы можем использовать оркестрированный поток, даже если исходный запрос был сделан в рамках более крупной хореографированной саги24.
Если вы все-таки решите смешать стили, то важно, чтобы у вас по-прежнему имел­
ся четкий способ выяснить, что произошло в рамках саги. Без этого понять режимы
сбоя становится сложно, и выполнить восстановление после сбоя трудно.

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

24 Это выходит за рамки данной книги, но Гектор Гарсия-Молина и Кеннет Салем продолжили разве­
дывать вопрос о том, как многочисленные саги могут "вкладываться" для имплементации более слож­
ных процессов. Для знакомства с этой темой поближе см. Гектор Гарсия-Молина и др. "Моделирова­
ние длительных операций как вложенных саг" (Modeling Long-Running Activities as Nested Sagas,
Hector Garcia-Molina et al, Data Engineering 14, No.l, March 1991: 14-18).

Декомпозиция базы данных

|

223

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

Саги против распределенных транзакций
Надеюсь, я уже разложил по полочкам, что распределенные транзакции сопровож­
даются некоторыми значительными трудностями, и я их стараюсь избегать за пре­
делами некоторых очень специфических ситуаций. Пэт Хелланд (Pat Helland), пио­
нер в области распределенных систем, выделяет фундаментальные трудности с им­
плементацией распределенных транзакций для тех видов приложений, которые мы
создаем сегодня25:

”В большинстве систем распределенных транзакций сбой одного узла приводит
к остановке фиксации транзакции. Это, в свою очередь, приводит к тому, что
приложение “заклинивается”. В таких системах чем больше она становится, тем
вероятнее, что система “ляжет”. В пилотировании самолетом, который нуждает­
ся в работе всех своих двигателей, добавление двигателя уменьшает годность
самолета”.
- Пэт Хелланд, Жизнь за пределами распределенных транзакций

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

Более полное обсуждение имплементации оркестровки и хореографии, наряду
с различными деталями имплементации, выходит за рамки этой книги. Данная тема
рассматривается в главе 4 книги ’’Создание микросервисов”, но я также рекомен­
дую книгу ’’Шаблоны интеграции предприятия” для глубокого погружения во мно­
гие аспекты указанной темы26.

25 См. Пэт Хелланд ’’Жизнь за пределами распределенных транзакций" (Life Beyond Distributed Trans­
actions, Pat Helland, acmqueue 14, No. 5).
26 Саги не упоминаются явно ни в одной из книг, но оркестровка и хореография освещены. Хотя я не
могу говорить об опыте авторов книги "Шаблоны интеграции предприятия", лично я не был осведом­
лен о сагах, когда писал книгу "Создание микросервисов".

224

|

Гпава 4

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

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

Декомпозиция базы данных

|

225

ГЛАВА 5

Болезни роста

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

В этой главе я надеюсь дать вам предостаточно информации о тех типах проблем,
с которыми вы столкнетесь. Я не смогу решить их все в этой книге, и многие про­
блемы, которые здесь описаны, более детально изложены в книге ’’Создание мик­
росервисов”, во многом написанной с учетом этих трудностей.
Я также хочу дать рекомендации в отношении того, какие сигналы искать, чтобы
помочь вам опознавать моменты, когда эти вопросы будут нуждаться в решении,
а также дать указание на то, где на вашем пути подобные вопросы, скорее всего,
будут возникать.

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

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

Не думайте о принятии на вооружение микрослужб, как о щелчке выключателя,
думайте об этом, как о повороте наборного диска. Когда вы поворачиваете этот
диск и создаете больше служб, то вы, надо надеяться, будете иметь больше воз­
можностей получить что-то нужное из микрослужб. Но, по мере того как вы пово­
рачиваете этот диск, вы по ходу попадаете в разные болевые точки. И, по мере того
227

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

На рис. 5.1 условно показаны ’’болевые точки”, которые мы рассмотрим далее
в этой главе, основываясь на том, где в вашем ’’выращивании” служб эти трудно­
сти, скорее всего, возникнут. Приведенный анализ далек от научного и в значи­
тельной степени основан на разрозненном опыте, но я по-прежнему считаю, что он
полезен в качестве общего представления.

Рис. 5.1. Обобщенная схема проявления некоторых из "болевых точек"

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

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

228

|

Гпава 5

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

С точки зрения универсального владения кодом Мартин Фаулер ранее выделил
разные типы владения1, и я нахожу, что, вообще говоря, они работают и в контексте
строительства микрослужб. Здесь в первую очередь мы рассматриваем ’’владение”
с точки зрения внесения изменений в код, а не с точки зрения того, кто управляет
развертыванием, поддержкой на первой линии и т. д. Прежде чем мы поговорим
о типах проблем, которые возникают, давайте сначала взглянем на концепции,
очерченные Мартином, и поместим их в контекст архитектуры на основе микро­
служб:
♦ Сильная степень владения кодом — все службы имеют владельцев. Если кто-то
за пределами этой группы владения хочет внести изменения, то он должен пред­
ставить данное изменение владельцам, которые решают, разрешено ли это де­
лать или нет. Использование запроса на включение внесенных изменений для
людей вне группы владения — один из примеров того, как это может регулиро­
ваться.

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

♦ Коллективное владение кодом — никто ничем не владеет, и каждый может из­
менить все, что захочет.

Как эта проблема проявляется?
По мере роста числа служб и разработчиков у вас возникают проблемы с коллек­
тивным владением. Для того чтобы коллективное владение работало, необходим
достаточно хорошо взаимосвязанный коллектив. Такая взаимосвязь позволяет ему
иметь общепринятое совместное понимание того, как выглядит хорошее изменение
и в каком направлении вы хотите воспользоваться конкретной службой с техниче­
ской точки зрения.
Отложив в сторону отдельные случаи, я убедился, что в широком масштабе кол­
лективное владение кодом было для архитектуры на основе микрослужб катастро­
фическим. Одна финансово-технологическая компания, с представителями которой
я беседовал, поделилась историями о небольшой группе, переживавшей быстрый
рост, перейдя с 30—40 разработчиков к более чем 100, но без назначения каких-либо

1 См. http://bit.ly/2n5pSAf.

Болезни роста

|

229

обязанностей разным частям системы или какой-либо концепции владения, кроме
того, что ’’народ знает, что является правильным”.
В результате по мере эволюции системной архитектуры возникло размытое ее ви­
дение и ужасно запутанный ’’распределенный монолит”. Один из разработчиков
назвал свою архитектуру ’’дуршлачной архитектурой”2, потому что она была ис­
пещрена дырами — люди просто-напросто ’’пробивали новую дыру”, когда им за­
благорассудится, выставляя данные наружу или просто делая много двухточечных
вызовов. Реальность такова, что такие трудности легче уладить с помощью моно­
литной системы, но гораздо сложнее с помощью распределенной — стоимость рас­
путывания распределенного монолита намного выше.

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

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

2 Дуршлаг — это миска с большим количеством отверстий, используемая, например, для процежива­
ния макарон.

230

|

Гпава 5

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

Мы думаем о функциональности, которую выставляем наружу другим микрослуж­
бам, в терминах контракта. Речь идет не только о том, чтобы сказать, что ’’вот эти
данные я буду возвращать”. Это также касается определения ожидаемого поведе­
ния вашей службы. Заключили ли вы контракт с вашими потребителями явным об­
разом, или нет— совершенно неважно; он просто существует. Когда вы вносите
изменения в своей службе, вам нужно обеспечить, чтобы вы не нарушали этот кон­
тракт, в противном случае возникнут неприятные производственные проблемы.

Рано или поздно вам придется устранять трудности, причинами которых являются
переломные изменения — либо потому, что вы приняли сознательное решение вне­
сти обратно несовместимое изменение, либо, возможно, потому, что вы внесли ’’не­
винное” изменение, предполагая, что оно повлияет только на вашу локальную
службу, в результате обнаружив, что это нарушило другие службы путями, о кото­
рых вы даже не представляли.

Как эта проблема проявляется?
Худшее проявление этой трудности возникает, когда вы видите перебои в произ­
водстве, вызванные отправкой в ’’прямой эфир” новых микрослужб, которые нару­
шают совместимость с существующими службами. Это признак того, что вы не от­
лавливаете нечаянные нарушения контракта заблаговременно. Подобные трудности
бывают катастрофическими, если у вас не установлен механизм быстрого отката.
Единственный положительный момент, который можно извлечь из этих режимов
сбоя, состоит в том, что они обычно проявляются довольно быстро сразу после ре­
лиза, если только обратно несовместимое изменение не было внесено в часть кон­
тракта с редко используемой службой.
Еще один признак — вы начинаете видеть, как люди пытаются вместе оркестрировать одновременные развертывания многочисленных служб (иногда это именуется
’’командно-строевым” релизом). Это также свидетельствует о попытках управлять
изменениями контракта между клиентом и службой. Нерегулярный командно­
строевой релиз не так уж плох внутри группы, но если он встречается часто, то чтото нужно расследовать.

Когда эта проблема возникает?
Я рассматриваю эту проблему как болезнь роста, с которой группы сталкиваются
на довольно ранней стадии, в особенности когда развитие ’’размазано” по двум и
более группам. Внутри одной группы люди более осведомлены, когда вносят пере­
Болезни роста

|

231

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

Со временем, по мере того как группы становятся более зрелыми, они действуют
аккуратнее при внесении изменений прежде всего во избежание нарушений, а так­
же создают механизмы для заблаговременного отлавливания проблем.

Потенциальные решения
Для управления случаями нарушения контрактов у меня есть набор правил. И они
довольно простые:

1. Не нарушать контракты.
2. См. правило 1.
Ладно, шучу, но только слегка. Вносить переломные изменения в контракты, кото­
рые вы выставляете наружу, — не очень замечательная идея, которая к тому же
служит источником головной боли при их управлении. На самом деле вы хотите
свести их к минимуму, если сможете. Тем не менее вот более реалистичные пра­
вила:

1. Устранять ’’нечаянные” переломные изменения.
2. Хорошенько подумать, прежде чем вносить переломное изменение, — нельзя ли
его избежать?

3. Если нужно внести переломные изменения, то следует давать своим потребите­
лям время на миграцию.

Давайте рассмотрим эти шаги подробнее.

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

3 См. http://bit.ly/2kUxvbq.

232

|

Гпава 5

Вариант, принятый многими людьми по умолчанию, состоит в использовании бессхемных форматов обмена, причем наиболее распространенным примером является
JSON. Хотя для JSON теоретически можно определять явные схемы, они не приме­
няются на практике. Изначально разработчики склонны проклинать ограничения
формальных схем— вынужденные покорпеть над критическими изменениями
в разных службах, они поменяют свое мнение. Также следует отметить, что неко­
торые форматы сериализации с использованием схем улучшают производитель­
ность десериализации данных благодаря формальным типам, об этом тоже стоит
подумать.
Однако структурные нарушения— лишь часть трудности. Вам также следует
учесть семантические нарушения. Если наш метод расчета по-прежнему берет два
целых числа, но последняя версия нашей микрослужбы эти два целых числа умно­
жает, тогда как раньше она просто их складывала, то такое изменение также явля­
ется нарушением контракта. Один из лучших практических способов обнаружить
подобное нарушение — тестирование. Мы вскоре его рассмотрим.

Что бы вы ни делали, самый быстрый выигрыш — сделать результат как можно
более очевидным для разработчиков, когда они вносят изменения во внешний кон­
тракт. Это может означать избегание технологии, которая ’’волшебным” образом
сериализует данные или генерирует схемы из кода, вместо нее предпочитая раскру­
чивать такие вещи вручную. Поверьте — сделать так, чтобы было трудно изменить
контракт со службой, лучше, чем постоянно ударять по потребителям.

Хорошенько подумать,
прежде чем вносить переломные изменения
Если это возможно, отдавайте предпочтение расширяющим изменениям в вашем
контракте со службой. Добавьте новые методы, ресурсы, темы или что-то еще, что
поддерживает новую функциональность, не удаляя старую. Старайтесь найти спо­
собы поддерживать старое и в то же время поддерживать новое. Это будет озна­
чать, что вам придется поддерживать старый код, но эта работа все равно будет
меньше, чем улаживание переломного изменения. Помните, что если вы решите
нарушить контракт, то именно вы и должны уладить последствия данного решения.

Давать потребителям время на миграцию
Как мне было ясно с самого начала, микрослужбы предназначены для независимо­
го развертывания. При внесении изменений в микрослужбу вам нужно иметь воз­
можность развертывать эту микрослужбу в производстве без необходимости раз­
вертывания чего-либо еще. Для того чтобы это работало как надо, вам желательно
изменить контракт со службой так, чтобы существующие потребители не были за­
тронуты — отсюда следует, что вам нужно разрешить потребителям по-прежнему
использовать старый контракт, даже если у вас имеется новый контракт. Затем вам
нужно дать всем потребителям время на то, чтобы изменить свои службы для
миграции на новую версию службы.
Болезни роста

|

233

Я видел два способа, как это делается. Первый— выполнять две версии микро­
службы, как показано на рис. 5.2. Здесь одновременно доступны две сборки служ­
бы "Уведомления", каждая из которых выставляет наружу разные несовместимые
конечные точки, между которыми потребители могут выбирать. Первостепенные
трудности с этим подходом заключаются в том, что для выполнения дополнитель­
ных служб вам нужно иметь добавочную инфраструктуру, вероятно, придется под­
держивать совместимость данных между версиями служб, и потребуется устране­
ние дефектов для всех работающих версий, что неизбежно повлечет за собой ветв­
ление исходного кода. Описанные проблемы несколько смягчаются, если вы даете
сосуществовать двум версиям только короткий период времени, что является един­
ственной ситуацией, где я бы рассматривал этот подход.

Рис. 5.2. Обеспечение сосуществования двух версий одной и той же микрослужбы

для поддержки обратно несовместимых изменений

Способ, который я предпочитаю, состоит в том, чтобы иметь одну работающую
версию вашей микрослужбы, но делать так, чтобы она поддерживала оба контрак­
та, как мы видим на рис. 5.3. Возможно, к примеру, предоставление двух API на
разных портах. Указанный подход усложняет имплементацию микрослужб, но по­
зволяет избежать трудностей предыдущего способа. Я беседовал с сотрудниками

Рис. 5.3. Одна служба, выставляющая наружу дваконтракта

234

|

Гпава 5

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

Конечно, если одна и та же группа улаживает вопросы как с потребителем, так и
с производителем, то вы можете выполнить ’’командно-строевой релиз” и развер­
нуть новые версии как потребителя, так и производителя одновременно. Этот под­
ход не из тех, которые я хотел бы применять часто, но, по крайней мере, внутри
одной группы он упрощает управление релизной координацией — просто не пре­
вращайте его в привычку!
Изменениями внутри группы легче управлять, т. к. вы контролируете обе стороны
уравнения. По мере того как микрослужба, которую вы хотите изменить, использу­
ется все шире, стоимость управления изменением становится больше. В результате
вы более расслаблены по поводу внесения переломных изменений внутри группы,
но нарушение API, который вы выставляете наружу сторонним организациям, ско­
рее всего, будет довольно болезненным.

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

Разберись с этим — быстро!
По мере того как в организациях растет число микрослужб, они в итоге вырабатывают
в целом эффективный способ устранения "нечаянных" переломных изменений и при­
думывают управляемый механизм для работы с целенаправленными изменениями.
Если этого не происходит, то последствия становятся настолько значительными, что
архитектура на основе микрослужб оказывается несостоятельной. Говоря по-другому,
у меня есть сильные подозрения в том, что малые организации, которые базируются
на микрослужбах, не разбирающиеся в этом вопросе, не продержатся достаточно дол­
го, чтобы вырасти в крупные организации.

Отчетность
Вместе с монолитной системой в типичной ситуации у вас имеется монолитная база
данных. Это означает, что заинтересованные стороны, которые хотят анализиро­
вать все данные вместе, что часто предусматривает крупные операции соединения
по всем данным, имеют готовую схему, относительно которой они исполняют свои
отчеты. Они могут исполнять их непосредственно относительно монолитной базы
данных, возможно, относительно реплики для чтения, как показано на рис. 5.4.
В архитектуре на основе микрослужб мы ’’разломали” эту монолитную схему.
В результате потребность в отчетности по всем нашим данным не исчезла, мы про­
сто намного затруднили ситуацию, т. к. теперь наши данные разбросаны по не­
скольким логически изолированным схемам.
Болезни роста

|

235

Рис. 5.4. Отчетность проводится непосредственно на базе данных монолита

Когда эта проблема возникает?
Эта проблема стремится ’’укусить” довольно рано и в обычных условиях приходит
на стадии, когда вы начинаете подумывать о декомпозиции монолитной схемы. На­
до надеяться, что она будет обнаружена до того, как появятся затруднения, но я ви­
дел немало проектов, в которых вплоть до середины проекта группа не понимала,
что архитектурное направление будет создавать страдания для сторон, заинтересо­
ванных в вариантах с использованием отчетности. Слишком часто потребности
в нижестоящей отчетности не рассматриваются заблаговременно, поскольку это
происходит вне сферы нормальной разработки софта и сопровождения системы —
”с глаз долой, из сердца вон”.

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

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

Наиболее прямолинейный подход к решению указанной проблемы — сначала от­
делить потребность в единой базе данных для хранения данных отчетности от баз
данных, которые используются микрослужбами для хранения и извлечения данных,
236

|

Гпава 5

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

Рис. 5.5. Выделенная база отчетных данных, в которую передаются данные из разных микрослужб

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

Я провожу разведывательный анализ трудностей и потенциальных решений, свя­
занных с этой темой, подробнее в главе 5 книги ’’Создание микросервисов”.

Мониторинг и устранение неполадок
"Мы заменили наш монолит микрослужбами, для того чтобы каждый перебой
в работе был больше похож на детективную историю убийства”.
- Честная страница статуса (@honest_update), http://bit.ly/2mldxqH
Со стандартным монолитным приложением подход к мониторингу довольно прост.
У нас есть небольшое число машин, о которых нужно беспокоиться, а режим сбоя
приложения является в некотором роде ’’двоичным” — приложение часто либо
’’поднято”, либо ’’лежит”. С архитектурой на основе микрослужб мы будем учиты­
вать сбой только одного экземпляра службы или только одного типа экземпляра —
можем ли мы их надлежаще восстанавливать?
Болезни роста

|

237

С монолитной системой, если наш процессор застрял на 100% в течение длительно­
го времени, то мы знаем, что это большая проблема. С архитектурой на основе
микрослужб с десятками или сотнями процессов можно ли сказать то же самое?
Нужно ли нам будить кого-то в 3 часа ночи, когда только один процесс ’’застрял” на
100%-ной загруженности CPU?

Выяснение того, где у вас проблемы, и понимание того, действительно ли нужно
беспокоиться о той или иной проблеме, которую вы видите, усложняется по мере
того, как у вас все больше ’’движущихся частей”. Подход к мониторингу и устране­
нию неисправностей будет меняться по мере роста архитектуры на основе микро­
служб. Эта область потребует постоянного внимания и вложений.

Когда эти проблемы возникают?
Предсказать, когда точно у вас возникнут тут проблемы, чуточку сложнее. Про­
стым ответом может быть фраза: ’’Впервые что-то не так в производстве”, но по­
пытки выяснить, что и где пошло не так, будет той работой, которой разработчикам
и тестировщикам, возможно, придется заниматься до того, как вы вообще добере­
тесь до производства. Вы столкнетесь с этими ограничениями, когда у вас будет
пара служб, или, пожалуй, не раньше, чем достигнете 20 или более служб.
Поскольку трудно точно предсказать, когда ваш существующий подход к монито­
рингу начнет вас подводить, можно предложить лишь заблаговременно приорити­
зировать имплементацию базовых усовершенствований.

Как эти проблемы проявляются?
В некотором смысле их довольно легко заметить. Вы увидите производственные
проблемы, которые вы не можете объяснить или понять, у вас будут оповещения,
которые будут срабатывать, несмотря на то что система, по всей видимости, явля­
ется здоровой, и вам будет труднее ответить на простой вопрос ’’Все ли в порядке?”

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

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

|

Гпава 5

Система агрегирования журналов позволит вам захватывать все ваши журналы и
пересылать их в центральное место, где в них можно производить поиск, а в неко­
торых случаях даже генерировать оповещения. Существует много вариантов, от
стека ELK с открытым исходным кодом (Elastic search, Logstash/Fluent D и Kibana)4
до лично мою любимого Humio5, и эти системы невероятно полезны.

Хорошенько подумайте об имплементации агрегирования журналов в качестве
первого шага перед имплементацией архитектуры на основе микрослужб. Это не­
вероятно полезно и является хорошей проверкой способности вашей организации
внедрять изменения в операционном пространстве.
Агрегирование журналов — один из самых простых в имплементации механизмов,
его следует применять на ранней стадии. На самом деле я считаю, что это первое,
что вы должны сделать при имплементации архитектуры на основе микрослужб.
Отчасти потому, что это очень полезно с самого начала. Кроме того, если ваша
организация испытывает трудности в имплементации подходящей системы агреги­
рования журналов, то вы, возможно, захотите пересмотреть вопрос о готовности
к переходу на микрослужбы. Работа, необходимая для имплементации системы
агрегирования журналов, довольно проста, и если вы не готовы к этому как органи­
зация, то шаг в сторону микрослужб, вероятно, будет излишним.

Трассировка
Понимание того, где последовательность вызовов между микрослужбами не срабо­
тала или какие службы вызвали всплеск задержки, бывает затруднено, если вы ана­
лизируете информацию только из каждой изолированной службы. Возможность
сопоставлять серию потоков и смотреть на них в целом невероятно полезна.
В качестве отправной точки создайте ИД корреляции для каждого входящего в сис­
тему вызова, как показано на рис. 5.6. Когда служба ’’Счет-фактура” получает вы­
зов, ей присваивается ИД корреляции. Когда она отправляет вызов микрослужбе
’’Уведомления”, она также передает ИД корреляции посредством заголовка HTTP
или поля в полезной нагрузке сообщения, или какого-либо другого механизма. Как
правило, в части генерирования исходного ИД корреляции я бы посмотрел на API
шлюза или сетку для служб.
Когда служба ’’Уведомления” улаживает вызов, она регистрирует информацию
о том, что она делает, в сочетании с тем же ИД корреляции, позволяя использовать
систему агрегирования журналов для опроса всех журналов, ассоциированных
с данным ИД корреляции (при условии, что вы помещаете ИД корреляции в стан­
дартное место в журнальном формате). Разумеется, с ИД корреляции можно делать
и другие вещи, например, управлять сагами (как мы обсуждали в главе 4).
Развивая эту идею дальше, мы можем использовать инструменты также для отсле­
живания времени, затрачиваемого на вызовы. Учитывая, как работают системы аг­
регирования журналов, где журналы укладываются в пакеты и передаются цен-

4 См. https://www.elastic.co/elk-stack.
5 См. https://humio.com/.

Болезни роста

|

239

Рис. 5.6. Использование ИД корреляции для обеспечения возможности сбора информации

о конкретной цепочке вызовов

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

Рис. 5.7. Jaeger — это инструмент с открытым исходным кодом для сбора информации

для распределенных трасс и анализа производительности отдельных вызовов

6 См. https://www.jaegertracing.io/.

240

|

Гпава 5

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

Испытание в производстве
Функциональные автоматизированные испытания в типичной ситуации позволяют
получить обратную связь перед развертыванием относительно того, обладает ли
наш софт достаточными качественными характеристиками для развертывания. Но
после того как софт попадает в производство, мы по-прежнему хотим получать ту
же обратную связь! Даже если данная функция раньше уже в производстве работа­
ла, новое развертывание службы или изменение среды может нарушить эту функ­
циональность позже.

Впрыскивая поведение ’’поддельного” пользователя в нашу систему в форме того,
что часто именуется синтетическими транзакциями, мы можем определять ожи­
даемое поведение и соответственно оповещать, если оно не является таким. В од­
ной из моих предыдущих компаний, Atomist, у нас был довольно сложный процесс
интеграции для новых клиентов, который требовал авторизации нашего софта
с помощью их учетных записей GitHub и Slack. Имелось достаточно ’’движущихся
частей”, которые на ранней стадии этого процесса сталкивались с трудностями, та­
кими, как ограничение числа запросов к API-интерфейсам GitHub. Один из моих
коллег, Сильвен Хеллегуарч (Sylvain Hellegouarch), написал сценарий регистрации
’’поддельных” клиентов. Для одного из этих ’’поддельных” клиентов мы на регуляр­
ной основе запускали процесс регистрации, который описывал весь процесс от на­
чала до конца. Когда он не срабатывал, это часто было признаком того, что какаято часть работает не так в наших системах, и ее было гораздо лучше отлавливать
с помощью ’’поддельного” пользователя, а не реального!
Хорошая отправная точка для проведения испытаний в производстве — использо­
вание существующих сквозных тестовых случаев и их переработка для применения
в производственной среде. Важно обеспечить, чтобы эти ’’тесты” не оказывали не­
предвиденного влияния на производство. С помощью Atomist мы создали учетные
записи GitHub и Slack, которые контролировали в синтетических транзакциях, по­
этому ни один реальный человек не был вовлечен или затронут, и наши сценарии
легко очищали указанные учетные записи после этого. С другой стороны, я слы­
шал, как одна компания по ошибке заказала 200 стиральных машин для доставки
в свой головной офис, потому что они не учли тот факт, что испытательные заказы
действительно будут отправлены. Поэтому будьте осторожны!

Болезни роста

|

241

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

По мере того как наши системы усложняются, становится все труднее предсказы­
вать все неприятные пути, которыми наша система может нас подвести. В данной
точке важно обеспечить возможность задавать открытые вопросы7 о наших систе­
мах, когда эти трудности возникают, чтобы помочь нам в первую очередь остано­
вить "кровотечение” и убедиться, что система может продолжать работу, а затем
позволить нам собирать информацию в достаточном объеме для устранения про­
блем в будущем.
Таким образом, мы должны быть в состоянии собрать много информации о том,
что делает наша система, позволяя нам постфактум задавать вопросы о данных,
о которых мы должны были спросить изначально, но о которых мы не знали. Трас­
сировка и журналы служат важным источником данных, на основе которых мы
можем формулировать вопросы и использовать реальную информацию, а не догад­
ки с целью определения причины проблемы. Секрет в том, чтобы упростить запрос
и просмотр этой информации в контексте.

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

Локальный опыт разработчиков
По мере того как у вас возникает все больше и больше служб, опыт разработчика
начнет страдать. Более ресурсоемкие среды выполнения, такие, как JVM, ограни­
чивают число микрослужб, которые способны выполняться на одном компьютере
разработчика. На своем ноутбуке я бы смог, вероятно, запустить четыре-пять мик­
рослужб на базе JVM в качестве отдельных процессов, но смогу ли я запустить де­
сять или двадцать? Скорее всего, нет. Даже с менее обременительными временами
выполнения существует ограничение на число вещей, которые вы можете запускать

7 Для справки: открытый вопрос (open-ended question) — это вопрос, который предполагает многова­
риантный ответ. На него невозможно ответить просто «да» или «нет» — Пер.
8 См. Синди Сридхаран «Наблюдаемость распределенных систем» (Cindy Sridharan, Distributed Systems
Observability, Sebastopol: O'Reilly Media, Inc., 2018).

242

|

Гпава 5

локально, что неизбежно приведет к разговорам о том, что делать, когда вы не мо­
жете запустить всю систему на одной машине.

Как эта проблема проявляется?
Процесс разработки изо дня в день начнет замедляться, при этом локальные сборки
и исполнение будут занимать больше времени из-за большего числа служб, кото­
рые должны быть подняты. Разработчики начнут запрашивать более крупные ма­
шины для урегулирования числа служб, которые им приходится улаживать, и, хотя
в краткосрочном плане, возможно, все с этим будет в порядке, вам удастся выиг­
рать лишь некоторое время, в случае если имущество служб продолжит расти.

Когда эта проблема возникает?
Момент, когда именно это проявится, скорее всего, зависит от числа служб, кото­
рые разработчик хочет выполнять локально, в сочетании с ресурсным следом этих
служб. Группа, использующая Go, Node или Python, вполне может обнаружить, что
у них локально работает больше служб, прежде чем проявится ограничение ресур­
сов, а вот группа, использующая JVM, столкнется с этой проблемой раньше.

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

Потенциальные решения
Если я хочу разрабатывать локально, но уменьшить число служб, которые мне
нужно выполнять, то общепринятым методом является установка ’’заглушек” на те
службы, которые я не хочу выполнять сам, или же иметь способ указать их на эк­
земпляры, работающие в другом месте. Чистая настройка удаленной разработки
позволяет вам вести разработку с участием многочисленных служб, размещаемых
на более вместительной инфраструктуре. Однако она сопровождается трудностями,
связанными с необходимостью подключения (что может быть проблемой для уда­
ленных работников или частых путешественников), потенциально более медлен­
ными циклами обратной связи с потребностью развертывания софта удаленно,
прежде чем вы сможете увидеть его работу, и потенциальным взрывным ростом
ресурсов (и связанных с ними затрат), необходимых для среды разработчика.
Telepresence9— пример инструмента, который стремится сделать гибридный локальный/удаленный трудовой поток по разработке софта проще для пользователей
Kubemetes. Вы можете развивать свою службу локально, но Telepresence способен

9 См. https://www.telepresence.io/.

Болезни роста

|

243

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

Выполнение слишком многого
По мере того как у вас появляется все больше служб и их экземпляров, у вас будет
все больше процессов, которые необходимо развернуть, настроить и которыми
нужно управлять. Существующие методы управления развертыванием и конфигу­
рацией монолитного приложения плохо масштабируются по мере увеличения числа
’’движущихся частей”, которыми необходимо управлять.
В частности, все большее значение приобретает управление желаемым состоянием.
Управление желаемым состоянием— это возможность указывать необходимое
число и расположение экземпляров служб, а также обеспечивать их постоянную
поддержку. Вы легко можете управлять этим с помощью вашего монолита, задей­
ствуя ручные процессы, но процесс не будет хорошо масштабироваться, когда у вас
десятки или сотни микрослужб, в особенности если каждой из них требуется дру­
гое желаемое состояние.

Как эта проблема проявляется?
Вы начнете видеть увеличивающийся процент времени, затрачиваемого на управ­
ление развертываниями и устранение неисправностей, возникающих во время этих
развертываний. Ошибки будут совершаться всегда, если процессы опираются на
ручные действия, и влияние на распределенные системы ’’невинных” ошибок ино­
гда трудно предсказать.
По мере добавления дополнительных служб и их экземпляров вам потребуется
больше людей для управления мероприятиями, связанными с развертыванием и
сопровождением производственного парка. Это приведет к просьбам об увеличе­
нии числа людей для поддержки вашей операционной группы или, возможно, к то­
му, что группа доставки больше времени будет затрачивать на развертывание ком­
понентов.

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

244

|

Гпава 5

газированных инструментов управления конфигурацией, таких, как Chef и Puppet,
перестают соответствовать требованиям.

Потенциальные решения
Вам нужен инструмент, который обеспечивает высокую степень автоматизации,
позволяет разработчикам в идеале выполнять самообслуживаемое развертывание
в облаке и берет на себя автоматическое управление желаемым состоянием.

Для микрослужб предпочтительным инструментом в этом пространстве стал
Kubemetes. Он требует от вас контейнеризации ваших служб, но как только вы это
сделаете, то сможете посредством Kubemetes управлять развертыванием экземпля­
ров служб на многочисленных машинах, давая возможность масштабироваться для
повышения робастности и справляться с нагрузкой (при условии, что у вас доста­
точно для этого аппаратного обеспечения).

’’Ванильный” Kubemetes — совсем не то, что я бы посчитал дружественным к раз­
работчикам. Масса людей работает над более удобными для разработчиков абст­
ракциями, и я надеюсь, что эта работа будет продолжаться. В будущем, я ожидаю,
что многие разработчики, которые выполняют софт на Kubemetes, даже не поймут
этого, поскольку это станет лишь деталью имплементации. Я склонен видеть, что
более крупные организации примут упакованную версию Kubemetes, такую, как
OpenShift от RedHat, которая укомплектовывает Kubemetes инструментами, облег­
чающими работу с корпоративной средой, возможно, беря на себя рычаги управле­
ния корпоративной идентичностью и доступом. Некоторые из таких упакованных
версий также предоставляют упрощенные абстракции для труда разработчиков.
Если вам посчастливилось находиться в публичном облаке, то вы можете исполь­
зовать целый ряд вариантов для улаживания развертываний своей архитектуры на
основе микрослужб, включая предложения управляемого Kubemetes. Например,
AWS и Azure предлагают в этом пространстве несколько вариантов. Я большой
поклонник технологии "функции-как-службы” (FaaS), подмножества инструментов,
именуемых бессерверными. При наличии подходящей платформы разработчики
беспокоятся лишь о коде, а опорная платформа берет на себя большую часть опе­
рационной работы. Хотя нынешний набор предложений FaaS имеет ограничения,
они, тем не менее, предлагают перспективу резкого сокращения операционных
накладных расходов.

В случае групп, с которыми я работаю и которые уже находятся в публичном обла­
ке, я обычно не начинаю с Kubemetes или подобных контейнерных платформ. Вме­
сто этого я принял подход ’’сначала без сервера” — попробовать использовать бессерверную технологию, такую, как FaaS, в качестве варианта по умолчанию, ввиду
сокращения операционной работы. Если ваша проблема не укладывается
в ограничения имеющихся для вас бессерверных продуктов, то поищите другие
варианты. Очевидно, что не все проблемные пространства равнозначны, но я чув­
ствую, что если вы уже находитесь в публичном облаке, то вам не всегда понадо­
бится сложная платформа на основе контейнеров, такая, как Kubemetes.
Болезни роста

|

245

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

Сквозное тестирование
С любым типом автоматизированного функционального испытания вам придется
пойти на тонкий компромисс. Чем больше функций тест исполняет (чем шире его
охват), тем больше уверенности вы имеете в своем приложении. С другой стороны,
чем больше охват теста, тем больше времени занимает его выполнение и тем труд­
нее будет выяснить, что нарушено в ситуациях, когда он не проходит.

Сквозные тесты любого типа систем находятся на крайнем конце шкалы с точки
зрения функциональности, которую они охватывают, и мы привыкли к тому, что их
писать и поддерживать проблематичнее, чем меньшие по охвату модульные тесты.
Хотя нередко это оправдано, поскольку мы хотим уверенности, которая исходит из
того, что сквозной тест использует наши системы таким же образом, как и реаль­
ный пользователь.
Но с архитектурой на основе микрослужб ’’охват" наших сквозных тестов стано­
вится очень большим. Теперь нам приходится выполнять тесты в нескольких служ­
бах, причем все они должны быть развернуты и надлежаще настроены для тесто­
вых сценариев. Мы также должны быть заранее подготовлены к ложным отри­
цаниям (false negative), которые возникают, когда проблемы среды, такие, как
"умирание" экземпляров служб или сетевые тайм-ауты безуспешных развертыва­
ний, приводят к неудаче наших тестов. Я бы сказал, что при выполнении сквозных
тестов архитектуры на основе микрослужб мы гораздо более уязвимы к проблемам
вне нашего контроля, чем со стандартной монолитной архитектурой.
По мере увеличения охвата тестов вы будете тратить больше времени на борьбу
с возникающими проблемами, вплоть до того момента, когда попытки создавать и
поддерживать сквозные тесты начинают пожирать огромные промежутки времени.

Как эта проблема проявляется?
Один из признаков проблемы — увеличение набора сквозных тестов и времени на
их завершение. Это вызвано тем, что многочисленные группы не уверены в том,
какие сценарии охватываются, и добавляют новые "на всякий случай". Вы видите
больше сбоев в наборе сквозных тестов, которые не высвечивают затруднения, вы­
званные вашим кодом, и разработчики часто просто прогоняют тесты снова, чтобы
увидеть, что они проходят.

246

|

Гпава 5

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

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

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

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

Использовать контракты,
обусловливаемые потребителем
Возможно, вы захотите подумать об использовании контрактов, обусловливаемых
потребителем (consumer-driven contract, CDC), чтобы исключить потребность в тес­
товых случаях, требующих пересечения служб. При наличии CDC-контрактов у вас
есть потребитель вашей микрослужбы, который определяет свои ожидания относи­
тельно того, как ваша служба должна себя вести с точки зрения исполняемой спе­
цификации— теста. Когда вы изменяете свою службу, необходимо обеспечить,
чтобы эти тесты по-прежнему проходили.
Поскольку эти тесты определяются с точки зрения потребителя, мы получаем
хороший охват для восстановления от нечаянного разрыва контракта. Мы также
можем понять требования наших потребителей с их точки зрения и, что очень важ­
но, уяснить, как разные потребители, возможно, хотят от нас разных вещей.
Болезни роста

|

247

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

Использовать автоматическую ремедиацию релиза
и прогрессивную доставку
В автоматизированном тестировании мы обычно пытаемся отыскать проблемы, до
того как они повлияют на производство, но бывает, что это оказывается все труднее
сделать, поскольку ваша система становится сложнее. Следовательно, стоит потра­
тить усилия на снижение влияния производственных проблем.
Как мы уже говорили в главе 3, прогрессивная доставка — это зонтичный термин,
обозначающий управление поступательным развертыванием новых версий софта
для своих клиентов. Идея заключается в том, что вы оцениваете влияние вашего
нового релиза с помощью меньшей группы клиентов, принимая решения о том, ко­
гда продолжать откат и продолжить ли вообще или же его отменить. Один из при­
меров метода прогрессивной доставки — ’’канареечный” релиз.
Определив приемлемые меры для того, как должна вести себя ваша служба, стано­
вится возможным контролировать поступательную доставку в автоматическом
режиме. В качестве простого примера можно определить допустимый порог про­
центиля задержек и частоты встречаемости ошибок, равный 95, и продолжать раз­
вертывание только в том случае, если эти меры соблюдены. В противном случае вы
автоматически откатываете последнюю версию, получая время для анализа про­
изошедшего.

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

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

10 См. https://pact.io/.

248

|

Гпава 5

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

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

Глобальная оптимизация
против локальной оптимизации
Если допустить, что вы внедрили модель, в рамках которой группа несет большую
ответственность за принятие локальных решений, возможно, владея всем жизнен­
ным циклом микрослужб, которыми они управляют, то вы дойдете до точки, где
вам нужно будет сбалансировать локальное принятие решений с более глобальны­
ми аспектами.
В качестве примера того, как эта проблема может проявиться, возьмем три группы,
которые управляют службами ’’Выписка счетов-фактур”, ’’Уведомления” и ’’Испол­
нение”. Группа ’’Выписка счетов-фактур” решает выбрать Oracle в качестве базы
данных, поскольку они хорошо ее знают. Группа ’’Уведомления” хочет использо­
вать MongoDB, потому что она хорошо подходит для их модели программирова­
ния. Между тем в группе ’’Исполнение” хотели бы использовать PostgreSQL, по­
скольку она у них уже есть. Когда вы смотрите на каждое решение по очереди, все
это имеет смысл, и вы понимаете, как та или иная группа сделала свой выбор.

Однако если вы отступите назад и посмотрите на ’’крупный план”, то вы должны
спросить себя, хотите ли вы как организация формировать навыки и платить лицен­
зионные сборы за три базы данных с несколько схожими возможностями. Может
быть, вам лучше принять на вооружение только одну базу данных, признав, что она
неидеальна для всех, но достаточно хороша для большинства? Без способности
видеть, что происходит на локальном уровне, и быть в состоянии помещать это ви­
дение в глобальный контекст, как вы вообще сможете принимать такие решения?
Болезни роста

|

249

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

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

Когда эта проблема возникает?
Эта проблема имеет тенденцию возникать в многогрупповых организациях по
прошествии некоторого времени, в особенности в организациях, которые предос­
тавляют группам больше свободы в том, как они выполняют свою работу. Не ожи­
дайте увидеть эту проблему на ранней стадии вашего пути по внедрению микро­
служб. Вы, вероятно, начнете с четкого общего понимания того, как все должно
делаться. Со временем каждая группа будет все больше сосредоточиваться на своих
локальных проблемах и будет оптимизировать способ решения конкретной про­
блемы, и поэтому стержневой совместный взгляд на ведение дел (’’вот так мы ведем
дела”) начнет смещаться.

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

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

250

|

Гпава 5

Потенциальные решения
Мы уже коснулись некоторых идей, которые помогают в этой области. В главе 2
мы разведали идею необратимых и обратимых решений, как это снова показано на
рис. 5.8. Чем выше стоимость изменений, тем сильнее влияние и тем больше вы
будете хотеть более широкого консенсуса в основе принятия решений. Чем меньше
влияние,тем легче откатить назад и тем больше решений можно оставить локаль­
ным группам.

Рис. 5.8. Различия между необратимыми и обратимыми решениями, с примерами вдоль спектра

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

Сквозная группа может работать в обоих направлениях. В дополнение к обеспече­
нию места, где группы могут выводить на поверхность локальные проблемы, кото­
рые они хотят обсудить на более крупном форуме, это также место, где люди могут
поднимать сквозные вопросы. Без некой связи между группами как понять, что на
локальном уровне мы решаем проблемы по-разному и что, пожалуй, решение их на
глобальном уровне будет иметь больше смысла?
В зависимости от природы вашей организации вы можете рассчитывать на более
нерегламентированный, неформальный процесс. Например, в Monzo сотрудники
представляют документы в свободной форме, которые внутри организации назы­
ваются ’’предложениями”. Они публикуются в совместном пространстве, которое,

Болезни роста

|

251

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

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

Робастность и отказоустойчивость
Распределенные системы демонстрируют целый ряд режимов сбоя, которые могут
быть вам незнакомы, если вы больше привыкли к монолитным системам. Сетевые
пакеты могут теряться, сетевые вызовы могут истекать, машины могут ’’умирать”
или переставать откликаться. Подобные ситуации бывают редкими в простых рас­
пределенных системах, таких, как традиционное монолитное приложение, но по
мере увеличения числа служб редкие случаи становятся все более распространен­
ными.

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

Когда эта проблема возникает?
Буду здесь честен — если бы я мог сказать вам заранее, когда ваша система будет
страдать от нестабильности, то не написал бы эту книгу, т. к., вероятно, проводил
бы свое время где-нибудь на пляже, попивая мохито. Могу лишь сказать, что по
мере роста числа служб и увеличения числа вызовов служб вы будете становиться
все более и более уязвимыми к проблемам отказоустойчивости. Чем более взаимо­

252

|

Гпава 5

связаны ваши службы, тем вероятнее, что вы будете страдать от таких вещей, как
каскадные сбои и встречное (обратное) давление.

Потенциальные решения
Хорошая отправная точка — задать себе пару вопросов о каждом вызове службы,
который вы делаете. Во-первых, знаю ли я, каким образом этот вызов может не
сработать? Во-вторых, если вызов не сработал, то знаю ли я, что мне делать?
После ответа на эти вопросы вы можете начать искать массу решений. Изолирова­
ние служб друг от друга, пожалуй, поможет, включая введение асинхронной ком­
муникации во избежание временной сопряженности (темы, которую мы затронули
в главе 7). Использование разумных тайм-аутов позволяет избежать конкуренции за
ресурсы с медленными нижестоящими службами, а в сочетании с такими моделя­
ми, как прерыватели цепи, вы начнете отказывать быстро11 во избежание проблем
со встречным давлением.

Запуск многочисленных копий служб выручает в случаях с ’’умиранием” экземпля­
ров, как и платформа, имплементирующая управление желаемым состоянием (ко­
торая обеспечивает перезапуск служб при аварийном сбое).
Еще раз повторю мысль, высказанную в главе 2. отказоустойчивость — это нечто
большее, чем просто имплементация нескольких шаблонов. Речь идет о целом спо­
собе выстраивания работы — строительстве организации, которая не только готова
справиться с непредвиденными и неизбежно возникающими проблемами, но и по
мере необходимости эволюционно формирует рабочие практики. Один из конкрет­
ных способов претворить эту идею в жизнь — документировать производственные
вопросы, когда они возникают, и вести учет того, что вы усвоили. Очень уж часто я
вижу, как организации слишком быстро двигаются дальше, после того как перво­
начальная проблема была решена или проработана со всех сторон, лишь только для
того, чтобы те же самые проблемы вернулись через несколько месяцев.

Честно говоря, я здесь лишь слегка прикоснулся к данной теме. Для более деталь­
ного знакомства с этими идеями я рекомендую прочитать главу 11 книги ’’Создание
микросервисов”, или взглянуть на книгу Майкла Найгарда ’’Выпускай!" (Release It!,
Michael Nygard, Pragmatic Bookshelf, 2018).

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

11 Быстрый отказ (fail-fast) в рамках системы раннего обнаружения ошибки означает прерывание
работы при возникновении ошибки вместо продолжения работы с ошибкой — Пер.

Болезни роста

|

253

По мере того как микрослужбы будут становиться еще более целенаправленными
в своем предназначении, вы обнаружите, что все больше и больше служб успешно
работают в течение недель, месяцев или, возможно, лет без каких-либо изменений.
С одной стороны, это именно то, что мы хотим. Независимая развертываемость
столь привлекательна потому, что позволяет остальной части системы оставаться
стабильной, и поддержание стабильности частей нашей системы, которые не нуж­
даются в изменении, является неплохой идеей.
Я называю эти службы ’’осиротевшими”, поскольку в принципе никто в компании
не берет на себя за них ответственность.

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

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

Когда эта проблема возникает?
Эта проблема обычно возникает в организациях, которые используют микрослуж­
бы в течение длительного периода времени, — достаточно долго, чтобы коллек­
тивная память о том, что делает та или иная служба, давно ослабла. Люди, свя­
занные с этой микрослужбой, либо забыли, что они с ней делали, либо, возможно,
покинули компанию.

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

Я говорил с сотрудниками ряда компаний, у которых были трудности подобного
рода, и это закончилось созданием простых внутриорганизационных реестров, по­
254

|

Гпава 5

могающих сопоставлять метаданные служб. Некоторые из реестров просто скани­
руют репозитории исходного кода, ища файлы метаданных для построения списка
имеющихся служб. Эта информация объединяется с реальными данными, посту­
пающими из систем обнаружения служб, таких, как consul или etcd с целью созда­
ния более подробной картины того, что работает и с кем вы могли бы об этом пого­
ворить.
В помощь решению этой проблемы Financial Times создала инструмент Biz Ops.
Указанная компания имеет несколько сотен служб, разработанных группами по
всему миру. Инструмент Biz Ops (рис. 5.9) предоставляет им единое место, где
можно найти много полезной информации об их микрослужбах, в дополнение
к информации о других ИТ-инфраструктурных службах, таких, как сети и фай­
ловые серверы. Построенный поверх графовой базы данных, Biz Ops обладает
большой гибкостью в отношении того, какие данные он собирает и каким образом
информация модифицируется.

Рис. 5.9. Инструмент Biz Ops компании Financial Times, который собирает информацию
о своих микрослужбах

Однако инструмент Biz Ops идет дальше, чем большинство других, которые я ви­
дел. Он вычисляет так называемый ’’балл операбельности” системы, как показано
на рис. 5.10. Идея заключается в том, что есть определенные вещи, которые службы
и их группы должны делать для обеспечения простоты оперирования службой.
Болезни роста

|

255

Рис. 5.10. Пример балла операбельности службы для микрослужбы в Financial Times

Сюда входит все, начиная с обеспечения от групп правильной информации в реест­
ре до надлежащей проверки готовности служб к работе. Эти баллы рассчитывают­
ся, позволяя группам сразу увидеть, что именно необходимо исправить.
Наличие чего-то вроде реестра служб помогает, но что произойдет, если ваша ’’оси­
ротевшая” служба предшествует вашему реестру? Главное — выровнять эти недав­
но обнаруженные "осиротевшие” службы по тому же принципу, как управляются
другие службы, а это потребует от вас либо назначить владение существующей
группе (если практикуется сильная степень владения), либо развернуть отдельные
работы для улучшаемой службы (если практикуется коллективное владение).

Резюме
Материал, приведенный в этой главе, — вовсе не исчерпывающий список всех
трудностей, причиной которых являются микрослужбы, и я не перечислил все
потенциальные их решения. Вместо этого все внимание было уделено наиболее
распространенным проблемам, с которыми, на моем опыте, люди справляются
с трудом.
Надеюсь, что я также дал ясно понять, что нет четкого и быстрого правила относи­
тельно того, когда именно вы увидите эти проблемы. Каждая ситуация отличается,
и в игру вступает масса факторов. Я пытался лишь подчеркнуть, что, хотя вы не
способны видеть будущее, вас можно, по крайней мере, предупредить. Сложнее
найти правильный баланс между устранением проблем до их возникновения и тра­
той времени на устранение проблем, которых у вас никогда не будет. Я надеюсь,
что прочитав эту главу, вы поймете, какое предупреждение следует ожидать.
256

|

Гпава 5

Заключение

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

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

257

ПРИЛОЖЕНИЕ 1

Библиография

Bird, Christian, Nachiappan Nagappan, Brendan Murphy, Harald Gall, and Premkumar Devanbu.
“Don’t Touch My Code! Examining the Effects of Ownership on Software Quality.”
http://bit.ly/2p5RlTl (He трогай мой код! Обследование влияния владения на качество
программно-информационного обеспечения).

Bland, Mike. “Test Mercenaries.” http://bitly/2omkxVy (Легионеры тестирования).
Bland, Mike. “Testing On The Toilet.” http://bit.ly/2ojpWwm (Тестирование на унитазе).

Brandolini, Alberto. Introducing EventStorming. Leanpub, 2019. http://bit.ly/2n0zCLU
(Введение в событийный штурм).

Brooks, Frederick P. The Mythical Man-Month, 20th Anniversary Edition. Addison Wesley, 1995
(Мифический человеко-месяц).
Bryant, Daniel. “Building Resilience in Netflix Production Data Migrations: Sangeeta Handa at
QCon SF.” http://bit.ly/2mlEwHT (Укрепление отказоустойчивости во время миграций
производственных данных Netflix).
Devops Research & Assessment. Accelerate: State Of Devops Report 2018.
http://bit.ly/2nPDNLe (Исследование и оценивание Devops. Ускорение.
Отчет о состоянии дел в области Devops за 2018 год).
Evans, Eric. Domain-Driven Design: Tackling Complexity in the Heart of Software.
Addison-Wesley, 2003 (Доменно-обусловленный дизайн: пути решения сложности
в центре программно-информационного обеспечения).

Feathers, Michael. Working Effectively with Legacy Code. Prentice-Hall, 2004 (Эффективная
работа с унаследованным кодом).
Fowler, Martin. “Strangler Fig Application.” http://bit.ly/2p5xMKo
(Приложение ’’фикус-удавка”).
Fowler, Martin. “Reporting Database.” http://bit.ly/2kWW9Ir (База отчетных данных).
Garcia-Molina, Hector, and Kenneth Salem. “Sagas.” ACM Sigmod Record 16, No. 3 (1987):
pp. 249-259 (Саги).

Garcia-Molina, Hector, Dieter Gawlick, Johannes Klein, Karl Kleissner, Kenneth Salem.
“Modeling Long-Running Activities as Nested Sagas.” Data Engineering 14, No. 1
(March 1991): p. 14-18 (Моделирование длительных операций как вложенных саг).

Helland, Pat. “Life Beyond Distributed Transactions.” Acmqueue 14, No. 5
(Жизнь за пределами распределенных транзакций).

Hodgson, Peter. “Feature Toggles (aka Feature Flags).” http://bit.ly/2m316zB
(Реле функций (ака флажки функций).
Hohpe, Gregor, and Bobby Woolf. Enterprise Integration Patterns. Addison-Wesley, 2003
(Шаблоны интеграции предприятия).

259

Humble, Jez, and David Farley. Continuous Delivery: Reliable Software Releases through Build,
Test, and Deployment Automation. Addison-Wesley, 2010 (Непрерывная доставка:
надежные релизы программно-информационного обеспечения посредством сборки,
тестирования и автоматизации развертывания).
Humble, Jez. “Make Large-Scale Changes Incrementally with Branch by Abstraction.”
http://bit.ly/2p951v7 (Вносите крупномасштабные изменения с помощью ветвления по
абстракции).

Kim, Gene, Patrick Debois, Jez Humble, and John Willis. The Devops Handbook. IT Revolution
Press, 2016 (Справочник no Devops).

Kleppmann, Martin. Designing Data-Intensive Applications. O’Reilly, 2017
(Дизайн приложений с интенсивным использованием данных).

Kniberg, Henrik, and Anders Ivarsson. “Scaling Agile @ Spotify.” October 2012.
http://bit.ly/2ogAz3d (Масштабирование Agile @ Spotify).
Kotter, John P. Leading Change. Harvard Business Review Press, 1996 (Во главе перемен).

Mitchell, Loma Jane. PHP Web Services, Second Edition. O’Reilly, 2016 (Веб-службы PHP,
2-е издание).
Newman, Sam. Building Microservices. O’Reilly, 2015 (Создание микросервисов).
Nygard, Michael T. Release It!: Design and Deploy Production-Ready Software, Second Edition.
Pragmatic Bookshelf, 2018 (Выпускай!).

Pamas, David. “On the Criteria to be Used in Decomposing Systems into Modules.” Information
Distributions Aspects of Design Methodology, Proceedings of IFIP Congress ‘71 (1972)
(О критериях, используемых при декомпозиции систем на модули).
Pamas, David. “The Secret History of Information Hiding.” David Pamas. In Software Pioneers,
edited by M. Broy and E. Denert. (Berlin: Springer, 2002) (Тайная история сокрытия
информации).

Pettersen, Snow. “The Road to an Envoy Service Mesh.” https://squ.re/2ntslGc
(Дорога к сетке для служб в Envoy).

Skelton, Matthew, and Manuel Pais. Team Topologies. IT Revolution Press, 2019 (Топологии
групп).
Smith, Steve. “Application Pattern: Verify Branch By Abstraction.” http://bit.ly/2mLVevz
(Шаблон приложения: верифицировать ветвление по абстракции).

Sridharan, Cindy. Distributed Systems Observability. O’Reilly, 2018. http://bit.ly/2nPZ73d
(Наблюдаемость распределенных систем).

Thorup, Kresten. “Riak on Drugs (and the Other Way Around).” http://bit.ly/2mlCvLP
(Riak на таблетках (и наоборот)).

Vernon, Vaughn. Domain-Driven Design Distilled. Addison-Wesley, 2016
(Основы доменно-обусловленного дизайна).
Woods, David. “Four concepts for resilience and the implications for the future of resilience
engineering.” Reliability Engineering & System Safety 141 (2015): 5-9 (Четыре концепции
отказоустойчивости и последствия для будущего инженерии отказоустойчивости).

Yourdon, Edward, and Larry Constantine. Structured Design: Fundamentals of a Discipline
of Computer Program and Systems Design. Prentice-Hall, 1979 (Структурный дизайн:
основы дисциплины дизайна компьютерных программ и систем).

260

|

Приложение 1

ПРИЛОЖЕНИЕ 2

Указатель шаблонов

Наименование

Оригинальное
название

Описание

Библиотека статических
справочных данных

Static reference data Перенос статических справочных данных
в библиотеку или конфигурационный файл,
library
упаковываемых с каждой микрослужбой, кото­
рая в них нуждается

Ветвление
по абстракции

Branch by
abstraction

Сосуществование двух имплементаций одной
и той же функциональности в одной и той же
кодовой базе одновременно, позволяя посту­
пательно разрабатывать новую имплемента­
цию, пока она не сможет заменить старую
имплементацию

Выделенная схема
справочных данных

Dedicated reference
data schema

Создание выделенной базы данных для раз­
мещения всех статически справочных данных.
К указанной базе данных могут обращаться
разные службы

Дублирование статических
справочных данных

Duplicate static
reference data

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

Захват изменений
в данных

Change data capture Передача изменений, вносимых в базовое
хранилище данных, другим заинтересованным
сторонам

Интерфейс
"база-да нных-как-служба"

Database-asa-Service interface

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

Композиция пользователь­
ского интерфейса

UI composition

Представление единого пользовательского
интерфейса путем компоновки большого
числа мелких деталей вместе

Монолит как слой доступа
к данным

Monolith as data
access layer

Доступ к данным, управляемым монолитом
через API-интерфейсы, вместо прямого досту­
па к базе данных

Монолит с выставлением
агрегата наружу

Aggregate exposing
monolith

Выделение доменных агрегатов наружу
из монолита, позволяя микрослужбам обра­
щаться к сущностям, управляемым монолитом

Мультисхемное хранение

Multischema storage Управление данными в разных базах данных
преимущественно при миграции из совместной
базы данных в модель "одна база данных —
одна служба"

261

(окончание)
Наименование

Оригинальное
название

Один репозиторий, один
ограниченный контекст

Repository per
bounded context

Параллельное выполнение Parallel run

Описание

Разбиение единого репозиторного слоя вокруг
разных частей домена, упрощая декомпози­
цию на службы

Выполнение двух имплементаций одной и той
же функциональности бок о бок для обеспече­
ния требуемого поведения новой функцио­
нальности

Перенос внешнего ключа
в код

Move foreign key
to code

Перенос управления и обеспечение соблюде­
ния связи по внешнему ключу из одной базы
данных на ярус вверх вашей службы

Приложение
"фикус-удавка”

Strangler fig
application

Обертывание вашей новой архитектуры
на основе микрослужб вокруг существующего
монолита. Вызовы функциональности, которая
была мигрирована из монолита в ваши микро­
службы, перенаправляются; другие вызовы
остаются неизменными

Проекция базы данных

Database view

Из опорной базы данных берется проекция,
позволяя скрывать части базы данных

Разбиение таблицы

Split table

Разбиение таблицы на две части
перед декомпозицией на службы

Синхронизация данных
в приложении

Synchronize data
in application

Синхронизация данных между двумя источни­
ками истины изнутри одного приложения

Служба ’’обертывания"
базы данных

Database wrapping
service

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

Служба статических спра­
вочных данных

Static reference data Выделенная служба, которая предоставляет
доступ к статическим справочным данным
service

Смена владельца данных

Change data
ownership

Перенос источника истины из монолита
в микрослужбу

Совместная база данных

Shared database

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

Сотрудник-декоратор

Decorating
collaborator

Активирование функциональности, работаю­
щей в отдельной микрослужбе, путем "выню­
хивания" запросов, отправляемых из моноли­
та, и откликов, отправляемых назад в ответ

Трассировочная запись

Tracer write

Поступательная миграция данных из одного
источника истины в другой, допуская два
источника истины во время миграции

262

|

Приложение 2

Предметный указатель

н

А
ACID-транзакция 207
0 нехватака атомарности 208
0 саги и атомарность 213
API: выставление наружу на монолитной
базе данных 186
AWS Lambda 205, 245
Azure: функции облачных служб 244

Homegate (риелторская фирма):
пример листингов недвижимости
с использованием шаблона параллельного
выполнения 115

J
Jaeger, распределенная система 195
JSON, форма обмена данными 233

в

к

Biz Ops, инструмент (Financial Times) 255
ВРМ-инструмент (Business Process
Modeling) 220

Kubemetes
0 использование с микрослужбами 245

D

N

DevOps 84

NGINX, прокси-сервер 108
NoSQL, базы данных 190

E
Erlang, среда выполнения 44

S
SchemaSpy, инструмент 183
Scientist, библиотека 139

F
FlywayDB, инструмент мигрирования
баз данных 182

т
Telepresence, инструмент 243

G
GitHub 241
Google: развертывание автоматизации
тестирования 72

V
Vault компании Hashicorp 151

263

A
Абстракция См. Шаблон "Ветвление
по абстракции"
Автономия групп
О улучшение 84
Агрегат 48
О в ограниченных контекстах 50
0 отображение с ограниченными
контекстами в микрослужбы 50
Агрегирование журналов в микрослужбах
238
Альтернатива использованию микрослужб
55
Архитектура дуршлачная 230
Атомарность 207
0 нехватка атомарности в транзакциях 208
0 саги 213
0 ACID-транзакции 207

Б
База данных
0 без совместного использования
микрослужбами 25
0 выделенная база отчетных данных 235
° в модульных монолитах 33
0 декомпозиция 147
о неспособность разбить базу данных
149
° передача владения данными 159-164
о примеры выделения схем 190
о синхронизация данных 164—178
° синхронизация данных в шаблоне
приложения 166—170
° транзакции 207-213
о шаблон интерфейса
"база-данных-как-служба" 157-159
о шаблон переноса связи по внешнему
ключу в код 193-207
° шаблон проекции базы данных 150—
154
° шаблон разложения таблицы 191-193
° шаблон совместной базы данных 147—
149
° шаблон трассировочной записи ПО178
0 с совместным использованием
в имплементационной сопряженности 39
0 схемы 149
0 реляционная 143, 190

264

|

Предметный указатель

0 совместная 147-149
Безос, Джефф 75
Библиотека справочных данных
0 совместное использование службами 201
Бизнес-домен
0 доменно-обусловленный дизайн 47
0 микрослужбы, моделируемые вокруг
него 22
Блэнд, Майк 71
Брандолини, Альберто 79
Брукс, Фредерик 60

в
Видение 70
0 коммуницирование видения перемен 70
Владение
0 база данных и проекции базы данных
153
0 владение кодом микрослужбы
в масштабе 229
0 группы, более полно владеющие всем
жизненым циклом софта 85
0 "осиротевшие" микрослужбы 253-256
0 коллективное службами 229
0 передача во время разбиения базы
данных 159-164
0 спутанные линии с монолитами 35
Владение кодом
0 микрослужбы в масштабе 229
Возвратность от инвестиций (ROI)
в переход на микрослужбы 54
Время до рынка
0 улучшение без принятия микрослужб
на вооружение 57
0 улучшение с использованием
микрослужб 57
Вставка боковая (ESI) 121
Вудс, Дэвид 59
Вызов синхронный 42
Выполнение слишком многого
в микрослужбах 244—246

г
Генерирование краткосрочных выигрышей
в организациях 72
Группа
0 владение кодом 229
0 качественные показатели успеха
транзита 92

О масштабирование числа разработчиков
60
0 организация групп, отражающая
трехъярусную архитектуру 23
0 проблема локального опыта
разработчиков 242
0 реорганизация для транзита
на микрослужбы 83-91
0 улучшение автономии
° без микрослужб 55
п с использованием микрослужб 55
Г руппа операционная
0 встраивание членов операционных групп
в группы доставки 85
0 устранение участия операционных групп
в обеспечении работы сред 87

д
Данные учетные
0 отдельные для доступа к базе данных
151
Декомпозиция
0 базы данных См. База данных;
Приложение монолитное
0 комбинированная модель для
приоритизации декомпозиции на службы
81
0 ограниченный контекст как
потенциальная единица 77
Дизайн доменно-обусловленный (DDD)
47-51,77-81
0 агрегаты 48
0 ограниченный контекст 50
0 отображение агрегатов и ограниченного
контекста в микрослужбы 50
0 пример высокоуровневой доменной
модели для Music Corp 77
0 ресурсы для дальнейшего чтения 51
0 событийный штурм 79
Долговечность (ACID-транзакции) 207
Домен См. Бизнес-домены;
Доменно-обусловленный дизайн
0 доменная сопряженность
в микрослужбах 44
0 неясный, неправильное понимание
контуров служб 63
Доставка
0 непрерывная (CD) 63
0 прогрессивная 139, 248

3
Закон
0 Конвея 24
0 Константина 36
Запуск темный
0 и шаблон параллельного выполнения 139

и
Идентификатор корреляции (CID) 223, 239
Изменение переломное 231-235
0 как эта проблема проявляется 231
0 когда эта проблема возникает 231
0 потенциальные решения 232
° предоставление потребителям
времени на миграцию 233
° тщательное обдумывание перед вне­
сением переломного изменения 233
о устранение нечаянных переломных
изменений 232
Изоляция (ACID-транзакции) 207
Имплементация
0 инструмента опроса журналов 144
0 пакетного копировальщика дельты 145
0 триггеров базы данных 143
Инкапсуляция 39
Инструмент моделирования бизнеспроцессов (Business Hrocess Modelling,
BPM) 220
Инструментарий
0 для изменений баз данных 182
0 моделирование бизнес-процессов (ВРМ)
220
0 системы агрегирования журналов 238
0 системы распределенной трассировки
240
Интерфейс пользовательский (UI)
0 Spotify компонентизированный 124
0 компонентно-обусловленный 124
0 проблемы с оставлением его
монолитным 28
0 рассмотрение интерфейсов микрослужб
как пользовательский интерфейс 42
Использование кода многоразовое 62
Испытание в производстве 241

й
Йордон, Эдвард 37

Предметный указатель

|

265

к

м

Карточка лояльности
О пример с выпуском карточек
с использованием шаблона захвата
изменений в данных 142
О пример шаблона ’’Сотрудник-декоратор”
140
Квалификация
0 обеспечивать удовлетворенность
разработчиков, давая им осваивать
новые навыки 61
0 оценивание и совершенствование
для членов групп 81
Коммуницирование видения перемен
в организациях 70
Компетентность стержневая
0 структурирование групп вокруг нее
24, 83
Конвей, Мелвин 24
Конкуренция за доставку 32, 35,60,122,
174
Консолидация выигрышей и порождение
новых изменений в организациях 73
Контекст ограниченный 50
0 отображение с агрегатами
в микрослужбы 50
0 шаблон ’’Один репозиторий на один
ограниченный контекст” 182
0 шаблон "Одна база данных на один
ограниченный контекст” 184
Контракт 231
0 обусловливаемый потребителем (CDC)
247
0 одна микрослужба, выставляющая
наружу два контракта 235
Копирование кода из монолита 98
Культура организационная
0 заякоревание новых подходов в культуре
73
0 адаптивность к изменениям или
улучшениям процессов 94
Кэширование
0 запуск обновлений для кэшей на стороне
клиента 205
0 использование во избежание временной
сопряженности 42

266

|

Предметный указатель

Маршрутизатор на основе содержимого
0 использование для перехвата вызовов,
связанных с обменом сообщениями 116
Масштабирование существующих
монолитов
0 вертикальное 58
0 горизонтальное 58
Методика релиза по требованию 43
Механизм отображения
0 имплементация для внутренней
и внешней баз данных 158
0 отображение изменений во внутренней
базе данных во внешнюю базу данных
157
Миграция
0 изменение поведения во время
мигрирования функциональности 119
0 поступательная 74
Микрослужба 21
0 агрегаты и микрослужбы 48
0 владение в масштабе 229
0 владение внутри организации 30
0 глобальная оптимизация против
локальной 249-252
0 использование совместных библиотек
203
0 история термина 30
0 ключевые выводы 257
0 локальный опыт разработчика 242-244
0 моделируемая вокруг базы данных 25
0 моделируемая вокруг бизнес-домена 22
0 мониторинг и устранение неполадок
237-242
0 независимая развертываемость 22
0 "осиротевшие” службы 253-256
0 отображение в них агрегатов
и ограниченного контекста 50
0 отчетность 235-237
0 переломные изменения 231-235
0 пользовательские интерфейсы 28
0 преимущества 26
0 размер 29
0 решение о принятии на вооружение 53
0 робастность и отказоустойчивость
252-253
0 ситуации, не подходящие для их
использования 63-66
° неясный домен 63

□ отсутствует веская причина их
использовать 65
° программно-информационное обеспе­
чение инсталлируется и управляется
клиентом 65
° стартапы 64
О сквозное тестирование 246
О совместное использование базы данных
148
О технологии 28
О чем больше служб, тем больше головной
боли 227
Многоразовое использование кода
внутри монолитов 36
Модель Spotify для групп 56, 84
Мониторинг и устранение неполадок
О проблемы с микрослужбами 237-242
° потенциальные решения 238
Монолит
О модульный 33, 99
О однопроцессный 32
О распределенный 34
О сторонний 35
О сторонний черно-ящичный 35
Моррис, Киф 57
Мышление "извне-вовнутрь"
при определении интерфейсов служб 40

н
Наблюдаемость 242
0 распределенных систем 242
Нарушение
0 семантическое 233
0 структурное 233
Непрерывная доставка 43

о
Облако 70, 72
0 базы данных от облачных провайдеров
149
0 облачные функции Azure 244
0 платформы функция-как-служба 205
0 публичное 245
0 шкалирование с учетом нагрузки 58
Обязанность по доставке
0 увязка с существующими группами 86
Операция
0 асинхронная: использование во избежа­
ние временной сопряженности 42
0 соединения: замена вызовами служб 194

Оптимизация микрослужб

0 глобальная и локальная 249-252
Опыт разработчика локальный 242
Организация
0 изменение 67-73
° коммуницирование видения перемен
70
о консолидация выигрышей
и порождение новых изменений 73
° развитие видения и стратегии 70
° расширение полномочий сотрудников
по широкому кругу действий 71
п создание направляющей коалиции 69
Отказоустойчивость
0 в сопоставлении с робастностью 59
0 отказоустойчивость и робастность
в микрослужбах 252-253
Откаты
0 в двухфазных фиксациях 210
0 в сагах 215
° переупорядочивание шагов с целью
их уменьшения 217
Отчетность
0 проблемы с микрослужбами 235-237

п
Пакетные задания
0 замена системой захвата изменений
в данных 158
0 массовая синхронизация данных 166
Паралич аналитический 53
Парнас, Дэвид 38
Передача владения 159
Перенос операции соединения 194
Переписывание монолитного кода
поступательное 100
Перехват сообщений
0 шаблон миграции "Фикус-удавка" 116
° маршрутизация на основе
содержимого 116
° селективное потребление сообщений
117
Платформа выгорающая 61
Поведение
0 изменение во время миграции
функциональности 119
Показатель успеха
0 качественный 92
0 количественный 92
Поток трудовой по разработке софта
локальный/удаленный (гибридный) 243

Предметный указатель

|

267

Правило Гринспена №10 44
Приложение монолитное 32
0 мониторинг и устранение неполадок 237
0 один процесс 32
° модульный монолит 33
0 преимущества 35
0 разложение базы данных
о интерфейс "база-данных-как-служба"
(шаблон) 157-159
° передача владения данными 159-164
° проекция базы данных (шаблон) 150—
154
° разбиение базы данных
п разложение таблицы (шаблон) 191—
193
° саги 213-224
° синхронизация данных 164—178
° синхронизировать данные
в приложении (шаблон) 166-170
° служба обертывания базы данных
(шаблон) 154-156
° транзакции 207-213
п трассировочная запись (шаблон) 170178
0 распределенное 34
0 сторонние черно-ящичные системы 35
0 трудности 35
0 эффективное по стоимости
горизонтальное масштабирование 57
Пример
0 FTP 115
0 виджетная композиция 121
0 выпуск карточек лояльности 142
0 заказы в Square 174
0 листинги компании Homegate 136
0 микрофронтэнды 124
0 обратный прокси-сервер HTTP 105
0 перехват сообщений 116
0 программа лояльности 140
0 совместные статические данные 198
0 сравнение ценообразования кредитных
деривативов 135
0 страничная композиция 120
Приоритизация
0 использование доменной модели 79
0 комбинированная модель для
приоритизации декомпозиции
на микрослужбы 81
0 компромиссы в процессе принятия
микрослужб на вооружение 66
Программирование N-вариантное 137

268

|

Предметный указатель

Программно-информационное обеспечение,
инсталлируемое и управляемое клиентом
65
Проекция материализованная 152
Производство
0 испытание в производстве 241
0 транзит микрослужбы в производство 74
Прокси-сервер HTTP обратный
0 пример
° варианты прокси-сервера 108
о вставка прокси-сервера 105
п данные 107
□ изменение протоколов 111
° мигрирование функциональности 106
п перенаправление вызовов 107
Протокол
0 возможности выставлять наружу службы
через многочисленные протоколы 112
0 использование в шаблоне "Фикусудавка” с протоколами помимо HTTP
118
0 смена в миграции шаблона
"Фикус-удавка” с обратным
прокси-сервером HTTP 111
° сетки для служб 113
Процесс 8-ступенчатый Коттера 68

р
Разбиение
0 базы данных 178
0 на обособленные подгруппы 83
Развертывание
0 в сопоставление с релизом 102
0 монолита 32
0 независимая развертываемость
микрослужб 22, 26, 30, 37, 39, 43, 59,
112, 184, 186, 202, 231,233
0 обследование длительностей
предразверточных процессов 57
0 одновременное многочисленных
микрослужб 231
0 сопряженность развертывания 43
Развитие видения и стратегии
в организациях 70
Разделение базы данных:
0 логическое и физическое 179
Разработчик
0 масштабирование их числа 60
0 проблема локального опыта
разработчиков 242-244

Расширение полномочий сотрудников 71
Реестр метаданных служб 254
Реле функции 107
0 использование для переключения между
имплементациями 129
Релиз
0 автоматическая ремедиация релиза 248
0 командно-строевой 231
0 канареечный 134
0 уменьшение рисков с помощью релиза,
меньшего по объему 43
Ремедиация релиза автоматическая 248
Рефакторизация монолита 99
Решение
0 необратимое 75, 251
0 обратимое 75, 251
Робастность
0 в сопоставлении с отказоустойчивостью
59
0 улучшение с использованием
микрослужб 58
0 улучшение с использования микрослужб
58
Робастность и отказоустойчивость
0 проблема с микрослужбами 252-253

с
Сага 213-224
0 имплементация 219
° выбор между хореографированной
и оркестрированной 223
° хореографированные саги 221
0 оркестрированная 219
0 против распределенной транзакции
224
0 режимы сбоя 215
° откаты 215
° переупорядочивание шагов с целью
уменьшения откатов 217
° смешивание ситуаций сбоя назад
и сбоя вперед 218
0 смешивание хореографированного
и оркестрированного стилей 223
0 хореографированная 221
° выбор между ней
и оркестрированным стилем 223
о смешивание с оркестрированным
стилем 223
Связность 36, 38

Связь по внешнему ключу
0 перенос ее в код 193-207
Сервер Apache, боковые вставки 121
Серия релизная 43
Сетка для служб 113
Сеть
0 задержки и сбои 27
0 общение микрослужб 21
Синхронизация данных 164—165
0 в шаблоне синхронизации данных
в приложении 166-170
0 в шаблоне трассировочной записи 173
Система
0 захвата изменений в данных 158
0 распределенная 34
° эволюция в микрослужбы 28
Служба
0 "осиротевшая" 253-256
Событие 135, 142, 157
0 два источника истины, подписанные
на одинаковые события 177
0 использование для уменьшения
доменной сопряженности 47
0 подписка на событие 177, 197
0 прослушивание и использование с целью
обновления внешней базы данных 158
0 публикация события 177
Согласованность данных 133
0 в ACID-транзакциях 207
0 в шаблоне переноса связи по внешнему
ключу в код 196
° выбор способа обработки удаления
197
° запрет удаления 197
° изящная обработка удаления 196
о проверка перед удалением 196
0 допущение несогласованности между
двумя системами 178
0 конечная 174, 176
Создание направляющей коалиции
в организациях 69
Сокрытие информации 38
Сопряженность 36, 38
0 балансирование со связностью 36
0 временная 42
0 доменная 44
0 имплементационная 39
0 развертывания 43
0 служб слабая 22
Сосуществование версий микрослужб 234

Предметный указатель

|

269

Стоимость
О предотвращение эффекта понесенных
расходов 93
О изменения 75-77
° более легкие места для эксперимента
77
» обратимые и необратимые решения 75
О эффективное по стоимости
шкалирование с учетом нагрузки 57
Стратегия
О развитие для организационных
изменений 70
Схема
0 выделенная совместная для справочных
данных 200
0 базы данных 149
0 использование проекций базы данных
для предоставления возможности
изменять лежащую в основе схему 152
0 однозначно выраженная для микрослужб
232
0 попытки монолита и микрослужбы
держать две одинаковые схемы
в синхронном состоянии 168
0 проекция базы данных, берущая
подмножество лежащей в ее основе
схемы 152

т
Тест автоматизированный
0 ограничение охвата 247
Тестирование
0 интеграция тестовых групп в другие
группы 84
0 сквозное микрослужб 246-249
Технология
0 внедрение новой технологии
без использования микрослужб 61
0 внедрение новой технологии
с использованием микрослужб 61
0 решение о том, когда менять технологию
при использовании микрослужб 28
0 смена с целью более оптимального
регулирования нагрузки 57
Тимпсон, Джон 55
Точка конечная
0 выделенная база данных, выставляемая
наружу как конечная точка 157-159
0 служба, напрямую выставляющая базу
данных наружу как заданную конечную
точку 149

270

|

Предметный указатель

Транзакция 207-213
0 ACID 207
о нехватка атомарности 208
0 двухфазные фиксации 210
0 долгоживущая 213
0 компенсирующая 215
0 предотвращение использования
распределенной транзакции 212
Транзакция распределенная
0 в сопоставлении с сагой 224
0 предотвращение 212
0 проблемы 224
Трассировка последовательностей вызовов
между микрослужбами 239

ф
Фаулер, Мартин 74
Фиксация двухфазная (2РС) 210
Фитерс, Майкл 99
Флажок функции См. Реле функции
Формат обмена данными бессхемный 233
Функция-как-служба (FaaS) 245

X
Хаммант, Пол 118
Хелланд, Пэт 224

ц
Ценообразование кредитных деривативов
0 сравнение с использованием
параллельного выполнения 135

ш
Шаблон
0 база отчетных данных 157
0 библиотека статических справочных
данных 201, 261
0 ветвление по абстракции 126-134, 261
° откат к предыдущей имплементации
133
° очистка, удаление старой имплемен­
тации 131
» переключение имплементации 129
» создание абстракции 127
° создание новой имплементации вызо­
ва службы 128
0 выделенная схема справочных данных
200, 261

О дублирование статических справочных
данных 199, 261
О захват изменений в данных 142-146, 261
О интерфейс "база-данных-как-служба"
157-159, 261
О композиция пользовательского
интерфейса 120-125, 261
0 монолит как слой доступа к данным 186,
261
0 монолит с выставлением агрегата
наружу 160, 261
0 мультисхемное хранение 188, 261
0 один репозиторий, один ограниченный
контекст 262
0 одна база данных на один ограниченный
контекст 184
0 параллельное выполнение 107, 134—140,
262
° методы верификации 137
о сравнение с темным запуском
и выпуском канареечных релизов 139
0 перенос связи по внешнему ключу в код
193
о перенос операции соединения 194
° согласованность данных 196
0 перенос внешнего ключа в код 262
0 приложение"Фикус-удавка” 62, 101-119,
134, 262
□ примеры использования 103, 118
0 проекция базы данных 150-154
° база данных как публичный контракт
151
° вопросы владения 153
о ограничения 153
° проекции в настоящее 152
□ сравнение с шаблоном интерфейса
"база-данных-как-служба" 159
0 разбиение таблицы 262
0 разложение таблицы 191
0 синхронизация данных в приложении
166-170, 262
° использование шаблона 169
о массовая синхронизация данных 166
° синхронизировать при записи, читать
из новой базы данных 168
° синхронизировать при записи, читать
из старой базы данных 167
0 служба обертывания базы данных 154—
156, 262
° где его использовать 155
о использование для уменьшения зави­
симости от центральной базы данных
155

0 служба статических справочных данных
204, 262
0 смена владельца данных 162, 262
0 совместная база данных 147, 262
0 "Сотрудник-декоратор" 140-142, 262
° где его использовать 141
о пример с программой лояльности 140
Шаблон конкурирующего потребителя 59
Шаблон миграции 100-146
0 "Ветвление по абстракции" 126-134
° где его использовать 134
° использование абстракции 127
о как он работает 126
о откат к предыдущей имплементации
133
о очистка, удаление старой имплемен­
тации 131
° переключение имплементации 129
° создание абстракции 127
° создание новой имплементации
вызова службы 128
0 "Захват изменений в данных" 142-146
° где его использовать 145
° имплементация инструментов опроса
журналов транзакций 144
о имплементация пакетного
копировальщика дельты 145
° имплементация триггеров базы
данных 143
о пример с выпуском карточек
лояльности 142
0 "Композиция пользовательского
интерфейса" 120-125
° где его использовать 125
° и мобильные приложения 123
° пример с виджетной композицией 121
° пример с микрофронтэндами 124
° страничная композиция 120
0 "Параллельное выполнение" 134—140
° верификация с использованием
библиотеки Scientist 139
° верификация с использованием
шпионов 137
° где его использовать 139
° методы верификации 137
° пример с листингами фирмы
Homegate 136
° пример со сравнением ценообразова­
ния кредитных деривативов 135
» сравнение с темным запуском
и выпуском канареечных релизов 139

Предметный указатель

|

271

Шаблон миграции (прод.)
О ”Приложение Фикус-удавка" 101-119
° где его использовать 103
° другие примеры использования 118
п использование с протоколами помимо
HTTP 118
» пример с FTP 115
о пример с обратным прокси-сервером
HTTP 105-7
° пример с перехватом сообщений 116
0 справочник шаблонов 261
Шпион: использование для верификации
параллельного выполнения 137
Штурм событийный 79

272

|

Предметный указатель

э
Эффект понесенных расходов 54
0 возникающий из-за чрезмерной
приверженности определенной стратегии
70
0 предотвращение 93

я
Язык программирования 26, 48, 139
0 выбор языков и микрослужбы 28
0 размер микрослужбы 29