本文将详细记录我从单体应用转向分布式架构的实战经验,包括服务拆分策略、分布式事务解决方案、服务治理、配置中心等核心内容。每个技术点都配有真实的业务场景和代码实现,展示分布式系统中的典型问题和解决方案。

1. 从单体到微服务的拆分之痛

初期单体架构的问题:

// 典型的单体应用结构 - 所有功能在一个项目中
com.example.monolith
├── controller
│   ├── UserController.java      // 用户管理
│   ├── OrderController.java     // 订单管理  
│   ├── ProductController.java   // 商品管理
│   └── PaymentController.java  // 支付管理
├── service
│   ├── UserService.java
│   ├── OrderService.java
│   ├── ProductService.java
│   └── PaymentService.java
└── mapper
    ├── UserMapper.java
    ├── OrderMapper.java
    ├── ProductMapper.java
    └── PaymentMapper.java

遇到的问题:

  1. 代码耦合严重​:修改用户模块可能影响订单功能
  2. 数据库压力大​:所有表在同一个数据库,连接数瓶颈
  3. 部署困难​:一个小功能修改需要部署整个应用
  4. 技术栈单一​:所有模块必须使用相同的技术栈

2. 服务拆分策略与实践

领域驱动设计(DDD)指导拆分:

// 按业务边界拆分微服务
com.example
├── user-service          // 用户服务
│   ├── UserController.java
│   ├── UserService.java
│   └── UserRepository.java
├── order-service         // 订单服务
│   ├── OrderController.java
│   ├── OrderService.java
│   └── OrderRepository.java
├── product-service       // 商品服务
│   ├── ProductController.java
│   ├── ProductService.java
│   └── ProductRepository.java
└── payment-service       // 支付服务
    ├── PaymentController.java
    ├── PaymentService.java
    └── PaymentRepository.java

数据库拆分方案:

-- 用户服务独立数据库
CREATE DATABASE user_db;
USE user_db;
CREATE TABLE users (
    id BIGINT PRIMARY KEY,
    username VARCHAR(50),
    email VARCHAR(100)
);

-- 订单服务独立数据库  
CREATE DATABASE order_db;
USE order_db;
CREATE TABLE orders (
    id BIGINT PRIMARY KEY,
    user_id BIGINT,        -- 用户ID(非外键)
    amount DECIMAL(10,2)
);

3. 服务间通信的挑战与解决方案

RESTful API通信:

// 订单服务调用用户服务
@Service
public class OrderService {
    
    @Autowired
    private RestTemplate restTemplate;
    
    public OrderDTO getOrderWithUserInfo(Long orderId) {
        // 查询订单信息
        Order order = orderRepository.findById(orderId);
        
        // 调用用户服务获取用户信息
        String userServiceUrl = "http://user-service/users/" + order.getUserId();
        UserDTO user = restTemplate.getForObject(userServiceUrl, UserDTO.class);
        
        // 组装返回数据
        return OrderDTO.builder()
                .orderId(order.getId())
                .amount(order.getAmount())
                .userName(user.getUsername())
                .userEmail(user.getEmail())
                .build();
    }
}

FeignClient声明式调用:

// 用户服务Feign客户端
@FeignClient(name = "user-service", path = "/api/users")
public interface UserServiceClient {
    
    @GetMapping("/{userId}")
    ResponseEntity<UserDTO> getUserById(@PathVariable("userId") Long userId);
    
    @PostMapping
    ResponseEntity<UserDTO> createUser(@RequestBody UserCreateRequest request);
}

// 在订单服务中使用
@Service
public class OrderService {
    
    @Autowired
    private UserServiceClient userServiceClient;
    
    public OrderDTO createOrder(OrderCreateRequest request) {
        // 验证用户是否存在
        ResponseEntity<UserDTO> userResponse = userServiceClient.getUserById(request.getUserId());
        if (!userResponse.getStatusCode().is2xxSuccessful()) {
            throw new RuntimeException("用户不存在");
        }
        
        // 创建订单逻辑
        Order order = new Order();
        order.setUserId(request.getUserId());
        order.setAmount(request.getAmount());
        Order savedOrder = orderRepository.save(order);
        
        return convertToDTO(savedOrder);
    }
}

4. 分布式事务的终极解决方案

本地消息表方案:

@Service
@Transactional
public class OrderService {
    
    public void createOrderWithMessage(OrderCreateRequest request) {
        // 1. 创建订单(本地事务)
        Order order = createOrder(request);
        
        // 2. 记录消息到本地表
        EventMessage message = new EventMessage();
        message.setEventType("ORDER_CREATED");
        message.setPayload(JSON.toJSONString(order));
        message.setStatus("PENDING");
        eventMessageRepository.save(message);
        
        // 3. 提交事务(订单和消息同时提交或回滚)
    }
}

