TCP与UDP选择策略:微服务场景的协议决策指南

引言 在前面的文章中,我们深入学习了TCP和UDP两种传输层协议的工作原理、优缺点和适用场景。今天是传输层协议篇的最后一篇,我们来系统总结:如何在实际项目中选择TCP还是UDP? 核心问题: ✅ 什么时候必须用TCP?什么时候必须用UDP? ✅ 微服务场景如何选择协议? ✅ 主流RPC框架(Dubbo、gRPC)为什么选择TCP? ✅ 如何权衡可靠性与性能? 今天我们来理解: ✅ TCP vs UDP的决策树 ✅ 微服务通信的协议选择 ✅ RPC框架的协议策略 ✅ 性能调优的权衡之道 TCP vs UDP决策树 决策流程图 开始选择协议 | ↓ 需要可靠传输? | ├─ 是 ────────────────────────┐ | | ↓ ↓ 需要顺序保证? 需要建立连接? | | ├─ 是 ─────┐ ├─ 是 ─────┐ | | | | ↓ ↓ ↓ ↓ 需要流量控制? → TCP 需要拥塞控制? → TCP | | ├─ 否 ─────┘ ├─ 否 ─────┘ | | ↓ ↓ 实时性优先? 支持广播/多播? | | ├─ 是 ─────┐ ├─ 是 ─────┐ | | | | ↓ ↓ ↓ ↓ 能容忍丢包? → UDP 简单请求响应? → UDP | | ├─ 否 ─────┘ └─ 否 ─────┘ | | └──────────────────────────────┘ | ↓ 使用TCP 快速决策表 需求 协议 典型应用 数据完整性最重要 TCP 文件传输、数据库同步、支付交易 实时性最重要 UDP 视频直播、在线游戏、VoIP 需要顺序保证 TCP HTTP/HTTPS、邮件传输 广播/多播 UDP 设备发现、IPTV组播 简单请求-响应 UDP DNS查询、SNMP监控 长连接 TCP WebSocket、数据库连接池 低延迟 UDP 高频交易、实时监控 微服务场景的协议选择 场景1:RESTful API(HTTP/HTTPS) 协议:TCP ...

2025-11-20 · maneng

Spring Cloud Alibaba深度集成

微服务架构整体方案 ┌─────────────┐ │ Nacos │ ← 服务注册、配置中心 └─────────────┘ ↓ ┌─────────────┐ │ Gateway │ ← 网关(Sentinel限流) └─────────────┘ ↓ ┌─────────────┐ │ 订单服务 │ ← Sentinel流控、熔断 └─────────────┘ ↓ ┌─────────────┐ │ 商品服务 │ ← Sentinel流控、熔断 └─────────────┘ 完整依赖配置 <dependencyManagement> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2022.0.0.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <!-- Nacos服务发现 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!-- Nacos配置中心 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <!-- Sentinel --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <!-- OpenFeign --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <!-- LoadBalancer --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency> </dependencies> Nacos + Sentinel配置 spring: application: name: order-service cloud: # Nacos配置 nacos: discovery: server-addr: localhost:8848 namespace: dev config: server-addr: localhost:8848 namespace: dev file-extension: yml # Sentinel配置 sentinel: transport: dashboard: localhost:8080 datasource: flow: nacos: server-addr: localhost:8848 dataId: ${spring.application.name}-flow-rules groupId: SENTINEL_GROUP rule-type: flow namespace: dev degrade: nacos: server-addr: localhost:8848 dataId: ${spring.application.name}-degrade-rules groupId: SENTINEL_GROUP rule-type: degrade namespace: dev # Feign配置 feign: sentinel: enabled: true client: config: default: connectTimeout: 5000 readTimeout: 5000 服务间调用保护 订单服务调用商品服务 @FeignClient( name = "product-service", fallback = ProductServiceFallback.class, fallbackFactory = ProductServiceFallbackFactory.class ) public interface ProductService { @GetMapping("/product/{id}") Product getProduct(@PathVariable Long id); } // Fallback实现 @Component public class ProductServiceFallback implements ProductService { @Override public Product getProduct(Long id) { return Product.builder() .id(id) .name("商品服务暂时不可用") .price(0.0) .build(); } } // FallbackFactory(可以获取异常信息) @Component public class ProductServiceFallbackFactory implements FallbackFactory<ProductService> { @Override public ProductService create(Throwable cause) { return new ProductService() { @Override public Product getProduct(Long id) { log.error("调用商品服务失败:{}", cause.getMessage()); return Product.builder() .id(id) .name("商品服务异常:" + cause.getMessage()) .build(); } }; } } 链路限流 场景:多个接口调用同一个服务 @Service public class OrderService { @Autowired private ProductService productService; // 接口1:创建订单 @SentinelResource(value = "createOrder") public Order createOrder(Long productId) { // 调用商品服务 getProductInfo(productId); return new Order(); } // 接口2:查询订单 @SentinelResource(value = "queryOrder") public Order queryOrder(Long orderId) { Order order = orderDao.findById(orderId); // 调用商品服务 getProductInfo(order.getProductId()); return order; } // 公共方法:获取商品信息 @SentinelResource(value = "getProductInfo", blockHandler = "handleBlock") private Product getProductInfo(Long productId) { return productService.getProduct(productId); } private Product handleBlock(Long productId, BlockException ex) { return Product.builder().id(productId).name("商品信息获取受限").build(); } } 配置链路限流 FlowRule rule = new FlowRule(); rule.setResource("getProductInfo"); rule.setGrade(RuleConstant.FLOW_GRADE_QPS); rule.setCount(100); rule.setStrategy(RuleConstant.STRATEGY_CHAIN); rule.setRefResource("createOrder"); // 只对createOrder链路限流 FlowRuleManager.loadRules(Collections.singletonList(rule)); 服务熔断配置 # 在Nacos中配置 # order-service-degrade-rules [ { "resource": "product-service", "grade": 0, "count": 1000, "timeWindow": 10, "minRequestAmount": 5, "statIntervalMs": 10000, "slowRatioThreshold": 0.5 }, { "resource": "inventory-service", "grade": 1, "count": 0.3, "timeWindow": 10, "minRequestAmount": 5, "statIntervalMs": 10000 } ] Gateway集成 spring: cloud: gateway: routes: - id: order-service uri: lb://order-service predicates: - Path=/api/order/** filters: - StripPrefix=2 sentinel: filter: enabled: false # 禁用默认过滤器 scg: fallback: mode: response response-status: 429 response-body: '{"code":429,"message":"请求过于频繁"}' 监控集成 暴露监控端点 management: endpoints: web: exposure: include: '*' endpoint: sentinel: enabled: true Prometheus集成 <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency> @Configuration public class SentinelMetricsConfig { @PostConstruct public void init() { // 启用Sentinel指标导出 MetricRegistry.getMetricRegistry() .addMetricProvider(new SentinelMetricProvider()); } } 完整微服务实战 订单服务 @SpringBootApplication @EnableDiscoveryClient @EnableFeignClients public class OrderServiceApplication { public static void main(String[] args) { SpringApplication.run(OrderServiceApplication.class, args); } } @RestController @RequestMapping("/order") public class OrderController { @Autowired private OrderService orderService; @PostMapping("/create") @SentinelResource(value = "orderCreateApi", blockHandler = "handleBlock") public Result createOrder(@RequestBody OrderDTO dto) { Order order = orderService.createOrder(dto); return Result.success(order); } public Result handleBlock(OrderDTO dto, BlockException ex) { return Result.error(429, "订单创建繁忙"); } } @Service public class OrderService { @Autowired private ProductService productService; @Autowired private InventoryService inventoryService; @SentinelResource(value = "createOrder", fallback = "handleFallback") @Transactional public Order createOrder(OrderDTO dto) { // 1. 检查商品 Product product = productService.getProduct(dto.getProductId()); // 2. 检查库存 boolean hasStock = inventoryService.checkStock(dto.getProductId(), dto.getQuantity()); if (!hasStock) { throw new BusinessException("库存不足"); } // 3. 扣减库存 inventoryService.deductStock(dto.getProductId(), dto.getQuantity()); // 4. 创建订单 Order order = new Order(); order.setProductId(product.getId()); order.setQuantity(dto.getQuantity()); order.setAmount(product.getPrice() * dto.getQuantity()); return orderDao.save(order); } public Order handleFallback(OrderDTO dto, Throwable ex) { log.error("订单创建失败", ex); throw new BusinessException("系统繁忙,请稍后重试"); } } 总结 Spring Cloud Alibaba + Sentinel集成要点: ...

