← Назад к вопросам

Какие операции записи микросервиса использовались на последней работе

1.7 Middle🔥 161 комментариев
#Spring Framework

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Операции записи микросервиса на последней работе

Для Java разработчика с опытом, практическое применение микросервисной архитектуры — это критически важный навык. На последней работе я был глубоко вовлечён в разработку и оптимизацию операций записи в микросервисной системе.

1. Синхронная запись с REST API

Основной механизм для операций записи был синхронный HTTP REST API:

@RestController
@RequestMapping("/api/v1/orders")
public class OrderController {
    private final OrderService orderService;
    
    @PostMapping
    public ResponseEntity<OrderResponse> createOrder(
        @Valid @RequestBody CreateOrderRequest request) {
        Order order = orderService.createOrder(request);
        return ResponseEntity.status(HttpStatus.CREATED)
            .body(OrderResponse.from(order));
    }
    
    @PutMapping("/{id}/status")
    public ResponseEntity<OrderResponse> updateOrderStatus(
        @PathVariable Long id,
        @Valid @RequestBody UpdateStatusRequest request) {
        Order order = orderService.updateOrderStatus(id, request.getStatus());
        return ResponseEntity.ok(OrderResponse.from(order));
    }
}

Преимущества этого подхода:

  • Простота реализации
  • Синхронный response с немедленной confirmацией
  • Лёгкий debugging
  • Стандартный REST pattern

2. Асинхронная запись через message queue (RabbitMQ)

Для операций, не требующих немедленного ответа, мы использовали RabbitMQ и Spring AMQP:

@Service
public class OrderEventPublisher {
    private final RabbitTemplate rabbitTemplate;
    private static final String EXCHANGE = "orders.exchange";
    private static final String ROUTING_KEY = "orders.created";
    
    public void publishOrderCreated(Order order) {
        OrderEvent event = new OrderEvent(
            order.getId(),
            order.getCustomerId(),
            order.getTotalAmount(),
            LocalDateTime.now()
        );
        
        rabbitTemplate.convertAndSend(
            EXCHANGE,
            ROUTING_KEY,
            event
        );
    }
}

@Service
public class OrderEventConsumer {
    private final EmailService emailService;
    private final NotificationService notificationService;
    
    @RabbitListener(queues = "orders.created.queue")
    public void handleOrderCreated(OrderEvent event) {
        // Отправить Email клиенту
        emailService.sendOrderConfirmation(event.getCustomerId(), event.getOrderId());
        
        // Отправить Notification
        notificationService.notifyOrderCreated(event.getCustomerId());
        
        // Обновить Analytics
        analyticsService.recordOrderEvent(event);
    }
}

Этот подход использовался для:

  • Отправки Email и SMS уведомлений
  • Обновления Analytics и Business Intelligence
  • Синхронизации с внешними системами
  • Обработки computationally expensive операций

3. Saga pattern для distributed transactions

Для сложных операций, затрагивающих несколько микросервисов, мы реализовали Saga pattern:

@Service
public class OrderSagaOrchestrator {
    private final OrderService orderService;
    private final PaymentServiceClient paymentClient;
    private final InventoryServiceClient inventoryClient;
    private final ShippingServiceClient shippingClient;
    
    @Transactional
    public OrderResponse createOrderWithSaga(CreateOrderRequest request) {
        // Step 1: Create Order
        Order order = orderService.createOrder(request);
        
        try {
            // Step 2: Reserve Inventory
            inventoryClient.reserveItems(order.getItems());
            
            // Step 3: Process Payment
            PaymentResult paymentResult = paymentClient.processPayment(
                order.getId(),
                order.getTotalAmount(),
                request.getPaymentDetails()
            );
            
            if (!paymentResult.isSuccessful()) {
                throw new PaymentFailedException(paymentResult.getMessage());
            }
            
            // Step 4: Create Shipping
            ShippingResult shippingResult = shippingClient.createShipment(
                order.getId(),
                order.getDeliveryAddress()
            );
            
            // Step 5: Confirm Order
            orderService.confirmOrder(order.getId());
            
            return OrderResponse.from(orderService.getOrder(order.getId()));
            
        } catch (Exception e) {
            // Compensating transactions (rollback)
            handleSagaFailure(order, e);
            throw new OrderCreationFailedException(e.getMessage());
        }
    }
    
    private void handleSagaFailure(Order order, Exception e) {
        try {
            // Отменить reservation
            inventoryClient.releaseItems(order.getItems());
            
            // Отменить платёж (refund)
            paymentClient.refund(order.getId());
            
            // Отменить shipment
            shippingClient.cancelShipment(order.getId());
            
            // Обновить статус заказа
            orderService.rejectOrder(order.getId(), e.getMessage());
            
        } catch (Exception compensationError) {
            logger.error("Failed to compensate order {}", order.getId(), compensationError);
            // Отправить alert для manual intervention
            notificationService.alertAdmins("Saga compensation failed for order " + order.getId());
        }
    }
}

4. Spring Cloud OpenFeign для inter-service communication

Для синхронного общения между микросервисами использовали Feign клиент:

@FeignClient(name = "payment-service", url = "${payment-service.url}")
public interface PaymentServiceClient {
    @PostMapping("/api/v1/payments")
    PaymentResponse createPayment(
        @RequestBody CreatePaymentRequest request
    );
    
    @PostMapping("/api/v1/payments/{id}/refund")
    RefundResponse refund(
        @PathVariable String id,
        @RequestBody RefundRequest request
    );
}

@Service
public class PaymentService {
    private final PaymentServiceClient paymentClient;
    private final CircuitBreaker circuitBreaker;
    
