Java基础(十四)分布式

一、CAP 理论

CAP 原则,又称 CAP 定理,指出在分布式系统中,Consistency(一致性)、Availability(可用性)和 Partition tolerance(分区容错性)这三个特性无法同时满足,最多只能满足其中两项。

  • 一致性(Consistency):所有节点在同一时刻具有相同的数据副本。即任何客户端在任何节点读取到的都是最新写入的数据。
  • 可用性(Availability):系统始终能够对请求做出响应,即使部分节点发生故障。
  • 分区容错性(Partition tolerance):系统在遇到网络分区(节点间无法通信)时仍能继续运行。

由于网络分区在分布式环境中难以避免,系统通常需要在 C 和 A 之间做出权衡。例如,银行系统可能选择 CP(强一致性),而互联网应用可能选择 AP(高可用性)。


二、Spring Cloud Alibaba 生态体系

Spring Cloud Alibaba 为分布式应用开发提供了一站式解决方案,集成了阿里巴巴众多开源组件。

1. 核心组件概览

组件 功能 替代方案 特点
Nacos 服务注册与发现、配置管理 Eureka + Config 支持AP/CP模式切换,实时配置推送
Sentinel 流量控制、熔断降级 Hystrix 可视化控制台,实时监控
Seata 分布式事务 - AT、TCC、Saga多种模式
RocketMQ 消息队列 Kafka、RabbitMQ 顺序消息,事务消息
Dubbo RPC框架 Spring Cloud OpenFeign 高性能,服务治理

2. Spring Cloud Alibaba 项目搭建

xml 复制代码
<!-- pom.xml 依赖配置 -->
<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>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
    </dependency>
</dependencies>

3. Nacos 服务注册与发现

yaml 复制代码
# application.yml 配置
spring:
  application:
    name: user-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        namespace: dev
        group: DEFAULT_GROUP
      config:
        server-addr: localhost:8848
        file-extension: yaml
        refresh-enabled: true
java 复制代码
// 服务注册与发现示例
@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {
    
    @RestController
    @RequestMapping("/users")
    public class UserController {
        
        @Autowired
        private DiscoveryClient discoveryClient;
        
        @GetMapping("/services")
        public List<String> getServices() {
            return discoveryClient.getServices();
        }
        
        @GetMapping("/{id}")
        public User getUser(@PathVariable Long id) {
            return userService.findById(id);
        }
    }
    
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}

4. Sentinel 流量控制与熔断

java 复制代码
// Sentinel 配置与使用
@Configuration
public class SentinelConfig {
    
    @PostConstruct
    public void init() {
        // 配置流量控制规则
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource("getUser");
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule.setCount(10); // 每秒最多10次请求
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
        
        // 配置熔断规则
        List<DegradeRule> degradeRules = new ArrayList<>();
        DegradeRule degradeRule = new DegradeRule();
        degradeRule.setResource("getUser");
        degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
        degradeRule.setCount(5); // 5个异常触发熔断
        degradeRule.setTimeWindow(10); // 熔断10秒
        degradeRules.add(degradeRule);
        DegradeRuleManager.loadRules(degradeRules);
    }
}

@Service
public class UserService {
    
    @SentinelResource(value = "getUser", blockHandler = "handleBlock", fallback = "getUserFallback")
    public User getUserById(Long id) {
        // 业务逻辑
        return userRepository.findById(id);
    }
    
    // 限流处理
    public User handleBlock(Long id, BlockException ex) {
        throw new RuntimeException("系统繁忙,请稍后重试");
    }
    
    // 熔断降级处理
    public User getUserFallback(Long id, Throwable ex) {
        return new User(id, "默认用户", "default@example.com");
    }
}

5. Seata 分布式事务

java 复制代码
// Seata 分布式事务示例
@Service
public class OrderService {
    
    @Autowired
    private OrderMapper orderMapper;
    
    @Autowired
    private AccountService accountService;
    
    @Autowired
    private StorageService storageService;
    
    @GlobalTransactional(name = "create-order", rollbackFor = Exception.class)
    public void createOrder(Order order) {
        // 1. 创建订单
        orderMapper.insert(order);
        
        // 2. 扣减库存
        storageService.deduct(order.getProductId(), order.getCount());
        
        // 3. 扣减余额
        accountService.debit(order.getUserId(), order.getMoney());
        
        // 4. 更新订单状态
        orderMapper.updateStatus(order.getId(), 1);
    }
}