2025-11-20 · maneng

为什么需要微服务?单体架构的困境与演进

引子:一个电商系统的架构抉择 2020年3月,某创业公司CTO王明面临一个艰难的技术决策: 现状: 团队规模:15个研发 业务现状:日订单量从1万增长到10万 核心痛点:每次发布需要2小时,任何一个小功能的上线都要全量发布,导致上线频率从每周3次降到每周1次 技术选型的两个方向: 继续单体架构:优化现有系统,加机器,做好模块化 切换微服务架构:拆分服务,引入Spring Cloud,重构系统 王明的困惑: “我们真的需要微服务吗?” “微服务能解决什么问题?” “微服务会带来什么代价?” 让我们通过两个完全不同的世界,来理解微服务架构的本质。 一、场景A:单体架构实现(初创期的最优解) 1.1 单体架构的完整代码实现 /** * 电商系统 - 单体架构实现 * 特点:所有功能在一个进程内,共享一个数据库 */ @SpringBootApplication public class ECommerceMonolithApplication { public static void main(String[] args) { SpringApplication.run(ECommerceMonolithApplication.class, args); } } /** * 订单服务(单体架构版本) * 依赖:用户服务、商品服务、库存服务、支付服务 * 特点:所有依赖都在同一个进程内,方法调用 */ @Service @Slf4j @Transactional(rollbackFor = Exception.class) public class OrderService { @Autowired private UserService userService; // 本地方法调用 @Autowired private ProductService productService; // 本地方法调用 @Autowired private InventoryService inventoryService; // 本地方法调用 @Autowired private PaymentService paymentService; // 本地方法调用 @Autowired private OrderRepository orderRepository; // 同一个数据库 /** * 创建订单 * 优势: * 1. 本地方法调用,性能极高(纳秒级) * 2. 本地事务,ACID保证强一致性 * 3. 调试方便,堆栈清晰 * * 问题: * 1. 单点故障:任何一个模块崩溃,整个系统不可用 * 2. 部署耦合:改一行代码,整个系统重启 * 3. 技术栈绑定:整个系统必须用同一种语言、框架 * 4. 资源竞争:所有模块共享JVM内存、CPU */ public Order createOrder(CreateOrderRequest request) { // ========== 1. 用户验证(本地方法调用,1ms) ========== User user = userService.getUserById(request.getUserId()); if (user == null) { throw new BusinessException("用户不存在"); } if (user.getStatus() != UserStatus.ACTIVE) { throw new BusinessException("用户状态异常"); } // ========== 2. 商品查询(本地方法调用,2ms) ========== Product product = productService.getProductById(request.getProductId()); if (product == null) { throw new BusinessException("商品不存在"); } if (product.getStatus() != ProductStatus.ON_SALE) { throw new BusinessException("商品已下架"); } // ========== 3. 库存扣减(本地方法调用,3ms) ========== boolean deductSuccess = inventoryService.deduct( product.getId(), request.getQuantity() ); if (!deductSuccess) { throw new BusinessException("库存不足"); } // ========== 4. 创建订单(本地数据库写入,5ms) ========== Order order = Order.builder() .orderNo(generateOrderNo()) .userId(user.getId()) .productId(product.getId()) .productName(product.getName()) .quantity(request.getQuantity()) .price(product.getPrice()) .amount(product.getPrice().multiply( new BigDecimal(request.getQuantity()) )) .status(OrderStatus.UNPAID) .createTime(LocalDateTime.now()) .build(); order = orderRepository.save(order); // ========== 5. 调用支付(本地方法调用,10ms) ========== boolean paymentSuccess = paymentService.pay( order.getOrderNo(), order.getAmount() ); if (!paymentSuccess) { throw new BusinessException("支付失败"); } // ========== 6. 更新订单状态(本地数据库更新,2ms) ========== order.setStatus(OrderStatus.PAID); order.setPayTime(LocalDateTime.now()); order = orderRepository.save(order); log.info("订单创建成功: orderNo={}, amount={}", order.getOrderNo(), order.getAmount()); // 总耗时约23ms(都是本地调用) return order; } /** * 生成订单号 */ private String generateOrderNo() { return "ORD" + System.currentTimeMillis() + ThreadLocalRandom.current().nextInt(1000); } } /** * 用户服务 */ @Service public class UserService { @Autowired private UserRepository userRepository; public User getUserById(Long userId) { return userRepository.findById(userId).orElse(null); } } /** * 商品服务 */ @Service public class ProductService { @Autowired private ProductRepository productRepository; public Product getProductById(Long productId) { return productRepository.findById(productId).orElse(null); } } /** * 库存服务 */ @Service public class InventoryService { @Autowired private InventoryRepository inventoryRepository; /** * 扣减库存 * 优势:本地事务,强一致性保证 */ public boolean deduct(Long productId, Integer quantity) { Inventory inventory = inventoryRepository.findByProductId(productId); if (inventory == null || inventory.getStock() < quantity) { return false; } inventory.setStock(inventory.getStock() - quantity); inventoryRepository.save(inventory); return true; } } /** * 支付服务 */ @Service public class PaymentService { @Autowired private PaymentRepository paymentRepository; /** * 支付 * 优势:本地事务,要么都成功,要么都失败 */ public boolean pay(String orderNo, BigDecimal amount) { // 调用第三方支付(这里模拟) boolean paySuccess = callThirdPartyPayment(orderNo, amount); if (paySuccess) { // 记录支付流水 Payment payment = Payment.builder() .orderNo(orderNo) .amount(amount) .status(PaymentStatus.SUCCESS) .payTime(LocalDateTime.now()) .build(); paymentRepository.save(payment); } return paySuccess; } private boolean callThirdPartyPayment(String orderNo, BigDecimal amount) { // 模拟第三方支付调用 return true; } } /** * 数据库实体:订单 */ @Entity @Table(name = "t_order") @Data @Builder public class Order { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String orderNo; private Long userId; private Long productId; private String productName; private Integer quantity; private BigDecimal price; private BigDecimal amount; @Enumerated(EnumType.STRING) private OrderStatus status; private LocalDateTime createTime; private LocalDateTime payTime; } /** * 数据库实体:用户、商品、库存、支付记录 * (省略具体实现) */ 1.2 单体架构的项目结构 ecommerce-monolith/ ├── src/main/java/com/example/ecommerce/ │ ├── ECommerceMonolithApplication.java # 启动类 │ ├── controller/ # 控制器层 │ │ ├── OrderController.java │ │ ├── UserController.java │ │ ├── ProductController.java │ │ └── InventoryController.java │ ├── service/ # 服务层 │ │ ├── OrderService.java # 订单服务 │ │ ├── UserService.java # 用户服务 │ │ ├── ProductService.java # 商品服务 │ │ ├── InventoryService.java # 库存服务 │ │ └── PaymentService.java # 支付服务 │ ├── repository/ # 数据访问层 │ │ ├── OrderRepository.java │ │ ├── UserRepository.java │ │ ├── ProductRepository.java │ │ ├── InventoryRepository.java │ │ └── PaymentRepository.java │ ├── entity/ # 实体层 │ │ ├── Order.java │ │ ├── User.java │ │ ├── Product.java │ │ ├── Inventory.java │ │ └── Payment.java │ └── config/ # 配置类 │ ├── DataSourceConfig.java │ └── TransactionConfig.java ├── src/main/resources/ │ ├── application.yml # 配置文件 │ └── db/migration/ # 数据库脚本 │ └── V1__init_schema.sql └── pom.xml # Maven配置 部署方式: 1. 打包:mvn clean package → ecommerce-monolith.jar(200MB) 2. 部署:java -jar ecommerce-monolith.jar 3. 运行:单个JVM进程,占用2GB内存 4. 数据库:MySQL单实例,5张表在同一个库 1.3 单体架构的核心特点 维度 特点 优势 劣势 部署 单个war/jar包 部署简单,运维成本低 改一行代码,全量重启 调用方式 本地方法调用 性能极高(纳秒级) 单点故障,一损俱损 事务 本地事务(ACID) 强一致性,简单可靠 无法独立扩展单个模块 技术栈 统一技术栈 团队技能统一,学习成本低 技术升级困难,框架绑定 开发效率 代码在同一个工程 IDE调试方便,定位问题快 代码库膨胀,启动变慢 团队协作 共享代码库 代码复用容易 代码冲突频繁,发布排队 二、场景B:微服务架构实现(规模化后的必然选择) 2.1 微服务架构的完整代码实现 /** * 订单服务(微服务架构版本) * 特点:独立进程,独立数据库,通过RPC调用其他服务 */ @SpringBootApplication @EnableDiscoveryClient // 服务注册 @EnableFeignClients // 远程调用 public class OrderServiceApplication { public static void main(String[] args) { SpringApplication.run(OrderServiceApplication.class, args); } } /** * 订单服务实现 * 依赖:远程调用用户服务、商品服务、库存服务、支付服务 */ @Service @Slf4j public class OrderService { @Autowired private UserServiceClient userServiceClient; // 远程调用(HTTP/gRPC) @Autowired private ProductServiceClient productServiceClient; // 远程调用 @Autowired private InventoryServiceClient inventoryServiceClient; // 远程调用 @Autowired private PaymentServiceClient paymentServiceClient; // 远程调用 @Autowired private OrderRepository orderRepository; // 独立数据库 @Autowired private RocketMQTemplate rocketMQTemplate; // 消息队列 /** * 创建订单(微服务版本) * * 优势: * 1. 服务独立部署:订单服务可以独立发布,不影响其他服务 * 2. 技术栈自由:订单服务用Java,用户服务可以用Go,商品服务可以用Python * 3. 独立扩展:订单服务压力大,可以只扩容订单服务 * 4. 故障隔离:支付服务挂了,不影响订单创建(降级返回"支付中") * * 挑战: * 1. 网络调用:性能下降(本地纳秒级 → 远程毫秒级) * 2. 分布式事务:无法保证强一致性(ACID → BASE) * 3. 调用链路长:5个服务,任何一个超时都影响整体 * 4. 运维复杂:5个服务 × 3个环境 = 15套部署 */ public Order createOrder(CreateOrderRequest request) { // ========== 1. 远程调用用户服务(网络调用,10ms + 超时风险) ========== try { UserDTO user = userServiceClient.getUserById(request.getUserId()); if (user == null || user.getStatus() != UserStatus.ACTIVE) { throw new BusinessException("用户不存在或状态异常"); } } catch (FeignException e) { log.error("调用用户服务失败: {}", e.getMessage()); throw new BusinessException("用户服务不可用"); } // ========== 2. 远程调用商品服务(网络调用,15ms + 超时风险) ========== ProductDTO product; try { product = productServiceClient.getProductById(request.getProductId()); if (product == null || product.getStatus() != ProductStatus.ON_SALE) { throw new BusinessException("商品不存在或已下架"); } } catch (FeignException e) { log.error("调用商品服务失败: {}", e.getMessage()); throw new BusinessException("商品服务不可用"); } // ========== 3. 远程调用库存服务(网络调用,20ms + 超时风险) ========== boolean deductSuccess; try { deductSuccess = inventoryServiceClient.deduct( product.getId(), request.getQuantity() ); if (!deductSuccess) { throw new BusinessException("库存不足"); } } catch (FeignException e) { log.error("调用库存服务失败: {}", e.getMessage()); throw new BusinessException("库存服务不可用"); } // ========== 4. 创建订单(本地数据库写入,5ms) ========== Order order = Order.builder() .orderNo(generateOrderNo()) .userId(request.getUserId()) .productId(product.getId()) .productName(product.getName()) .quantity(request.getQuantity()) .price(product.getPrice()) .amount(product.getPrice().multiply( new BigDecimal(request.getQuantity()) )) .status(OrderStatus.UNPAID) .createTime(LocalDateTime.now()) .build(); order = orderRepository.save(order); // ========== 5. 异步调用支付服务(通过消息队列,解耦) ========== // 不直接调用支付服务,而是发送消息到MQ,支付服务异步消费 PaymentMessage paymentMessage = PaymentMessage.builder() .orderNo(order.getOrderNo()) .amount(order.getAmount()) .build(); rocketMQTemplate.syncSend("PAYMENT_TOPIC", paymentMessage); log.info("订单创建成功: orderNo={}, amount={}", order.getOrderNo(), order.getAmount()); // 总耗时约50ms(网络调用 + 超时重试) // 相比单体架构的23ms,慢了2倍,但换来了独立部署、独立扩展、故障隔离 return order; } /** * 生成订单号(分布式唯一ID) * 单体架构:可以用数据库自增ID * 微服务架构:需要用雪花算法、UUID等分布式ID生成策略 */ private String generateOrderNo() { // 雪花算法生成分布式唯一ID return "ORD" + SnowflakeIdWorker.generateId(); } } /** * 用户服务客户端(Feign声明式HTTP客户端) */ @FeignClient( name = "user-service", // 服务名(从注册中心获取) fallback = UserServiceFallback.class // 降级策略 ) public interface UserServiceClient { @GetMapping("/api/users/{userId}") UserDTO getUserById(@PathVariable("userId") Long userId); } /** * 用户服务降级策略(熔断后的备选方案) */ @Component public class UserServiceFallback implements UserServiceClient { @Override public UserDTO getUserById(Long userId) { log.warn("用户服务调用失败,触发降级策略"); // 返回一个默认用户,或者抛出异常 throw new BusinessException("用户服务不可用,请稍后重试"); } } /** * 商品服务客户端 */ @FeignClient( name = "product-service", fallback = ProductServiceFallback.class ) public interface ProductServiceClient { @GetMapping("/api/products/{productId}") ProductDTO getProductById(@PathVariable("productId") Long productId); } /** * 库存服务客户端 */ @FeignClient( name = "inventory-service", fallback = InventoryServiceFallback.class ) public interface InventoryServiceClient { @PostMapping("/api/inventory/deduct") boolean deduct(@RequestParam("productId") Long productId, @RequestParam("quantity") Integer quantity); } /** * 支付服务(独立的微服务,监听MQ消息) */ @Service @Slf4j public class PaymentService { @Autowired private PaymentRepository paymentRepository; @Autowired private OrderServiceClient orderServiceClient; /** * 监听支付消息(异步处理) * 优势:解耦订单服务和支付服务,支付失败不影响订单创建 */ @RocketMQMessageListener( topic = "PAYMENT_TOPIC", consumerGroup = "payment-consumer-group" ) public class PaymentMessageListener implements RocketMQListener<PaymentMessage> { @Override public void onMessage(PaymentMessage message) { log.info("接收到支付消息: {}", message); try { // 调用第三方支付 boolean paySuccess = callThirdPartyPayment( message.getOrderNo(), message.getAmount() ); if (paySuccess) { // 记录支付流水 Payment payment = Payment.builder() .orderNo(message.getOrderNo()) .amount(message.getAmount()) .status(PaymentStatus.SUCCESS) .payTime(LocalDateTime.now()) .build(); paymentRepository.save(payment); // 回调订单服务,更新订单状态 orderServiceClient.updateOrderStatus( message.getOrderNo(), OrderStatus.PAID ); log.info("支付成功: orderNo={}", message.getOrderNo()); } else { log.error("支付失败: orderNo={}", message.getOrderNo()); // 支付失败,可以重试或者发送通知 } } catch (Exception e) { log.error("支付处理异常: orderNo={}, error={}", message.getOrderNo(), e.getMessage()); // 异常时,消息会重新入队,重试机制 throw new RuntimeException("支付处理失败", e); } } } private boolean callThirdPartyPayment(String orderNo, BigDecimal amount) { // 模拟第三方支付调用 return true; } } 2.2 微服务架构的项目结构 microservices-ecommerce/ ├── order-service/ # 订单服务 │ ├── src/main/java/com/example/order/ │ │ ├── OrderServiceApplication.java # 启动类 │ │ ├── controller/OrderController.java │ │ ├── service/OrderService.java │ │ ├── repository/OrderRepository.java │ │ ├── entity/Order.java │ │ ├── client/ # Feign客户端 │ │ │ ├── UserServiceClient.java │ │ │ ├── ProductServiceClient.java │ │ │ ├── InventoryServiceClient.java │ │ │ └── PaymentServiceClient.java │ │ └── config/ # 配置类 │ ├── src/main/resources/ │ │ └── application.yml # 订单服务配置 │ └── pom.xml # 独立的Maven配置 │ ├── user-service/ # 用户服务 │ ├── src/main/java/com/example/user/ │ │ ├── UserServiceApplication.java │ │ ├── controller/UserController.java │ │ ├── service/UserService.java │ │ ├── repository/UserRepository.java │ │ └── entity/User.java │ ├── src/main/resources/ │ │ └── application.yml │ └── pom.xml │ ├── product-service/ # 商品服务 │ ├── src/main/java/com/example/product/ │ │ ├── ProductServiceApplication.java │ │ ├── controller/ProductController.java │ │ ├── service/ProductService.java │ │ ├── repository/ProductRepository.java │ │ └── entity/Product.java │ ├── src/main/resources/ │ │ └── application.yml │ └── pom.xml │ ├── inventory-service/ # 库存服务 │ ├── src/main/java/com/example/inventory/ │ │ ├── InventoryServiceApplication.java │ │ ├── controller/InventoryController.java │ │ ├── service/InventoryService.java │ │ ├── repository/InventoryRepository.java │ │ └── entity/Inventory.java │ ├── src/main/resources/ │ │ └── application.yml │ └── pom.xml │ ├── payment-service/ # 支付服务 │ ├── src/main/java/com/example/payment/ │ │ ├── PaymentServiceApplication.java │ │ ├── service/PaymentService.java │ │ ├── repository/PaymentRepository.java │ │ ├── entity/Payment.java │ │ └── listener/PaymentMessageListener.java │ ├── src/main/resources/ │ │ └── application.yml │ └── pom.xml │ ├── common/ # 公共模块 │ ├── src/main/java/com/example/common/ │ │ ├── dto/ # 数据传输对象 │ │ ├── exception/ # 异常定义 │ │ └── util/ # 工具类 │ └── pom.xml │ ├── gateway/ # API网关(Spring Cloud Gateway) │ ├── src/main/java/com/example/gateway/ │ │ ├── GatewayApplication.java │ │ └── config/GatewayConfig.java │ └── pom.xml │ └── registry/ # 服务注册中心(Nacos) └── nacos-server/ 部署方式: 1. 打包:每个服务独立打包 → order-service.jar, user-service.jar... 2. 部署:每个服务独立部署(可以部署在不同的机器上) 3. 运行:5个JVM进程,每个占用1GB内存(总共5GB) 4. 数据库:5个独立的MySQL数据库(或5个独立的Schema) 2.3 微服务架构的核心特点 维度 特点 优势 劣势 部署 独立部署单元 改一行代码,只重启一个服务 运维复杂度高,需要容器编排 调用方式 远程调用(HTTP/gRPC) 故障隔离,服务独立演进 性能下降(纳秒→毫秒),网络不可靠 事务 分布式事务(BASE) 独立扩展,高可用 最终一致性,业务逻辑复杂 技术栈 多语言异构 技术自由,选择最合适的技术 技能要求高,学习成本大 开发效率 代码分散在多个工程 独立迭代,避免冲突 调试困难,链路追踪复杂 团队协作 按服务划分团队 团队自治,减少沟通成本 接口约定复杂,版本管理困难 三、数据对比:单体 vs 微服务 3.1 性能对比 指标 单体架构 微服务架构 差异分析 接口响应时间 23ms 50ms 微服务慢2倍(网络调用开销) QPS 5000 3000 微服务下降40%(网络+序列化) CPU使用率 60% 70% 微服务高10%(序列化+网络) 内存占用 2GB(单进程) 5GB(5进程) 微服务多2.5倍 启动时间 120s 30s/服务 微服务单个服务更快 关键发现: ...

2025-11-03 · maneng

为什么需要熔断限流?从一次生产事故说起

核心观点: 熔断限流不是性能优化,而是系统稳定性的生命线。本文从一次真实生产事故出发,深度剖析为什么微服务架构必须要有熔断限流机制。 引子:2024年11月11日,一次惊心动魄的生产事故 事故背景 某电商平台,日常订单量10万单/天,流量1000 QPS。2024年双十一活动,预计流量增长3-5倍。技术团队提前扩容服务器,增加数据库连接池,准备迎接流量高峰。 然而,谁也没想到,活动开始仅10分钟,整个系统就崩溃了。 时间线复盘 10:00:00 - 活动正式开始 运营团队启动促销活动,用户涌入。前端监控显示流量快速攀升: 10:00:00 → 1,000 QPS(正常) 10:02:00 → 3,000 QPS(预期内) 10:05:00 → 8,000 QPS(超预期) 10:08:00 → 12,000 QPS(远超预期) 10:05:30 - 第一个异常信号 监控系统开始报警: [ALERT] 订单服务响应时间: 50ms → 800ms (P99) [ALERT] 订单服务线程池占用: 50/200 → 180/200 技术团队看到告警,以为是正常的流量压力,决定继续观察。 10:07:15 - 雪崩的开始 [CRITICAL] 订单服务响应时间: 800ms → 5000ms (P99) [CRITICAL] 订单服务线程池占用: 200/200 (100%,线程池耗尽) [ERROR] 用户服务调用超时: connection timeout after 5s 技术团队意识到不对劲,开始排查。日志显示: java.net.SocketTimeoutException: Read timed out at UserServiceClient.getUser(UserServiceClient.java:45) at OrderService.createOrder(OrderService.java:87) ... 原因找到了:用户服务的数据库出现慢查询(某个未加索引的查询,平时10ms,高峰期变成5秒)。 ...

2025-11-03 · maneng

服务拆分第一性原理:从领域驱动到康威定律

引子:一次失败的微服务拆分 2019年某月,某金融科技公司CTO李明决定将单体应用拆分为微服务。 拆分方案(按技术层拆分): 前端服务:负责所有页面渲染 业务服务:负责所有业务逻辑 数据服务:负责所有数据访问 3个月后的结果: 部署次数:从每周1次降到每月1次(更慢了!) 数据库连接:3个服务共享同一个数据库(还是耦合) 代码冲突:业务服务有50个类,15个人修改,冲突率40%(比单体更高) 故障影响:数据服务挂了,整个系统不可用(单点依旧存在) 李明的困惑: “我们明明拆分了,为什么比单体还糟糕?” “什么才是正确的拆分方式?” “服务边界应该如何划分?” 这个案例揭示了一个核心问题:拆分微服务的本质不是"拆分技术层",而是"拆分业务领域"。 让我们从第一性原理出发,系统化解答这个问题。 一、服务拆分的本质问题 1.1 什么是服务边界? 服务边界的定义: 物理边界:独立的进程、独立的数据库、独立的部署单元 逻辑边界:独立的业务职责、独立的团队所有权、独立的变更频率 好的服务边界的三个特征: 高内聚:服务内部的功能紧密相关(订单创建、订单查询、订单取消都在订单服务内) 低耦合:服务之间的依赖最小化(订单服务不依赖评论服务) 独立演进:服务可以独立开发、测试、部署(订单服务升级,不影响商品服务) 1.2 拆分的三个核心目标 目标1:独立部署 单体架构的问题: 改订单服务的一个Bug,整个系统重启 部署时间:120分钟 微服务的解决方案: 改订单服务的Bug,只重启订单服务 部署时间:15分钟 目标2:独立扩展 单体架构的问题: 订单服务压力大,整体扩容,浪费80%资源 微服务的解决方案: 订单服务压力大,只扩容订单服务 目标3:独立演进 单体架构的问题: 整个系统必须用同一技术栈(Java + Spring) 微服务的解决方案: 订单服务用Java,推荐服务用Python,搜索服务用Go 1.3 拆分的代价 不要忘记:拆分微服务是有代价的! 代价维度 单体架构 微服务架构 增加幅度 网络调用延迟 0ms(本地调用) 10-50ms +∞ 事务复杂度 ACID(本地事务) BASE(分布式事务) +10倍 运维复杂度 1个服务 100+服务 +100倍 问题定位难度 单进程堆栈 链路追踪 +5倍 核心原则:只有当拆分的收益 > 拆分的成本时,才应该拆分! ...

2025-11-03 · maneng

服务间通信:同步调用、异步消息与事件驱动

引子:一次服务雪崩引发的思考 2020年双11凌晨2点,某电商平台订单服务突然不可用,导致用户无法下单。 故障链路: 用户下单 → 订单服务 → 库存服务(超时20秒) → 订单服务线程池耗尽 → 整个系统不可用 问题根源: 订单服务同步调用库存服务(HTTP请求) 库存服务压力大,响应慢(20秒超时) 订单服务线程池耗尽(200个线程全部阻塞) 新的订单请求无法处理,系统崩溃 架构师王明的反思: “同步调用的问题是什么?” “为什么不用异步消息?” “什么场景用同步,什么场景用异步?” 这个案例揭示了微服务通信的核心问题:如何选择合适的通信模式,平衡性能、可靠性、复杂度? 一、通信模式的本质:耦合度与可靠性的权衡 1.1 通信模式的两个维度 维度1:同步 vs 异步 维度 同步通信 异步通信 调用方式 请求→等待→响应 请求→立即返回→回调 阻塞性 调用方阻塞等待 调用方不阻塞 耦合度 强耦合(时间耦合) 弱耦合(时间解耦) 响应时间 快(毫秒级) 慢(秒级或分钟级) 可用性 低(被调用方挂了,调用方也挂) 高(被调用方挂了,消息不丢失) 复杂度 低(简单直接) 高(需要消息队列) 维度2:点对点 vs 发布订阅 维度 点对点(P2P) 发布订阅(Pub/Sub) 调用关系 一对一 一对多 耦合度 强耦合(空间耦合) 弱耦合(空间解耦) 扩展性 差(新增消费者要修改代码) 好(新增消费者不影响发布者) 典型场景 RPC调用 领域事件 1.2 耦合度的四个维度 1. 时间耦合(Temporal Coupling) ...

2025-11-03 · maneng

熔断降级实战:从Hystrix到Sentinel

核心观点: 熔断器是微服务架构的安全气囊,通过快速失败隔离故障,防止雪崩。Sentinel是当前生产环境的最佳选择。 熔断器核心原理 什么是熔断器? 熔断器(Circuit Breaker)借鉴了电路中的断路器概念: 电路断路器: 正常 → 短路 → 断路器跳闸 → 保护电路 服务熔断器: 正常 → 下游故障 → 熔断器打开 → 保护上游 核心思想: 当下游服务故障时,快速失败优于漫长等待。 熔断器状态机 熔断器有三种状态: 错误率>阈值 Closed ───────────→ Open ↑ │ │ │ 等待恢复时间 │ ↓ │ Half-Open │ │ │ 探测成功 │ 探测失败 └──────────────────┘ 状态说明: Closed(闭合): 正常状态 放行所有请求 统计错误率 错误率>阈值 → 转Open Open(打开): 熔断状态 拒绝所有请求,快速失败 不调用下游服务 等待一段时间 → 转Half-Open Half-Open(半开): 探测状态 放行少量请求(探测) 成功 → 转Closed 失败 → 转Open 手写熔断器 /** * 简化版熔断器 */ public class SimpleCircuitBreaker { // 状态枚举 enum State { CLOSED, OPEN, HALF_OPEN } private State state = State.CLOSED; private int failureCount = 0; private int successCount = 0; private long lastFailureTime = 0; // 配置 private final int failureThreshold; // 失败阈值 private final long timeoutMillis; // 熔断时长 private final int halfOpenSuccessThreshold; // 半开成功阈值 public SimpleCircuitBreaker(int failureThreshold, long timeoutMillis) { this.failureThreshold = failureThreshold; this.timeoutMillis = timeoutMillis; this.halfOpenSuccessThreshold = 3; } /** * 执行受保护的调用 */ public <T> T execute(Callable<T> callable, Function<Exception, T> fallback) { // 检查状态 if (state == State.OPEN) { // 检查是否可以进入半开状态 if (System.currentTimeMillis() - lastFailureTime >= timeoutMillis) { state = State.HALF_OPEN; successCount = 0; } else { // 快速失败,调用降级 return fallback.apply(new CircuitBreakerOpenException()); } } try { // 调用实际方法 T result = callable.call(); // 调用成功 onSuccess(); return result; } catch (Exception e) { // 调用失败 onFailure(); return fallback.apply(e); } } private synchronized void onSuccess() { failureCount = 0; if (state == State.HALF_OPEN) { successCount++; if (successCount >= halfOpenSuccessThreshold) { // 连续成功,恢复闭合 state = State.CLOSED; } } } private synchronized void onFailure() { lastFailureTime = System.currentTimeMillis(); if (state == State.HALF_OPEN) { // 半开状态失败,立即打开 state = State.OPEN; successCount = 0; } else if (state == State.CLOSED) { failureCount++; if (failureCount >= failureThreshold) { // 失败次数达到阈值,打开熔断器 state = State.OPEN; } } } public State getState() { return state; } } // 使用示例 public class UserService { private SimpleCircuitBreaker breaker = new SimpleCircuitBreaker(5, 10000); // 5次失败,熔断10秒 public User getUser(Long userId) { return breaker.execute( // 实际调用 () -> userServiceClient.getUser(userId), // 降级方法 (ex) -> { log.warn("用户服务熔断,返回默认用户"); return User.defaultUser(userId); } ); } } 工作流程: ...

2025-11-03 · maneng

分布式事务:从ACID到BASE的演进

引子:一次支付失败引发的数据不一致 2021年某电商平台出现严重Bug:用户支付成功,但订单状态未更新,导致重复支付。 故障流程: 1. 订单服务:创建订单(成功) 2. 库存服务:扣减库存(成功) 3. 支付服务:调用支付(成功) 4. 订单服务:更新订单状态(失败,网络超时) 结果:支付成功,但订单状态仍为"未支付",用户再次支付 核心问题:微服务架构下,如何保证多个服务的数据一致性? 一、事务的本质:ACID四大特性 1.1 本地事务(单体架构) ACID特性: 原子性(Atomicity):要么都成功,要么都失败 一致性(Consistency):数据始终处于一致状态 隔离性(Isolation):并发事务互不干扰 持久性(Durability):提交后永久保存 示例: @Transactional public void createOrder(OrderRequest request) { // 1. 创建订单 Order order = new Order(); orderRepository.save(order); // 2. 扣减库存 Inventory inventory = inventoryRepository.findByProductId(request.getProductId()); inventory.setStock(inventory.getStock() - request.getQuantity()); inventoryRepository.save(inventory); // 3. 创建支付记录 Payment payment = new Payment(); paymentRepository.save(payment); // 如果任何一步失败,全部回滚 } 1.2 分布式事务的困境 微服务架构下: 订单服务 → Order_DB 库存服务 → Inventory_DB 支付服务 → Payment_DB 问题:三个独立的数据库,无法用本地事务保证一致性 二、CAP定理与BASE理论 2.1 CAP定理 CAP定理指出,分布式系统最多只能同时满足以下三项中的两项: ...

2025-11-03 · maneng

Spring Cloud第一性原理:从单体到微服务的架构演进

系列导航:本文是《Spring框架第一性原理》系列的第5篇 第1篇:为什么我们需要Spring框架? 第2篇:IoC容器:从手动new到自动装配的演进 第3篇:AOP:从代码重复到面向切面编程 第4篇:Spring Boot:约定优于配置的威力 第5篇:Spring Cloud:从单体到微服务的架构演进(本文) 引子:单体应用的困境 场景重现:一个电商系统的演进之路 让我们从一个真实的电商系统的成长历程说起。 第一阶段:创业初期(2015年) 团队规模:5人(2个后端、1个前端、1个产品、1个UI) 技术选型:单体架构 + Spring Boot 系统架构: ┌─────────────────────────────────────┐ │ 电商单体应用 │ │ (monolithic-ecommerce-app) │ ├─────────────────────────────────────┤ │ 用户模块 (UserModule) │ │ 商品模块 (ProductModule) │ │ 订单模块 (OrderModule) │ │ 库存模块 (InventoryModule) │ │ 支付模块 (PaymentModule) │ │ 物流模块 (LogisticsModule) │ │ 营销模块 (MarketingModule) │ ├─────────────────────────────────────┤ │ Spring Boot + MyBatis + MySQL │ └─────────────────────────────────────┘ ↓ MySQL数据库 代码结构: ecommerce-app/ ├── src/main/java/com/example/ │ ├── user/ # 用户模块 │ │ ├── UserController.java │ │ ├── UserService.java │ │ └── UserRepository.java │ ├── product/ # 商品模块 │ │ ├── ProductController.java │ │ ├── ProductService.java │ │ └── ProductRepository.java │ ├── order/ # 订单模块 │ │ ├── OrderController.java │ │ ├── OrderService.java │ │ └── OrderRepository.java │ ├── inventory/ # 库存模块 │ ├── payment/ # 支付模块 │ ├── logistics/ # 物流模块 │ └── marketing/ # 营销模块 └── pom.xml 典型业务流程(创建订单): ...

2025-11-03 · maneng

服务治理:注册发现、负载均衡与熔断降级

引子:一次服务雪崩事故 2020年双11,某电商平台因评论服务故障导致整个系统瘫痪3小时,损失上亿。 故障链路: 用户下单 → 订单服务 → 评论服务(响应慢,20秒超时) → 订单服务线程池耗尽 → 用户服务调用订单服务失败 → 整个系统崩溃 问题根源:缺乏有效的服务治理机制 一、服务注册与发现 1.1 为什么需要服务注册中心? 问题:微服务架构下,服务IP动态变化 订单服务 → 库存服务(192.168.1.10:8080) 问题: 1. 库存服务重启,IP可能变化 2. 库存服务扩容,新增实例 3. 库存服务下线,需要摘除 解决方案:服务注册中心 订单服务 → 注册中心 → 获取库存服务列表 ↓ [192.168.1.10:8080, 192.168.1.11:8080, 192.168.1.12:8080] 1.2 Nacos服务注册与发现 服务提供者:注册服务 /** * 库存服务:自动注册到Nacos */ @SpringBootApplication @EnableDiscoveryClient public class InventoryServiceApplication { public static void main(String[] args) { SpringApplication.run(InventoryServiceApplication.class, args); } } # application.yml spring: application: name: inventory-service # 服务名 cloud: nacos: discovery: server-addr: 127.0.0.1:8848 namespace: dev group: DEFAULT_GROUP 服务消费者:发现服务 ...

2025-11-03 · maneng

如约数科科技工作室

浙ICP备2025203501号

👀 本站总访问量 ...| 👤 访客数 ...| 📅 今日访问 ...