分布式

单体架构 vs 分布式架构 vs 微服务架构

单体架构(Monolithic)

特点

  • 整个系统打包成一个应用(通常一个 war/jar 包)。
  • 所有功能模块(用户、订单、商品、支付…)都在一个工程里。

优点

  • 开发简单,上手快。
  • 部署方便,只需要一个应用包。

缺点

  • 耦合度高,一个模块出问题可能影响整个系统。
  • 修改或扩展困难(要重新编译、打包、部署)。
  • 无法灵活扩展(只能整体扩容)。

👉 适合 小型项目初创项目


分布式架构(Distributed)

特点

  • 把系统拆分成多个子系统(但粒度比较大,比如用户系统、订单系统)。
  • 子系统之间通过 RPC、HTTP、MQ 等方式通信。

优点

  • 各个子系统可以独立部署和扩展。
  • 适合团队协作开发(不同小组负责不同子系统)。

缺点

  • 子系统还是比较大,内部功能没有彻底拆开。
  • 依赖复杂,系统间通信、事务处理变难。

👉 适合 中大型系统,例如传统电商网站:商品系统、支付系统、会员系统。


微服务架构(Microservices)

特点

  • 在分布式的基础上进一步细化,把系统拆成 更小的服务(通常围绕业务边界,比如订单服务、库存服务、优惠券服务)。
  • 服务之间独立部署、独立扩展,通常使用 Spring Cloud / Dubbo / gRPC

优点

  • 高度解耦:每个服务独立开发、测试、部署。
  • 弹性扩展:热门服务可以单独扩容(比如“秒杀服务”扩容,而不是整个电商系统扩容)。
  • 技术栈多样:不同服务可以用不同语言、数据库。

缺点

  • 架构复杂,需要服务注册发现、配置中心、链路追踪、分布式事务处理。
  • 运维要求高,需要容器化、CI/CD、监控体系。

CAP 定理、BASE 理论

CAP 是 一致性(Consistency)、可用性(Availability)、分区容错性(Partition Tolerance) 的缩写。

CAP 定理

三个概念:

  • 一致性 C:所有节点的数据要保持一致(好比大家看到的余额都是同一个数)。
  • 可用性 A:系统必须随时响应请求,不能“挂掉”。
  • 分区容错性 P:系统在出现网络分区(节点间通信失败)时还能继续工作。

在分布式系统中,CAP 三个特性不能同时满足,最多只能同时满足两个:

  • CP 系统:保证一致性和分区容错,但可能牺牲可用性(比如 Zookeeper)。
  • AP 系统:保证可用性和分区容错,但数据可能短暂不一致(比如 Eureka、Cassandra)。
  • CA 系统:保证一致性和可用性,但无法容忍分区(单机数据库,没法真正分布式)。

👉 总结:分布式系统一定要容错(P),所以大多数系统在 C 和 A 之间做权衡。

BASE 理论

BASE 理论是 CAP 的工程化妥协方案

BASE = Basically Available(基本可用) + Soft State(软状态) + Eventual Consistency(最终一致性)

三个概念:

  • 基本可用:在极端情况(如高并发),允许部分服务降级,比如结算页稍微慢一点。
  • 软状态:允许存在中间状态,不必实时强一致。
  • 最终一致性:系统经过一段时间后,数据最终会达到一致(如银行跨行转账)。

👉 总结:BASE 是在 CAP 中 放弃强一致性,追求最终一致性,保证系统高可用。

单点故障

在分布式系统中,单点故障(Single Point of Failure, SPoF) 是指系统中某个唯一依赖的组件 / 节点—— 当它发生故障(如宕机、网络断开、硬件损坏等)时,会直接导致整个分布式系统的核心功能中断整体不可用的现象。

微服务解决方案组件

服务注册与发现

解决 “服务在哪里” 的问题,让服务之间能动态感知对方的地址(IP / 端口),支持服务上下线自动更新。

  • Eureka(Netflix):AP 架构,强调可用性,适合自我保护机制(网络分区时不剔除服务)。
  • Consul:支持服务发现 + 配置管理,自带健康检查,CP 架构(强一致性)。
  • Nacos(阿里):融合注册中心 + 配置中心,支持 AP/CP 切换,国产生态友好。

配置中心

  • Apollo(携程):支持配置灰度发布、权限管理、配置历史回溯,功能完善。
  • Nacos:兼具注册中心和配置中心功能,轻量易用。
  • Config Server(Spring Cloud):与 Spring 生态无缝集成,依赖 Git 仓库存储配置。

服务通信

  • 典型协议 / 框架:
    • RESTful API:基于 HTTP,简单通用(如 Spring MVC)。
    • RPC:远程过程调用,性能更高(如 Dubbo、gRPC)。
  • 核心组件:
    • OpenFeign(Spring Cloud):声明式 REST 客户端,简化 HTTP 调用。
    • Dubbo:阿里开源 RPC 框架,支持多种注册中心,性能优异。

负载均衡

将请求均匀分发到多个服务实例,避免单实例过载。

  • Ribbon(Spring Cloud):客户端负载均衡,支持轮询、权重、随机等策略。
  • Dubbo 内置负载均衡:支持一致性哈希、最小活跃数等策略。

熔断与降级

防止服务雪崩(一个服务故障导致依赖它的所有服务连锁失败)。

  • Hystrix(Netflix):老牌熔断组件,支持线程隔离、请求缓存。
  • Sentinel(阿里):轻量级熔断降级工具,支持流量控制、热点参数限流。

网关

作为服务入口,统一处理路由、认证、限流、监控等横切功能。

  • Spring Cloud Gateway:基于 Netty 的响应式网关,支持动态路由、熔断集成。
  • Zuul(Netflix):基于 Servlet 的网关,功能简单但性能略低。

分布式事务

保证跨多个服务的操作要么全成功,要么全失败(如 “下单 + 扣库存”)。

  • Seata(阿里):支持 AT(自动补偿)、TCC、SAGA 等模式,易用性高。
  • RocketMQ 事务消息:通过半消息 + 回查机制实现最终一致性。

RPC的概念是什么?

RPC(Remote Procedure Call,远程过程调用)是一种让本地程序像调用本地函数一样调用远程服务器上的函数或方法的技术

RPC 的核心逻辑:

  1. 本地调用伪装:本地发者写代码时,调用远程函数的语法和调用用本地函数一样(如 remoteService.queryData(param))。

  2. 网络通信封装

    :RPC 框架在背后自动完成:

    • 把函数名、参数序列化(转成二进制数据);
    • 通过网络(如 TCP)发送给远程服务器;
    • 远程服务器收到后,反序列化数据,找到对应的函数执行;
    • 把执行结果序列化后,通过网络返回给本地;
    • 本地再反序列化结果,返回给调用者。

