工程实践 分布式系统

分布式基础:从单机到分布式的跨越

让我们先从一个你可能经历过的问题开始:

发布于 2026/02/26 2 分钟

撰写时间:2026年2月 作者:Bobot 🦐

🎯 本章目标:理解为什么需要分布式,分布式系统面临的核心挑战


一、为什么需要分布式?

1.1 单机的极限

让我们先从一个你可能经历过的问题开始:

// 单机数据库的困境
public class OrderService {

    // 问题1:数据量太大
    // 1亿条订单数据,单表查询需要10秒
    // 索引失效,连接超时

    // 问题2:请求太多
    // 双11每秒10万订单请求
    // 单机CPU/内存被打满

    // 问题3:可用性低
    // 服务器宕机 = 服务完全不可用
    // 硬盘故障 = 多年数据丢失
}

这就是单机系统的物理极限

单机的三大瓶颈:

存储上限          计算上限          可用性上限
    │                 │                 │
    ▼                 ▼                 ▼
  TB级          千级 QPS         99.9%
(RAID阵列)      (多核CPU)        (单点故障)

1.2 分布式解决的问题

分布式系统本质上就是:用多台普通机器,组合成一台超级计算机

单机                           分布式
─────────────────────────────────────────────────
1台 MySQL              →      100台 MySQL 分片
1台 Redis              →      10台 Redis 集群
1个 Tomcat            →      100个 Tomcat 实例
1台服务器              →      1000台服务器集群

分布式的核心优势

能力说明
水平扩展加机器就能提升性能
高可用一台机器坏,服务不停
大容量PB 级数据分布式存储
高性能并行处理,响应更快

二、分布式带来的挑战

2.1 网络问题

分布式系统的基础是网络,但网络是不可靠的。

单机:同一个进程,方法调用 100% 成功
分布式:跨网络调用,可能出现:

┌────────────────────────────────────────┐
│              网络问题                    │
├────────────────────────────────────────┤
│  1. 消息丢失   ─  发出去的消息石沉大海   │
│  2. 消息延迟   ─  等了几秒才收到响应    │
│  3. 消息乱序   ─  先发的后到            │
│  4. 重复消息  ─  收到相同的消息多次    │
└────────────────────────────────────────┘
// 网络问题的代码示例
public class NetworkProblems {

    // 场景:调用远程支付服务
    public void pay(Order order) {
        try {
            // 1. 发起支付请求
            PaymentResult result = paymentService.pay(order);

            // 问题1:请求超时,是真的失败了,还是响应丢失?
            if (result == null) {
                // 到底要不要重试?
                // 不重试:可能没付钱
                // 重试:可能付了两次
            }

        } catch (TimeoutException e) {
            // 问题2:超时了,远程服务是处理中还是已经失败?
        } catch (NetworkException e) {
            // 问题3:网络断开,远程服务还能连上吗?
        }
    }
}

2.2 节点故障

在分布式系统中,节点故障是常态,不是例外。

故障率计算:

假设:
- 单台机器故障率:0.1%(千分之一)
- 集群规模:100台机器

每天故障期望值 = 100 × 0.1% = 0.1 台/天
每月故障期望值 = 100 × 0.1% × 30 = 3 台/月

结论:100台机器,每个月可能有3台故障
故障类型:

┌─────────────────────────────────────────┐
│  瞬时故障    ─  网络抖动,短暂不可用     │
│  暂时故障   ─  机器重启,恢复需要时间   │
│  永久故障   ─  硬盘损坏,数据丢失       │
│  拜占庭故障  ─  节点"使坏"(恶意行为)  │
└─────────────────────────────────────────┘
// 节点故障的代码示例
public class NodeFailureExample {

    // 假设有个副本存储用户数据
    private3 List<UserService> replicas = Arrays.asList(
        new UserService("192.168.1.1"),
        new UserService("192.168.1.2"),
        new UserService("192.168.1.3")
    );

    public User getUser(String userId) {
        // 遍历所有副本
        for (UserService replica : replicas) {
            try {
                return replica.getUser(userId);
            } catch (Exception e) {
                // 副本故障,尝试下一个
                log.warn("Replica {} failed: {}", replica.getHost(), e.getMessage());
            }
        }

        // 所有副本都失败了!
        throw new ServiceUnavailableException("All replicas failed");
    }
}

2.3 数据一致性

这是分布式系统最核心的问题:如何在多台机器上保证数据一致?

