Распределенные системы. Паттерны проектирования - [9]

Шрифт
Интервал

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

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

Кроме изоляции ресурсов, существует множество причин раз-делять одноузловое приложение на несколько контейнеров. Рас-смотрим масштабирование команды. Есть достаточно оснований  верить тому, что идеальное количество человек в команде — от  шести  до  восьми.  Чтобы  так  структурировать  команды  и  при  этом создавать системы значительного размера, членам каждой  команды  необходимо  давать  небольшой,  четко  ограниченный  32 Часть I. Одноузловые паттерны проектирования

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

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

Надеюсь, приведенные примеры натолкнули вас на мысль о де-композиции своих приложений на несколько контейнеров, даже  если они работают в рамках одного узла. В последующих главах  Часть I. Одноузловые паттерны проектирования 33

будут  описаны  паттерны,  которые  помогут  вам  сориентиро-ваться в построении модульных групп контейнеров. В отличие  от многоузловых распределенных паттернов эти паттерны под-разумевают тесную связь между всеми контейнерами. В частно-сти, они предполагают, что исполнение контейнеров в паттерне  может быть надежно распланировано в рамках одной машины.  Они  также  подразумевают,  что  все  контейнеры  в  рамках  пат-терна  могут  при  необходимости совместно  использовать тома  или  части  файловых  систем,  а  также  иные  ключевые  ресурсы,  например  сетевые  пространства  имен  и  общую  память.  Такая  тесно  связанная  группа  в  Kubernetes> 1   называется  подом (pod) ,  но сама идея в общем случае применима к разным оркестрато-рам контейнеров, хотя некоторые из них могут поддерживать ее  более естественным образом, нежели другие. 2> Паттерн Sidecar Sidecar — это одноузловой паттерн, состоящий из двух контей-неров.  Первый  из  них  —  контейнер приложения .  Он  содержит  основную логику программы. Без этого контейнера приложения  бы не существовало. Вдобавок к контейнеру приложения пред-усмотрен еще  «прицепной» (sidecar) контейнер . Роль прицепа —  дополнить  и  улучшить  контейнер  приложения,  часто  таким  образом,  чтобы  приложение  не  знало  о  его  существовании.  В  простейшей  форме  контейнер-прицеп  можно  использовать,  чтобы добавить функциональности контейнеру, который было  бы сложно улучшить иным способом.