典型 RPC 框架:

  • Dubbo:阿里开源,适合 Java 生态,支持服务注册发现、负载均衡。
  • gRPC:Google 开源,基于 HTTP/2 和 Protobuf,跨语言支持好(Java、Go、Python 等)。
  • Thrift:Facebook 开源,支持多语言,适合高性能场景。

分布式锁

为什么需要分布式锁

在单体系统中,用本地锁(如 Java 的ReentrantLock)就能保证多线程互斥;但在分布式架构中,服务部署在多个服务器(JVM)上,本地锁只能控制单个服务器内的线程,无法跨节点生效。

实现方案

基于 Redis 实现(最常用)

利用 Redis 的SET NX EX命令(不存在则设置键值,同时指定过期时间):

  • 获取锁:执行SET lock_key unique_value NX EX 10(NX表示只在键不存在时设置,EX 表示 10 秒后自动过期)。
    • 成功:获取锁(unique_value用 UUID,确保唯一,用于释放锁时验证)。
    • 失败:表示锁被其他节点持有,等待重试。
  • 释放锁:通过 Lua 脚本原子执行 “判断 value 是否匹配 + 删除键”(避免误删其他节点的锁):
if redis.call('get', KEYS[1]) == ARGV[1] then
return redis.call('del', KEYS[1])
else
return 0
end

基于 ZooKeeper 实现

利用 ZooKeeper 的临时有序节点和 Watcher 机制:

获取锁:在指定节点下创建临时有序子节点(如/lock/node-0000001),判断自己是否是序号最小的子节点:
是:获取锁。
否:监听前一个子节点的删除事件(等待前一个节点释放锁)。
释放锁:节点断开连接(如服务宕机),临时节点自动删除,后续节点收到事件后尝试获取锁。

基于数据库实现

利用数据库的唯一索引或行锁:

  • 获取锁:插入一条带唯一索引的记录(如lock_key),成功则获取锁,失败则等待。
  • 释放锁:删除该记录。

基于Redisson 实现

Redisson 的 RLock 接口封装了分布式锁的所有操作,核心方法:

  • lock():获取锁(默认加锁 30 秒,后台自动续期)。
  • lock(long leaseTime, TimeUnit unit):指定锁的过期时间(若 leaseTime > 0,则不会自动续期)。
  • tryLock():尝试获取锁,立即返回结果(成功返回 true,失败返回 false)。
  • tryLock(long waitTime, long leaseTime, TimeUnit unit):指定等待时间(超时未获取则返回 false)。
  • unlock():释放锁(必须在 finally 中调用,确保锁释放)。

Redisson 如何保证分布式锁的可靠性?

  1. 原子性获取锁:Redisson 底层通过 Lua 脚本执行 Redis 命令,确保 “判断锁是否存在 + 设置锁” 的原子性(类似 SET NX EX 但更完善),避免并发问题。
  2. 自动续期(看门狗机制)
    • 若未指定 leaseTime(即 lock() 无参方法),Redisson 会默认加锁 30 秒,并启动一个 “看门狗” 线程(后台定时任务)。
    • 每隔 10 秒(30 秒的 1/3),看门狗会自动将锁的过期时间重置为 30 秒,直到业务执行完调用 unlock(),看门狗才会停止。
    • 这解决了 “业务执行时间超过锁过期时间,导致锁提前释放” 的问题。
  3. 安全释放锁
    • 锁的 value 是 Redisson 生成的唯一 ID(关联当前线程),释放锁时会先验证 ID 是否匹配,避免误删其他线程 / 节点的锁。
    • unlock() 方法底层同样通过 Lua 脚本实现 “验证 + 删除” 的原子操作。
  4. 集群适配:若 Redis 是主从 / 哨兵 / 集群模式,Redisson 会通过 RedLock 算法(可选)保证在 Redis 节点故障时,锁依然可用(多节点加锁,超过半数成功才认为获取锁成功)。

分布式事务

分布式事务的解决方案你知道哪些?

2PC(两阶段提交,Two-Phase Commit)

  • 核心思想:分 “准备阶段” 和 “提交阶段”,由协调者(Coordinator)统一管理所有参与者(Participant)的事务状态。
    • 准备阶段:协调者询问所有参与者是否可以执行事务提交,参与者执行操作并记录日志(未提交),返回 “就绪” 或 “中止”。
    • 提交阶段:若所有参与者均 “就绪”,协调者下达 “提交” 指令,参与者完成最终提交;若有任一参与者 “中止”,则下达 “回滚” 指令。
  • 优点:实现简单,强一致性。
  • 缺点:
    • 同步阻塞:准备阶段所有参与者需锁定资源,等待协调者指令,性能较差。
    • 协调者单点故障风险:若协调者宕机,参与者可能长期阻塞。
    • 数据不一致风险:提交阶段若部分参与者未收到指令,会导致数据不一致。
  • 适用场景:对一致性要求极高、并发量低的场景(如银行核心交易)。

3PC(三阶段提交,Three-Phase Commit)

  • 核心思想:在 2PC 基础上增加 “预提交阶段”,解决 2PC 的阻塞问题。
    • 阶段 1(CanCommit):协调者询问参与者是否可执行事务(类似 2PC 准备阶段的前置检查)。
    • 阶段 2(PreCommit):若所有参与者同意,协调者发送预提交指令,参与者执行操作并记录日志(可回滚)。
    • 阶段 3(DoCommit):协调者确认所有参与者预提交成功后,下达最终提交指令;若超时或失败,则下达回滚指令。

TCC(Try-Confirm-Cancel)

  • 核心思想:基于业务逻辑拆分事务为三个操作,由业务代码控制一致性。
    • Try:资源检查与预留(如扣减库存前锁定商品)。
    • Confirm:确认执行业务操作(如实际扣减库存),需保证幂等性。
    • Cancel:取消操作(如释放锁定的库存),需保证幂等性和补偿性。

Saga 模式

  • 核心思想:将分布式事务拆分为一系列本地事务(子事务),每个子事务对应一个 “补偿事务”,若某子事务失败,则按相反顺序执行补偿事务。
  • 实现方式:
    • 编排式:由一个中央协调器(Saga Coordinator)控制子事务的执行顺序和补偿逻辑。
    • ** choreography 式 **:子事务间通过事件通知触发执行,无中央协调器(如基于消息队列)。
  • 优点:
    • 无锁阻塞,性能优于 2PC,适合长事务。
    • 对业务侵入性较低(相比 TCC)。
  • 缺点:
    • 最终一致性(非强一致性),中间状态可能可见。
    • 补偿逻辑设计复杂,需处理网络重试、幂等性等问题。

