📖 Глава 1: "Как три кота построили облачный город"
Жили-были три кота: Изи 🐱, Санни 🐱 и Фанни 🐱. Они мечтали построить удобный облачный город для всех кошек, где можно было бы легко регистрироваться, заказывать еду и быстро оплачивать покупки.
Сначала коты решили сделать огромный дворец, где будет один большой сервис для всего. В этом сервисе обрабатывались и пользователи, и заказы, и платежи. Такой подход называется монолитной архитектурой.
Если ломалась одна часть, страдали все. Если падал сервис оплаты, коты не могли даже зарегистрироваться!
Добавлять новые функции стало сложно. Каждый раз, когда Санни хотел добавить новый тип заказа, приходилось изменять огромный код монолита.
Масштабировать было трудно. Когда пользователей стало больше, котам нужно было запускать целый сервис, даже если нагрузка была только на оплату.
"Так не пойдёт!" — сказали коты. "Давайте разделим наш город на независимые дома, каждый из которых будет заниматься своим делом!"
Так они перешли на микросервисную архитектуру, где каждый сервис — это свой домик в облачном городе. Этот город теперь можно легко расширять, добавляя новые дома-сервисы без ущерба для остальных.
🏠 Разбивка на три облачных сервиса
Теперь у каждого кота была своя ответственность:
Сервис пользователей (“User Service”) — отвечает за регистрацию и авторизацию. Управляет Изи 🐱. Ее дом — это городская администрация.
Сервис заказов (“Order Service”) — отвечает за создание и управление заказами. Управляет Санни 🐱. Его дом — это ресторанная площадь.
Сервис оплаты (“Payment Service”) — отвечает за платежи и баланс. Управляет Фанни 🐱. Её дом — это банк в центре города.
Теперь, если банк временно закроется, рестораны и администрация продолжат работать. А если в ресторанах много посетителей, можно просто открыть ещё один ресторан (экземпляр сервиса заказов), не трогая остальные.
🚀 Создание первых облачных сервисов
На данном этапе рассматриваются только контроллеры, без сервисного и репозиторного слоёв. В будущем коты улучшат свой город, добавив обработку бизнес-логики и работу с базами данных.
Maven-конфигурация
Перед тем как начать, убедимся, что у нас есть базовый pom.xml для каждого сервиса:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
🐱 Сервис пользователей (User Service) — городская администрация
@RestController
@RequestMapping("/users")
public class UserController {
private final Map<Long, String> users = new HashMap<>();
@PostMapping("/register")
public ResponseEntity<String> registerUser(@RequestParam String name) {
long id = users.size() + 1;
users.put(id, name);
return ResponseEntity.ok("Пользователь зарегистрирован с ID: " + id);
}
@GetMapping("/{id}")
public ResponseEntity<String> getUser(@PathVariable Long id) {
return users.containsKey(id) ?
ResponseEntity.ok("Имя пользователя: " + users.get(id)) :
ResponseEntity.notFound().build();
}
}
🐱 Сервис заказов (Order Service) — ресторанная площадь
@RestController
@RequestMapping("/orders")
public class OrderController {
private final List<String> orders = new ArrayList<>();
@PostMapping("/create")
public ResponseEntity<String> createOrder(@RequestParam String item) {
orders.add(item);
return ResponseEntity.ok("Заказ создан: " + item);
}
@GetMapping
public ResponseEntity<List<String>> getOrders() {
return ResponseEntity.ok(orders);
}
}
@RestController
@RequestMapping("/payments")
public class PaymentController {
private final Map<Long, Double> balances = new HashMap<>();
@PostMapping("/pay")
public ResponseEntity<String> makePayment(@RequestParam Long userId, @RequestParam double amount) {
balances.put(userId, balances.getOrDefault(userId, 0.0) - amount);
return ResponseEntity.ok("Оплата на сумму " + amount + " выполнена.");
}
@GetMapping("/{userId}")
public ResponseEntity<String> getBalance(@PathVariable Long userId) {
return balances.containsKey(userId) ?
ResponseEntity.ok("Баланс: " + balances.get(userId)) :
ResponseEntity.notFound().build();
}
}
☁️ Как облачные сервисы взаимодействуют?
Теперь сервисы работают отдельно, но иногда нужно, чтобы они общались. Например, перед тем как создать заказ, надо убедиться, что пользователь существует.
Для этого сервис заказов может вызывать сервис пользователей через REST API:
RestTemplate restTemplate = new RestTemplate();
String userExists = restTemplate.getForObject("http://localhost:8081/users/" + userId, String.class);
if (userExists == null) {
return ResponseEntity.badRequest().body("Пользователь не найден!");
}
Но такой способ плох, потому что сервисы жёстко связаны. Например:
1) Сервис заказов не знает, существует ли пользователь.
Прежде чем создать заказ, нужно проверить, зарегистрирован ли пользователь. Сейчас Order Service делает REST-запрос к User Service, но если тот временно недоступен, заказ не получится создать.
2) Сервис оплаты не может проверить заказ.
Перед оплатой нужно убедиться, что заказ существует и его статус корректен. Сейчас Payment Service должен отправлять запрос в Order Service, что создаёт жёсткую зависимость.
3) Жёсткие связи между сервисами.
Если поменяется API одного сервиса, придётся менять код в других. В монолите это было проще, но в микросервисах приходится продумывать более гибкие механизмы, например асинхронные события через Kafka.
В следующих главах мы разберём как использовать Service Discovery и API Gateway для улучшения взаимодействия!
💡 Подведем итоги
Коты перешли с монолита на облачную микросервисную архитектуру, создав три независимых сервиса:
User Service (администрация) — регистрация и авторизация.
Order Service (рестораны) — создание заказов.
Payment Service (банк) — управление балансом.
Теперь город стал устойчивее и легче масштабировать! Но пока сервисы не умеют удобно общаться друг с другом. Как коты решат эту проблему?
📖 Продолжение следует в следующей главе!
Top comments (1)
Awesome !)