微服务架构设计模式

概述

微服务架构是现代分布式系统的主流架构模式,它将单一应用程序开发为一套小服务,每个服务运行在自己的进程中,并通过轻量级机制通信。本文深入讲解微服务的设计模式、服务治理、以及实践中的关键技术。

核心面试问题

1. 微服务拆分策略

面试问题:如何进行微服务拆分?拆分的原则和边界是什么?

服务拆分原则

// 1. 业务边界拆分 - DDD领域驱动设计
// 用户域服务
@RestController
@RequestMapping("/api/users")
public class UserServiceController {

    @Autowired
    private UserDomainService userDomainService;

    @PostMapping
    public ResponseEntity<UserDTO> createUser(@RequestBody CreateUserRequest request) {
        // 用户域的核心业务逻辑
        User user = userDomainService.createUser(request);
        return ResponseEntity.ok(UserDTO.from(user));
    }

    @GetMapping("/{userId}")
    public ResponseEntity<UserDTO> getUser(@PathVariable Long userId) {
        User user = userDomainService.getUser(userId);
        return ResponseEntity.ok(UserDTO.from(user));
    }

    @PutMapping("/{userId}/profile")
    public ResponseEntity<Void> updateProfile(@PathVariable Long userId, 
                                            @RequestBody UpdateProfileRequest request) {
        userDomainService.updateProfile(userId, request);
        return ResponseEntity.ok().build();
    }
}

// 订单域服务
@RestController
@RequestMapping("/api/orders")
public class OrderServiceController {

    @Autowired
    private OrderDomainService orderDomainService;

    @Autowired
    private UserServiceClient userServiceClient; // 远程调用用户服务

    @PostMapping
    public ResponseEntity<OrderDTO> createOrder(@RequestBody CreateOrderRequest request) {
        // 验证用户信息(跨服务调用)
        UserDTO user = userServiceClient.getUser(request.getUserId());
        if (user == null) {
            throw new UserNotFoundException("用户不存在");
        }

        Order order = orderDomainService.createOrder(request);
        return ResponseEntity.ok(OrderDTO.from(order));
    }

    @GetMapping("/{orderId}")
    public ResponseEntity<OrderDTO> getOrder(@PathVariable Long orderId) {
        Order order = orderDomainService.getOrder(orderId);
        return ResponseEntity.ok(OrderDTO.from(order));
    }
}

// 2. 数据拆分 - 数据库分离
@Configuration
public class DatabaseConfig {

    // 用户服务数据源
    @Bean
    @Primary
    @ConfigurationProperties(prefix = "app.datasource.user")
    public DataSource userDataSource() {
        return DataSourceBuilder.create().build();
    }

    // 订单服务数据源
    @Bean
    @ConfigurationProperties(prefix = "app.datasource.order")
    public DataSource orderDataSource() {
        return DataSourceBuilder.create().build();
    }

    // 用户服务的JPA配置
    @Bean
    @Primary
    public LocalContainerEntityManagerFactoryBean userEntityManagerFactory() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(userDataSource());
        em.setPackagesToScan("com.example.user.entity");

        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);

        return em;
    }

    // 订单服务的JPA配置
    @Bean
    public LocalContainerEntityManagerFactoryBean orderEntityManagerFactory() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(orderDataSource());
        em.setPackagesToScan("com.example.order.entity");

        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);

        return em;
    }
}

// 3. 团队组织结构对应 - Conway's Law
// 每个微服务对应一个独立的开发团队
public class ServiceOwnership {

    // 用户服务团队负责
    public static class UserServiceTeam {
        // 团队成员:产品经理、架构师、开发工程师、测试工程师、运维工程师
        // 技术栈:Spring Boot、MySQL、Redis
        // 职责:用户注册、登录、个人信息管理、权限认证
    }

    // 订单服务团队负责
    public static class OrderServiceTeam {
        // 团队成员:产品经理、架构师、开发工程师、测试工程师、运维工程师
        // 技术栈:Spring Boot、PostgreSQL、RabbitMQ
        // 职责:订单创建、支付、物流、售后
    }

    // 商品服务团队负责
    public static class ProductServiceTeam {
        // 团队成员:产品经理、架构师、开发工程师、测试工程师、运维工程师
        // 技术栈:Spring Boot、MongoDB、Elasticsearch
        // 职责:商品管理、库存管理、搜索推荐
    }
}

服务拆分实战

// 拆分前的单体应用
@RestController
public class MonolithController {

    @Autowired
    private UserService userService;

    @Autowired
    private OrderService orderService;

    @Autowired
    private ProductService productService;

    @Autowired
    private PaymentService paymentService;

    // 下单流程 - 单体应用中的复杂业务逻辑
    @PostMapping("/orders")
    @Transactional
    public ResponseEntity<Order> createOrder(@RequestBody CreateOrderRequest request) {
        // 1. 验证用户
        User user = userService.validateUser(request.getUserId());

        // 2. 验证商品和库存
        Product product = productService.getProduct(request.getProductId());
        productService.checkStock(request.getProductId(), request.getQuantity());

        // 3. 计算价格
        BigDecimal totalAmount = product.getPrice().multiply(BigDecimal.valueOf(request.getQuantity()));

        // 4. 创建订单
        Order order = orderService.createOrder(user, product, request.getQuantity(), totalAmount);

        // 5. 扣减库存
        productService.reduceStock(request.getProductId(), request.getQuantity());

        // 6. 处理支付
        Payment payment = paymentService.processPayment(order.getId(), totalAmount);

        // 7. 更新订单状态
        orderService.updateOrderStatus(order.getId(), OrderStatus.PAID);

        return ResponseEntity.ok(order);
    }
}

// 拆分后的微服务架构
// 订单编排服务(Orchestrator Pattern)
@Service
public class OrderOrchestrationService {

    @Autowired
    private UserServiceClient userServiceClient;

    @Autowired
    private ProductServiceClient productServiceClient;

    @Autowired
    private PaymentServiceClient paymentServiceClient;

    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    private EventPublisher eventPublisher;