本地消息表(Local Message Table)

  • 核心思想:通过本地事务保证 “业务操作” 与 “消息记录” 的原子性,再通过消息队列异步通知其他节点,实现最终一致性。
    • 步骤 1:在本地数据库中创建消息表,记录需要发送的跨节点消息。
    • 步骤 2:业务操作与消息表插入在同一本地事务中提交(保证要么都成功,要么都失败)。
    • 步骤 3:通过定时任务扫描消息表,将未发送的消息投递到消息队列。
    • 步骤 4:接收方消费消息并执行对应业务,完成后通知发送方删除消息。
  • 优点:实现简单,依赖本地事务和消息队列,可靠性高。
  • 缺点:
    • 消息表与业务表耦合,增加数据库存储成本。
    • 需处理消息重复消费(幂等性)和定时任务的效率问题。

事务消息(Transactional Message)

  • 核心思想:基于消息队列的 “事务消息” 机制(如 RocketMQ、RabbitMQ 的扩展实现),将消息发送与本地事务绑定。
    • 步骤 1:发送方发送 “半消息”(消息队列暂存,不投递)。
    • 步骤 2:执行本地事务,若成功则 “确认发送” 消息,若失败则 “取消发送”。
    • 步骤 3:消息队列将确认的消息投递到接收方,接收方执行业务并返回确认。
    • 步骤 4:通过回查机制处理发送方超时未确认的情况。
  • 优点:解耦消息表与业务表,依赖成熟的消息队列,可靠性高。
  • 缺点:依赖消息队列的事务消息支持,实现复杂度高于本地消息表。
  • 适用场景:依赖消息队列的分布式系统,需最终一致性(如异步通知、数据同步)。

阿里的seata框架了解过吗?

Seata 是阿里巴巴开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。它支持多种分布式事务模式,适配不同业务场景,目前已成为微服务领域主流的分布式事务框架之一。

​ Seata 定义了三个核心角色,来实现分布式事务的协调:

  • **Transaction Coordinator (TC)**:事务协调者,独立的中间件,负责维护全局事务的运行状态,协调全局事务的提交或回滚。
  • **Transaction Manager (TM)**:事务管理器,嵌入到发起全局事务的微服务中(如订单服务),负责发起全局事务、定义全局事务的范围(开始、提交、回滚)。
  • **Resource Manager (RM)**:资源管理器,嵌入到参与全局事务的各个微服务中(如库存服务、支付服务),负责管理本地事务资源,与 TC 通信注册资源、汇报事务状态,并执行 TC 下达的提交 / 回滚指令。

三者的交互流程:

  1. TM 向 TC 申请开启全局事务,TC 生成全局事务 ID(XID)并返回给 TM;
  2. XID 通过服务调用链路传递到各个 RM 所在的微服务;
  3. 各 RM 向 TC 注册分支事务(本地事务),并汇报执行状态;
  4. TM 根据所有分支事务的状态,向 TC 发起全局提交或回滚请求;
  5. TC 协调所有 RM 执行本地事务的提交或回滚,完成全局事务。

Seata 的 几种模式

场景需求 推荐模式 核心考量
简单 CRUD、低侵入 AT 模式 自动补偿,性能较好
复杂业务、跨资源 TCC 模式 灵活性高,手动控制资源
长事务、多步骤流程 Saga 模式 无锁阻塞,容忍中间状态
强一致性、金融核心交易 XA 模式 严格 ACID,牺牲性能
异步通信、数据同步 本地消息表模式 实现简单,依赖消息队列

1. AT 模式(Automatic Transaction,自动事务)

Seata 的默认模式,基于 2PC 思想优化,通过 自动生成补偿逻辑 实现低侵入式的分布式事务,是最常用的模式之一。

核心原理

  • 第一阶段(本地事务执行)
    1. RM 拦截业务 SQL,解析并记录数据修改前的快照(生成 undo log,用于回滚);
    2. 执行本地事务并提交(释放数据库锁,解决传统 2PC 的阻塞问题);
    3. 向 TC 汇报分支事务状态为 “准备就绪”。
  • 第二阶段(全局提交 / 回滚)
    • 若全局事务提交:TC 通知所有 RM 删除 undo log,事务完成。
    • 若全局事务回滚:TC 通知 RM 根据 undo log 自动执行回滚(补偿逻辑)。

特点

  • 优点:对业务代码无侵入(无需手动写补偿逻辑),性能较好(第一阶段释放锁),适合简单 CRUD 场景。
    • 缺点:仅支持关系型数据库(依赖 SQL 解析生成 undo log),不适合复杂业务逻辑。

适用场景:电商下单、库存扣减等基于数据库的简单分布式事务。

2. TCC 模式(Try-Confirm-Cancel)

基于业务逻辑拆分的手动事务模式,需要开发者手动实现 Try(资源检查与预留)、Confirm(确认提交)、Cancel(取消回滚) 三个接口,Seata 负责协调三个阶段的执行。

核心原理

  • Try 阶段:检查资源是否可用(如库存是否充足),并预留资源(如冻结部分库存),确保后续操作可执行。
  • Confirm 阶段:若所有分支 Try 成功,执行实际业务提交(如扣减冻结的库存),需保证幂等性。
  • Cancel 阶段:若任一分支 Try 失败,释放预留的资源(如解冻冻结的库存),需保证幂等性和补偿性。

Seata 增强

  • 自动处理分支事务的注册、状态汇报和协调逻辑;
  • 支持空回滚(无 Try 却收到 Cancel)、幂等性(重复调用不影响结果)、悬挂(Cancel 先于 Try 执行)等问题。

特点

  • 优点:不依赖数据库,灵活性高,适合跨库、跨服务的复杂业务(如金融转账)。
  • 缺点:侵入业务代码,开发成本高(需手动实现三个接口)。

适用场景:金融交易、复杂资源操作(如跨系统资金划转)。

3. Saga 模式

针对 长事务场景 设计,将分布式事务拆分为多个本地子事务,每个子事务对应一个补偿事务,通过状态机或事件驱动执行,失败时按逆序执行补偿。

