Какие знаешь шаблоны проектирования микросервисной архитектуры?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Шаблоны проектирования микросервисной архитектуры
Микросервисная архитектура — это новая парадигма, которую я активно применяю в своих проектах. Существует множество проверенных паттернов, которые помогают избежать типичных ошибок.
1. Service Discovery
Микросервисы должны динамически обнаруживать друг друга без жёсткого конфигурирования IP адресов.
Реализация с Eureka (Spring Cloud):
@SpringBootApplication
@EnableEurekaServer
public class ServiceDiscoveryApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceDiscoveryApplication.class, args);
}
}
// В микросервисе
@SpringBootApplication
@EnableEurekaClient
public class UserServiceApplication {
@LoadBalanced
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
@Service
public class OrderService {
private final RestTemplate restTemplate;
public void createOrder(Order order) {
// Eureka автоматически разрешает адрес
restTemplate.postForObject(
"http://user-service/api/v1/users/validate",
order.getUserId(),
User.class
);
}
}
2. API Gateway
API Gateway — это единая точка входа для всех запросов клиентов. Маршрутизирует их к нужным микросервисам.
# application.yml
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/v1/users/**
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/v1/orders/**
@Component
public class AuthenticationFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (token == null || !isValidToken(token)) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
}
3. Circuit Breaker
Если один микросервис падает, остальная система должна продолжать работать.
@Service
public class PaymentService {
@CircuitBreaker(name = "paymentBreaker", fallbackMethod = "fallbackPayment")
public void processPayment(Order order) {
// Вызов внешнего сервиса
paymentGateway.charge(order.getAmount());
}
public void fallbackPayment(Order order, Exception e) {
// Откладываем платёж в очередь для обработки позже
paymentQueue.enqueue(order);
logger.warn("Payment gateway unavailable, queued order: {}", order.getId());
}
}
// application.yml конфигурация
resilience4j:
circuitbreaker:
instances:
paymentBreaker:
registerHealthIndicator: true
slidingWindowSize: 10
failureRateThreshold: 50
waitDurationInOpenState: 5000
4. Saga Pattern для распределённых транзакций
Разных сервисов не могут работать в одной ACID транзакции. Используем Saga:
// Choreography-based Saga
@Service
public class OrderService {
private final ApplicationEventPublisher publisher;
@Transactional
public void createOrder(Order order) {
Order savedOrder = orderRepository.save(order);
// Публикуем событие
publisher.publishEvent(new OrderCreatedEvent(savedOrder));
}
}
@Service
public class InventoryService {
@EventListener
@Transactional
public void handleOrderCreated(OrderCreatedEvent event) {
Order order = event.getOrder();
try {
// Резервируем товар
inventory.reserve(order.getItems());
publisher.publishEvent(new InventoryReservedEvent(order));
} catch (InsufficientInventoryException e) {
// Компенсирующая транзакция
publisher.publishEvent(new OrderCancelledEvent(order));
}
}
}
5. Event-Driven Architecture
Микросервисы общаются через события, а не прямыми вызовами.
@Configuration
public class EventConfig {
@Bean
public NewTopic userCreatedTopic() {
return TopicBuilder.name("user-events")
.partitions(3)
.replicas(2)
.build();
}
}
@Service
public class UserEventPublisher {
private final KafkaTemplate<String, UserEvent> kafkaTemplate;
public void publishUserCreated(User user) {
kafkaTemplate.send("user-events",
user.getId().toString(),
new UserCreatedEvent(user));
}
}
@Service
public class NotificationService {
@KafkaListener(topics = "user-events", groupId = "notification-group")
public void onUserCreated(UserCreatedEvent event) {
// Отправляем приветственное письмо
emailService.sendWelcomeEmail(event.getUser());
}
}
6. Distributed Tracing
Для отладки запросов, проходящих через несколько сервисов, используем трейсинг:
@Configuration
public class TracingConfig {
@Bean
public Sampler defaultSampler() {
return Sampler.ALWAYS_SAMPLE;
}
}
@Service
public class OrderService {
private final Tracer tracer;
public void processOrder(Order order) {
Span span = tracer.startSpan("process-order");
try (SpanInScope ignored = tracer.withSpanInScope(span)) {
span.tag("order.id", order.getId().toString());
span.tag("order.amount", order.getAmount().toString());
// Обработка
} finally {
span.finish();
}
}
}
7. Strangler Fig Pattern
Миграция от монолита к микросервисам делается постепенно:
// API Gateway перенаправляет запросы либо на микросервис, либо на старый монолит
@Component
public class LegacyRouterFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
if (isNewFeature(exchange.getRequest().getPath())) {
// Переходит на новый микросервис
return chain.filter(exchange);
} else {
// Остаётся на старом монолите
return routeToLegacySystem(exchange);
}
}
}
8. CQRS (Command Query Responsibility Segregation)
Разделение логики чтения и записи для оптимизации:
// Command service (запись)
@Service
public class CreateUserCommand {
private final UserRepository userRepository;
public User execute(CreateUserRequest request) {
User user = new User(request.getEmail(), request.getName());
return userRepository.save(user);
}
}
// Query service (чтение из денормализованного хранилища)
@Service
public class GetUserQuery {
private final UserReadRepository readRepository; // MongoDB или Elasticsearch
public UserReadModel execute(UUID userId) {
return readRepository.findById(userId);
}
}
9. Service Mesh (Istio, Linkerd)
Делегирует cross-cutting concerns (логирование, авторизация, rate limiting) в инфраструктуру:
# Istio VirtualService
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: order-service
spec:
hosts:
- order-service
http:
- match:
- headers:
user-type:
exact: premium
route:
- destination:
host: order-service
subset: v2
weight: 100
- route:
- destination:
host: order-service
subset: v1
weight: 100
Рекомендации по выбору
Начало проекта:
- Используй API Gateway + Service Discovery
- Внедри Circuit Breaker рано
- Логируй всё через централизованное логирование
Масштабирование:
- Добавь Event-Driven архитектуру
- Внедри CQRS если есть асимметрия читаемых/записываемых операций
- Рассмотри Service Mesh при >5 сервисов
Мониторинг:
- Distributed Tracing обязателен для отладки
- Используй метрики Prometheus
- Настрой алерты в Grafana
Все эти паттерны работают вместе, создавая надёжную и масштабируемую архитектуру.