本文将详细记录我从单体应用转向分布式架构的实战经验,包括服务拆分策略、分布式事务解决方案、服务治理、配置中心等核心内容。每个技术点都配有真实的业务场景和代码实现,展示分布式系统中的典型问题和解决方案。
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遇到的问题:
- 代码耦合严重:修改用户模块可能影响订单功能
- 数据库压力大:所有表在同一个数据库,连接数瓶颈
- 部署困难:一个小功能修改需要部署整个应用
- 技术栈单一:所有模块必须使用相同的技术栈
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. 总结:分布式架构的最佳实践
经验教训总结:
- 渐进式拆分:不要一次性拆分所有服务
- 契约优先:先定义API契约,再实现功能
- 容错设计:每个服务都要有降级方案
- 监控先行:在拆分前建立完善的监控体系
- 数据最终一致性:接受短暂的不一致,通过补偿机制保证最终一致
分布式架构检查清单:
分布式系统检查项:
服务治理:
- 服务注册发现: 已实现
- 负载均衡: 已配置
- 熔断降级: 已实现
- 链路追踪: 已集成
数据一致性:
- 分布式事务: 本地消息表
- 数据同步: 事件驱动
- 缓存策略: 读写分离
安全防护:
- API网关: 已部署
- 认证授权: JWT令牌
- 传输加密: HTTPS总结:
两年的分布式系统实战经验让我深刻理解到,分布式不是银弹,而是权衡的艺术。从单体到微服务的演进过程中,最重要的不是技术选型,而是对业务的理解和架构原则的把握。分布式架构解决了单体应用的问题,但也带来了新的复杂性,需要在一致性、可用性、性能之间做出合理的权衡。
真正的分布式架构能力,体现在预见问题、设计容错、快速恢复的综合能力上。这需要不断学习、实践和总结,才能在分布式系统的复杂世界中游刃有余。