【分布式系统架构设计实战:从单体到微服务】

分布式系统是大型互联网应用的基础,掌握分布式架构是架构师的核心能力。本文将深入剖析分布式系统的核心概念、常见问题和解决方案,助你构建高可用、高性能的分布式系统。

一、分布式系统基础

1.1 什么是分布式系统?

关键点: 分布式系统是由多个独立计算机组成,通过网络通信协作完成任务的系统。

单体架构 vs 分布式架构:

java 复制代码
// ❌ 单体架构
@SpringBootApplication
public class MonolithApplication {
    // 所有功能在一个应用中
    // - 用户服务
    // - 订单服务
    // - 商品服务
    // - 支付服务
    
    // 问题:
    // 1. 代码耦合严重
    // 2. 部署困难
    // 3. 扩展性差
    // 4. 技术栈单一
}

// ✅ 分布式架构(微服务)
// 用户服务
@SpringBootApplication
public class UserServiceApplication {
    // 只负责用户相关功能
}

// 订单服务
@SpringBootApplication
public class OrderServiceApplication {
    // 只负责订单相关功能
}

// 商品服务
@SpringBootApplication
public class ProductServiceApplication {
    // 只负责商品相关功能
}

// 优点:
// 1. 服务独立部署
// 2. 技术栈灵活
// 3. 易于扩展
// 4. 故障隔离

1.2 CAP理论

关键点: 分布式系统无法同时满足一致性(C)、可用性(A)、分区容错性(P)。

复制代码
CAP理论
├── C(Consistency)一致性
│   所有节点同一时间看到相同的数据
│
├── A(Availability)可用性
│   每个请求都能得到响应(成功或失败)
│
└── P(Partition Tolerance)分区容错性
    系统在网络分区时仍能继续工作

选择:
- CP:牺牲可用性,保证一致性(如:ZooKeeper、HBase)
- AP:牺牲一致性,保证可用性(如:Eureka、Cassandra)
- CA:不存在(网络分区无法避免)
java 复制代码
// CP示例:ZooKeeper
public class ZooKeeperCPDemo {
    public void write(String path, String data) {
        // 写入时,必须等待半数以上节点确认
        // 如果网络分区,少数节点无法写入(牺牲可用性)
        // 但保证了数据一致性
    }
}

// AP示例:Eureka
public class EurekaAPDemo {
    public void register(String serviceName) {
        // 注册时,即使部分节点不可用
        // 仍然可以注册成功(保证可用性)
        // 但可能出现数据不一致
    }
}

二、服务注册与发现

2.1 Eureka实现

java 复制代码
// Eureka Server
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

// application.yml
server:
  port: 8761

eureka:
  instance:
    hostname: localhost
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

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

// application.yml
spring:
  application:
    name: user-service

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

// 服务消费者
@RestController
public class OrderController {
    
    @Autowired
    private RestTemplate restTemplate;
    
    @GetMapping("/order/{id}")
    public Order getOrder(@PathVariable Long id) {
        // 通过服务名调用
        String url = "http://user-service/user/" + id;
        User user = restTemplate.getForObject(url, User.class);
        
        Order order = new Order();
        order.setUser(user);
        return order;
    }
}

@Configuration
public class RestTemplateConfig {
    @Bean
    @LoadBalanced  // 负载均衡
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

2.2 Nacos实现(推荐)

java 复制代码
// Nacos配置
spring:
  application:
    name: user-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
      config:
        server-addr: localhost:8848
        file-extension: yaml

// 服务提供者
@RestController
public class UserController {
    @GetMapping("/user/{id}")
    public User getUser(@PathVariable Long id) {
        return userService.getById(id);
    }
}

// 服务消费者(使用Feign)
@FeignClient(name = "user-service")
public interface UserFeignClient {
    @GetMapping("/user/{id}")
    User getUser(@PathVariable("id") Long id);
}

@RestController
public class OrderController {
    @Autowired
    private UserFeignClient userFeignClient;
    