    public OrderResult createOrder(CreateOrderRequest request) {
        String orderId = UUID.randomUUID().toString();

        try {
            // 1. 验证用户(远程调用)
            UserValidationResult userResult = userServiceClient.validateUser(request.getUserId());
            if (!userResult.isValid()) {
                return OrderResult.failure("用户验证失败");
            }

            // 2. 验证商品和预占库存(远程调用)
            StockReservationResult stockResult = productServiceClient.reserveStock(
                request.getProductId(), request.getQuantity(), orderId);
            if (!stockResult.isSuccess()) {
                return OrderResult.failure("库存不足");
            }

            // 3. 创建订单(本地操作)
            Order order = new Order(orderId, request.getUserId(), request.getProductId(), 
                                  request.getQuantity(), stockResult.getTotalAmount());
            order.setStatus(OrderStatus.CREATED);
            orderRepository.save(order);

            // 4. 处理支付(远程调用)
            PaymentResult paymentResult = paymentServiceClient.processPayment(
                orderId, stockResult.getTotalAmount());

            if (paymentResult.isSuccess()) {
                // 支付成功,确认库存扣减
                productServiceClient.confirmStockReduction(orderId);

                // 更新订单状态
                order.setStatus(OrderStatus.PAID);
                orderRepository.save(order);

                // 发布订单支付成功事件
                eventPublisher.publishEvent(new OrderPaidEvent(orderId));

                return OrderResult.success(orderId);
            } else {
                // 支付失败,释放库存
                productServiceClient.releaseStock(orderId);

                order.setStatus(OrderStatus.PAYMENT_FAILED);
                orderRepository.save(order);

                return OrderResult.failure("支付失败");
            }

        } catch (Exception e) {
            // 异常处理,清理资源
            cleanupResources(orderId);
            return OrderResult.failure("系统异常: " + e.getMessage());
        }
    }

    private void cleanupResources(String orderId) {
        try {
            productServiceClient.releaseStock(orderId);
        } catch (Exception e) {
            System.err.println("清理库存失败: " + e.getMessage());
        }
    }
}

// Saga模式 - 分布式事务处理
@Component
public class OrderSagaOrchestrator {

    private final Map<String, SagaTransaction> activeSagas = new ConcurrentHashMap<>();

    @EventListener
    public void handleOrderCreated(OrderCreatedEvent event) {
        String sagaId = event.getOrderId();
        SagaTransaction saga = new SagaTransaction(sagaId);
        activeSagas.put(sagaId, saga);

        // 执行Saga步骤
        executeReserveInventory(saga, event);
    }

    private void executeReserveInventory(SagaTransaction saga, OrderCreatedEvent event) {
        try {
            productServiceClient.reserveInventory(event.getProductId(), event.getQuantity(), saga.getId());
            saga.addCompletedStep(new ReserveInventoryStep(event.getProductId(), event.getQuantity()));

            // 下一步:处理支付
            executeProcessPayment(saga, event);

        } catch (Exception e) {
            // 补偿操作
            compensateSaga(saga);
        }
    }

    private void executeProcessPayment(SagaTransaction saga, OrderCreatedEvent event) {
        try {
            paymentServiceClient.processPayment(event.getOrderId(), event.getAmount());
            saga.addCompletedStep(new ProcessPaymentStep(event.getOrderId(), event.getAmount()));

            // Saga成功完成
            completeSaga(saga);

        } catch (Exception e) {
            // 补偿操作
            compensateSaga(saga);
        }
    }

    private void compensateSaga(SagaTransaction saga) {
        // 逆序执行补偿操作
        List<SagaStep> completedSteps = saga.getCompletedSteps();
        Collections.reverse(completedSteps);

        for (SagaStep step : completedSteps) {
            try {
                step.compensate();
            } catch (Exception e) {
                System.err.println("补偿操作失败: " + e.getMessage());
            }
        }

        activeSagas.remove(saga.getId());
    }

    private void completeSaga(SagaTransaction saga) {
        activeSagas.remove(saga.getId());
        System.out.println("Saga事务完成: " + saga.getId());
    }
}

2. 服务通信模式

面试问题:微服务之间的通信方式有哪些?同步调用和异步消息的适用场景?

同步通信实现

// 1. RESTful API调用
@Component
public class UserServiceClient {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private LoadBalancer loadBalancer; // 负载均衡器

    @Value("${services.user-service.url}")
    private String userServiceUrl;

    public UserDTO getUser(Long userId) {
        try {
            String url = userServiceUrl + "/api/users/" + userId;
            return restTemplate.getForObject(url, UserDTO.class);
        } catch (RestClientException e) {
            throw new ServiceCallException("调用用户服务失败", e);
        }
    }

    public UserValidationResult validateUser(Long userId) {
        try {
            String url = userServiceUrl + "/api/users/" + userId + "/validate";
            return restTemplate.getForObject(url, UserValidationResult.class);
        } catch (RestClientException e) {
            // 服务降级
            return UserValidationResult.defaultValid();
        }
    }

    // 使用服务发现的动态调用
    public UserDTO getUserWithDiscovery(Long userId) {
        ServiceInstance instance = loadBalancer.choose("user-service");
        if (instance == null) {
            throw new ServiceUnavailableException("用户服务不可用");
        }

        String url = "http://" + instance.getHost() + ":" + instance.getPort() + 
                    "/api/users/" + userId;

        return restTemplate.getForObject(url, UserDTO.class);
    }
}

// 2. gRPC调用(高性能场景)
@Service
public class OrderServiceGrpcClient {

    private final OrderServiceGrpc.OrderServiceBlockingStub blockingStub;
    private final OrderServiceGrpc.OrderServiceStub asyncStub;

    public OrderServiceGrpcClient(@Value("${services.order-service.grpc.host}") String host,
                                 @Value("${services.order-service.grpc.port}") int port) {
        ManagedChannel channel = ManagedChannelBuilder.forAddress(host, port)
                .usePlaintext()
                .build();

        this.blockingStub = OrderServiceGrpc.newBlockingStub(channel);
        this.asyncStub = OrderServiceGrpc.newStub(channel);
    }