实现方式

  • 编排式:通过 JSON 配置定义子事务的执行顺序、依赖关系和补偿逻辑,由 Seata 协调器统一调度。
  • 注解式:通过 @SagaTask 注解标记子事务和补偿方法,简化配置。

核心原理

  1. 按顺序执行各子事务(如 “下单→支付→发货→物流”);
  2. 若某子事务失败,触发补偿机制,按逆序执行已完成子事务的补偿逻辑(如 “物流回滚→发货回滚→支付回滚→下单回滚”)。

特点

  • 优点:无锁阻塞,性能好,适合长事务(跨多个服务、步骤多的流程)。
  • 缺点:最终一致性(中间状态可能可见),补偿逻辑需手动实现。

适用场景:订单全链路履约、流程审批等长事务流程。

4. XA 模式

基于传统 XA 协议(分布式事务规范)实现的强一致性模式,依赖数据库原生 XA 支持(如 MySQL、Oracle 的 XA 接口)。

  • 流程:
    1. 各分支事务执行 SQL 后,通过 XA PREPARE 进入 “准备就绪” 状态(持有数据库锁,未提交);
    2. TC 确认所有分支就绪后,发送 XA COMMIT 指令完成提交;若任一分支失败,发送 XA ROLLBACK 回滚。

特点

  • 优点:强一致性(符合 ACID),对业务无侵入(依赖数据库 XA 支持)。
  • 缺点:性能低(数据库锁全程持有,阻塞严重),仅支持 XA 协议的数据库。

适用场景:金融核心交易等对强一致性要求极高、可接受低并发的场景。

zookeeper拿来做什么?核心的原理是什么?

ZooKeeper 是一款专注于分布式系统协调的开源工具,主要解决分布式环境中多节点之间的 状态同步、一致性保障、协作控制 等问题。

一、ZooKeeper 能做什么?

ZooKeeper 的典型应用场景包括但不限于:

  1. 分布式锁多个节点竞争同一资源时,通过 ZooKeeper 创建临时有序节点,利用节点的唯一性和有序性实现分布式锁(如公平锁)。例如,秒杀系统中控制库存扣减的并发冲突。
  2. 服务注册与发现服务提供者启动时在 ZooKeeper 上创建临时节点(记录服务地址、端口等信息),服务消费者通过监听这些节点获取服务列表,并感知服务上下线变化。
  3. 集群选举分布式集群(如 Hadoop、Kafka)中,通过 ZooKeeper 的临时节点和监听机制实现 leader 节点的自动选举(如 Kafka Controller 选举)。当 leader 故障时,快速从 follower 中选出新 leader。
  4. 配置中心将分布式系统的配置信息(如数据库地址、阈值参数)存储在 ZooKeeper 的节点中,所有节点监听配置节点的变化,实现配置的集中管理和动态更新(无需重启服务)。
  5. 数据发布与订阅基于 “发布 - 订阅” 模式,一个节点发布数据到 ZooKeeper 节点,其他节点通过监听该节点实时获取数据更新(如分布式系统中的全局状态同步)。
    1. 分布式队列利用 ZooKeeper 的节点顺序性,实现 FIFO 队列(如任务调度系统中按顺序执行分布式任务)。

二、ZooKeeper 的核心原理

ZooKeeper 的核心能力依赖于其 数据模型、集群架构、ZAB 协议Watcher 机制,四者共同保障了分布式协调的可靠性。

1. 数据模型:树形结构(ZNode)

ZooKeeper 的数据存储类似文件系统的树形结构,每个节点称为 ZNode,具有以下特点:

  • 层级结构:根节点为 /,子节点通过路径标识(如 /services/user-service)。

  • 数据存储:每个 ZNode 可存储少量数据(默认最大 1MB),适合存储配置、状态等元数据。

  • 节点类型

    • 持久节点(PERSISTENT):创建后永久存在,除非手动删除。
    • 临时节点(EPHEMERAL):创建节点的客户端会话结束后,节点自动删除(常用于服务注册,服务下线后节点自动清除)。
    • 有序节点(SEQUENTIAL):创建时会自动添加一个自增序号(如 lock-000000001),用于实现分布式锁、队列等。
  • 版本号:每个 ZNode 有版本号(dataVersion),修改数据时需指定版本号,实现乐观锁(避免并发冲突)。

2. 集群架构:主从复制(Leader + Follower + Observer)

ZooKeeper 通常以集群形式部署(节点数为奇数,如 3、5 个),避免单点故障,角色分为:

  • Leader:集群的主节点,负责处理所有写请求(如创建、修改 ZNode),并通过 ZAB 协议同步数据到其他节点;同时负责 leader 选举的发起。
  • Follower:从节点,负责处理读请求,参与写请求的投票(Leader 发起写操作时,需多数 Follower 确认),并在 Leader 故障时参与选举。
  • Observer(可选):仅处理读请求,不参与投票和选举,用于扩展读性能(不影响集群一致性)。

集群特性

  • 写操作需 Leader 处理,且需超过半数节点(Leader + Follower)确认才能成功(保证一致性)。
  • 读操作可由任意节点处理(本地读取,性能高)。

3. 一致性协议:ZAB 协议(ZooKeeper Atomic Broadcast)

ZAB 是 ZooKeeper 自定义的原子广播协议,保证集群中所有节点的数据一致性,类似 Paxos 但更简单,核心流程分为两部分:

  • 阶段一:Leader 选举集群启动或 Leader 故障时,所有 Follower 进入选举状态,通过投票选出新 Leader(得票超过半数的节点当选)。选举依据是节点的 myid(配置的唯一标识)zxid(事务 ID,反映数据更新顺序,值越大越新),优先选择 zxid 最大的节点(确保数据最新)。

  • 阶段二:原子广播(数据同步)Leader 当选后,集群进入正常工作状态,写操作通过以下步骤同步到所有节点:

    1. 提议(Propose):Leader 收到写请求后,生成一个全局唯一的 zxid,向所有 Follower 发送提议(包含数据变更内容)。
    2. 确认(Ack):Follower 收到提议后,执行数据变更并返回确认(Ack)。
    3. 提交(Commit):当 Leader 收到超过半数 Follower 的 Ack 后,向所有节点发送 Commit 指令,所有节点正式提交数据变更(本地持久化)。

    这一过程保证了 所有节点要么同时提交数据,要么同时失败,实现强一致性。

4. 事件监听:Watcher 机制

Watcher 是 ZooKeeper 实现分布式协调的核心机制,允许客户端注册监听某个 ZNode 的变化(如节点创建、删除、数据修改),当变化发生时,ZooKeeper 会主动通知客户端。