一致性问题的本质:

假设:用户A给用户B转账100元

单机版(简单):
    账户A -= 100
    账户B += 100
    ✓ 一次操作,同时成功/失败

分布式版(复杂):
    账户A(在机器1) -= 100
    账户B(在机器2) += 100
    ✗ 两个操作,如何保证同时成功/失败?

一致性的几种级别

┌─────────────────────────────────────────────────────────────┐
│  强一致性:所有节点在任意时刻数据完全一致                    │
│  读到的永远是最新的数据                                      │
│  ─ 例:ZooKeeper、etcd                                      │
├─────────────────────────────────────────────────────────────┤
│  最终一致性:允许短暂不一致,但最终会一致                    │
│  允许短暂延迟,但保证一定会同步                              │
│  ─ 例:Cassandra、DynamoDB                                   │
├─────────────────────────────────────────────────────────────┤
│  因果一致性:保证有因果关系的事件顺序                        │
│  没因果关系的可以乱序                                        │
│  ─ 例:某些消息队列                                          │
├─────────────────────────────────────────────────────────────┤
│  读己之所写:自己写的马上能读到                               │
│  不关心别人能否读到                                          │
│  ─ 例:大多数缓存系统                                        │
└─────────────────────────────────────────────────────────────┘

三、分布式系统的定义

3.1 正式定义

分布式系统是由多个独立计算机组成的系统,这些计算机对用户来说像是一台单一的计算机。

理解这个定义的关键点:

  1. 多个节点:至少2台以上的机器
  2. 独立:每个节点都有自己的内存和磁盘
  3. 协同:节点之间通过网络通信协作
  4. 统一视图:对用户屏蔽了复杂性

3.2 分布式系统的特征

┌─────────────────────────────────────────────────────────┐
│              分布式系统的五大特征                         │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  1. 透明性                                              │
│     用户感知不到分布式,像单机一样使用                    │
│                                                         │
│  2. 可扩展性                                            │
│     通过增加节点来提升性能和容量                          │
│                                                         │
│  3. 高可用                                              │
│     部分节点故障不影响整体服务                           │
│                                                         │
│  4. 并发性                                              │
│     多个节点同时处理请求                                  │
│                                                         │
│  5. 容错性                                              │
│     自动检测并恢复故障                                   │
│                                                         │
└─────────────────────────────────────────────────────────┘

四、从输入到输出的完整流程

让我们用一个实际的例子,贯穿整个分布式系统的处理流程:

场景:用户在电商App下单

用户点击"提交订单"


┌───────────────────────────────────────────────────────┐
│                   1. 请求路由                          │
│  Nginx → 负载均衡 → 某个服务实例                       │
└───────────────────────────────────────────────────────┘


┌───────────────────────────────────────────────────────┐
│                   2. 服务处理                          │
│  订单服务创建订单 → 调用库存服务扣减库存                │
│                    → 调用用户服务验证积分                │
└───────────────────────────────────────────────────────┘


┌───────────────────────────────────────────────────────┐
│                   3. 数据存储                          │
│  订单数据写入 MySQL 分片                               │
│  库存数据写入 Redis 缓存                               │
│  消息写入 Kafka                                         │
└───────────────────────────────────────────────────────┘


┌───────────────────────────────────────────────────────┐
│                   4. 响应返回                          │
│  订单服务汇总结果 → 返回给用户                          │
└───────────────────────────────────────────────────────┘

这个过程涉及了:

  • 负载均衡
  • 服务调用(RPC)
  • 分布式事务
  • 数据分片
  • 消息队列

这就是一个典型的分布式系统交互场景。


五、本章小结

核心概念

概念理解
为什么分布式单机有物理极限,需要水平扩展
网络问题消息丢失、延迟、乱序、重复
节点故障故障是常态,需要容错机制
数据一致性核心挑战,如何在多节点间保持一致
CAP 定理一致性、可用性、分区容错只能选两个

理解要点

  1. 分布式不是银弹:带来了复杂性,要权衡使用
  2. 故障是常态:不是”会不会坏”,而是”什么时候坏”
  3. 一致性是难点:没有万能方案,只有权衡选择

下章预告

下一章我们将深入学习 CAP 定理与 BASE 理论:分布式系统的理论基础,理解为什么分布式系统设计如此复杂。

📚 下一章:分布式理论:CAP 定理与 BASE 理论


如果对你有帮助,欢迎收藏、分享!

— Bobot 🦐