    public CreateOrderResponse createOrder(CreateOrderRequest request) {
        CreateOrderGrpcRequest grpcRequest = CreateOrderGrpcRequest.newBuilder()
                .setUserId(request.getUserId())
                .setProductId(request.getProductId())
                .setQuantity(request.getQuantity())
                .build();

        try {
            CreateOrderGrpcResponse grpcResponse = blockingStub.createOrder(grpcRequest);

            return CreateOrderResponse.builder()
                    .orderId(grpcResponse.getOrderId())
                    .status(grpcResponse.getStatus())
                    .message(grpcResponse.getMessage())
                    .build();
        } catch (StatusRuntimeException e) {
            throw new ServiceCallException("gRPC调用失败: " + e.getStatus(), e);
        }
    }

    // 异步gRPC调用
    public CompletableFuture<CreateOrderResponse> createOrderAsync(CreateOrderRequest request) {
        CreateOrderGrpcRequest grpcRequest = CreateOrderGrpcRequest.newBuilder()
                .setUserId(request.getUserId())
                .setProductId(request.getProductId())
                .setQuantity(request.getQuantity())
                .build();

        CompletableFuture<CreateOrderResponse> future = new CompletableFuture<>();

        asyncStub.createOrder(grpcRequest, new StreamObserver<CreateOrderGrpcResponse>() {
            @Override
            public void onNext(CreateOrderGrpcResponse response) {
                CreateOrderResponse result = CreateOrderResponse.builder()
                        .orderId(response.getOrderId())
                        .status(response.getStatus())
                        .message(response.getMessage())
                        .build();
                future.complete(result);
            }

            @Override
            public void onError(Throwable t) {
                future.completeExceptionally(new ServiceCallException("异步gRPC调用失败", t));
            }

            @Override
            public void onCompleted() {
                // 调用完成
            }
        });

        return future;
    }
}

// 3. 服务熔断器模式
@Component
public class PaymentServiceClient {

    @Autowired
    private RestTemplate restTemplate;

    private final CircuitBreaker circuitBreaker;

    public PaymentServiceClient() {
        this.circuitBreaker = CircuitBreaker.ofDefaults("payment-service");

        // 配置熔断器
        circuitBreaker.getEventPublisher()
            .onStateTransition(event -> 
                System.out.println("熔断器状态变更: " + event.getStateTransition()));
    }

    public PaymentResult processPayment(String orderId, BigDecimal amount) {
        Supplier<PaymentResult> decoratedSupplier = CircuitBreaker
            .decorateSupplier(circuitBreaker, () -> doProcessPayment(orderId, amount));

        try {
            return decoratedSupplier.get();
        } catch (CallNotPermittedException e) {
            // 熔断器打开,使用降级逻辑
            return PaymentResult.failure("支付服务暂时不可用,请稍后重试");
        }
    }

    private PaymentResult doProcessPayment(String orderId, BigDecimal amount) {
        String url = "http://payment-service/api/payments";

        PaymentRequest request = new PaymentRequest(orderId, amount);
        PaymentResponse response = restTemplate.postForObject(url, request, PaymentResponse.class);

        if (response != null && response.isSuccess()) {
            return PaymentResult.success(response.getTransactionId());
        } else {
            throw new PaymentException("支付处理失败");
        }
    }
}

异步通信实现

// 1. 事件驱动架构
@Component
public class OrderEventHandler {

    @Autowired
    private InventoryService inventoryService;

    @Autowired
    private NotificationService notificationService;

    @Autowired
    private EventPublisher eventPublisher;

    // 处理订单创建事件
    @EventListener
    @Async
    public void handleOrderCreated(OrderCreatedEvent event) {
        try {
            // 异步扣减库存
            inventoryService.reduceInventory(event.getProductId(), event.getQuantity());

            // 发布库存扣减成功事件
            eventPublisher.publishEvent(new InventoryReducedEvent(
                event.getOrderId(), event.getProductId(), event.getQuantity()));

        } catch (Exception e) {
            // 发布库存扣减失败事件
            eventPublisher.publishEvent(new InventoryReductionFailedEvent(
                event.getOrderId(), e.getMessage()));
        }
    }

    // 处理支付成功事件
    @EventListener
    @Async
    public void handlePaymentSucceeded(PaymentSucceededEvent event) {
        try {
            // 发送订单确认通知
            notificationService.sendOrderConfirmation(event.getOrderId());

            // 更新用户积分
            updateUserPoints(event.getUserId(), event.getAmount());

        } catch (Exception e) {
            System.err.println("处理支付成功事件失败: " + e.getMessage());
        }
    }

    private void updateUserPoints(Long userId, BigDecimal amount) {
        // 异步更新用户积分
        CompletableFuture.runAsync(() -> {
            try {
                userServiceClient.addPoints(userId, amount.intValue() / 10);
            } catch (Exception e) {
                System.err.println("更新用户积分失败: " + e.getMessage());
            }
        });
    }
}

// 2. 消息队列通信
@Component
public class OrderMessageProducer {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private KafkaTemplate<String, Object> kafkaTemplate;

    // 发送订单事件到RabbitMQ
    public void sendOrderEvent(OrderEvent event) {
        String routingKey = getRoutingKey(event.getEventType());

        rabbitTemplate.convertAndSend("order.exchange", routingKey, event, message -> {
            // 设置消息属性
            message.getMessageProperties().setMessageId(UUID.randomUUID().toString());
            message.getMessageProperties().setTimestamp(new Date());
            message.getMessageProperties().setPersistent(true);
            return message;
        });
    }

    // 发送订单事件到Kafka
    public void sendOrderEventToKafka(OrderEvent event) {
        String topic = "order-events";
        String key = event.getOrderId(); // 使用订单ID作为分区键,保证同一订单的事件有序

        kafkaTemplate.send(topic, key, event).addCallback(
            result -> System.out.println("订单事件发送成功: " + event.getOrderId()),
            failure -> System.err.println("订单事件发送失败: " + failure.getMessage())
        );
    }