特点

  • 一次性:Watcher 触发后立即失效,若需持续监听,需重新注册。
  • 异步通知:通知通过客户端的回调函数处理,不阻塞客户端操作。
  • 轻量级:仅通知发生了变化,不包含变化前后的具体数据(客户端需主动读取新数据)。

常见的限流算法你知道哪些?

算法 核心特点 优点 缺点 适用场景
固定窗口 时间分片固定 简单、高效 临界问题 低精度场景
滑动窗口 子窗口平滑过渡 精度较高 子窗口越多越耗资源 中等精度场景(如 API 网关)
漏桶 固定速率处理 流量绝对平稳 不支持突发流量 保护后端系统(如数据库)
令牌桶 允许突发,长期速率可控 灵活,支持峰值 实现稍复杂 大多数限流场景(推荐)
计数器滑动窗口 精确统计时间窗口请求 精度极高 高并发下性能差 高精度、低并发场景

1. 固定窗口限流(Fixed Window)

核心思想

将时间划分为固定大小的窗口(如 1 秒),统计每个窗口内的请求数,若超过预设阈值则拒绝后续请求。

  • 示例:窗口大小 1 秒,阈值 100 次请求。第 1 秒内若请求达 100 次,后续请求被拒绝,直到第 2 秒窗口刷新。

实现

  • 用一个计数器记录当前窗口内的请求数,窗口起始时间戳标记窗口边界。
  • 每次请求到来时,判断是否在当前窗口内:
    • 是:计数器 + 1,若超过阈值则限流。
    • 否:重置计数器和窗口起始时间。

优点:实现简单,内存占用低。

缺点:存在 “窗口临界问题”—— 若窗口边界前后各涌入阈值的请求(如第 1 秒末 50 次 + 第 2 秒初 50 次,实际 1 秒内可能达 100 次),会瞬间超过阈值,导致流量突刺。

适用场景:对精度要求不高的场景(如简单接口限流)。

2. 滑动窗口限流(Sliding Window)

核心思想

将固定窗口拆分为多个更小的 “子窗口”,通过滑动计算一定时间范围内的总请求数,解决固定窗口的临界问题。

  • 示例:1 秒窗口拆分为 10 个 100ms 的子窗口,每个子窗口记录请求数。任意连续 1 秒内的总请求数若超过阈值,则限流。

实现

  • 维护一个子窗口数组(如 10 个元素),每个元素记录对应时间段的请求数。
  • 每次请求到来时,计算当前时间属于哪个子窗口,更新对应计数,并累加最近 N 个子窗口的总请求数(覆盖完整时间窗口),若超过阈值则限流。

优点:解决了固定窗口的临界问题,精度更高。

缺点:子窗口划分越细,内存占用和计算成本越高(需维护更多子窗口状态)。

适用场景:对限流精度有一定要求的场景(如 API 网关限流)。

3. 漏桶算法(Leaky Bucket)

核心思想

将请求比作 “水流”,系统比作 “漏桶”:请求先进入漏桶,漏桶以固定速率(如每秒 100 次)处理请求,若请求量超过漏桶容量,则溢出(被限流)。

  • 特点:强制限制请求的处理速率,平滑流量,不受突发流量影响。

实现

  • 维护两个变量:漏桶当前水量(请求数)、漏桶容量、漏水速率(单位时间处理请求数)。
  • 每次请求到来时:
    • 先计算 “漏水” 量(根据上次处理时间到当前的间隔,按速率减去已处理的请求)。
    • 若新增请求后水量超过容量,则限流;否则水量 + 1。

优点:输出流量稳定,适合保护后端系统(如数据库)不被突发流量冲击。

缺点:无法应对短时间的突发流量(即使系统空闲,也只能按固定速率处理)。

适用场景:需要严格控制输出速率的场景(如接口调用第三方服务,避免触发对方限流)。

4. 令牌桶算法(Token Bucket)

核心思想

系统按固定速率(如每秒 100 个)向 “令牌桶” 中放入令牌,请求到来时需从桶中获取令牌,若能获取则处理,否则限流。桶有最大容量,令牌满了之后不再新增。

  • 特点:允许一定程度的突发流量(若桶中有积累的令牌,可一次性处理多个请求),同时长期速率不超过令牌生成速率。

实现

  • 维护变量:令牌桶当前令牌数、桶容量、令牌生成速率(单位时间新增令牌数)。
  • 每次请求到来时:
    • 先计算当前应生成的令牌数(根据上次生成时间到当前的间隔,按速率增加令牌,不超过桶容量)。
    • 若令牌数≥1,则令牌数 - 1,处理请求;否则限流。

优点:兼顾限流和突发流量处理,灵活性高,是最常用的限流算法之一。

缺点:实现稍复杂(需动态计算令牌生成量)。

适用场景:大多数需要限流的场景(如 API 接口、网关、秒杀系统),尤其适合允许短期流量峰值的业务。

5. 计数器滑动窗口(Counting Sliding Window)

核心思想

是滑动窗口的一种优化,通过记录每个请求的时间戳,计算最近时间窗口内的请求数(如最近 1 秒内的请求数),超过阈值则限流。

  • 实现:用一个有序列表(如红黑树、链表)存储请求的时间戳,每次请求到来时,先删除列表中超过窗口时间的时间戳,再判断剩余数量是否超过阈值。

优点:精度极高,无窗口划分带来的误差。

缺点:高并发下,列表操作(插入、删除)可能成为性能瓶颈(需锁或并发数据结构)。

适用场景:对精度要求极高但并发量不高的场景。

6. 分布式限流(基于 Redis 等)

以上算法均为单机限流,分布式系统中需统一统计全量请求,常用方案:

  • Redis + 滑动窗口:用 Redis 的ZSET存储请求时间戳,通过ZREMRangeByScore删除过期时间戳,ZCARD统计数量,结合 Lua 脚本保证原子性。
  • Redis + 令牌桶:用 Redis 存储令牌数,定时任务按速率生成令牌,请求时原子性减少令牌数。
  • 网关层限流:如 Nginx 的limit_req(基于漏桶)、Spring Cloud Gateway 结合 Redis 实现分布式限流。

分布式一致性算法

1. Paxos 算法

Paxos 是由 Leslie Lamport 提出的分布式一致性算法,是许多现代一致性协议的基础(如 Raft 是 Paxos 的简化版)。其核心目标是在 异步网络环境(允许节点故障和消息延迟 / 丢失,但不允许消息篡改)中,让多个节点对某个值达成一致。

