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 项目搭建
<!-- 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 服务注册与发现
# application.yml 配置
spring:application:name: user-servicecloud:nacos:discovery:server-addr: localhost:8848namespace: devgroup: DEFAULT_GROUPconfig:server-addr: localhost:8848file-extension: yamlrefresh-enabled: true
// 服务注册与发现示例
@SpringBootApplication
@EnableDiscoveryClient
public class UserServiceApplication {@RestController@RequestMapping("/users")public class UserController {@Autowiredprivate 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 流量控制与熔断
// Sentinel 配置与使用
@Configuration
public class SentinelConfig {@PostConstructpublic 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 分布式事务
// Seata 分布式事务示例
@Service
public class OrderService {@Autowiredprivate OrderMapper orderMapper;@Autowiredprivate AccountService accountService;@Autowiredprivate 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 {@Beanpublic DataSourceProxy dataSourceProxy(DataSource dataSource) {return new DataSourceProxy(dataSource);}
}
三、分布式锁的实现
1. 基于 Redis 的分布式锁
Redis 通过 SET
命令的 NX
和 PX
选项实现分布式锁:
// 加锁示例(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 机制实现分布式锁:
- 在
/locks
下创建临时顺序节点。 - 判断当前节点是否为最小序号节点,若是则获取锁。
- 若非最小,则监听前一个节点。
- 业务完成后删除节点,释放锁。
ZooKeeper 提供强一致性(CP),适用于对一致性要求高的场景,但性能低于 Redis。
四、分布式事务解决方案
方案 | 一致性 | 性能 | 复杂度 | 适用场景 |
---|---|---|---|---|
2PC | 强一致性 | 低 | 中 | 传统数据库、金融系统 |
3PC | 强一致性 | 中低 | 高 | 需减少阻塞的场景 |
TCC | 最终一致性 | 高 | 高 | 高并发业务(支付、库存) |
Saga | 最终一致性 | 中 | 高 | 长事务、跨服务流程 |
消息队列 | 最终一致性 | 高 | 中 | 事件驱动架构 |
本地消息表 | 最终一致性 | 中 | 低 | 异步通知(如订单-积分) |
Seata 框架
Seata 是阿里开源的分布式事务解决方案,支持以下模式:
- AT 模式:基于数据库快照和回滚日志,无需业务侵入。
- TCC 模式:需实现 Try、Confirm、Cancel 接口。
- Saga 模式:通过补偿事务回滚长事务。
示例(AT 模式):
@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 注册示例
// 服务提供者注册
@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication {public static void main(String[] args) {SpringApplication.run(ProviderApplication.class, args);}
}// 服务消费者发现
@RestController
public class ConsumerController {@Autowiredprivate RestTemplate restTemplate;@GetMapping("/call")public String callService() {return restTemplate.getForObject("http://service-provider/hello", String.class);}
}
六、API 网关
1. 网关核心功能
API 网关是微服务架构的入口,主要功能包括:
- 路由转发:将请求路由到相应的微服务
- 认证鉴权:统一身份验证和权限控制
- 限流熔断:保护后端服务免受过载影响
- 日志监控:集中收集请求日志和监控指标
- 协议转换:支持不同协议间的转换
2. Spring Cloud Gateway 配置示例
spring:cloud:gateway:routes:- id: user_routeuri: lb://user-servicepredicates:- Path=/api/users/**filters:- name: RequestRateLimiterargs:redis-rate-limiter.replenishRate: 10redis-rate-limiter.burstCapacity: 20- name: CircuitBreakerargs:name: userServiceCircuitBreakerfallbackUri: forward:/fallback/user
七、熔断器
1. 熔断器模式
熔断器是防止分布式系统雪崩效应的重要组件,工作原理类似电路熔断器:
- 关闭状态:正常请求通过,统计失败率
- 打开状态:失败率超过阈值,直接拒绝请求
- 半开状态:定期尝试放行部分请求,检测是否恢复
2. Resilience4j 熔断器示例
// 配置熔断器
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. 熔断器监控
熔断器状态可通过指标和事件进行监控:
// 事件监听
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):
RateLimiter limiter = RateLimiter.create(10.0); // 每秒10个令牌
if (limiter.tryAcquire()) {// 处理请求
} else {// 限流
}
十、分布式一致性算法
Raft 协议
- 角色:Leader、Follower、Candidate。
- 流程:
- Leader 选举:超时未收到心跳则发起选举。
- 日志复制:Leader 同步日志,多数确认后提交。
- 安全性:保证日志一致性。
应用:Etcd、Consul。
Paxos 协议
- 角色:Proposer、Acceptor、Learner。
- 阶段:
- Prepare:Proposer 发送提案编号。
- Accept:Acceptor 接受提案并广播。
- Learn:Learner 学习已接受的提案。
Paxos 更通用但实现复杂,Raft 更易理解与实现。
十一、总结
分布式系统设计需在一致性、可用性、性能之间权衡。Spring Cloud Alibaba 提供了一整套完善的分布式系统解决方案:
- 服务治理:Nacos(注册中心+配置中心)
- 流量控制:Sentinel(限流+熔断+降级)
- 分布式事务:Seata(AT/TCC/Saga模式)
- 消息队列:RocketMQ(顺序消息+事务消息)
- RPC框架:Dubbo(高性能服务调用)
- API网关:Spring Cloud Gateway(路由+过滤)