4 ключевых аспекта проектирования распределенных систем

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

Надежность

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

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

Почему это важно?

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

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

Как добиваться надежности

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

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

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

Доступность

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

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

Почему это важно?

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

Как добиваться доступности

Это будет сильно зависеть от инфраструктуры системы. Планируете создавать все автономно или положитесь на облачного провайдера? Если автономно, то придется поддерживать работу серверов 24/7 и обеспечивать аппаратное резервирование.

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

Обслуживаемость

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

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

Почему это важно?

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

Как добиваться обслуживаемости

Печально, но четкого уникального ответа на этот вопрос нет. Некоторые известные принципы, которые вы можете применить к коду, например SOLID, KISS и YANGL, ориентированы на простоту.

Я считаю Zen of Python хорошим обобщением правил по написанию кода.

Красивый лучше страшного.
Явный лучше неявного.
Простой лучше сложного.
Сложный лучше усложненного.
Плоский лучше вложенного.
Просторный лучше плотного.
Читаемость важна.
Особые случаи не достаточно особые, чтобы нарушать правила.
Практичность побеждает чистоту.
Ошибки никогда не должны проскальзывать незаметно, если только не были умышленно заглушены.
В случае двусмысленности противьтесь соблазну угадывать.
Должен быть один и желательно всего один способ сделать задуманное, хотя этот способ поначалу может не быть очевиден.
Сейчас лучше, чем никогда.
Хотя никогда всегда лучше, чем “прямо” сейчас.
Если реализацию сложно объяснить, то она плоха.
Если реализацию объяснить легко, то она может быть хороша.
Пространства имен  —  это отличная идея, давайте создавать их больше!

Масштабируемость

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

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

Почему это важно?

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

Как добиться масштабируемости

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

  • количество пользователей или параллельных пользователей;
  • количество запросов в секунду или минуту;
  • размер размещаемых файлов или сочетание размера файлов с количеством параллельных пользователей, их размещающих;
  • что-то совсем другое.

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

Далее нужно выяснить, быстро или медленно будет расти нагрузка, и будут ли возникать ее пики. Представьте себе бар  —  будет ли он равно заполнен во вторник и субботу? А что, если во вторник проходит полуфинал кубка мира по футболу?

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

Выводы

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

Читайте также:

Читайте нас в TelegramVK и Дзен


Перевод статьи Rubén Romero: 4 Key Aspects for Designing Distributed Systems

Предыдущая статьяЗаменит ли аутентификация по лицу традиционную систему веб-аутентификации
Следующая статьяКак улучшить навыки работы с Python в 2023 году