核心角色

  • Proposer(提议者):提出需要达成一致的值(如数据更新请求)。
  • Acceptor(接受者):负责接收和表决提议,只有获得多数 Acceptor 接受的提议才能成为最终共识。
  • Learner(学习者):同步最终达成一致的值,不参与提议和表决(可理解为从节点)。

核心流程(简化)

Paxos 分为 准备(Prepare)接受(Accept) 两个阶段,通过 “两阶段提交” 避免冲突:

  1. 准备阶段:Proposer 向多数 Acceptor 发送包含唯一提案编号 N 的 Prepare 请求。Acceptor 若未响应过编号更大的提案,会回复 “承诺(Promise)” 不接受编号小于 N 的提案,并返回已接受的最大编号提案(若有)。
  2. 接受阶段:若 Proposer 收到多数 Acceptor 的 Promise,则发送包含编号 N 和值 V(根据 Accept 回复的提案确定,若无则用自己的提议值)的 Accept 请求。Acceptor 若未承诺过更大编号的提案,则接受该提案。
  3. 共识达成:当一个提案被多数 Acceptor 接受后,该值 V 成为共识,Learner 同步此值。

特点

  • 优点:严谨性高,能在异步环境下容错(最多容忍 (n-1)/2 个节点故障,n 为总节点数)。
  • 缺点:设计复杂(存在多个 Proposer 时需处理活锁),难以实现和理解。
  • 适用场景:分布式数据库(如 Google Spanner)、分布式存储(如 Cassandra 部分功能)。

2. Raft 算法

Raft 是为了简化 Paxos 而设计的一致性算法,强调 可理解性,通过将问题分解为 “领导者选举”“日志复制”“安全性” 三个部分,降低了实现难度,成为目前最流行的分布式一致性算法之一。

核心角色

  • Leader(领导者):唯一负责接收客户端请求,并向 Follower 同步日志(数据变更记录)。
  • Follower(跟随者):被动接收 Leader 的日志同步,若超时未收到 Leader 心跳,则转换为 Candidate 参与选举。
  • Candidate(候选者):发起选举,争取成为新 Leader。

核心流程

  1. 领导者选举
    • 集群启动时,所有节点为 Follower,定期等待 Leader 心跳(默认超时时间 150-300ms)。
    • 若 Follower 超时未收到心跳,转换为 Candidate,向其他节点发送投票请求。
    • 节点仅为任期(Term,递增的选举轮次编号)更大的 Candidate 投票,获得多数票的 Candidate 成为 Leader。
    • 若选举平局(无节点获多数票),则随机延迟后重新选举,避免活锁。
  2. 日志复制
    • Leader 接收客户端请求后,将其作为日志条目追加到本地日志,并向所有 Follower 发送同步请求。
    • Follower 收到日志后追加到本地日志并返回确认(Ack)。
    • 当 Leader 收到多数 Follower 的 Ack 后,将该日志条目标记为 “已提交”,并通知 Follower 提交,此时客户端请求生效。
  3. 安全性保障
    • 确保 Leader 拥有所有已提交的日志条目(选举时,Candidate 需证明自己的日志至少与其他节点一样新,否则不被投票)。
    • 日志条目按顺序提交,保证数据一致性。

特点

  • 优点:逻辑清晰(拆分角色和阶段),易于实现和调试,容错能力与 Paxos 相同(最多容忍 (n-1)/2 个节点故障)。
  • 缺点:依赖 Leader 节点,Leader 故障后需重新选举,期间服务不可用(短暂)。
  • 适用场景:分布式系统的元数据管理(如 etcd、Consul、Kubernetes 的 etcd 集群)、分布式数据库(如 CockroachDB)。

3. ZAB 协议(ZooKeeper Atomic Broadcast)

ZAB 是 ZooKeeper 自定义的原子广播协议,专为分布式协调服务设计,兼具 一致性高可用性,可视为简化的 Paxos 变种。

核心目标

  • 保证分布式事务的原子性(所有节点要么都执行,要么都不执行)。
  • 在 Leader 故障时快速选举新 Leader,恢复服务。

核心流程

ZAB 分为 崩溃恢复消息广播 两个阶段:

  1. 崩溃恢复:当 Leader 故障或集群启动时,通过选举产生新 Leader,确保新 Leader 拥有所有已提交的事务日志(与 Raft 选举类似,优先选择日志最新的节点)。
  2. 消息广播:正常运行时,Leader 接收客户端写请求,生成事务提案(带全局唯一 ZXID),通过 “两阶段提交” 同步到所有 Follower:
    • Leader 向 Follower 发送提案,Follower 写入日志后返回 Ack。
    • 当 Leader 收到多数 Follower 的 Ack 后,向所有节点发送 Commit 指令,完成事务提交。

特点

  • 优点:专为 ZooKeeper 设计,兼顾一致性和高可用,支持快速故障转移。
  • 缺点:耦合 ZooKeeper 的数据模型(ZNode),通用性较弱。
  • 适用场景:ZooKeeper 集群(用于分布式锁、服务发现等协调场景)。

什么是Nacos,它的核心功能是什么?

是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台,致力于解决微服务中的服务发现、配置动态更新、服务健康检查等问题。

  • 服务发现与注册:支持基于 DNS 和 RPC 的服务发现,服务提供者可注册服务,消费者可动态发现服务。
  • 配置管理:集中管理应用的配置信息,支持动态更新(无需重启服务)、多环境 / 多集群配置、配置版本控制。
  • 服务健康检查:自动检测服务实例的健康状态,剔除不健康实例,保证服务可用性。
  • 动态 DNS 服务:通过 DNS 协议解析服务域名,支持权重路由、流量控制等。

Nacos 的服务注册与发现原理是什么?支持哪些注册中心模式?

  • 服务注册原理
    1. 服务提供者启动时,通过 Nacos SDK 向 Nacos Server 发送注册请求(包含服务名、IP、端口、健康检查参数等)。
    2. Nacos Server 将服务信息存储在内存注册表中,并持久化到数据库(默认 Derby,可配置 MySQL)。
    3. 服务提供者定期向 Nacos Server 发送心跳(默认 5 秒),证明自身健康;Nacos Server 若超过 15 秒未收到心跳,标记实例为不健康;超过 30 秒则剔除实例。
  • 服务发现原理
    1. 服务消费者通过 Nacos SDK 订阅目标服务,Nacos Server 记录订阅关系。
    2. 当服务实例变化(如新增、下线、健康状态变更)时,Nacos Server 通过 Push 机制主动通知消费者(基于长连接),消费者更新本地服务列表。
  • 支持的注册中心模式
    • AP 模式:优先保证可用性和分区容错性,适合服务发现场景(允许网络分区时存在短暂数据不一致,最终会同步)。
    • CP 模式:优先保证一致性和分区容错性,适合需要强一致性的场景(如配置管理、集群选举)。
    • 注意:Nacos 可针对不同服务动态切换 AP/CP 模式(通过 nacos.core.protocol=grpc 等配置)。