    @GetMapping("/order/{id}")
    public Order getOrder(@PathVariable Long id) {
        User user = userFeignClient.getUser(id);
        
        Order order = new Order();
        order.setUser(user);
        return order;
    }
}

三、分布式事务

3.1 两阶段提交(2PC)

java 复制代码
/**
 * 两阶段提交:
 * 阶段1:准备阶段(Prepare)
 *   - 协调者询问所有参与者是否可以提交
 *   - 参与者执行事务但不提交
 * 
 * 阶段2:提交阶段(Commit)
 *   - 如果所有参与者都同意,协调者发送提交命令
 *   - 否则发送回滚命令
 * 
 * 缺点:
 * - 同步阻塞
 * - 单点故障
 * - 数据不一致
 */

// XA事务示例
@Service
public class OrderService {
    
    @Autowired
    private DataSource orderDataSource;
    
    @Autowired
    private DataSource inventoryDataSource;
    
    @Transactional
    public void createOrder(Order order) throws Exception {
        // 开启XA事务
        XAResource orderXA = getXAResource(orderDataSource);
        XAResource inventoryXA = getXAResource(inventoryDataSource);
        
        Xid xid = new MyXid(1, new byte[]{0x01}, new byte[]{0x02});
        
        try {
            // 阶段1:准备
            orderXA.start(xid, XAResource.TMNOFLAGS);
            // 插入订单
            insertOrder(order);
            orderXA.end(xid, XAResource.TMSUCCESS);
            
            inventoryXA.start(xid, XAResource.TMNOFLAGS);
            // 扣减库存
            reduceInventory(order.getProductId(), order.getQuantity());
            inventoryXA.end(xid, XAResource.TMSUCCESS);
            
            // 准备提交
            int orderPrepare = orderXA.prepare(xid);
            int inventoryPrepare = inventoryXA.prepare(xid);
            
            // 阶段2:提交
            if (orderPrepare == XAResource.XA_OK && 
                inventoryPrepare == XAResource.XA_OK) {
                orderXA.commit(xid, false);
                inventoryXA.commit(xid, false);
            } else {
                orderXA.rollback(xid);
                inventoryXA.rollback(xid);
            }
        } catch (Exception e) {
            orderXA.rollback(xid);
            inventoryXA.rollback(xid);
            throw e;
        }
    }
}

3.2 TCC事务

java 复制代码
/**
 * TCC(Try-Confirm-Cancel):
 * - Try:尝试执行,预留资源
 * - Confirm:确认执行,使用预留资源
 * - Cancel:取消执行,释放预留资源
 */

// 订单服务
@Service
public class OrderTccService {
    
    // Try:创建订单,状态为"待确认"
    @Transactional
    public boolean tryCreateOrder(Order order) {
        order.setStatus("PENDING");
        orderMapper.insert(order);
        return true;
    }
    
    // Confirm:确认订单,状态改为"已确认"
    @Transactional
    public boolean confirmCreateOrder(Long orderId) {
        Order order = orderMapper.selectById(orderId);
        order.setStatus("CONFIRMED");
        orderMapper.updateById(order);
        return true;
    }
    
    // Cancel:取消订单,状态改为"已取消"
    @Transactional
    public boolean cancelCreateOrder(Long orderId) {
        Order order = orderMapper.selectById(orderId);
        order.setStatus("CANCELLED");
        orderMapper.updateById(order);
        return true;
    }
}

// 库存服务
@Service
public class InventoryTccService {
    
    // Try:冻结库存
    @Transactional
    public boolean tryReduceInventory(Long productId, Integer quantity) {
        Inventory inventory = inventoryMapper.selectById(productId);
        
        if (inventory.getAvailable() < quantity) {
            return false;
        }
        
        inventory.setAvailable(inventory.getAvailable() - quantity);
        inventory.setFrozen(inventory.getFrozen() + quantity);
        inventoryMapper.updateById(inventory);
        return true;
    }
    
    // Confirm:扣减冻结库存
    @Transactional
    public boolean confirmReduceInventory(Long productId, Integer quantity) {
        Inventory inventory = inventoryMapper.selectById(productId);
        inventory.setFrozen(inventory.getFrozen() - quantity);
        inventoryMapper.updateById(inventory);
        return true;
    }
    
