Какие преимущества и недостатки у микросервисной архитектуры?

Ответ

Преимущества:

  1. Независимое масштабирование – каждый сервис масштабируется отдельно под свою нагрузку.
  2. Технологическая гибкость – разные сервисы могут быть реализованы на различных языках и технологических стеках.
  3. Устойчивость к отказам – сбой одного сервиса не приводит к полному отказу системы.
  4. Независимые циклы разработки и развертывания – команды могут работать и выпускать обновления автономно.

Недостатки:

  1. Высокая операционная сложность – требуется оркестрация (Kubernetes), централизованное логирование, трассировка и мониторинг.
  2. Сетевое взаимодействие – вызовы между сервисами (HTTP, gRPC) медленнее внутрипроцессных и подвержены сетевым сбоям.
  3. Сложность управления данными – обеспечение согласованности данных между сервисами требует паттернов вроде Saga или CQRS вместо простых ACID-транзакций.
  4. Нагрузка на DevOps – необходима сложная автоматизация сборки, тестирования и развертывания (CI/CD).

Практический пример разделения:

// Микросервис User Service (управление пользователями)
@RestController
@RequestMapping("/api/users")
public class UserController {
    @GetMapping("/{id}")
    public ResponseEntity<User> getUser(@PathVariable Long id) {
        return ResponseEntity.ok(userService.findById(id));
    }
}
// Микросервис Order Service (управление заказами) вызывает User Service
@FeignClient(name = "user-service")
public interface UserServiceClient {
    @GetMapping("/api/users/{id}")
    User getUserById(@PathVariable("id") Long userId);
}

@Service
public class OrderService {
    public Order createOrder(Long userId) {
        // Вызов другого микросервиса для получения данных
        User user = userServiceClient.getUserById(userId);
        // ... логика создания заказа
    }
}

Ответ 18+ 🔞

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

Что хорошего, спросишь? Ну, во-первых, масштабирование независимое. Представь: у тебя сервис с картинками котиков лопается от трафика, а сервис с расчётом пенсии деда лежит мёртвым грузом. Так вот, котиков ты можешь размножить на десять инстансов, а деда оставить в покое. Экономия, блядь!

Технологический зоопарк – это второй плюс. Один сервис можешь на Go написать, потому что он сетевой и быстрый, а другой – на Python, потому что там data science мудак сидит, который только на нём и умеет. И никто никого не ебёт, все в своих песочницах.

Устойчивость, мать её. Один сервис накрылся медным тазом – ну, допустим, «Служба отправки спама» легла. А основное-то приложение, «Интернет-магазин», живое! Покупатели даже не заметят, что им перестали названивать. Пиздец как удобно.

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


А теперь, сука, ложка дёгтя, размером с лопату.

Операционная сложность – овердохуища. Раньше был один жирный сервер, ты на него зашёл, лог посмотрел – и всё ясно. А теперь у тебя этих сервисов, как тараканов, сорок штук. Где логи? Кто кого вызывает? Кто сдох? Приходится ставить кучу хуйни: Kubernetes (этот ёбаный оркестратор), централизованное логирование, трассировку, мониторинг. Это целая наука, блядь, отдельная вакансия «Инженер, который всё это ебёт».

Сетевое общение – тормоза и проблемы. В монолите один метод другой вызвал – и всё, наносекунды. А тут один сервис другому через HTTP стучится: «Э, чувак, дай-ка данные пользователя!». А сеть-то, сука, может лежать! Таймауты, ретраи, circuit breaker'ы... В общем, доверия ебать ноль к этому каналу.

С данными – пиздец и раздрай. В монолите была одна база, транзакция ACID – и порядок. Создал заказ, списал деньги, всё в одной транзакции. А тут у каждого сервиса своя база! Как обеспечить, что если заказ создался, то деньги точно списались? Приходится городить огород из паттернов типа Saga – это когда сервисы друг другу события кидают, и если что-то пошло не так, надо откатывать всё по цепочке. Головная боль, блядь, на неделю.

DevOps нагрузка – терпения ноль ебать. Раньше собрал один jar-ник и задеплоил. А теперь тебе надо для каждого из сорока говнышек свой пайплайн в CI/CD, свои образы в Docker, свои конфиги. Команда девопсов разрастается, как опухоль.


Ну и пример, чтобы было понятно, как они друг другу мозги ебут:

Вот у нас Сервис Пользователей. Сидит, хранит данные о людях.

// Микросервис User Service (управление пользователями)
@RestController
@RequestMapping("/api/users")
public class UserController {
    @GetMapping("/{id}")
    public ResponseEntity<User> getUser(@PathVariable Long id) {
        return ResponseEntity.ok(userService.findById(id));
    }
}

А вот Сервис Заказов. Ему, чтобы заказ создать, надо знать, кто его создаёт. И он идёт, стучится к первому сервису через сеть.

// Микросервис Order Service (управление заказами) вызывает User Service
@FeignClient(name = "user-service") // Смотри, какая хитрая жопа - Feign Client!
public interface UserServiceClient {
    @GetMapping("/api/users/{id}")
    User getUserById(@PathVariable("id") Long userId); // Тыкается в эндпоинт чужого сервиса
}

@Service
public class OrderService {
    public Order createOrder(Long userId) {
        // И вот он, ебаный сетевой вызов! Может ответить, а может и нет.
        User user = userServiceClient.getUserById(userId);
        // ... логика создания завода
    }
}

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