    private String getRoutingKey(OrderEventType eventType) {
        switch (eventType) {
            case ORDER_CREATED:
                return "order.created";
            case ORDER_PAID:
                return "order.paid";
            case ORDER_SHIPPED:
                return "order.shipped";
            default:
                return "order.unknown";
        }
    }
}

@Component
public class OrderMessageConsumer {

    @Autowired
    private OrderService orderService;

    // 消费RabbitMQ消息
    @RabbitListener(queues = "inventory.order.queue")
    public void handleInventoryUpdate(InventoryUpdateEvent event, Acknowledgment ack) {
        try {
            orderService.updateOrderInventoryStatus(event.getOrderId(), event.getStatus());
            ack.acknowledge();
        } catch (Exception e) {
            System.err.println("处理库存更新事件失败: " + e.getMessage());
            // 消息会重新入队重试
        }
    }

    // 消费Kafka消息
    @KafkaListener(topics = "payment-events", groupId = "order-service-group")
    public void handlePaymentEvent(PaymentEvent event) {
        try {
            if (event.getEventType() == PaymentEventType.PAYMENT_SUCCEEDED) {
                orderService.markOrderAsPaid(event.getOrderId());
            } else if (event.getEventType() == PaymentEventType.PAYMENT_FAILED) {
                orderService.markOrderAsPaymentFailed(event.getOrderId());
            }
        } catch (Exception e) {
            System.err.println("处理支付事件失败: " + e.getMessage());
        }
    }
}

// 3. 请求-响应模式的异步实现
@Service
public class AsyncOrderService {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    private final Map<String, CompletableFuture<OrderResult>> pendingRequests = new ConcurrentHashMap<>();

    // 异步创建订单
    public CompletableFuture<OrderResult> createOrderAsync(CreateOrderRequest request) {
        String requestId = UUID.randomUUID().toString();
        CompletableFuture<OrderResult> future = new CompletableFuture<>();

        // 存储待处理的请求
        pendingRequests.put(requestId, future);

        // 发送异步请求
        AsyncOrderCreateRequest asyncRequest = new AsyncOrderCreateRequest(requestId, request);
        rabbitTemplate.convertAndSend("order.async.request", asyncRequest);

        // 设置超时
        CompletableFuture.delayedExecutor(30, TimeUnit.SECONDS).execute(() -> {
            CompletableFuture<OrderResult> timeoutFuture = pendingRequests.remove(requestId);
            if (timeoutFuture != null && !timeoutFuture.isDone()) {
                timeoutFuture.completeExceptionally(new TimeoutException("订单创建超时"));
            }
        });

        return future;
    }

    // 处理异步响应
    @RabbitListener(queues = "order.async.response")
    public void handleAsyncOrderResponse(AsyncOrderCreateResponse response) {
        String requestId = response.getRequestId();
        CompletableFuture<OrderResult> future = pendingRequests.remove(requestId);

        if (future != null) {
            if (response.isSuccess()) {
                future.complete(OrderResult.success(response.getOrderId()));
            } else {
                future.complete(OrderResult.failure(response.getErrorMessage()));
            }
        }
    }
}

3. 服务发现与注册

面试问题:服务发现的实现方式有哪些?Eureka、Consul、Nacos的区别?

服务注册与发现实现

// 1. Eureka服务注册与发现
@SpringBootApplication
@EnableEurekaClient
public class OrderServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }

    @Bean
    @LoadBalanced // 启用客户端负载均衡
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

@Service
public class EurekaServiceDiscovery {

    @Autowired
    private DiscoveryClient discoveryClient;

    @Autowired
    private EurekaClient eurekaClient;

    public List<ServiceInstance> getServiceInstances(String serviceName) {
        return discoveryClient.getInstances(serviceName);
    }

    public ServiceInstance chooseInstance(String serviceName) {
        List<ServiceInstance> instances = getServiceInstances(serviceName);
        if (instances.isEmpty()) {
            throw new ServiceNotFoundException("服务不存在: " + serviceName);
        }

        // 简单的轮询负载均衡
        int index = ThreadLocalRandom.current().nextInt(instances.size());
        return instances.get(index);
    }

    // 使用Eureka原生API
    public Application getApplication(String serviceName) {
        return eurekaClient.getApplication(serviceName);
    }

    public List<InstanceInfo> getInstancesByVipAddress(String vipAddress) {
        return eurekaClient.getInstancesByVipAddress(vipAddress, false);
    }
}

// 2. Consul服务注册与发现
@Configuration
@EnableConsulServiceRegistry
public class ConsulConfig {

    @Bean
    public ConsulServiceRegistryAutoConfiguration.ConsulServiceRegistry consulServiceRegistry(
            ConsulClient consulClient, ConsulDiscoveryProperties properties) {
        return new ConsulServiceRegistryAutoConfiguration.ConsulServiceRegistry(
                consulClient, properties, new HeartbeatProperties());
    }

    @Bean
    public ConsulClient consulClient(@Value("${spring.cloud.consul.host:localhost}") String host,
                                   @Value("${spring.cloud.consul.port:8500}") int port) {
        return new ConsulClient(host, port);
    }
}

@Service
public class ConsulServiceDiscovery {

    @Autowired
    private ConsulClient consulClient;

    @Autowired
    private DiscoveryClient discoveryClient;

    public List<ServiceInstance> getHealthyInstances(String serviceName) {
        return discoveryClient.getInstances(serviceName).stream()
                .filter(instance -> isInstanceHealthy(serviceName, instance))
                .collect(Collectors.toList());
    }

    private boolean isInstanceHealthy(String serviceName, ServiceInstance instance) {
        try {
            Response<List<HealthService>> response = consulClient.getHealthServices(
                    serviceName, true, QueryParams.DEFAULT);

            return response.getValue().stream()
                    .anyMatch(service -> 
                            service.getService().getAddress().equals(instance.getHost()) &&
                            service.getService().getPort().equals(instance.getPort()));
        } catch (Exception e) {
            return false;
        }
    }