    // Cancel:释放冻结库存
    @Transactional
    public boolean cancelReduceInventory(Long productId, Integer quantity) {
        Inventory inventory = inventoryMapper.selectById(productId);
        inventory.setAvailable(inventory.getAvailable() + quantity);
        inventory.setFrozen(inventory.getFrozen() - quantity);
        inventoryMapper.updateById(inventory);
        return true;
    }
}

3.3 Seata分布式事务(推荐)

java 复制代码
// Seata配置
@Configuration
public class SeataConfig {
    @Bean
    public GlobalTransactionScanner globalTransactionScanner() {
        return new GlobalTransactionScanner("order-service", "default");
    }
}

// 使用@GlobalTransactional注解
@Service
public class OrderService {
    
    @Autowired
    private OrderMapper orderMapper;
    
    @Autowired
    private InventoryFeignClient inventoryFeignClient;
    
    @Autowired
    private AccountFeignClient accountFeignClient;
    
    @GlobalTransactional(name = "create-order", rollbackFor = Exception.class)
    public void createOrder(Order order) {
        // 1. 创建订单
        orderMapper.insert(order);
        
        // 2. 扣减库存(远程调用)
        inventoryFeignClient.reduce(order.getProductId(), order.getQuantity());
        
        // 3. 扣减账户余额(远程调用)
        accountFeignClient.reduce(order.getUserId(), order.getAmount());
        
        // 如果任何一步失败,Seata会自动回滚所有操作
    }
}

// 库存服务
@Service
public class InventoryService {
    @Autowired
    private InventoryMapper inventoryMapper;
    
    @Transactional
    public void reduce(Long productId, Integer quantity) {
        Inventory inventory = inventoryMapper.selectById(productId);
        
        if (inventory.getStock() < quantity) {
            throw new RuntimeException("库存不足");
        }
        
        inventory.setStock(inventory.getStock() - quantity);
        inventoryMapper.updateById(inventory);
    }
}

四、分布式限流

4.1 单机限流

java 复制代码
// 使用Guava RateLimiter
public class RateLimiterDemo {
    // 每秒允许10个请求
    private RateLimiter rateLimiter = RateLimiter.create(10.0);
    
    public String handleRequest() {
        // 尝试获取令牌
        if (rateLimiter.tryAcquire()) {
            return "请求成功";
        } else {
            return "请求被限流";
        }
    }
    
    // 阻塞等待
    public String handleRequestBlocking() {
        rateLimiter.acquire();  // 阻塞直到获取到令牌
        return "请求成功";
    }
}

// 使用注解限流
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimit {
    double value() default 10.0;  // 每秒请求数
}

@Aspect
@Component
public class RateLimitAspect {
    private Map<String, RateLimiter> limiters = new ConcurrentHashMap<>();
    
    @Around("@annotation(rateLimit)")
    public Object around(ProceedingJoinPoint point, RateLimit rateLimit) throws Throwable {
        String key = point.getSignature().toString();
        RateLimiter limiter = limiters.computeIfAbsent(key, 
            k -> RateLimiter.create(rateLimit.value()));
        
        if (limiter.tryAcquire()) {
            return point.proceed();
        } else {
            throw new RuntimeException("请求过于频繁");
        }
    }
}

// 使用
@RestController
public class UserController {
    @GetMapping("/user/{id}")
    @RateLimit(10.0)  // 每秒最多10个请求
    public User getUser(@PathVariable Long id) {
        return userService.getById(id);
    }
}

4.2 分布式限流(Redis)

java 复制代码
// 使用Redis + Lua脚本实现分布式限流
@Service
public class RedisRateLimiter {
    @Autowired
    private StringRedisTemplate redisTemplate;
    
    // Lua脚本:令牌桶算法
    private static final String SCRIPT = 
        "local key = KEYS[1]\n" +
        "local limit = tonumber(ARGV[1])\n" +
        "local current = tonumber(redis.call('get', key) or '0')\n" +
        "if current + 1 > limit then\n" +
        "    return 0\n" +
        "else\n" +
        "    redis.call('INCRBY', key, 1)\n" +
        "    redis.call('EXPIRE', key, 1)\n" +
        "    return 1\n" +
        "end";
    