分布式系统中如何实现负载均衡?

客户端负载均衡:消费者从注册中心获取服务列 表,本地实现负载策略(如 Ribbon、 SpringCloudLoadBanlance)。

服务端负载均衡:通过负载均衡器(如 Nginx、 LVS)转发请求到后端服务。

分布式全局唯一id的解决方案

方案 核心原理 唯一性保障 有序性 性能 实现复杂度 适用场景
UUID/GUID 随机数 + 时间戳 + 硬件信息 概率上唯一 无序 极高 极低 对有序性无要求的场景(如日志 ID)
数据库自增 ID 单库 / 主从库自增序列 数据库主键约束 单库有序 极低 小型分布式系统(并发量低)
数据库分段 ID 预分配 ID 段(如每个节点分配 1000 个) 段不重叠 + 段内自增 段内有序 中小并发场景(如订单 ID)
Redis 自增 ID Redis 的 INCR/INCRBY 命令 单 Redis 节点原子性 全局有序 高并发场景(需解决 Redis 单点问题)
雪花算法(Snowflake) 时间戳 + 机器 ID + 序列号 结构分段不重叠 时间序 + 机器内有序 极高 高并发、需有序的核心场景(如交易)
美团 Leaf 整合 “数据库分段” 与 “Snowflake” 双方案兜底 段内 / 时间序有序 极高 超大规模分布式系统(如电商)
百度 UidGenerator 优化 Snowflake(动态机器 ID) 结构分段 + 动态 ID 分配 时间序有序 极高 容器化(K8s)场景

UUID(通用唯一识别码)

GUID 是微软对 UUID 的实现,本质一致。

随机数+时间戳+硬件信息

实现起来比较简单,并且性能高,缺点是无序性,占用空间大,可读性比较差

适用场景:日志 ID、临时会话 ID、分布式缓存 Key(非排序场景)等对有序性无要求的场景。

数据库自增 ID(单库 / 主从)

利用关系型数据库(MySQL、PostgreSQL)的AUTO_INCREMENT(MySQL)或SERIAL(PostgreSQL)特性,单库中通过主键自增生成唯一 ID;主从架构下,所有写入走主库,从库同步数据,确保 ID 唯一。

优点是实现零成本,全局有序;缺点就是有这个性能瓶颈,扩展性比较差,可用性比较差

适合用于小型分布式系统,单库单表的场景

数据库分段id(预分配id段)

提前向数据库申请一段连续的 ID(如 1000-1999),节点本地缓存该段 ID,用完后再申请下一段

优点就是说性能提升:本地缓存id段,减少了数据库的交互。有序性、同一个id段内严格递增,满足大部分的排序要求

并且有一定的扩展性,不同业务类型独立分配,互不影响。

缺点就是说段与段之间无序,id浪费,未用完的id段会丢失

适合中小并发场景,如电商订单,用户注册等需要有序id的业务

Redis自增id

利用 Redis 的单线程原子性,通过INCR key(自增 1)或INCRBY key step(自增 step)命令生成唯一 ID。

例如:

  • 生成用户 ID:INCR user_id → 返回 1、2、3…
  • 生成订单 ID:INCRBY order_id 100 → 每次申请 100 个 ID 段。

优点是性能极高,全局有序,轻量易扩展;

缺点是维护成本高,数据又丢失风险,有序性比较局限

雪花算法(Snowflake)

Twitter 开源的分布式 ID 生成算法,核心是将64 位 Long 型 ID拆分为 5 个分段,通过 “分段不重叠” 保障唯一性,通过 “时间戳高位” 保障有序性。

  • 符号位:固定为 0,确保 ID 为正数;
  • 时间戳:41 位可表示2^41-1毫秒(约 69 年),需设置 “起始时间戳”(如系统上线时间);
  • 机器 ID:10 位可支持2^10=1024个节点;
  • 序列号:12 位可支持同一节点同一毫秒生成2^12=4096个 ID。

优点是性能好,全局有序,无中心依赖,可读性比较强

缺点是机器id需要预分配,又时钟回拨的问题导致id重复

高并发、强有序、无中心依赖的核心场景,如金融交易、电商订单、物流跟踪等。

美团的Leaf(企业级方案)

美团开源的分布式 ID 生成系统,整合了 “数据库分段 ID”(Leaf-segment)“优化版 Snowflake”(Leaf-snowflake) 两种方案,可根据业务场景切换。

  • Leaf-segment:在 “数据库分段” 基础上优化,通过 “双 Buffer 预申请”(一段在用、一段预申请)避免 ID 段用完时的等待,提升性能;
  • Leaf-snowflake:解决原生 Snowflake 的机器 ID 问题,通过 “ZooKeeper 生成临时节点” 动态分配机器 ID(节点启动时向 ZK 申请,退出时释放),适配容器化场景。

优点是高可用,高性能,适合复杂场景:动态机器id适配k8s容器集群

缺点是架构比较复杂 ,维护的成本高

适合超大规模的分布式系统(比如这个美团和京东等电商平台),需要兼顾高并发,高可用和复杂部署环境

百度 UidGenerator

百度开源的 Snowflake 优化方案,核心改进是 “动态机器 ID 分配” 和 “时间戳位宽可配置”

  • 动态机器 ID:通过 “数据库自增” 分配机器 ID(节点启动时向数据库申请唯一 ID),无需 ZK;

  • 可配置位宽:支持自定义 “时间戳、机器 ID、序列号” 的位宽(如机器 ID16 位支持 65536 个节点);

  • 预生成缓冲:通过 “RingBuffer” 预生成 ID 并缓存,进一步提升性能。

  • 优点

    1. 更灵活:位宽可适配不同集群规模;
    2. 无 ZK 依赖:简化部署,降低维护成本;
    3. 性能优异:单节点 QPS 可达百万级。
  • 缺点

    1. 仍依赖数据库:机器 ID 分配需数据库支持;
    2. 时钟回拨问题:需额外处理。

容器化(K8s)、大规模集群场景,如互联网大厂的用户中心、内容平台等。