    public PaymentResponse processPayment(PaymentRequest request) {
        try {
            // Вызов с circuit breaker protection
            return circuitBreaker.executeSupplier(() ->
                paymentClient.createPayment(request)
            );
        } catch (CircuitBreakerOpenException e) {
            logger.error("Payment service unavailable");
            throw new PaymentServiceUnavailableException("Payment service is down");
        }
    }
}

5. Database Write Patterns

Event Sourcing

Для audit trail и полной истории всех операций:

@Service
public class OrderEventStore {
    private final OrderEventRepository eventRepository;
    
    public void recordOrderEvent(OrderEvent event) {
        event.setTimestamp(LocalDateTime.now(UTC));
        event.setVersion(getCurrentVersion() + 1);
        eventRepository.save(event);
    }
}

public class OrderEvent {
    private Long orderId;
    private String eventType; // CREATED, UPDATED, CANCELLED, SHIPPED
    private LocalDateTime timestamp;
    private int version;
    private String payload; // JSON с полными данными события
}

CQRS (Command Query Responsibility Segregation)

Разделение операций чтения и записи:

// Command side - Write
@Service
public class OrderCommandHandler {
    private final OrderRepository writeRepository;
    private final OrderEventStore eventStore;
    
    public void handleCreateOrderCommand(CreateOrderCommand command) {
        Order order = Order.create(command);
        writeRepository.save(order);
        eventStore.recordOrderEvent(
            new OrderCreatedEvent(order.getId(), command)
        );
    }
}

// Query side - Read (read-optimized model)
@Service
public class OrderQueryService {
    private final OrderReadModelRepository readRepository;
    
    public OrderReadModel getOrderDetails(Long orderId) {
        return readRepository.findById(orderId)
            .orElseThrow(() -> new OrderNotFoundException(orderId));
    }
}

6. Batch Write Operations

Для высокопроизводительных операций массовой записи:

@Service
public class OrderBatchProcessor {
    private final OrderRepository orderRepository;
    private final BatchSize batchSize = 1000;
    
    @Transactional
    public void processBatchOrders(List<CreateOrderRequest> requests) {
        int processed = 0;
        
        for (int i = 0; i < requests.size(); i += batchSize) {
            int end = Math.min(i + batchSize, requests.size());
            List<Order> batch = requests.subList(i, end)
                .stream()
                .map(Order::from)
                .collect(Collectors.toList());
            
            orderRepository.saveAll(batch);
            
            // Flush и clear для оптимизации памяти
            entityManager.flush();
            entityManager.clear();
            
            processed += batch.size();
            logger.info("Processed {} orders out of {}", processed, requests.size());
        }
    }
}

7. Write-ahead Logging (WAL)

Для гарантирования durability:

@Service
public class WriteAheadLogger {
    private final WriteLogRepository logRepository;
    private final OrderRepository orderRepository;
    
    @Transactional
    public void writeWithLogging(Order order) {
        // Step 1: Write to log first
        WriteLogEntry logEntry = new WriteLogEntry(
            "ORDER_CREATE",
            order.getId(),
            order.toJson(),
            LocalDateTime.now(UTC)
        );
        logRepository.save(logEntry);
        
        // Step 2: Write actual data
        orderRepository.save(order);
        
        // Step 3: Mark log entry as committed
        logRepository.markAsCommitted(logEntry.getId());
    }
}

8. Idempotency Keys

Для защиты от дублирования при retry операций:

@RestController
@RequestMapping("/api/v1/orders")
public class OrderController {
    private final OrderService orderService;
    private final IdempotencyKeyStore keyStore;
    
    @PostMapping
    public ResponseEntity<OrderResponse> createOrder(
        @Valid @RequestBody CreateOrderRequest request,
        @RequestHeader("X-Idempotency-Key") String idempotencyKey) {
        
        // Check if we already processed this request
        Optional<OrderResponse> cached = keyStore.get(idempotencyKey);
        if (cached.isPresent()) {
            return ResponseEntity.ok(cached.get());
        }
        
        // Process order
        Order order = orderService.createOrder(request);
        OrderResponse response = OrderResponse.from(order);
        
        // Store result for future retries
        keyStore.store(idempotencyKey, response);
        
        return ResponseEntity.status(HttpStatus.CREATED).body(response);
    }
}

9. Monitoring и Observability

Для отслеживания операций записи:

@Aspect
@Service
public class WriteOperationAspect {
    private final MeterRegistry meterRegistry;
    
    @Around("@annotation(WriteOperation)")
    public Object trackWriteOperation(ProceedingJoinPoint joinPoint) throws Throwable {
        Timer.Sample sample = Timer.start(meterRegistry);
        
        try {
            Object result = joinPoint.proceed();
            meterRegistry.counter("write.operations.success").increment();
            return result;
        } catch (Exception e) {
            meterRegistry.counter("write.operations.error", 
                "exception", e.getClass().getSimpleName()).increment();
            throw e;
        } finally {
            sample.stop(Timer.builder("write.operation.duration")
                .publishPercentiles(0.5, 0.95, 0.99)
                .record(meterRegistry));
        }
    }
}

Резюме операций записи

Микросервисная архитектура требует различных паттернов для операций записи:

  1. REST API — для синхронных операций
  2. Message Queues — для асинхронных операций
  3. Saga Pattern — для distributed transactions
  4. Event Sourcing — для полной audit trail
  5. CQRS — для разделения read/write моделей
  6. Batch Processing — для массовых операций
  7. Write-ahead Logging — для durability
  8. Idempotency Keys — для защиты от дублей
  9. Monitoring — для наблюдаемости операций

Эти паттерны вместе обеспечивают надёжность, масштабируемость и maintainability микросервисной системы.

Какие операции записи микросервиса использовались на последней работе | PrepBro