9.3 微服务架构设计

面试重要程度:⭐⭐⭐⭐⭐

常见提问方式: "你们是如何进行微服务拆分的?服务间如何通信?"

技术深度: 架构设计、服务治理、Spring Cloud Alibaba

预计阅读时间:40分钟

🎯 微服务架构基础

什么是微服务架构

微服务架构是一种将单一应用程序拆分为一组小服务的架构模式,每个服务运行在独立的进程中,通过轻量级通信机制进行交互。

核心特征:

  • 服务自治:独立开发、部署、扩展
  • 去中心化:数据和治理去中心化
  • 容错设计:服务故障不影响整体系统
  • 技术多样性:不同服务可使用不同技术栈

微服务 vs 单体架构

/**
 * 单体架构示例
 */
@RestController
public class MonolithController {
    
    @Autowired
    private UserService userService;
    
    @Autowired
    private OrderService orderService;
    
    @Autowired
    private ProductService productService;
    
    @PostMapping("/orders")
    public ResponseEntity<Order> createOrder(@RequestBody CreateOrderRequest request) {
        // 所有业务逻辑在一个应用中
        User user = userService.getUser(request.getUserId());
        Product product = productService.getProduct(request.getProductId());
        Order order = orderService.createOrder(user, product, request.getQuantity());
        
        return ResponseEntity.ok(order);
    }
}

/**
 * 微服务架构示例
 */
// 用户服务
@RestController
@RequestMapping("/users")
public class UserController {
    
    @GetMapping("/{userId}")
    public ResponseEntity<User> getUser(@PathVariable Long userId) {
        User user = userService.findById(userId);
        return ResponseEntity.ok(user);
    }
}

// 订单服务
@RestController
@RequestMapping("/orders")
public class OrderController {
    
    @Autowired
    private UserServiceClient userServiceClient;
    
    @Autowired
    private ProductServiceClient productServiceClient;
    
    @PostMapping
    public ResponseEntity<Order> createOrder(@RequestBody CreateOrderRequest request) {
        // 通过服务调用获取数据
        User user = userServiceClient.getUser(request.getUserId());
        Product product = productServiceClient.getProduct(request.getProductId());
        
        Order order = orderService.createOrder(user, product, request.getQuantity());
        return ResponseEntity.ok(order);
    }
}

🏗️ Spring Cloud Alibaba技术栈

核心组件介绍

/**
 * Spring Cloud Alibaba技术栈
 */
@SpringBootApplication
@EnableDiscoveryClient  // 服务注册发现
@EnableFeignClients     // 声明式HTTP客户端
public class OrderServiceApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }
}

/**
 * 配置文件 application.yml
 */
/*
spring:
  application:
    name: order-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        namespace: dev
        group: DEFAULT_GROUP
      config:
        server-addr: localhost:8848
        file-extension: yml
        namespace: dev
        group: DEFAULT_GROUP
    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8719
    gateway:
      routes:
        - id: order-service
          uri: lb://order-service
          predicates:
            - Path=/orders/**
          filters:
            - StripPrefix=1
*/

服务注册与发现(Nacos)

/**
 * Nacos服务注册配置
 */
@Configuration
public class NacosConfig {
    
    /**
     * 服务实例信息配置
     */
    @Bean
    public NacosServiceRegistry nacosServiceRegistry() {
        return new NacosServiceRegistry();
    }
    
    /**
     * 服务发现配置
     */
    @Bean
    public NacosDiscoveryClient nacosDiscoveryClient() {
        return new NacosDiscoveryClient();
    }
}

/**
 * 服务提供者
 */
@RestController
@RequestMapping("/products")
public class ProductController {
    
    @Value("${server.port}")
    private String port;
    
    @GetMapping("/{productId}")
    public ResponseEntity<Product> getProduct(@PathVariable Long productId) {
        Product product = productService.findById(productId);
        product.setPort(port); // 用于测试负载均衡
        
        return ResponseEntity.ok(product);
    }
    
    @GetMapping("/health")
    public ResponseEntity<String> health() {
        return ResponseEntity.ok("Product service is healthy on port: " + port);
    }
}

/**
 * 服务消费者 - 使用Feign客户端
 */
@FeignClient(name = "product-service", fallback = ProductServiceFallback.class)
public interface ProductServiceClient {
    