    public boolean tryAcquire(String key, int limit) {
        DefaultRedisScript<Long> script = new DefaultRedisScript<>();
        script.setScriptText(SCRIPT);
        script.setResultType(Long.class);
        
        Long result = redisTemplate.execute(script, 
            Collections.singletonList(key), 
            String.valueOf(limit));
        
        return result != null && result == 1;
    }
}

// 使用
@RestController
public class OrderController {
    @Autowired
    private RedisRateLimiter rateLimiter;
    
    @PostMapping("/order")
    public Result createOrder(@RequestBody Order order) {
        String key = "rate:limit:order:" + order.getUserId();
        
        // 每个用户每秒最多创建5个订单
        if (!rateLimiter.tryAcquire(key, 5)) {
            return Result.error("请求过于频繁");
        }
        
        orderService.create(order);
        return Result.success();
    }
}

五、服务熔断与降级

5.1 Hystrix实现

java 复制代码
// 服务提供者
@RestController
public class UserController {
    @GetMapping("/user/{id}")
    public User getUser(@PathVariable Long id) {
        // 模拟慢查询
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return userService.getById(id);
    }
}

// 服务消费者(使用Hystrix)
@Service
public class OrderService {
    @Autowired
    private RestTemplate restTemplate;
    
    @HystrixCommand(
        fallbackMethod = "getUserFallback",
        commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000"),
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50")
        }
    )
    public User getUser(Long id) {
        String url = "http://user-service/user/" + id;
        return restTemplate.getForObject(url, User.class);
    }
    
    // 降级方法
    public User getUserFallback(Long id) {
        User user = new User();
        user.setId(id);
        user.setName("默认用户");
        return user;
    }
}

5.2 Sentinel实现(推荐)

java 复制代码
// Sentinel配置
@Configuration
public class SentinelConfig {
    @PostConstruct
    public void initRules() {
        // 流控规则
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource("getUser");
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule.setCount(10);  // QPS阈值
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
        
        // 降级规则
        List<DegradeRule> degradeRules = new ArrayList<>();
        DegradeRule degradeRule = new DegradeRule();
        degradeRule.setResource("getUser");
        degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
        degradeRule.setCount(100);  // 响应时间阈值(ms)
        degradeRule.setTimeWindow(10);  // 熔断时长(秒)
        degradeRules.add(degradeRule);
        DegradeRuleManager.loadRules(degradeRules);
    }
}

// 使用@SentinelResource注解
@Service
public class UserService {
    
    @SentinelResource(
        value = "getUser",
        blockHandler = "handleBlock",
        fallback = "handleFallback"
    )
    public User getUser(Long id) {
        return userMapper.selectById(id);
    }
    
    // 限流处理
    public User handleBlock(Long id, BlockException ex) {
        User user = new User();
        user.setName("系统繁忙,请稍后再试");
        return user;
    }
    
    // 降级处理
    public User handleFallback(Long id, Throwable ex) {
        User user = new User();
        user.setName("服务降级");
        return user;
    }
}

六、实战案例:电商秒杀系统

java 复制代码
// 秒杀系统架构
@Service
public class SeckillService {
    @Autowired
    private StringRedisTemplate redisTemplate;
    
    @Autowired
    private RedissonClient redissonClient;
    
    @Autowired
    private RabbitTemplate rabbitTemplate;
    
    /**
     * 秒杀流程:
     * 1. 前端限流:按钮置灰、验证码
     * 2. 网关限流:Sentinel限流
     * 3. Redis预减库存
     * 4. 分布式锁
     * 5. 异步下单(MQ)
     * 6. 数据库扣库存
     */
    