    public void registerService(String serviceName, String serviceId, String host, int port) {
        NewService newService = new NewService();
        newService.setId(serviceId);
        newService.setName(serviceName);
        newService.setAddress(host);
        newService.setPort(port);

        // 设置健康检查
        NewService.Check check = new NewService.Check();
        check.setHttp("http://" + host + ":" + port + "/actuator/health");
        check.setInterval("10s");
        newService.setCheck(check);

        consulClient.agentServiceRegister(newService);
    }
}

// 3. 自定义服务注册与发现
@Component
public class CustomServiceRegistry {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private ApplicationContext applicationContext;

    private static final String SERVICE_REGISTRY_KEY = "services:registry:";
    private static final String SERVICE_HEARTBEAT_KEY = "services:heartbeat:";

    // 服务注册
    @PostConstruct
    public void registerService() {
        String serviceName = getServiceName();
        String serviceId = getServiceId();
        ServiceInstance instance = createServiceInstance();

        // 注册服务实例
        String registryKey = SERVICE_REGISTRY_KEY + serviceName;
        redisTemplate.opsForHash().put(registryKey, serviceId, JSON.toJSONString(instance));

        // 设置服务过期时间
        redisTemplate.expire(registryKey, Duration.ofMinutes(5));

        // 启动心跳
        startHeartbeat(serviceName, serviceId);
    }

    private void startHeartbeat(String serviceName, String serviceId) {
        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();

        executor.scheduleWithFixedDelay(() -> {
            try {
                // 发送心跳
                String heartbeatKey = SERVICE_HEARTBEAT_KEY + serviceName + ":" + serviceId;
                redisTemplate.opsForValue().set(heartbeatKey, System.currentTimeMillis(), Duration.ofMinutes(2));

                // 续约服务注册
                String registryKey = SERVICE_REGISTRY_KEY + serviceName;
                redisTemplate.expire(registryKey, Duration.ofMinutes(5));

            } catch (Exception e) {
                System.err.println("服务心跳失败: " + e.getMessage());
            }
        }, 30, 30, TimeUnit.SECONDS);
    }

    // 服务发现
    public List<ServiceInstance> discoverServices(String serviceName) {
        String registryKey = SERVICE_REGISTRY_KEY + serviceName;
        Map<Object, Object> serviceMap = redisTemplate.opsForHash().entries(registryKey);

        List<ServiceInstance> instances = new ArrayList<>();
        for (Map.Entry<Object, Object> entry : serviceMap.entrySet()) {
            String serviceId = (String) entry.getKey();
            String instanceJson = (String) entry.getValue();

            // 检查心跳
            if (isServiceAlive(serviceName, serviceId)) {
                ServiceInstance instance = JSON.parseObject(instanceJson, ServiceInstance.class);
                instances.add(instance);
            }
        }

        return instances;
    }

    private boolean isServiceAlive(String serviceName, String serviceId) {
        String heartbeatKey = SERVICE_HEARTBEAT_KEY + serviceName + ":" + serviceId;
        Object lastHeartbeat = redisTemplate.opsForValue().get(heartbeatKey);

        if (lastHeartbeat == null) {
            return false;
        }

        long lastHeartbeatTime = Long.parseLong(lastHeartbeat.toString());
        long currentTime = System.currentTimeMillis();

        // 心跳超时阈值:2分钟
        return (currentTime - lastHeartbeatTime) < 120000;
    }

    private String getServiceName() {
        return applicationContext.getEnvironment().getProperty("spring.application.name", "unknown");
    }

    private String getServiceId() {
        return getServiceName() + "-" + UUID.randomUUID().toString().substring(0, 8);
    }

    private ServiceInstance createServiceInstance() {
        String host = getLocalHost();
        int port = getServerPort();

        ServiceInstance instance = new ServiceInstance();
        instance.setServiceName(getServiceName());
        instance.setHost(host);
        instance.setPort(port);
        instance.setHealthy(true);
        instance.setMetadata(getServiceMetadata());

        return instance;
    }

    private String getLocalHost() {
        try {
            return InetAddress.getLocalHost().getHostAddress();
        } catch (Exception e) {
            return "localhost";
        }
    }

    private int getServerPort() {
        return applicationContext.getEnvironment().getProperty("server.port", Integer.class, 8080);
    }

    private Map<String, String> getServiceMetadata() {
        Map<String, String> metadata = new HashMap<>();
        metadata.put("version", "1.0.0");
        metadata.put("environment", getEnvironment());
        metadata.put("startTime", String.valueOf(System.currentTimeMillis()));
        return metadata;
    }

    private String getEnvironment() {
        return applicationContext.getEnvironment().getProperty("spring.profiles.active", "default");
    }
}

4. API网关模式

面试问题:API网关的作用是什么?如何实现路由、认证、限流等功能?

API网关实现

// 1. 使用Spring Cloud Gateway
@Configuration
public class GatewayConfig {

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                // 用户服务路由
                .route("user-service", r -> r.path("/api/users/**")
                        .filters(f -> f
                                .stripPrefix(1) // 去掉 /api 前缀
                                .addRequestHeader("X-Gateway", "Spring-Cloud-Gateway")
                                .circuitBreaker(c -> c
                                        .setName("user-service-cb")
                                        .setFallbackUri("forward:/fallback/user"))
                                .retry(retryConfig -> retryConfig
                                        .setRetries(3)
                                        .setBackoff(Duration.ofSeconds(1), Duration.ofSeconds(5), 2, true)))
                        .uri("lb://user-service"))

                // 订单服务路由
                .route("order-service", r -> r.path("/api/orders/**")
                        .filters(f -> f
                                .stripPrefix(1)
                                .addRequestHeader("X-Gateway", "Spring-Cloud-Gateway")
                                .requestRateLimiter(rl -> rl
                                        .setRateLimiter(redisRateLimiter())
                                        .setKeyResolver(userKeyResolver())))
                        .uri("lb://order-service"))

                // 商品服务路由
                .route("product-service", r -> r.path("/api/products/**")
                        .and().method(HttpMethod.GET)
                        .filters(f -> f
                                .stripPrefix(1)
                                .addResponseHeader("Cache-Control", "max-age=300"))
                        .uri("lb://product-service"))