// 消息轮询发送
@Component
public class EventMessagePoller {
    
    @Scheduled(fixedRate = 5000) // 每5秒执行一次
    public void pollAndSendMessages() {
        List<EventMessage> pendingMessages = eventMessageRepository.findByStatus("PENDING");
        
        for (EventMessage message : pendingMessages) {
            try {
                // 发送到消息队列
                rabbitTemplate.convertAndSend("order-events", message.getPayload());
                
                // 更新消息状态为已发送
                message.setStatus("SENT");
                eventMessageRepository.save(message);
                
            } catch (Exception e) {
                log.error("消息发送失败: {}", message.getId(), e);
                message.setRetryCount(message.getRetryCount() + 1);
                eventMessageRepository.save(message);
            }
        }
    }
}

Seata AT模式分布式事务:

// 全局事务注解
@GlobalTransactional
public void createOrderDistributed(OrderCreateRequest request) {
    // 1. 扣减库存(商品服务)
    productServiceClient.deductStock(request.getProductId(), request.getQuantity());
    
    // 2. 创建订单(订单服务)
    orderService.createOrder(request);
    
    // 3. 扣减余额(用户服务)
    userServiceClient.deductBalance(request.getUserId(), request.getAmount());
}

5. 服务注册与发现

Spring Cloud Netflix Eureka配置:

// 注册中心配置
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

// 服务提供者配置
@SpringBootApplication
@EnableEurekaClient
public class UserServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}

// 应用配置
spring:
  application:
    name: user-service
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true
    instance-id: ${spring.cloud.client.ip-address}:${server.port}

6. 配置中心统一管理

Spring Cloud Config配置:

// 配置中心服务端
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}

// 客户端配置刷新
@RestController
@RefreshScope
public class ConfigController {
    
    @Value("${app.notify.email.enabled:false}")
    private boolean emailNotifyEnabled;
    
    @GetMapping("/config")
    public Map<String, Object> getConfig() {
        Map<String, Object> config = new HashMap<>();
        config.put("emailNotifyEnabled", emailNotifyEnabled);
        return config;
    }
}

// 动态刷新配置
@Component
public class ConfigChangeListener {
    
    @EventListener
    public void handleRefreshEvent(EnvironmentChangeEvent event) {
        log.info("配置发生变化: {}", event.getKeys());
        // 重新初始化相关组件
        reinitializeComponents();
    }
}

7. 服务容错与降级

Hystrix熔断器配置:

// Feign客户端集成Hystrix
@FeignClient(name = "user-service", 
             fallback = UserServiceFallback.class,
             configuration = FeignConfig.class)
public interface UserServiceClient {
    
    @GetMapping("/users/{id}")
    @HystrixCommand(fallbackMethod = "getUserFallback")
    UserDTO getUserById(@PathVariable("id") Long id);
    
    default UserDTO getUserFallback(Long id) {
        return UserDTO.builder()
                .id(id)
                .username("默认用户")
                .email("default@example.com")
                .build();
    }
}

// 降级实现
@Component
public class UserServiceFallback implements UserServiceClient {
    
    @Override
    public UserDTO getUserById(Long id) {
        log.warn("用户服务不可用,返回降级数据");
        return UserDTO.builder()
                .id(id)
                .username("服务降级用户")
                .email("fallback@example.com")
                .build();
    }
}

8. 分布式链路追踪

Sleuth + Zipkin集成:

// 添加依赖和配置
dependencies {
    implementation 'org.springframework.cloud:spring-cloud-starter-sleuth'
    implementation 'org.springframework.cloud:spring-cloud-starter-zipkin'
}

// 配置类
@Configuration
public class TracingConfig {
    
    @Bean
    public Sampler alwaysSampler() {
        return Sampler.ALWAYS_SAMPLE;
    }
}

// 在业务代码中记录追踪信息
@Service
@Slf4j
public class OrderService {
    
    @Autowired
    private Tracer tracer;
    
    public OrderDTO createOrder(OrderCreateRequest request) {
        // 创建自定义span
        Span orderSpan = tracer.nextSpan().name("orderCreation").start();
        try (Tracer.SpanInScope ws = tracer.withSpanInScope(orderSpan)) {
            orderSpan.tag("user.id", request.getUserId().toString());
            orderSpan.tag("order.amount", request.getAmount().toString());
            
            // 业务逻辑
            Order order = processOrderCreation(request);
            
            return convertToDTO(order);
        } finally {
            orderSpan.finish();
        }
    }
}

