Все наши проекты в Коде устроены просто:
- вся разработка ведётся одними и теми же программистами;
- каждый понимает, что делает любая строчка кода;
- если что-то непонятно, это можно выяснить и разобраться за 5 минут в чате;
- а главное, каждый проект — это один большой скрипт или страница, которые полностью отвечают за всю логику работы.
Такой подход работает в маленьких командах. Но что будет, если проект будет намного сложнее? Давайте разбираться.
Проблемы монолитной разработки
Наш подход принято называть монолитной разработкой. Это значит, что все компоненты программы соединяются в одной точке. Например, если мы делаем онлайн-сервис для ведения списка дел, то в нашем коде могут быть такие функции:
- регистрация в сервисе,
- напоминание пароля,
- создание нового списка задач,
- управление списками,
- создание новой задачи,
- редактирование задачи,
- удаление задачи.
Чтобы работа шла быстрее, мы зовём ещё двоих программистов. Каждый делает свой набор функций, встраивает их в один код, а на выходе получается один большой скрипт.
Проблема в том, что чем больше в коде элементов, тем сложнее поддерживать всю систему в целом. Уже не получится просто поменять одну строчку в функции регистрации, потому что она может повлиять на работу остальных функций. Например, мы убрали обязательную регистрацию по электронной почте, но тогда сломается функция напоминания пароля — в ней написано, что пароль нужно отправить именно на почту.
Ещё такие проекты сложно оптимизировать, если мы нашли более быструю реализацию какой-то функции. Если мы заменим функцию редактирования задачи на более быструю, нам нужно будет перепроверить заново весь остальной код и убедиться, что ничего не сломалось. Это трудозатратно.
Микросервисы — разбиваем программу на автономные части
Когда проект разрастается, одно из решений — разбить его на отдельные части, а потом связать их между собой. Следите за руками:
- Каждая смысловая часть программы выносится в отдельный код, который делает что-то одно: получает данные от сервера, отправляет логин и пароль на проверку, даёт разрешение пользователю на вход и т. д.
- Каждая такая программа может получать и отправлять данные в каком-то формате. Благодаря этому программы могут обмениваться данными и управлять друг другом.
- Такие мини-программы и называются микросервисами.
Каждый такой микросервис работает автономно от остальных, и единственная его задача — вовремя и правильно прореагировать на полученные данные и отправить ответ по нужному адресу.
👉 Главный принцип в таком подходе — сделать так, чтобы у каждого микросервиса было понятное описание, в каком формате он получает данные, в каком отправляет и куда именно отправляет.
Пример
Разобъём нашу программу из начала статьи на микросервисы:
Обратите внимание — у нас появились функциональные элементы, которых не было в исходной картинке: например отрисовка интерфейса, запрос данных от пользователя, отправка данных на сервер, запрос в БД.
Всё дело в том, что сама программа и была тем обвесом с дополнительными функциями, которая делала всю остальную работу. Как только мы убрали центральный «пульт управления», нам пришлось добавить несколько микросервисов, которые взяли на себя эту работу.
Плюсы и минусы микросервисов
Микросервисная архитектура решает главную задачу программистов на масштабных проектах: превращает сложную и объёмную программу в набор простых деталей, которые работают вместе. Ещё из плюсов:
- Каждый микросервис можно полностью заменить или переписать без потери качества для проекта, если у него будет тот же формат общения с другими микросервисами.
- Если нужно, можно запустить одновременно несколько одинаковых микросервисов на разных компьютерах, чтобы повысить устойчивость и скорость работы приложения.
- Если какой-то микросервис откажет, то чаще всего это не приводит к падению всего сервиса или программы. Ещё можно настроить автоматический перезапуск микросервиса после аварийного завершения.
- Неважно, на каком языке написан микросервис, если он делает то, что нужно, и умеет общаться с другими. Например, для высокопроизводительных частей можно использовать С++, а для остальных — Java или Kotlin.
- Можно постепенно наращивать возможности приложения, просто подключая новые микросервисы к системе.
Но и минусы у такого подхода тоже есть:
- В простых проектах микросервисы потребуют больше времени, сил и внимания.
- Нет единого стандарта общения между микросервисами. Каждая компания сама определяет формат сообщений и способ передачи данных.
- Если работа одних микросервисов зависит от времени отклика других, а те, в свою очередь, зависят от третьих, то время обработки всех этих запросов может стать проблемой.
- Чем больше микросервисов работает в программе, тем сложнее ими управлять, чтобы всё работало без сбоёв. Часто для этих целей используют специальный софт, например Kubernetes, но владение им требует отдельных навыков.
Пример: работа системы под нагрузкой
Допустим, у нас есть две версии одного и того же сервиса: один сделан единым кодом, второй — на микросервисах.
Пока нагрузка в рамках нормы, оба сервиса работают примерно одинаково:
Но если посетителей внезапно больше (например, отлично сработала рекламная кампания), то монолитный сервис может упасть под нагрузкой. Оказывается, базу данных не оптимизировали под такое количество запросов. А если у нас всё на микросервисах, то отдельная программа, которая за ними следит, увидит, что запросов стало слишком много, и запустит ещё несколько микросервисов с обработками запросов в базу данных:
Это что, теперь каждую программу нужно писать на микросервисах?
Нет, не обязательно. Микросервисы хороши только в сложных проектах или в сервисах с высокой нагрузкой.
Но если вы с командой точно знаете, какой фрагмент кода за что отвечает и как всё это связано в одно целое, — вам не нужны микросервисы, это будет лишним усложнением. Это как покупать профессиональный краскопульт, чтобы покрасить две доски на даче — вроде и круто, но затраты того не стоят.