    @SentinelResource(value = "seckill", blockHandler = "handleBlock")
    public Result seckill(Long productId, Long userId) {
        String stockKey = "seckill:stock:" + productId;
        String userKey = "seckill:user:" + productId + ":" + userId;
        String lockKey = "seckill:lock:" + productId;
        
        // 1. 判断是否已经购买
        if (redisTemplate.hasKey(userKey)) {
            return Result.error("您已经参与过该商品的秒杀");
        }
        
        // 2. Redis预减库存
        Long stock = redisTemplate.opsForValue().decrement(stockKey);
        if (stock < 0) {
            redisTemplate.opsForValue().increment(stockKey);
            return Result.error("商品已售罄");
        }
        
        // 3. 获取分布式锁
        RLock lock = redissonClient.getLock(lockKey);
        try {
            if (lock.tryLock(5, 10, TimeUnit.SECONDS)) {
                // 4. 记录用户购买
                redisTemplate.opsForValue().set(userKey, "1", 24, TimeUnit.HOURS);
                
                // 5. 发送MQ消息,异步创建订单
                SeckillMessage message = new SeckillMessage();
                message.setProductId(productId);
                message.setUserId(userId);
                rabbitTemplate.convertAndSend("seckill.exchange", 
                    "seckill.order", message);
                
                return Result.success("秒杀成功,正在生成订单");
            } else {
                return Result.error("系统繁忙,请稍后再试");
            }
        } catch (InterruptedException e) {
            return Result.error("系统异常");
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
    
    // 限流处理
    public Result handleBlock(Long productId, Long userId, BlockException ex) {
        return Result.error("当前访问人数过多,请稍后再试");
    }
}

// MQ消费者:异步创建订单
@Component
@RabbitListener(queues = "seckill.order.queue")
public class SeckillOrderConsumer {
    @Autowired
    private OrderService orderService;
    
    @Autowired
    private InventoryService inventoryService;
    
    @RabbitHandler
    @GlobalTransactional  // Seata分布式事务
    public void handleMessage(SeckillMessage message) {
        try {
            // 1. 创建订单
            Order order = new Order();
            order.setProductId(message.getProductId());
            order.setUserId(message.getUserId());
            order.setStatus("PENDING");
            orderService.create(order);
            
            // 2. 扣减数据库库存
            inventoryService.reduce(message.getProductId(), 1);
            
            // 3. 更新订单状态
            order.setStatus("SUCCESS");
            orderService.update(order);
            
        } catch (Exception e) {
            // 失败处理:恢复Redis库存
            String stockKey = "seckill:stock:" + message.getProductId();
            redisTemplate.opsForValue().increment(stockKey);
            
            // 删除用户购买记录
            String userKey = "seckill:user:" + message.getProductId() + ":" + message.getUserId();
            redisTemplate.delete(userKey);
        }
    }
}

七、总结

分布式系统核心要点:

  1. 服务拆分 - 按业务领域拆分微服务
  2. 服务治理 - 注册发现、负载均衡
  3. 分布式事务 - Seata、TCC
  4. 限流熔断 - Sentinel、Hystrix
  5. 高可用 - 集群部署、故障转移

最佳实践:

  • 合理拆分服务,避免过度拆分
  • 使用配置中心统一管理配置
  • 实现服务监控和链路追踪
  • 做好容错和降级处理
  • 定期进行压力测试

相关资源


💡 小贴士: 分布式系统复杂度高,要根据业务规模选择合适的架构!

关注我,获取更多架构干货! 🏗️

相关推荐
没有bug.的程序员2 小时前
Ribbon vs LoadBalancer 深度解析
jvm·后端·spring cloud·微服务·ribbon·架构·gc调优
青年夏日科技工作者2 小时前
docker运行debian / Ubuntu桌面容器 xrdp(带声音) x11 vnc novnc
云原生·eureka
忍冬行者2 小时前
kubernetes安装traefik ingress,替换原来的nginx-ingress
云原生·容器·kubernetes
篙芷2 小时前
k8s Service 暴露方式详解:ClusterIP、NodePort、LoadBalancer 与 Headless Service
云原生·容器·kubernetes
aashuii2 小时前
k8s POD上RDMA网卡VF不生效问题
云原生·容器·kubernetes
weixin_46682 小时前
K8S-Ingress
云原生·容器·kubernetes
Wang201220132 小时前
AI 相关的算法;架构等专有名称总结和介绍
人工智能·算法·架构
乾元2 小时前
红队 / 蓝队:用 AI 自动生成攻击场景并评估防御效果——从“安全演练”到“可计算的网络对抗系统”
运维·网络·人工智能·网络协议·安全·web安全·架构
小怪兽会微笑2 小时前
MoM (Mixture-of-Memories)新型线性序列建模架构
人工智能·深度学习·架构