    @GetMapping("/products/{productId}")
    Product getProduct(@PathVariable("productId") Long productId);
    
    @GetMapping("/products/batch")
    List<Product> getProducts(@RequestParam("productIds") List<Long> productIds);
}

/**
 * Feign客户端降级处理
 */
@Component
public class ProductServiceFallback implements ProductServiceClient {
    
    @Override
    public Product getProduct(Long productId) {
        log.warn("Product service fallback triggered for productId: {}", productId);
        
        Product fallbackProduct = new Product();
        fallbackProduct.setId(productId);
        fallbackProduct.setName("商品暂时不可用");
        fallbackProduct.setPrice(BigDecimal.ZERO);
        
        return fallbackProduct;
    }
    
    @Override
    public List<Product> getProducts(List<Long> productIds) {
        return productIds.stream()
            .map(this::getProduct)
            .collect(Collectors.toList());
    }
}

配置中心(Nacos Config)

/**
 * 动态配置管理
 */
@Component
@RefreshScope  // 支持配置热更新
public class OrderConfigProperties {
    
    @Value("${order.max-items:10}")
    private Integer maxItems;
    
    @Value("${order.timeout:30000}")
    private Integer timeout;
    
    @Value("${order.discount-rate:0.1}")
    private BigDecimal discountRate;
    
    // 配置变更监听
    @NacosConfigListener(dataId = "order-service.yml", groupId = "DEFAULT_GROUP")
    public void onConfigChange(String newConfig) {
        log.info("Order service config changed: {}", newConfig);
        // 可以在这里处理配置变更逻辑
    }
    
    // Getters...
}

/**
 * 使用配置
 */
@Service
public class OrderService {
    
    @Autowired
    private OrderConfigProperties configProperties;
    
    public void createOrder(CreateOrderRequest request) {
        // 使用动态配置
        if (request.getItems().size() > configProperties.getMaxItems()) {
            throw new BusinessException("订单商品数量超过限制: " + configProperties.getMaxItems());
        }
        
        // 应用折扣
        BigDecimal totalAmount = calculateTotalAmount(request.getItems());
        BigDecimal discountAmount = totalAmount.multiply(configProperties.getDiscountRate());
        BigDecimal finalAmount = totalAmount.subtract(discountAmount);
        
        // 创建订单...
    }
}

服务网关(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(2)  // 去掉 /api/users 前缀
                    .addRequestHeader("X-Service", "user-service")
                    .circuitBreaker(config -> config
                        .setName("user-service-cb")
                        .setFallbackUri("forward:/fallback/user")
                    )
                )
                .uri("lb://user-service")
            )
            // 订单服务路由
            .route("order-service", r -> r
                .path("/api/orders/**")
                .filters(f -> f
                    .stripPrefix(2)
                    .addRequestHeader("X-Service", "order-service")
                    .requestRateLimiter(config -> config
                        .setRateLimiter(redisRateLimiter())
                        .setKeyResolver(userKeyResolver())
                    )
                )
                .uri("lb://order-service")
            )
            .build();
    }
    
    /**
     * 限流配置
     */
    @Bean
    public RedisRateLimiter redisRateLimiter() {
        return new RedisRateLimiter(10, 20); // 每秒10个请求,突发20个
    }
    
    @Bean
    public KeyResolver userKeyResolver() {
        return exchange -> exchange.getRequest().getHeaders()
            .getFirst("X-User-Id");
    }
}

/**
 * 全局过滤器
 */
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();
        
        // 白名单路径
        if (isWhiteListPath(path)) {
            return chain.filter(exchange);
        }
        
        // 验证JWT Token
        String token = request.getHeaders().getFirst("Authorization");
        if (StringUtils.isEmpty(token)) {
            return unauthorized(exchange);
        }
        
        try {
            // 解析Token
            Claims claims = JwtUtils.parseToken(token);
            String userId = claims.getSubject();
            
            // 添加用户信息到请求头
            ServerHttpRequest mutatedRequest = request.mutate()
                .header("X-User-Id", userId)
                .header("X-User-Name", claims.get("username", String.class))
                .build();
            
            return chain.filter(exchan

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

Java面试圣经 文章被收录于专栏

Java面试圣经,带你练透java圣经

全部评论
欢迎讨论
点赞 回复 分享
发布于 09-06 11:26 江西

相关推荐

09-20 15:52
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务