                .build();
    }

    @Bean
    public RedisRateLimiter redisRateLimiter() {
        return new RedisRateLimiter(10, 20); // 每秒10个请求,突发20个
    }

    @Bean
    public KeyResolver userKeyResolver() {
        return exchange -> {
            String userId = exchange.getRequest().getHeaders().getFirst("User-Id");
            return Mono.just(userId != null ? userId : "anonymous");
        };
    }
}

// 2. 自定义过滤器
@Component
public class AuthenticationGatewayFilter implements GatewayFilter, Ordered {

    @Autowired
    private AuthService authService;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();

        // 跳过不需要认证的路径
        if (isPublicPath(path)) {
            return chain.filter(exchange);
        }

        // 获取认证令牌
        String token = extractToken(request);
        if (token == null) {
            return handleUnauthorized(exchange, "缺少认证令牌");
        }

        // 验证令牌
        return authService.validateToken(token)
                .flatMap(userInfo -> {
                    if (userInfo != null) {
                        // 添加用户信息到请求头
                        ServerHttpRequest mutatedRequest = request.mutate()
                                .header("User-Id", userInfo.getUserId().toString())
                                .header("User-Name", userInfo.getUsername())
                                .header("User-Roles", String.join(",", userInfo.getRoles()))
                                .build();

                        ServerWebExchange mutatedExchange = exchange.mutate()
                                .request(mutatedRequest)
                                .build();

                        return chain.filter(mutatedExchange);
                    } else {
                        return handleUnauthorized(exchange, "无效的认证令牌");
                    }
                })
                .onErrorResume(throwable -> {
                    return handleUnauthorized(exchange, "认证服务异常");
                });
    }

    private boolean isPublicPath(String path) {
        List<String> publicPaths = Arrays.asList(
                "/api/auth/login",
                "/api/auth/register",
                "/api/health",
                "/api/docs"
        );

        return publicPaths.stream().anyMatch(path::startsWith);
    }

    private String extractToken(ServerHttpRequest request) {
        String authorization = request.getHeaders().getFirst("Authorization");
        if (authorization != null && authorization.startsWith("Bearer ")) {
            return authorization.substring(7);
        }
        return null;
    }

    private Mono<Void> handleUnauthorized(ServerWebExchange exchange, String message) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add("Content-Type", "application/json");

        String body = JSON.toJSONString(new ErrorResponse("UNAUTHORIZED", message));
        DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8));

        return response.writeWith(Mono.just(buffer));
    }

    @Override
    public int getOrder() {
        return -100; // 高优先级,在其他过滤器之前执行
    }
}

// 3. 限流过滤器
@Component
public class RateLimitingGatewayFilter implements GatewayFilter, Ordered {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String clientId = getClientId(request);
        String path = request.getURI().getPath();

        return checkRateLimit(clientId, path)
                .flatMap(allowed -> {
                    if (allowed) {
                        return chain.filter(exchange);
                    } else {
                        return handleRateLimitExceeded(exchange);
                    }
                });
    }

    private Mono<Boolean> checkRateLimit(String clientId, String path) {
        return Mono.fromCallable(() -> {
            String key = "rate_limit:" + clientId + ":" + path;

            // 使用滑动窗口算法
            long currentTime = System.currentTimeMillis();
            long windowSize = 60000; // 1分钟窗口
            int maxRequests = 100; // 每分钟最多100个请求

            // 使用Lua脚本保证原子性
            String script = """
                local key = KEYS[1]
                local window = tonumber(ARGV[1])
                local limit = tonumber(ARGV[2])
                local current = tonumber(ARGV[3])

                -- 清除过期的记录
                redis.call('zremrangebyscore', key, '-inf', current - window)

                -- 获取当前窗口内的请求数
                local count = redis.call('zcard', key)

                if count < limit then
                    -- 添加当前请求
                    redis.call('zadd', key, current, current)
                    redis.call('expire', key, math.ceil(window / 1000))
                    return 1
                else
                    return 0
                end
                """;

            DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
            Long result = redisTemplate.execute(redisScript,
                    Collections.singletonList(key),
                    String.valueOf(windowSize),
                    String.valueOf(maxRequests),
                    String.valueOf(currentTime));

            return result != null && result == 1;
        });
    }

    private String getClientId(ServerHttpRequest request) {
        // 优先使用用户ID
        String userId = request.getHeaders().getFirst("User-Id");
        if (userId != null) {
            return "user:" + userId;
        }

        // 其次使用API Key
        String apiKey = request.getHeaders().getFirst("X-API-Key");
        if (apiKey != null) {
            return "api:" + apiKey;
        }

        // 最后使用IP地址
        String clientIP = getClientIP(request);
        return "ip:" + clientIP;
    }

    private String getClientIP(ServerHttpRequest request) {
        String xForwardedFor = request.getHeaders().getFirst("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
            return xForwardedFor.split(",")[0].trim();
        }

        String xRealIP = request.getHeaders().getFirst("X-Real-IP");
        if (xRealIP != null && !xRealIP.isEmpty()) {
            return xRealIP;
        }

        return request.getRemoteAddress() != null ?
                request.getRemoteAddress().getAddress().getHostAddress() : "unknown";
    }

    private Mono<Void> handleRateLimitExceeded(ServerWebExchange exchange) {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
        response.getHeaders().add("Content-Type", "application/json");

        String body = JSON.toJSONString(new ErrorResponse("RATE_LIMIT_EXCEEDED", "请求频率超过限制"));
        DataBuffer buffer = response.bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8));

        return response.writeWith(Mono.just(buffer));
    }

    @Override
    public int getOrder() {
        return -50; // 在认证过滤器之后执行
    }
}

// 4. 全局异常处理
@Component
public class GlobalErrorWebExceptionHandler extends DefaultErrorWebExceptionHandler {

    public GlobalErrorWebExceptionHandler(ErrorAttributes errorAttributes,
                                        WebProperties.Resources resources,
                                        ApplicationContext applicationContext) {
        super(errorAttributes, resources, applicationContext);
    }

