Как строить надёжные приложения? Делаем хорошо, а плохо — не делаем.
Если вам всё это знакомо, тогда этот чек-лист для вас.
Автоматизируйте, насколько это возможно
Проверки контрактов в межсервисном взаимодействии это непросто, но необходимо для больших систем. Будь то интеграционные тесты, staging-окружение с выполнением регрессионных тестов или что-то ещё — главное, чтобы вы до деплоя в prod увидели ломающее изменение в API. Это касается и синхронных, и асинхронных взаимодействий.
Сбалансированные метрики и алерты
Стройте понятные для всей команды метрики и алерты. Плохо, когда алерты не срабатывают при проблемах, потому что пороги срабатывания некорректные. Не менее плохо, когда алерты слишком чувствительные, так что на них перестают реагировать. Просыпаться по ночам, потому что на проде проблемы, а алерт говорит, что «что-то сломалось» — так себе идея, когда у вас десяток сервисов, вам нужно посмотреть кучу дашбордов, а хочется спать.
Используйте feature flags
Feature flags позволяют включать и отключать функциональность без повторного деплоя (если правильно применять). Это особенно полезно для A/B-тестирования, постепенного развёртывания и быстрого отката проблемных изменений.
Минимум велосипедов
Retries, rate limiters, circuit breakers — всё это можно закрыть через Service Mesh. В идеальном мире ваш код даже не должен заботиться о таких вещах. В реальном мире... ну, вы же видели, каких Франкенштейнов иногда строят?
Если ваш сервис всё ещё сам делает ретраи, и вы вручную прописываете таймауты, руками добавляете circuit breakers — пора задуматься о Service Mesh.
Внедряйте практики SRE, если ещё не
Готовьтесь к отказам заранее
Деградации и даунтаймы неизбежны, поэтому их нужно учитывать при проектировании системы. Внедряйте Chaos Engineering, чтобы выявлять слабые места и повышать устойчивость системы. Если ваша система не способна подняться под нагрузкой, chaos engineering позволит вам это понять, протестировать и в идеале поправить (но это не точно).
Минимизируйте эффект неожиданности
Стройте простые и прямолинейные системы. Если вам кажется, что можно немного усложнить код ради оптимизации — не делайте этого без веской причины. Кому-то потом придется в этом разбираться.
Например, вы решили параллелить обработку запросов ради производительности? Померяйте, сделайте бенчмарки. Возможно, оно и так достаточно быстро. А если нет, сначала убедитесь, что проблема не в БД, не в блокировках или троттлинге CPU.
Сложные системы всегда становятся сложными сами по себе, не нужно им в этом помогать. Делайте проще.
Больше полезных материалов — в канале «Kubernetes и кот Лихачева».
Как часто вы наблюдали деградации в больших системах?
Как много раз вам приходилось разбираться, почему в очередной раз что-то сломалось или деградировало, потому что, по независящим от вас причинам, произошли изменения в зависимостях, будь то инфраструктура или API, от которых вы зависите? 🤯
Если вам всё это знакомо, тогда этот чек-лист для вас.
Автоматизируйте, насколько это возможно
Проверки контрактов в межсервисном взаимодействии это непросто, но необходимо для больших систем. Будь то интеграционные тесты, staging-окружение с выполнением регрессионных тестов или что-то ещё — главное, чтобы вы до деплоя в prod увидели ломающее изменение в API. Это касается и синхронных, и асинхронных взаимодействий.
Сбалансированные метрики и алерты
Стройте понятные для всей команды метрики и алерты. Плохо, когда алерты не срабатывают при проблемах, потому что пороги срабатывания некорректные. Не менее плохо, когда алерты слишком чувствительные, так что на них перестают реагировать. Просыпаться по ночам, потому что на проде проблемы, а алерт говорит, что «что-то сломалось» — так себе идея, когда у вас десяток сервисов, вам нужно посмотреть кучу дашбордов, а хочется спать.
Используйте feature flags
Feature flags позволяют включать и отключать функциональность без повторного деплоя (если правильно применять). Это особенно полезно для A/B-тестирования, постепенного развёртывания и быстрого отката проблемных изменений.
Минимум велосипедов
Retries, rate limiters, circuit breakers — всё это можно закрыть через Service Mesh. В идеальном мире ваш код даже не должен заботиться о таких вещах. В реальном мире... ну, вы же видели, каких Франкенштейнов иногда строят?
Если ваш сервис всё ещё сам делает ретраи, и вы вручную прописываете таймауты, руками добавляете circuit breakers — пора задуматься о Service Mesh.
Внедряйте практики SRE, если ещё не
- Capacity planning и capacity testing. У вас есть лимиты, просто вы о них пока не знаете. Проверьте заранее, прежде чем узнать это в проде, когда kubelet решит убить ваши поды по out of memory.
- Частые выкатки небольшими изменениями. Чем меньше изменений за раз, тем проще откатить, если что-то пойдёт не так.
- Управление инцидентами. Лучшая инженерная культура — это не поиск виноватых, а поиск причин ошибок. k8s не винит сбойный pod, он просто его перезапускает. Будьте как k8s.
Готовьтесь к отказам заранее
Деградации и даунтаймы неизбежны, поэтому их нужно учитывать при проектировании системы. Внедряйте Chaos Engineering, чтобы выявлять слабые места и повышать устойчивость системы. Если ваша система не способна подняться под нагрузкой, chaos engineering позволит вам это понять, протестировать и в идеале поправить (но это не точно).
Минимизируйте эффект неожиданности
Стройте простые и прямолинейные системы. Если вам кажется, что можно немного усложнить код ради оптимизации — не делайте этого без веской причины. Кому-то потом придется в этом разбираться.
Например, вы решили параллелить обработку запросов ради производительности? Померяйте, сделайте бенчмарки. Возможно, оно и так достаточно быстро. А если нет, сначала убедитесь, что проблема не в БД, не в блокировках или троттлинге CPU.
Итог
Сложные системы всегда становятся сложными сами по себе, не нужно им в этом помогать. Делайте проще.
Больше полезных материалов — в канале «Kubernetes и кот Лихачева».