// 配置 seata
@Configuration
public class SeataConfig {
    
    @Bean
    public DataSourceProxy dataSourceProxy(DataSource dataSource) {
        return new DataSourceProxy(dataSource);
    }
}

三、分布式锁的实现

1. 基于 Redis 的分布式锁

Redis 通过 SET 命令的 NXPX 选项实现分布式锁:

java 复制代码
// 加锁示例(Java + Redis)
public boolean tryLock(String key, String value, long expireTime) {
    String result = jedis.set(key, value, "NX", "PX", expireTime);
    return "OK".equals(result);
}

// 释放锁(使用 Lua 脚本保证原子性)
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object result = jedis.eval(script, Collections.singletonList(key), Collections.singletonList(value));

注意:需确保 value 具有唯一性(如 UUID + 线程ID),避免误释。

2. 基于 ZooKeeper 的分布式锁

ZooKeeper 通过临时顺序节点和 Watch 机制实现分布式锁:

  1. /locks 下创建临时顺序节点。
  2. 判断当前节点是否为最小序号节点,若是则获取锁。
  3. 若非最小,则监听前一个节点。
  4. 业务完成后删除节点,释放锁。

ZooKeeper 提供强一致性(CP),适用于对一致性要求高的场景,但性能低于 Redis。


四、分布式事务解决方案

方案 一致性 性能 复杂度 适用场景
2PC 强一致性 传统数据库、金融系统
3PC 强一致性 中低 需减少阻塞的场景
TCC 最终一致性 高并发业务(支付、库存)
Saga 最终一致性 长事务、跨服务流程
消息队列 最终一致性 事件驱动架构
本地消息表 最终一致性 异步通知(如订单-积分)

Seata 框架

Seata 是阿里开源的分布式事务解决方案,支持以下模式:

  • AT 模式:基于数据库快照和回滚日志,无需业务侵入。
  • TCC 模式:需实现 Try、Confirm、Cancel 接口。
  • Saga 模式:通过补偿事务回滚长事务。

示例(AT 模式):

java 复制代码
@GlobalTransactional
public void placeOrder(Order order) {
    orderDao.insert(order);
    inventoryService.deduct(order.getProductId(), order.getCount());
}

五、服务注册与发现

1. 注册中心核心功能

服务注册与发现是微服务架构的核心组件,主要功能包括:

  • 服务注册:服务实例启动时向注册中心注册自身信息
  • 服务发现:消费者从注册中心获取可用服务实例列表
  • 健康检查:定期检测服务实例健康状态,剔除异常实例
  • 负载均衡:提供多种负载均衡策略

2. 常见注册中心对比

组件 CAP模型 一致性协议 特点 适用场景
Eureka AP 简单易用,自我保护机制 高可用性要求场景
Nacos AP/CP切换 Raft 功能丰富,支持配置管理 云原生微服务
ZooKeeper CP ZAB 强一致性,可靠性高 金融、对一致性要求高的系统
Consul CP Raft 多数据中心,服务网格集成 复杂分布式系统

3. Nacos 注册示例

java 复制代码
// 服务提供者注册
@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class, args);
    }
}

// 服务消费者发现
@RestController
public class ConsumerController {
    @Autowired
    private RestTemplate restTemplate;
    
    @GetMapping("/call")
    public String callService() {
        return restTemplate.getForObject("http://service-provider/hello", String.class);
    }
}

六、API 网关

1. 网关核心功能

API 网关是微服务架构的入口,主要功能包括:

  • 路由转发:将请求路由到相应的微服务
  • 认证鉴权:统一身份验证和权限控制
  • 限流熔断:保护后端服务免受过载影响
  • 日志监控:集中收集请求日志和监控指标
  • 协议转换:支持不同协议间的转换

2. Spring Cloud Gateway 配置示例