    @Override
    protected Mono<ServerResponse> renderErrorResponse(ServerRequest request) {
        Throwable error = getError(request);

        if (error instanceof ConnectException) {
            // 服务连接异常
            return ServerResponse.status(HttpStatus.SERVICE_UNAVAILABLE)
                    .contentType(MediaType.APPLICATION_JSON)
                    .body(BodyInserters.fromValue(new ErrorResponse("SERVICE_UNAVAILABLE", "服务暂时不可用")));
        } else if (error instanceof TimeoutException) {
            // 请求超时
            return ServerResponse.status(HttpStatus.GATEWAY_TIMEOUT)
                    .contentType(MediaType.APPLICATION_JSON)
                    .body(BodyInserters.fromValue(new ErrorResponse("GATEWAY_TIMEOUT", "请求超时")));
        } else {
            // 其他异常
            return ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .contentType(MediaType.APPLICATION_JSON)
                    .body(BodyInserters.fromValue(new ErrorResponse("INTERNAL_ERROR", "网关内部错误")));
        }
    }
}

5. 微服务监控与治理

面试问题:如何监控微服务的健康状态?分布式链路追踪的实现原理?

监控与治理实现

// 1. 健康检查
@Component
public class CustomHealthIndicator implements HealthIndicator {

    @Autowired
    private DataSource dataSource;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public Health health() {
        try {
            // 检查数据库连接
            boolean dbHealthy = checkDatabaseHealth();

            // 检查Redis连接
            boolean redisHealthy = checkRedisHealth();

            // 检查外部依赖
            boolean externalHealthy = checkExternalDependencies();

            if (dbHealthy && redisHealthy && externalHealthy) {
                return Health.up()
                        .withDetail("database", "UP")
                        .withDetail("redis", "UP")
                        .withDetail("external", "UP")
                        .withDetail("timestamp", new Date())
                        .build();
            } else {
                return Health.down()
                        .withDetail("database", dbHealthy ? "UP" : "DOWN")
                        .withDetail("redis", redisHealthy ? "UP" : "DOWN")
                        .withDetail("external", externalHealthy ? "UP" : "DOWN")
                        .withDetail("timestamp", new Date())
                        .build();
            }

        } catch (Exception e) {
            return Health.down()
                    .withDetail("error", e.getMessage())
                    .withDetail("timestamp", new Date())
                    .build();
        }
    }

    private boolean checkDatabaseHealth() {
        try (Connection connection = dataSource.getConnection()) {
            return connection.isValid(5); // 5秒超时
        } catch (Exception e) {
            return false;
        }
    }