9. API网关统一入口

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)
                                .addRequestHeader("X-User-Service", "gateway"))
                        .uri("lb://user-service"))
                .route("order_service", r -> r.path("/api/orders/**")
                        .filters(f -> f.stripPrefix(1)
                                .circuitBreaker(config -> config.setName("orderCircuitBreaker")))
                        .uri("lb://order-service"))
                .build();
    }
    
    // 全局过滤器
    @Bean
    public GlobalFilter customGlobalFilter() {
        return (exchange, chain) -> {
            // 认证、日志等统一处理
            ServerHttpRequest request = exchange.getRequest();
            log.info("请求路径: {} {}", request.getMethod(), request.getPath());
            return chain.filter(exchange);
        };
    }
}

10. 分布式锁的实现

Redis分布式锁:

@Component
public class RedisDistributedLock {
    
    private static final String LOCK_PREFIX = "distributed_lock:";
    private static final long DEFAULT_EXPIRE_TIME = 30000; // 30秒
    
    public boolean tryLock(String lockKey, long expireTime) {
        String key = LOCK_PREFIX + lockKey;
        String value = generateLockValue();
        
        return redisTemplate.execute((RedisCallback<Boolean>) connection -> {
            // SET key value NX PX timeout
            String result = connection.set(
                key.getBytes(),
                value.getBytes(),
                Expiration.milliseconds(expireTime),
                RedisStringCommands.SetOption.SET_IF_ABSENT
            );
            return "OK".equals(result);
        });
    }
    
    public void unlock(String lockKey) {
        String key = LOCK_PREFIX + lockKey;
        redisTemplate.delete(key);
    }
}

11. 数据一致性方案

最终一致性事件模式:

// 领域事件发布
@Service
public class OrderService {
    
    @Autowired
    private DomainEventPublisher eventPublisher;
    
    @Transactional
    public Order createOrder(OrderCreateRequest request) {
        Order order = new Order();
        // 设置订单属性
        Order savedOrder = orderRepository.save(order);
        
        // 发布领域事件
        eventPublisher.publish(new OrderCreatedEvent(
            savedOrder.getId(),
            savedOrder.getUserId(),
            savedOrder.getAmount()
        ));
        
        return savedOrder;
    }
}

// 事件处理器
@Component
public class OrderCreatedEventHandler {
    
    @EventListener
    @Async
    public void handleOrderCreated(OrderCreatedEvent event) {
        // 更新用户订单统计
        userStatisticsService.updateOrderCount(event.getUserId());
        
        // 发送通知
        notificationService.sendOrderCreatedNotification(event);
        
        // 其他后续处理
        inventoryService.updateStock(event);
    }
}

12. 监控与运维

Spring Boot Actuator监控:

// 监控端点配置
management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,env
  endpoint:
    health:
      show-details: always
    metrics:
      enabled: true

// 自定义健康检查
@Component
public class CustomHealthIndicator implements HealthIndicator {
    
    @Autowired
    private UserRepository userRepository;
    
    @Override
    public Health health() {
        try {
            // 检查数据库连接
            long userCount = userRepository.count();
            if (userCount >= 0) {
                return Health.up()
                    .withDetail("database", "连接正常")
                    .withDetail("userCount", userCount)
                    .build();
            }
        } catch (Exception e) {
            return Health.down(e).build();
        }
        return Health.unknown().build();
    }
}

13. 总结:分布式架构的最佳实践

经验教训总结:

  1. 渐进式拆分​:不要一次性拆分所有服务
  2. 契约优先​:先定义API契约,再实现功能
  3. 容错设计​:每个服务都要有降级方案
  4. 监控先行​:在拆分前建立完善的监控体系
  5. 数据最终一致性​:接受短暂的不一致,通过补偿机制保证最终一致

分布式架构检查清单:

分布式系统检查项:
  服务治理:
    - 服务注册发现: 已实现
    - 负载均衡: 已配置
    - 熔断降级: 已实现
    - 链路追踪: 已集成
    
  数据一致性:
    - 分布式事务: 本地消息表
    - 数据同步: 事件驱动
    - 缓存策略: 读写分离
    
  安全防护:
    - API网关: 已部署
    - 认证授权: JWT令牌
    - 传输加密: HTTPS

总结:

两年的分布式系统实战经验让我深刻理解到,​分布式不是银弹,而是权衡的艺术​。从单体到微服务的演进过程中,最重要的不是技术选型,而是对业务的理解和架构原则的把握。分布式架构解决了单体应用的问题,但也带来了新的复杂性,需要在一致性、可用性、性能之间做出合理的权衡。

真正的分布式架构能力,体现在预见问题、设计容错、快速恢复的综合能力上。这需要不断学习、实践和总结,才能在分布式系统的复杂世界中游刃有余。

如果觉得我的文章对你有用,请随意赞赏