yaml 复制代码
spring:
  cloud:
    gateway:
      routes:
        - id: user_route
          uri: lb://user-service
          predicates:
            - Path=/api/users/**
          filters:
            - name: RequestRateLimiter
              args:
                redis-rate-limiter.replenishRate: 10
                redis-rate-limiter.burstCapacity: 20
            - name: CircuitBreaker
              args:
                name: userServiceCircuitBreaker
                fallbackUri: forward:/fallback/user

七、熔断器

1. 熔断器模式

熔断器是防止分布式系统雪崩效应的重要组件,工作原理类似电路熔断器:

  • 关闭状态:正常请求通过,统计失败率
  • 打开状态:失败率超过阈值,直接拒绝请求
  • 半开状态:定期尝试放行部分请求,检测是否恢复

2. Resilience4j 熔断器示例

java 复制代码
// 配置熔断器
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
    .failureRateThreshold(50) // 失败率阈值50%
    .waitDurationInOpenState(Duration.ofMillis(1000)) // 熔断持续时间1s
    .slidingWindowSize(10) // 滑动窗口大小
    .build();

CircuitBreaker circuitBreaker = CircuitBreaker.of("userService", config);

// 使用熔断器保护服务调用
Supplier<String> decoratedSupplier = CircuitBreaker
    .decorateSupplier(circuitBreaker, () -> userService.getUser(userId));

try {
    String result = decoratedSupplier.get();
} catch (CallNotPermittedException e) {
    // 处理熔断器打开时的异常
    return "fallback response";
}

3. 熔断器监控

熔断器状态可通过指标和事件进行监控:

java 复制代码
// 事件监听
circuitBreaker.getEventPublisher()
    .onStateTransition(event -> {
        log.info("CircuitBreaker state changed from {} to {}",
            event.getStateTransition().getFromState(),
            event.getStateTransition().getToState());
    });

// 指标收集
Metrics metrics = circuitBreaker.getMetrics();
float failureRate = metrics.getFailureRate();
int numberOfBufferedCalls = metrics.getNumberOfBufferedCalls();

八、ZooKeeper 的应用与原理

应用场景

  • 配置管理:集中存储配置,动态更新。
  • 服务注册与发现:微服务实例注册,消费者动态发现。
  • 分布式锁:通过临时顺序节点实现。

核心原理

  • 数据模型:类似文件系统的树形结构(Znode)。
  • 节点类型
    • 持久节点(PERSISTENT)
    • 临时节点(EPHEMERAL)
    • 顺序节点(SEQUENTIAL)
  • ZAB 协议
    • 消息广播:Leader 广播提案,多数确认后提交。
    • 崩溃恢复:Leader 故障后选举新 Leader,保证数据一致性。

九、限流算法

1. 固定窗口算法

每单位时间窗口内计数,超限则拒绝。简单但存在窗口临界问题。

2. 滑动窗口算法

将窗口划分为更小时间片,平滑流量,避免临界问题。

3. 漏桶算法

以固定速率处理请求,超出容量则丢弃。适合平滑流量,但无法应对突发流量。

4. 令牌桶算法

以固定速率生成令牌,请求获取令牌后执行。允许突发流量,推荐使用。

Java 实现示例(Guava RateLimiter):

java 复制代码
RateLimiter limiter = RateLimiter.create(10.0); // 每秒10个令牌
if (limiter.tryAcquire()) {
    // 处理请求
} else {
    // 限流
}

十、分布式一致性算法

Raft 协议

  • 角色:Leader、Follower、Candidate。
  • 流程
    1. Leader 选举:超时未收到心跳则发起选举。
    2. 日志复制:Leader 同步日志,多数确认后提交。
    3. 安全性:保证日志一致性。

应用:Etcd、Consul。

Paxos 协议

  • 角色:Proposer、Acceptor、Learner。
  • 阶段
    1. Prepare:Proposer 发送提案编号。
    2. Accept:Acceptor 接受提案并广播。
    3. Learn:Learner 学习已接受的提案。

Paxos 更通用但实现复杂,Raft 更易理解与实现。


十一、总结

分布式系统设计需在一致性、可用性、性能之间权衡。Spring Cloud Alibaba 提供了一整套完善的分布式系统解决方案:

  • 服务治理:Nacos(注册中心+配置中心)
  • 流量控制:Sentinel(限流+熔断+降级)
  • 分布式事务:Seata(AT/TCC/Saga模式)
  • 消息队列:RocketMQ(顺序消息+事务消息)
  • RPC框架:Dubbo(高性能服务调用)
  • API网关:Spring Cloud Gateway(路由+过滤)