    private boolean checkRedisHealth() {
        try {
            redisTemplate.execute((RedisCallback<String>) connection -> connection.ping());
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    private boolean checkExternalDependencies() {
        // 检查外部服务可用性
        return checkUserService() && checkPaymentService();
    }

    private boolean checkUserService() {
        try {
            RestTemplate restTemplate = new RestTemplate();
            ResponseEntity<String> response = restTemplate.getForEntity(
                    "http://user-service/actuator/health", String.class);
            return response.getStatusCode().is2xxSuccessful();
        } catch (Exception e) {
            return false;
        }
    }

    private boolean checkPaymentService() {
        try {
            RestTemplate restTemplate = new RestTemplate();
            ResponseEntity<String> response = restTemplate.getForEntity(
                    "http://payment-service/actuator/health", String.class);
            return response.getStatusCode().is2xxSuccessful();
        } catch (Exception e) {
            return false;
        }
    }
}

// 2. 指标收集
@Component
public class CustomMetrics {

    private final Counter orderCreatedCounter;
    private final Timer orderProcessingTimer;
    private final Gauge activeOrdersGauge;

    @Autowired
    private OrderRepository orderRepository;

    public CustomMetrics(MeterRegistry meterRegistry) {
        this.orderCreatedCounter = Counter.builder("orders.created")
                .description("Total orders created")
                .register(meterRegistry);

        this.orderProcessingTimer = Timer.builder("order.processing.time")
                .description("Order processing time")
                .register(meterRegistry);

        this.activeOrdersGauge = Gauge.builder("orders.active")
                .description("Number of active orders")
                .register(meterRegistry, this, CustomMetrics::getActiveOrderCount);
    }

    public void recordOrderCreated() {
        orderCreatedCounter.increment();
    }

    public Timer.Sample startOrderProcessingTimer() {
        return Timer.start();
    }

    public void recordOrderProcessingTime(Timer.Sample sample) {
        sample.stop(orderProcessingTimer);
    }

    private double getActiveOrderCount() {
        return orderRepository.countByStatus(OrderStatus.PROCESSING);
    }

    // 自定义业务指标
    @EventListener
    public void handleOrderEvent(OrderEvent event) {
        Tags tags = Tags.of(
                "event_type", event.getEventType().toString(),
                "service", "order-service"
        );

        switch (event.getEventType()) {
            case ORDER_CREATED:
                recordOrderCreated();
                break;
            case ORDER_PAID:
                Metrics.counter("orders.paid", tags).increment();
                break;
            case ORDER_SHIPPED:
                Metrics.counter("orders.shipped", tags).increment();
                break;
            case ORDER_CANCELLED:
                Metrics.counter("orders.cancelled", tags).increment();
                break;
        }
    }
}

// 3. 分布式链路追踪
@Component
public class TracingConfiguration {

    // 使用Sleuth进行链路追踪
    @Bean
    public Sampler alwaysSampler() {
        return Sampler.create(1.0f); // 100%采样
    }

    // 自定义Span
    @NewSpan("order-processing")
    public OrderResult processOrder(@SpanTag("orderId") String orderId, CreateOrderRequest request) {
        Span span = tracer.nextSpan()
                .name("process-order")
                .tag("order.id", orderId)
                .tag("user.id", request.getUserId().toString())
                .start();

        try (Tracer.SpanInScope ws = tracer.withSpanInScope(span)) {
            // 添加自定义事件
            span.event("order.validation.start");

            // 执行业务逻辑
            validateOrder(request);
            span.event("order.validation.complete");

            span.event("order.creation.start");
            OrderResult result = createOrder(request);
            span.event("order.creation.complete");

            span.tag("order.status", result.getStatus());

            return result;

        } catch (Exception e) {
            span.tag("error", e.getMessage());
            throw e;
        } finally {
            span.end();
        }
    }

    @Autowired
    private Tracer tracer;

    private void validateOrder(CreateOrderRequest request) {
        // 订单验证逻辑
    }

    private OrderResult createOrder(CreateOrderRequest request) {
        // 订单创建逻辑
        return OrderResult.success("order-123");
    }
}

// 4. 日志聚合
@Component
public class StructuredLogging {

    private static final Logger logger = LoggerFactory.getLogger(StructuredLogging.class);

    public void logOrderEvent(String orderId, String eventType, Map<String, Object> details) {
        // 结构化日志
        MDC.put("service", "order-service");
        MDC.put("orderId", orderId);
        MDC.put("eventType", eventType);
        MDC.put("timestamp", Instant.now().toString());

        String jsonLog = JSON.toJSONString(Map.of(
                "service", "order-service",
                "orderId", orderId,
                "eventType", eventType,
                "details", details,
                "timestamp", Instant.now().toString()
        ));

        logger.info("Order event: {}", jsonLog);

        // 清理MDC
        MDC.clear();
    }

    // 使用ELK Stack进行日志收集和分析
    @EventListener
    public void handleOrderCreated(OrderCreatedEvent event) {
        Map<String, Object> details = Map.of(
                "userId", event.getUserId(),
                "productId", event.getProductId(),
                "quantity", event.getQuantity(),
                "amount", event.getAmount()
        );

        logOrderEvent(event.getOrderId(), "ORDER_CREATED", details);
    }
}

// 5. 服务熔断与降级
@Component
public class CircuitBreakerService {

    private final CircuitBreaker userServiceCircuitBreaker;
    private final CircuitBreaker paymentServiceCircuitBreaker;

    public CircuitBreakerService() {
        // 配置用户服务熔断器
        this.userServiceCircuitBreaker = CircuitBreaker.ofDefaults("user-service");
        configureCircuitBreaker(userServiceCircuitBreaker);

        // 配置支付服务熔断器
        this.paymentServiceCircuitBreaker = CircuitBreaker.ofDefaults("payment-service");
        configureCircuitBreaker(paymentServiceCircuitBreaker);
    }

    private void configureCircuitBreaker(CircuitBreaker circuitBreaker) {
        circuitBreaker.getEventPublisher()
                .onStateTransition(event -> {
                    System.out.println("熔断器状态变更: " + event);
                    // 发送告警通知
                    sendAlert(event);
                })
                .onCallNotPermitted(event -> {
                    System.out.println("熔断器阻断调用: " + event);
                })
                .onError(event -> {
                    System.out.println("熔断器记录错误: " + event);
                });
    }

    public UserDTO getUserWithFallback(Long userId) {
        Supplier<UserDTO> decoratedSupplier = CircuitBreaker
                .decorateSupplier(userServiceCircuitBreaker, () -> userServiceClient.getUser(userId));

        try {
            return decoratedSupplier.get();
        } catch (CallNotPermittedException e) {
            // 熔断器打开,使用降级策略
            return getFallbackUser(userId);
        }
    }

    private UserDTO getFallbackUser(Long userId) {
        // 降级策略:返回默认用户信息或从缓存获取
        return UserDTO.builder()
                .id(userId)
                .username("Unknown User")
                .email("unknown@example.com")
                .status(1)
                .build();
    }

    private void sendAlert(CircuitBreakerOnStateTransitionEvent event) {
        if (event.getStateTransition().getToState() == CircuitBreaker.State.OPEN) {
            // 熔断器打开告警
            String message = String.format("服务熔断器打开: %s", event.getCircuitBreakerName());
            alertService.sendAlert("CIRCUIT_BREAKER_OPEN", message);
        }
    }

    @Autowired
    private AlertService alertService;

    @Autowired
    private UserServiceClient userServiceClient;
}

高频面试题目

1. 理论深度题目

Q: 微服务和单体应用的优缺点对比?

A: 微服务优点:

  • 技术多样性:不同服务可使用不同技术栈
  • 独立部署:服务可独立发布和扩展
  • 团队自治:小团队独立开发维护
  • 故障隔离:单个服务故障不影响整体

微服务缺点:

  • 分布式复杂性:网络延迟、分布式事务
  • 运维复杂度:需要完善的监控和治理
  • 数据一致性:跨服务事务处理困难

Q: 如何解决微服务的数据一致性问题?

A: 数据一致性解决方案:

  • 最终一致性:通过事件驱动达到最终一致
  • Saga模式:长事务拆分为多个短事务
  • TCC模式:Try-Confirm-Cancel两阶段提交
  • 事件溯源:通过事件重放恢复状态

2. 实战应用题目

Q: 如何设计一个电商系统的微服务架构?

答题要点:

  1. 服务拆分:用户、商品、订单、支付、库存等服务
  2. 数据设计:每个服务独立数据库
  3. 通信方式:同步调用+异步消息
  4. 一致性保证:事件驱动+补偿机制
  5. 监控治理:链路追踪+健康检查

Q: 微服务部署策略有哪些?

答题要点:

  1. 蓝绿部署:零停机时间部署
  2. 金丝雀发布:灰度发布降低风险
  3. 滚动更新:逐步替换实例
  4. 容器化部署:Docker+Kubernetes
  5. 服务网格:Istio统一治理

总结

微服务架构面试重点:

  1. 架构设计:服务拆分原则、边界定义
  2. 通信模式:同步/异步通信、服务间调用
  3. 服务治理:注册发现、负载均衡、熔断降级
  4. 数据管理:分布式事务、数据一致性
  5. 运维监控:健康检查、链路追踪、日志聚合

建议结合实际微服务项目经验,能够描述完整的架构设计和技术选型思路。

powered by Gitbook© 2025 编外计划 | 最后修改: 2025-07-28 18:05:38

results matching ""

    No results matching ""