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圣经
查看11道真题和解析