方案选型

  1. 优先选 UUID:若无需有序性、追求极简实现(如日志 ID);
  2. 优先选数据库分段:中小并发、需有序、不想引入 Redis(如中小电商订单);
  3. 优先选 Redis 自增:高并发、需全局有序、已部署 Redis 集群(如秒杀);
  4. 优先选 Snowflake/Leaf/UidGenerator:高并发、强有序、无中心依赖(如金融交易、核心业务);
    • 小型集群→原生 Snowflake;
    • 容器化 / 大规模集群→UidGenerator;
    • 超大规模 / 高可用要求→Leaf。

时间回拨问题

时钟回拨(Clock Backward)是分布式 ID 生成中(尤其是基于时间戳的方案,如雪花算法)的典型问题,指服务器时钟因同步、故障等原因出现时间倒退,可能导致 ID 重复。以下是针对性的解决方案及典型实现:

1. 等待时钟追平(最常用)

原理

检测到当前时间戳小于上次生成 ID 的时间戳时,暂停 ID 生成,等待系统时钟自然追上上次时间后再继续。

2. 使用物理时钟 + 逻辑时钟补偿

原理:不直接依赖系统时钟,而是维护一个 “逻辑时钟”:

  • 当物理时钟正常时,逻辑时钟同步物理时钟;
  • 当物理时钟回拨时,逻辑时钟继续自增(确保不会倒退)。

3. 预生成 ID 缓冲池

原理:提前生成一批 ID 并缓存,当检测到时钟回拨时,优先使用缓冲池中的 ID,同时异步触发新 ID 生成(避开回拨时段)。

如何监控分布式系统的健康状态?常用组件有哪些?

  • 监控维度 服务指标:QPS、响应时间、错误率。
  • 资源指标:CPU、内存、磁盘 IO、网络流量。
  • 分布式指标:节点存活状态、数据同步延迟。

常用组件

  • Prometheus + Grafana:采集指标并可视化展示。
  • ELK Stack:日志收集(Elasticsearch)、分析 (Logstash)、展示(Kibana)。
  • Skywalking:分布式链路追踪,定位服务调用瓶颈。

服务熔断和服务限流

服务熔断

核心目标:当依赖的服务出现频繁故障(如超时、错误率过高)时,主动切断调用链路,避免故障 “蔓延” 导致整个系统级联崩溃(“雪崩效应”),同时给故障服务留出恢复时间。

工作原理(类似电路断路器)

  • 闭合状态(Closed):正常调用依赖服务,实时统计错误率 / 超时率。
  • 打开状态(Open):当错误率超过阈值(如 50%),触发熔断,直接返回降级结果(如默认值、缓存数据),不再调用目标服务。
  • 半开状态(Half-Open):熔断一段时间后(如 5 秒),允许少量请求尝试调用目标服务,若成功则恢复 “闭合状态”,否则继续保持 “打开状态”。

典型场景

  • 支付服务依赖的银行接口超时率突增,触发熔断后,支付服务直接返回 “系统繁忙,请稍后再试”,避免大量请求阻塞在支付环节。

服务限流

核心目标:对服务的请求流量进行控制,限制单位时间内的请求数量(如 QPS、并发数),防止超出服务的处理能力,导致响应延迟或崩溃。

常见限流维度

  • QPS 限流:限制每秒请求数(如每秒最多 1000 次请求)。
  • 并发数限流:限制同时处理的请求数(如最多 500 个并发请求)。
  • 基于来源限流:对特定 IP、用户或接口单独设置限流规则(如限制某 IP 每秒最多 10 次请求)。

典型场景

  • 电商秒杀活动中,限制商品详情接口 QPS=10000,超出部分直接返回 “排队中”,避免服务器被冲垮。

你了解 QPS、TPS、RT、吞吐量 这些高并发性能指标吗?

1. QPS(Queries Per Second)

  • 定义:每秒处理的查询请求数,通常用于描述读操作密集型的系统(如数据库查询、缓存查询、API 接口的查询类请求)。
  • 示例:一个商品详情接口每秒被请求 1000 次,其 QPS 为 1000。
  • 注意:QPS 关注 “查询” 动作,不严格区分请求是否包含写操作,但更偏向读场景。

2. TPS(Transactions Per Second)

  • 定义:每秒处理的事务数,一个事务通常包含一组连续的操作(如 “查询库存→创建订单→扣减库存”),且需满足 ACID 特性(原子性、一致性等),常用于描述包含读写混合操作的业务场景(如支付流程、订单创建)。
  • 示例:支付系统每秒完成 500 笔支付(包含查询余额、扣钱、生成流水等步骤),其 TPS 为 500。
  • 与 QPS 的区别:TPS 是 “业务逻辑完整的事务”,QPS 是 “单一查询请求”;一个事务可能包含多个查询(即 1 TPS 可能对应多个 QPS)。

3. RT(Response Time)

  • 定义:响应时间,指从请求发出到收到完整响应的总耗时(单位通常为毫秒 ms),反映系统处理请求的速度。
  • 关键指标:
    • 平均 RT:所有请求的平均耗时(需结合分布情况,避免被极端值误导)。
    • P99/P95 RT:99%/95% 的请求耗时不超过该值(更能反映用户实际体验,如 P99=500ms 表示 99% 的请求在 500ms 内完成)。
  • 意义:RT 是衡量系统 “快慢” 的核心指标,过高会导致用户体验差(如页面加载超时)。

4. 吞吐量(Throughput)

  • 定义:单位时间内系统处理的数据总量(单位通常为 MB/s、GB/h 等),反映系统处理数据的能力,与请求数量、单个请求的数据大小相关。
  • 示例:一个文件上传服务每秒处理 100 个请求,每个请求平均 2MB,其吞吐量为 200MB/s。
  • 与 QPS/TPS 的关系:吞吐量 = (QPS/TPS)× 平均请求数据大小;高吞吐量不一定意味着高 QPS(如大文件传输,QPS 低但吞吐量高)。

指标间的关联与应用

  • QPS/TPS 与 RT 的关系:在系统资源饱和前,QPS/TPS 随并发量增加而上升,RT 基本稳定;当并发超过阈值后,QPS/TPS 下降,RT 急剧上升(因资源竞争、排队等待)。
    • 公式参考:QPS ≈ 并发数 / 平均 RT(如并发用户 1000,平均 RT=100ms,则 QPS≈1000/0.1=10000)。
  • 性能优化目标:在满足 RT 要求(如 P99<1s)的前提下,提升 QPS/TPS 和吞吐量,同时避免系统过载(如 CPU、内存、网络瓶颈)。