分布式系统是大型互联网应用的基础,掌握分布式架构是架构师的核心能力。本文将深入剖析分布式系统的核心概念、常见问题和解决方案,助你构建高可用、高性能的分布式系统。
一、分布式系统基础
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);
}
}
}
七、总结
分布式系统核心要点:
- 服务拆分 - 按业务领域拆分微服务
- 服务治理 - 注册发现、负载均衡
- 分布式事务 - Seata、TCC
- 限流熔断 - Sentinel、Hystrix
- 高可用 - 集群部署、故障转移
最佳实践:
- 合理拆分服务,避免过度拆分
- 使用配置中心统一管理配置
- 实现服务监控和链路追踪
- 做好容错和降级处理
- 定期进行压力测试
相关资源
- Spring Cloud官方文档
- 《微服务架构设计模式》
- 《分布式系统原理与范型》
💡 小贴士: 分布式系统复杂度高,要根据业务规模选择合适的架构!
关注我,获取更多架构干货! 🏗️