2024 年双十一,天猫交易峰值达到 58.3 万笔/秒。这个数字背后,是阿里巴巴十余年架构演进的结晶——从最初的单体 LAMP 栈,到如今横跨全球多个数据中心的单元化架构(Logical Data Center,LDC),每一次双十一都是对系统极限的真实检验。本文将从单元化架构、分库分表中间件、全链路压测、弹性伸缩、高可用交易链路、消息中间件、分布式事务七个维度,完整拆解阿里巴巴流量工程的核心设计。
一、阿里巴巴技术架构演进概览
1.1 四个关键阶段
阿里巴巴的技术架构大致经历了四个阶段:
| 阶段 | 时间范围 | 核心特征 | 代表技术 |
|---|---|---|---|
| 单体时代 | 2003-2007 | LAMP 单体应用,Oracle 数据库 | PHP,Oracle |
| 服务化时代 | 2008-2012 | 去 IOE,SOA 拆分 | HSF,TDDL,OceanBase |
| 异地多活时代 | 2013-2017 | 单元化部署,三地五中心 | LDC,DRC,GSLB |
| 云原生时代 | 2018-至今 | 全面上云,Serverless,Service Mesh | ACK,MSE,ARMS |
1.2 去 IOE 的战略决策
2009 年,阿里巴巴正式启动”去 IOE”(IBM 小型机、Oracle 数据库、EMC 存储)战略。这并非单纯的技术偏好,而是业务增速远超硬件垂直扩展能力后的必然选择。每年双十一的流量增长率在 30%-50%,而 Oracle RAC(Real Application Cluster)的扩展上限约在 16 节点左右,且授权费用随节点数线性增长。
去 IOE 的核心路径:
- 将 Oracle 替换为 MySQL(MySQL),通过分库分表实现水平扩展
- 用 PC 服务器集群替代 IBM 小型机
- 用分布式文件系统(TFS,Tair)替代 EMC 集中式存储
1.3 架构全景
以下是阿里巴巴双十一交易系统的整体架构分层:
graph TB
subgraph 接入层
CDN["CDN(全球节点)"]
GSLB["GSLB 全局负载均衡"]
Tengine["Tengine / Aserver"]
end
subgraph 网关层
Gateway["统一接入网关"]
RateLimit["限流模块(Sentinel)"]
Auth["鉴权服务"]
end
subgraph 业务层
Trade["交易中心"]
Inventory["库存中心"]
Order["订单中心"]
Payment["支付中心"]
User["用户中心"]
Promotion["营销中心"]
end
subgraph 中间件层
HSF["HSF / Dubbo RPC"]
RocketMQ["RocketMQ 消息"]
TDDL["TDDL 数据层"]
Diamond["Diamond 配置中心"]
Tair["Tair 分布式缓存"]
end
subgraph 数据层
MySQL_Group["MySQL 主从集群"]
OceanBase["OceanBase 分布式数据库"]
Lindorm["Lindorm 宽表"]
end
CDN --> GSLB
GSLB --> Tengine
Tengine --> Gateway
Gateway --> RateLimit
Gateway --> Auth
RateLimit --> Trade
RateLimit --> Inventory
RateLimit --> Order
Trade --> HSF
Trade --> RocketMQ
Trade --> TDDL
Inventory --> Tair
Order --> TDDL
Payment --> HSF
HSF --> MySQL_Group
TDDL --> MySQL_Group
TDDL --> OceanBase
Tair --> Lindorm
二、单元化架构(LDC)设计
2.1 为什么需要单元化
传统的集中式部署在应对双十一级别的流量时面临三个根本性问题:
- 单机房容量上限:即使是阿里张北数据中心,单机房物理机数量也有上限,网络带宽存在瓶颈
- 故障爆炸半径不可控:一次网络抖动可能影响全部用户
- 扩容周期过长:采购服务器到上架调试至少需要 2-3 个月
单元化架构的核心思想是:将用户按照某个维度(通常是用户 ID)进行分片,每个分片的全部业务流量在一个逻辑单元(Unit)内闭环处理。
2.2 LDC 架构模型
LDC 的全称是 Logical Data Center(逻辑数据中心),它是阿里巴巴单元化架构的工程实现。
graph LR
subgraph 杭州中心
GZone_HZ["GZone(全局服务)"]
RZone_HZ_1["RZone-01"]
RZone_HZ_2["RZone-02"]
RZone_HZ_3["RZone-03"]
end
subgraph 上海中心
RZone_SH_1["RZone-04"]
RZone_SH_2["RZone-05"]
RZone_SH_3["RZone-06"]
end
subgraph 张北中心
GZone_ZB["GZone(全局服务备)"]
RZone_ZB_1["RZone-07"]
RZone_ZB_2["RZone-08"]
end
GSLB_Global["GSLB 全局调度"] --> RZone_HZ_1
GSLB_Global --> RZone_HZ_2
GSLB_Global --> RZone_HZ_3
GSLB_Global --> RZone_SH_1
GSLB_Global --> RZone_SH_2
GSLB_Global --> RZone_SH_3
GSLB_Global --> RZone_ZB_1
GSLB_Global --> RZone_ZB_2
RZone_HZ_1 -.->|只读| GZone_HZ
RZone_SH_1 -.->|只读| GZone_HZ
RZone_ZB_1 -.->|只读| GZone_ZB
GZone_HZ <-->|数据同步| GZone_ZB
2.3 三种 Zone 类型
LDC 将服务划分为三种 Zone 类型:
RZone(Region Zone):按用户分片部署的业务单元,承载交易、订单、库存等核心写操作。每个 RZone 包含完整的业务服务栈和对应分片的数据库。流量在 RZone 内闭环,不跨 Zone 调用。
GZone(Global Zone):部署全局共享服务,如商品信息、类目数据、卖家信息等。这类数据写少读多,不适合按用户分片。GZone 在所有数据中心间做数据同步,各 RZone 就近读取本地 GZone 副本。
CZone(City Zone):介于 RZone 和 GZone 之间的折中方案。部署在每个城市级数据中心,用于承载那些有一定写入量但不需要全局唯一写入点的服务。
2.4 用户分片路由
用户分片的路由规则嵌入在每一层:
/**
* 用户 ID 路由到 RZone 的核心逻辑
* 使用 userId 的后两位作为分片键,将用户映射到 00-99 共 100 个逻辑分片
* 再通过路由表将逻辑分片映射到物理 RZone
*/
public class UnitRouter {
// 路由表:逻辑分片 -> 物理 RZone
// 通过配置中心动态下发,支持运行时切换
private volatile Map<Integer, String> routeTable;
/**
* 根据用户 ID 获取目标 RZone
*/
public String getTargetUnit(long userId) {
// 取用户 ID 后两位,得到 0-99 的逻辑分片号
int slot = (int) (userId % 100);
// 查路由表获取物理 RZone
String targetZone = routeTable.get(slot);
if (targetZone == null) {
throw new RouteException("No route found for slot: " + slot);
}
return targetZone;
}
/**
* 切换指定分片的路由目标
* 用于单元扩缩容和故障切换
*/
public void switchRoute(int slot, String newZone) {
Map<Integer, String> newTable = new HashMap<>(routeTable);
newTable.put(slot, newZone);
this.routeTable = Collections.unmodifiableMap(newTable);
}
/**
* 批量切换分片路由
* 用于整个 RZone 故障时的批量迁移
*/
public void batchSwitchRoute(String fromZone, String toZone) {
Map<Integer, String> newTable = new HashMap<>(routeTable);
for (Map.Entry<Integer, String> entry : newTable.entrySet()) {
if (entry.getValue().equals(fromZone)) {
newTable.put(entry.getKey(), toZone);
}
}
this.routeTable = Collections.unmodifiableMap(newTable);
}
}2.5 数据同步:DRC
DRC(Data Replication Center,数据复制中心)负责跨数据中心的数据同步。它解析 MySQL 的 binlog,以近实时的方式将数据变更复制到其他数据中心。
DRC 的核心设计要点:
- 低延迟:正常情况下端到端延迟在 200ms 以内,跨城同步在 1s 以内
- 冲突检测:对于 GZone 的双向同步,DRC 采用”最后写入胜出”(Last Write Wins)策略,并结合业务层的乐观锁做冲突兜底
- 精确过滤:只复制需要同步的表和字段,减少带宽消耗
- 断点续传:基于 GTID(Global Transaction ID)实现断点续传,网络恢复后自动补数据
# DRC 同步任务配置示例
drc_task:
name: "gzone_product_sync"
source:
cluster: "hz-gzone-mysql"
database: "product_db"
tables:
- name: "product_info"
columns: ["id", "title", "price", "status", "gmt_modified"]
- name: "category"
columns: "*"
target:
cluster: "zb-gzone-mysql"
database: "product_db"
sync_mode: "bidirectional"
conflict_strategy: "last_write_wins"
filter:
exclude_patterns:
- "tmp_*"
- "*_backup"
monitor:
delay_threshold_ms: 500
alert_channels: ["dingding", "sms"]三、TDDL 分库分表中间件
3.1 TDDL 的定位
TDDL(Taobao Distributed Data Layer)是阿里巴巴自研的分布式数据访问中间件。它以 JDBC 驱动的形式嵌入应用,在 SQL 层面实现分库分表路由、读写分离和容灾切换,对上层业务代码几乎透明。
TDDL 在整体数据链路中的位置:
应用代码
↓
MyBatis / JPA
↓
TDDL(SQL 解析 → 路由 → 执行 → 结果合并)
↓
JDBC Driver
↓
MySQL 集群(主库 + 从库)
3.2 分库分表策略
TDDL 支持多种分片策略,最常用的是哈希取模和范围分片的组合:
/**
* TDDL 分库分表规则配置示例
* 以订单表为例:按 buyer_id 分 8 个库,每个库 32 张表
* 总共 256 个分片,支撑千万级 TPS
*/
public class OrderShardingRule implements ShardingRule {
private static final int DB_COUNT = 8;
private static final int TABLE_COUNT_PER_DB = 32;
/**
* 计算目标库索引
* 使用 buyer_id 做分库键,保证同一买家的订单落在同一个库
*/
@Override
public int calculateDbIndex(long buyerId) {
// 先对总分片数取模,再除以每库表数
int totalShardIndex = (int) (buyerId % (DB_COUNT * TABLE_COUNT_PER_DB));
return totalShardIndex / TABLE_COUNT_PER_DB;
}
/**
* 计算目标表后缀
*/
@Override
public int calculateTableIndex(long buyerId) {
int totalShardIndex = (int) (buyerId % (DB_COUNT * TABLE_COUNT_PER_DB));
return totalShardIndex % TABLE_COUNT_PER_DB;
}
/**
* 生成物理表名
* 例如:order_0023 表示第 23 号分片表
*/
@Override
public String getPhysicalTableName(long buyerId) {
int tableIndex = calculateTableIndex(buyerId);
return String.format("order_%04d", tableIndex);
}
/**
* 生成物理库名
* 例如:order_db_03 表示第 3 号分片库
*/
@Override
public String getPhysicalDbName(long buyerId) {
int dbIndex = calculateDbIndex(buyerId);
return String.format("order_db_%02d", dbIndex);
}
}3.3 SQL 解析与路由
TDDL 的 SQL 处理流程包含四个阶段:
- SQL 解析:使用自研的 SQL Parser(FastSQL)将 SQL 文本解析为 AST(抽象语法树),提取分片键的值
- 路由计算:根据分片规则和分片键值,计算出目标物理库表
- SQL 改写:将逻辑表名替换为物理表名,修正 LIMIT、ORDER BY 等子句
- 结果合并:跨分片查询时,合并多个分片的结果集,执行全局排序、聚合、分页
/**
* TDDL SQL 执行流程简化示例
*/
public class TddlExecutor {
private final SqlParser parser;
private final ShardingRouter router;
private final ConnectionPool connPool;
/**
* 执行一条 SQL
*/
public ResultSet execute(String sql, Object[] params) throws SQLException {
// 阶段一:SQL 解析
SqlStatement stmt = parser.parse(sql);
ShardingKey key = stmt.extractShardingKey(params);
// 阶段二:路由计算
List<TargetNode> targets = router.route(stmt, key);
if (targets.size() == 1) {
// 单分片查询:直接下推
return executeSingle(targets.get(0), stmt, params);
}
// 阶段三:跨分片查询 - 并行执行
List<Future<ResultSet>> futures = new ArrayList<>();
for (TargetNode target : targets) {
futures.add(asyncExecute(target, stmt, params));
}
// 阶段四:结果合并
List<ResultSet> results = collectResults(futures);
return mergeResults(results, stmt);
}
/**
* 合并多分片结果
* 处理 ORDER BY、GROUP BY、LIMIT 等聚合操作
*/
private ResultSet mergeResults(List<ResultSet> results, SqlStatement stmt) {
if (stmt.hasOrderBy()) {
return new MergeSortResultSet(results, stmt.getOrderByColumns());
}
if (stmt.hasGroupBy()) {
return new GroupByMergeResultSet(results, stmt.getGroupByColumns());
}
return new SimpleUnionResultSet(results);
}
}3.4 读写分离与权重配置
# TDDL 数据源配置示例
tddl:
app_name: "trade-center"
group_rules:
- group: "order_db_00"
master: "10.0.1.10:3306"
slaves:
- host: "10.0.1.11:3306"
weight: 5
- host: "10.0.1.12:3306"
weight: 3
- host: "10.0.1.13:3306"
weight: 2
read_strategy: "weight_random"
slave_delay_threshold_ms: 1000
# 从库延迟超过阈值时自动切到主库读
failover_on_delay: true
- group: "order_db_01"
master: "10.0.2.10:3306"
slaves:
- host: "10.0.2.11:3306"
weight: 5
- host: "10.0.2.12:3306"
weight: 5
read_strategy: "round_robin"
slave_delay_threshold_ms: 800
failover_on_delay: true3.5 分库分表的常见陷阱
| 陷阱 | 现象 | 解决方案 |
|---|---|---|
| 跨分片 JOIN | SQL 性能急剧下降 | 冗余数据或在应用层做关联 |
| 全表扫描 | 查询未命中分片键,扫描所有分片 | 建立路由索引表或使用搜索引擎 |
| 分布式唯一 ID | 自增 ID 跨库冲突 | 使用 Snowflake 算法或 Leaf 发号器 |
| 数据倾斜 | 某些分片数据量远大于其他分片 | 采用虚拟桶映射,支持动态调整 |
| 扩容迁移 | 增加分片数需要大规模数据迁移 | 预分配足够分片,使用逻辑分片到物理分片的映射表 |
| 分布式事务 | 跨分片写入无法保证 ACID | 使用 TCC 或 Saga 模式 |
四、全链路压测平台
4.1 全链路压测的必要性
双十一的流量模式极其特殊:零点峰值可能是日常流量的 20-30 倍,且持续时间短(通常只有前 5 分钟是真正的流量高峰)。传统的单服务压测无法暴露系统间的级联故障和资源竞争问题。
全链路压测(Full-Link Stress Testing)是指在生产环境中,使用与真实流量高度相似的模拟流量,对完整业务链路进行压力测试。阿里巴巴从 2013 年开始建设全链路压测平台,是业界最早将这一实践工业化的公司之一。
4.2 压测流量与真实流量的隔离
全链路压测最大的技术挑战是:如何在生产环境中注入大量压测流量,同时保证不污染真实业务数据。
/**
* 压测流量标记传递机制
* 通过 ThreadLocal 在整个调用链中传递压测标记
*/
public class ShadowFlag {
private static final ThreadLocal<Boolean> IS_SHADOW = ThreadLocal.withInitial(() -> false);
/**
* 标记当前请求为压测流量
*/
public static void markAsShadow() {
IS_SHADOW.set(true);
}
/**
* 清除压测标记
*/
public static void clear() {
IS_SHADOW.remove();
}
/**
* 判断当前请求是否为压测流量
*/
public static boolean isShadow() {
return IS_SHADOW.get();
}
}
/**
* 压测数据路由 - 数据源层面的隔离
* 压测流量写入影子表(Shadow Table),不影响正式数据
*/
public class ShadowDataSourceRouter {
private final DataSource normalDataSource;
private final DataSource shadowDataSource;
public ShadowDataSourceRouter(DataSource normal, DataSource shadow) {
this.normalDataSource = normal;
this.shadowDataSource = shadow;
}
/**
* 根据压测标记选择数据源
*/
public Connection getConnection() throws SQLException {
if (ShadowFlag.isShadow()) {
return shadowDataSource.getConnection();
}
return normalDataSource.getConnection();
}
}
/**
* 影子表 SQL 改写器
* 将正式表名改写为影子表名
* 例如:order -> __shadow_order
*/
public class ShadowTableRewriter {
private static final String SHADOW_PREFIX = "__shadow_";
/**
* 改写 SQL 中的表名为影子表名
*/
public String rewrite(String sql, List<String> tableNames) {
if (!ShadowFlag.isShadow()) {
return sql;
}
String rewritten = sql;
for (String table : tableNames) {
rewritten = rewritten.replace(table, SHADOW_PREFIX + table);
}
return rewritten;
}
}4.3 压测流量模型构建
压测流量模型需要尽可能还原双十一零点的真实访问模式:
"""
压测流量模型生成器
根据历史数据分析,构建符合双十一流量分布的压测模型
"""
import random
import time
from dataclasses import dataclass
from typing import List
@dataclass
class TrafficModel:
"""流量模型定义"""
qps_curve: List[float] # 每秒 QPS 曲线
api_distribution: dict # API 调用比例
user_behavior_chain: List[str] # 用户行为链
hot_item_ratio: float # 热点商品比例
cart_size_distribution: dict # 购物车大小分布
def build_double11_model() -> TrafficModel:
"""构建双十一零点流量模型"""
# QPS 曲线:模拟零点前 10 秒到零点后 300 秒的流量变化
# 零点前缓慢上升,零点瞬间达到峰值,然后缓慢下降
qps_curve = []
for t in range(-10, 301):
if t < 0:
# 零点前:指数上升
qps = 50000 * (2 ** (t / 3.0))
elif t == 0:
# 零点:峰值
qps = 583000
elif t <= 5:
# 峰值持续 5 秒
qps = 583000 * (1 - 0.02 * t)
elif t <= 60:
# 快速下降
qps = 500000 * (0.9 ** ((t - 5) / 10.0))
else:
# 平稳期
qps = 200000 + random.gauss(0, 5000)
qps_curve.append(max(0, qps))
# API 调用比例:基于历史数据
api_distribution = {
"query_item": 0.35, # 商品查询
"add_cart": 0.15, # 加购物车
"create_order": 0.20, # 下单
"pay_order": 0.15, # 支付
"query_order": 0.10, # 查询订单
"query_logistics": 0.05, # 查物流
}
# 用户行为链:典型的购买路径
user_behavior_chain = [
"browse_item",
"add_to_cart",
"checkout",
"confirm_order",
"pay",
"query_order_status",
]
return TrafficModel(
qps_curve=qps_curve,
api_distribution=api_distribution,
user_behavior_chain=user_behavior_chain,
hot_item_ratio=0.2,
cart_size_distribution={1: 0.3, 2: 0.25, 3: 0.2, 5: 0.15, 10: 0.1},
)
def generate_pressure_plan(model: TrafficModel, target_peak_qps: int) -> dict:
"""生成压测计划"""
scale_factor = target_peak_qps / max(model.qps_curve)
scaled_curve = [int(qps * scale_factor) for qps in model.qps_curve]
return {
"total_duration_sec": len(scaled_curve),
"peak_qps": target_peak_qps,
"qps_curve": scaled_curve,
"api_distribution": model.api_distribution,
"estimated_total_requests": sum(scaled_curve),
}4.4 压测数据清理
压测结束后必须清理影子数据,防止残留数据影响后续业务:
-- 影子表数据清理脚本
-- 在压测结束后执行
-- 清理影子订单表
TRUNCATE TABLE __shadow_order;
-- 清理影子支付表
TRUNCATE TABLE __shadow_payment;
-- 清理影子库存变更日志
DELETE FROM __shadow_inventory_log
WHERE gmt_create >= '2026-10-20 00:00:00'
AND gmt_create <= '2026-10-21 00:00:00';
-- 重置影子序列号
ALTER TABLE __shadow_order AUTO_INCREMENT = 1;
-- 验证清理结果
SELECT '__shadow_order' AS table_name, COUNT(*) AS remaining_rows
FROM __shadow_order
UNION ALL
SELECT '__shadow_payment', COUNT(*)
FROM __shadow_payment
UNION ALL
SELECT '__shadow_inventory_log', COUNT(*)
FROM __shadow_inventory_log;4.5 压测平台架构
graph TB
subgraph 压测控制台
Console["压测控制台 Web"]
SceneManager["场景管理"]
ReportEngine["报告引擎"]
end
subgraph 流量引擎
TrafficEngine["流量调度引擎"]
AgentCluster["压测 Agent 集群"]
ModelGen["流量模型生成"]
end
subgraph 数据隔离层
ShadowRouter["影子路由"]
ShadowDB["影子数据库"]
ShadowMQ["影子消息队列"]
ShadowCache["影子缓存空间"]
end
subgraph 监控层
RealTimeMonitor["实时监控大盘"]
AlarmSystem["异常熔断系统"]
CompareAnalysis["基线对比分析"]
end
Console --> TrafficEngine
SceneManager --> ModelGen
ModelGen --> TrafficEngine
TrafficEngine --> AgentCluster
AgentCluster -->|压测流量| ShadowRouter
ShadowRouter --> ShadowDB
ShadowRouter --> ShadowMQ
ShadowRouter --> ShadowCache
AgentCluster -->|指标上报| RealTimeMonitor
RealTimeMonitor --> AlarmSystem
AlarmSystem -->|自动停止| TrafficEngine
RealTimeMonitor --> CompareAnalysis
CompareAnalysis --> ReportEngine
五、弹性伸缩与容量规划
5.1 容量评估模型
双十一的容量规划始于大促前 3 个月。容量评估的核心公式:
所需机器数 = 峰值 QPS × 单请求资源消耗 × 安全系数 / 单机处理能力
其中:
- 峰值 QPS:根据业务预测,通常取去年峰值的 1.5 倍
- 单请求资源消耗:CPU 时间 + 内存占用 + IO 次数的综合指标
- 安全系数:通常取 1.5-2.0,预留容灾和突发余量
- 单机处理能力:通过单机压测得出的稳定处理上限
5.2 弹性伸缩策略
/**
* 弹性伸缩决策引擎
* 根据实时指标和预测模型决定扩缩容
*/
public class AutoScalingEngine {
// 扩容触发阈值
private static final double CPU_SCALE_UP_THRESHOLD = 0.70;
// 缩容触发阈值
private static final double CPU_SCALE_DOWN_THRESHOLD = 0.30;
// 最小观测窗口(秒)
private static final int OBSERVATION_WINDOW = 60;
// 冷却时间(秒),避免频繁伸缩
private static final int COOLDOWN_PERIOD = 300;
/**
* 计算目标实例数
*/
public ScalingDecision evaluate(ClusterMetrics metrics) {
double avgCpu = metrics.getAvgCpuUsage();
double avgMemory = metrics.getAvgMemoryUsage();
int currentInstances = metrics.getCurrentInstanceCount();
double avgRt = metrics.getAvgResponseTimeMs();
// 多维度综合判断
if (avgCpu > CPU_SCALE_UP_THRESHOLD || avgRt > 200) {
// 计算需要扩容到多少实例
double targetCpuUsage = 0.50;
int targetInstances = (int) Math.ceil(
currentInstances * avgCpu / targetCpuUsage
);
// 单次扩容不超过当前实例数的 50%
int maxScaleUp = (int) (currentInstances * 1.5);
targetInstances = Math.min(targetInstances, maxScaleUp);
return new ScalingDecision(
ScalingAction.SCALE_UP,
targetInstances,
String.format("CPU=%.1f%%, RT=%.0fms", avgCpu * 100, avgRt)
);
}
if (avgCpu < CPU_SCALE_DOWN_THRESHOLD && avgRt < 50) {
int targetInstances = (int) Math.ceil(
currentInstances * avgCpu / 0.50
);
// 至少保留最小实例数
targetInstances = Math.max(targetInstances, getMinInstances());
return new ScalingDecision(
ScalingAction.SCALE_DOWN,
targetInstances,
String.format("CPU=%.1f%%, RT=%.0fms", avgCpu * 100, avgRt)
);
}
return new ScalingDecision(ScalingAction.NO_OP, currentInstances, "stable");
}
private int getMinInstances() {
return 3;
}
}5.3 混部与资源借调
双十一期间,阿里巴巴通过”资源借调”机制在不同业务间调配计算资源:
- 离线让在线:大促期间暂停非紧急的离线计算任务(如数据仓库 ETL),释放计算资源给在线服务
- 低优先级让高优先级:搜索推荐等非核心链路降级运行,将资源让给交易支付链路
- 弹性容器:使用 Pouch 容器在秒级完成资源分配和服务部署
| 资源调配策略 | 可释放资源比例 | 恢复时间 | 业务影响 |
|---|---|---|---|
| 离线任务暂停 | 30%-40% | 分钟级 | 离线报表延迟 |
| 搜索降级 | 10%-15% | 秒级 | 搜索相关性下降 |
| 推荐降级 | 5%-10% | 秒级 | 推荐精度下降 |
| 日志采样 | 5%-8% | 秒级 | 日志完整性降低 |
| 图片降质 | 3%-5% | 秒级 | 图片清晰度降低 |
六、交易链路的高可用设计
6.1 多级限流体系
阿里巴巴的限流体系从接入层到服务层共分四级:
/**
* Sentinel 限流规则配置示例
* 实现令牌桶 + 滑动窗口的多层限流
*/
public class SentinelConfig {
/**
* 配置交易接口的限流规则
*/
public static void initFlowRules() {
List<FlowRule> rules = new ArrayList<>();
// 第一层:接口级别限流(集群维度)
FlowRule clusterRule = new FlowRule();
clusterRule.setResource("createOrder");
clusterRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
clusterRule.setCount(100000);
clusterRule.setClusterMode(true);
clusterRule.setClusterConfig(
new ClusterFlowConfig()
.setFlowId(1001L)
.setThresholdType(ClusterRuleConstant.FLOW_THRESHOLD_GLOBAL)
);
rules.add(clusterRule);
// 第二层:单机级别限流
FlowRule localRule = new FlowRule();
localRule.setResource("createOrder");
localRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
localRule.setCount(500);
localRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP);
localRule.setWarmUpPeriodSec(10);
rules.add(localRule);
// 第三层:热点参数限流(防止单商品被刷)
// 限制单个商品 ID 的下单 QPS
ParamFlowRule hotRule = new ParamFlowRule();
hotRule.setResource("createOrder");
hotRule.setParamIdx(0);
hotRule.setCount(50);
hotRule.setDurationInSec(1);
FlowRuleManager.loadRules(rules);
}
}6.2 多级降级策略
| 降级级别 | 触发条件 | 降级动作 | 恢复策略 |
|---|---|---|---|
| L0 预警 | RT > 100ms 或 CPU > 60% | 关闭非核心功能(推荐、评价) | 指标恢复后自动开启 |
| L1 轻度 | RT > 300ms 或 错误率 > 1% | 返回缓存数据,关闭个性化 | 人工确认后恢复 |
| L2 中度 | RT > 1s 或 错误率 > 5% | 核心链路静态化,关闭库存实时校验 | 人工确认 + 数据校验后恢复 |
| L3 重度 | 服务不可用 | 全站降级页面,仅保留核心下单支付 | 故障恢复后逐步放开 |
6.3 预案系统
阿里巴巴的预案系统是一套自动化的故障应对框架。所有可能的故障场景都被预先编排成可执行的预案:
/**
* 预案执行引擎
* 预案是一组原子操作的有序编排
*/
public class ContingencyPlanEngine {
private final Map<String, ContingencyPlan> planRegistry = new ConcurrentHashMap<>();
/**
* 注册预案
*/
public void register(ContingencyPlan plan) {
planRegistry.put(plan.getId(), plan);
}
/**
* 执行预案
*/
public PlanResult execute(String planId, Map<String, Object> context) {
ContingencyPlan plan = planRegistry.get(planId);
if (plan == null) {
return PlanResult.notFound(planId);
}
List<ActionResult> actionResults = new ArrayList<>();
for (PlanAction action : plan.getActions()) {
try {
ActionResult result = action.execute(context);
actionResults.add(result);
if (!result.isSuccess() && action.isRequired()) {
// 必要步骤失败,中止预案并回滚已执行步骤
rollback(actionResults);
return PlanResult.failed(planId, actionResults);
}
} catch (Exception e) {
actionResults.add(ActionResult.error(action.getName(), e));
if (action.isRequired()) {
rollback(actionResults);
return PlanResult.failed(planId, actionResults);
}
}
}
return PlanResult.success(planId, actionResults);
}
/**
* 回滚已执行的操作
*/
private void rollback(List<ActionResult> results) {
// 逆序回滚
for (int i = results.size() - 1; i >= 0; i--) {
ActionResult result = results.get(i);
if (result.isSuccess() && result.getRollbackAction() != null) {
try {
result.getRollbackAction().execute(Collections.emptyMap());
} catch (Exception e) {
// 回滚失败记录告警,人工介入
log.error("Rollback failed for action: {}", result.getActionName(), e);
}
}
}
}
}6.4 秒杀系统设计
秒杀场景是双十一最极端的流量形态。阿里的秒杀系统采用分层过滤的思路:
用户请求(1000 万/秒)
↓ CDN 静态化(过滤 90%)
用户端请求(100 万/秒)
↓ 接入层限流(过滤 80%)
有效请求(20 万/秒)
↓ 本地库存预扣减(过滤 99%)
实际扣减(2000/秒)
↓ 数据库写入
每一层的过滤都基于一个原则:尽早拒绝无效请求,减少下游压力。
七、消息中间件 RocketMQ
7.1 RocketMQ 在交易链路中的角色
RocketMQ 是阿里巴巴自研的分布式消息中间件,在双十一交易链路中承担异步解耦和削峰填谷的核心职责。
主要使用场景:
- 订单创建后的异步通知:下单成功后,通过消息通知库存扣减、物流预分配、积分累加等下游服务
- 分布式事务的最终一致性:使用事务消息保证跨服务的数据一致性
- 削峰填谷:将瞬时的写入高峰平滑成下游可承受的速率
7.2 事务消息机制
/**
* RocketMQ 事务消息使用示例
* 场景:下单时需要同时扣减库存,保证订单和库存的一致性
*/
public class OrderTransactionProducer {
private final TransactionMQProducer producer;
public OrderTransactionProducer() {
this.producer = new TransactionMQProducer("order_transaction_group");
this.producer.setNamesrvAddr("namesrv1:9876;namesrv2:9876");
this.producer.setTransactionListener(new OrderTransactionListener());
}
/**
* 发送事务消息
* 流程:
* 1. 发送 Half 消息到 Broker
* 2. Broker 返回成功后,执行本地事务(创建订单)
* 3. 根据本地事务结果,提交或回滚消息
* 4. 消费者收到消息后扣减库存
*/
public SendResult createOrderWithTransaction(OrderDTO order) throws Exception {
Message msg = new Message(
"ORDER_TOPIC",
"CREATE",
order.getOrderId().getBytes(),
JSON.toJSONBytes(order)
);
// 将订单信息作为参数传递给本地事务执行器
return producer.sendMessageInTransaction(msg, order);
}
}
/**
* 事务消息监听器
*/
public class OrderTransactionListener implements TransactionListener {
private final OrderService orderService;
private final TransactionLogMapper txLogMapper;
/**
* 执行本地事务
* 在 Half 消息发送成功后被回调
*/
@Override
public LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
OrderDTO order = (OrderDTO) arg;
try {
// 执行本地事务:创建订单 + 记录事务日志
orderService.createOrder(order);
txLogMapper.insert(new TransactionLog(
order.getOrderId(),
"ORDER_CREATE",
"SUCCESS"
));
return LocalTransactionState.COMMIT_MESSAGE;
} catch (Exception e) {
return LocalTransactionState.ROLLBACK_MESSAGE;
}
}
/**
* 事务回查
* 当 Broker 长时间未收到提交/回滚指令时回调
* 通过查询事务日志判断本地事务是否执行成功
*/
@Override
public LocalTransactionState checkLocalTransaction(MessageExt msg) {
String orderId = new String(msg.getKeys().getBytes());
TransactionLog log = txLogMapper.findByOrderId(orderId);
if (log != null && "SUCCESS".equals(log.getStatus())) {
return LocalTransactionState.COMMIT_MESSAGE;
}
return LocalTransactionState.ROLLBACK_MESSAGE;
}
}7.3 消息堆积与背压
双十一峰值期间,下游消费速度跟不上生产速度是常态。RocketMQ 通过以下机制应对:
- 磁盘级堆积:消息持久化到磁盘,单个 Broker 可堆积数十亿条消息
- 消费者扩容:动态增加消费者实例数(不超过队列数)
- 消费降速:当消费者处理能力不足时,主动降低拉取频率
- 死信队列:消费失败超过阈值的消息进入死信队列(Dead Letter Queue),后续人工处理
八、分布式事务解决方案
8.1 阿里巴巴的事务模式选择
不同场景下的分布式事务方案对比:
| 事务模式 | 一致性级别 | 性能开销 | 适用场景 | 阿里实际应用 |
|---|---|---|---|---|
| TCC(Try-Confirm-Cancel) | 强一致 | 高(三次网络调用) | 资金交易 | 支付宝核心支付链路 |
| Saga | 最终一致 | 中 | 长事务流程 | 物流履约链路 |
| 事务消息 | 最终一致 | 低 | 异步解耦场景 | 订单 -> 库存通知 |
| AT(Auto Transaction) | 最终一致 | 低 | 通用数据库操作 | Seata 框架默认模式 |
| XA | 强一致 | 极高(两阶段锁) | 对一致性要求极高的场景 | 极少使用 |
8.2 TCC 模式实现
/**
* TCC 分布式事务示例:转账场景
* Try:冻结金额
* Confirm:扣减冻结金额,增加对方余额
* Cancel:解冻金额
*/
public interface AccountTccService {
/**
* Try 阶段:冻结转出金额
* 在 account 表中将 amount 从 balance 转移到 frozen
*/
@TwoPhaseBusinessAction(
name = "accountTransfer",
commitMethod = "confirm",
rollbackMethod = "cancel"
)
boolean tryFreezeAmount(
BusinessActionContext context,
@BusinessActionContextParameter(paramName = "accountId") String accountId,
@BusinessActionContextParameter(paramName = "amount") BigDecimal amount
);
/**
* Confirm 阶段:确认扣减
* 将 frozen 中的金额正式扣除
*/
boolean confirm(BusinessActionContext context);
/**
* Cancel 阶段:取消冻结
* 将 frozen 中的金额还原到 balance
*/
boolean cancel(BusinessActionContext context);
}
/**
* TCC 服务实现
*/
public class AccountTccServiceImpl implements AccountTccService {
private final AccountMapper accountMapper;
private final TccTransactionLogMapper logMapper;
@Override
public boolean tryFreezeAmount(
BusinessActionContext context, String accountId, BigDecimal amount
) {
// 幂等检查:防止重复冻结
String xid = context.getXid();
if (logMapper.existsByXid(xid)) {
return true;
}
// 检查余额是否充足
Account account = accountMapper.selectForUpdate(accountId);
if (account.getBalance().compareTo(amount) < 0) {
throw new InsufficientBalanceException(accountId, amount);
}
// 冻结金额:balance 减少,frozen 增加
accountMapper.freezeAmount(accountId, amount);
// 记录事务日志
logMapper.insert(new TccTransactionLog(xid, accountId, amount, "TRY"));
return true;
}
@Override
public boolean confirm(BusinessActionContext context) {
String xid = context.getXid();
String accountId = (String) context.getActionContext("accountId");
BigDecimal amount = new BigDecimal(
context.getActionContext("amount").toString()
);
// 幂等检查
TccTransactionLog log = logMapper.findByXid(xid);
if (log != null && "CONFIRMED".equals(log.getStatus())) {
return true;
}
// 确认扣减:减少 frozen
accountMapper.confirmDeduction(accountId, amount);
// 更新事务日志
logMapper.updateStatus(xid, "CONFIRMED");
return true;
}
@Override
public boolean cancel(BusinessActionContext context) {
String xid = context.getXid();
String accountId = (String) context.getActionContext("accountId");
BigDecimal amount = new BigDecimal(
context.getActionContext("amount").toString()
);
// 幂等检查
TccTransactionLog log = logMapper.findByXid(xid);
if (log == null) {
// 空回滚:Try 未执行,直接记录日志防悬挂
logMapper.insert(new TccTransactionLog(xid, accountId, amount, "CANCELLED"));
return true;
}
if ("CANCELLED".equals(log.getStatus())) {
return true;
}
// 取消冻结:frozen 减少,balance 增加
accountMapper.unfreezeAmount(accountId, amount);
// 更新事务日志
logMapper.updateStatus(xid, "CANCELLED");
return true;
}
}8.3 Seata AT 模式
Seata(原 Fescar)是阿里巴巴开源的分布式事务框架。AT 模式通过自动生成反向 SQL 实现低侵入的分布式事务:
/**
* Seata AT 模式使用示例
* 只需在业务方法上添加 @GlobalTransactional 注解
* Seata 自动完成分支事务注册、提交和回滚
*/
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private InventoryFeignClient inventoryClient;
@Autowired
private AccountFeignClient accountClient;
/**
* 创建订单的全局事务
* Seata 在 SQL 执行前后自动记录 undo_log
* 如果任何分支失败,自动回滚所有分支
*/
@GlobalTransactional(name = "create-order", timeoutMills = 30000)
@Override
public OrderResult createOrder(OrderRequest request) {
// 分支一:创建订单记录
Order order = new Order();
order.setOrderId(IdGenerator.nextId());
order.setBuyerId(request.getBuyerId());
order.setItemId(request.getItemId());
order.setQuantity(request.getQuantity());
order.setTotalAmount(request.getTotalAmount());
order.setStatus("CREATED");
orderMapper.insert(order);
// 分支二:扣减库存(远程调用,Seata 自动传播事务上下文)
inventoryClient.deduct(request.getItemId(), request.getQuantity());
// 分支三:扣减账户余额
accountClient.debit(request.getBuyerId(), request.getTotalAmount());
return new OrderResult(order.getOrderId(), "SUCCESS");
}
}九、工程案例:双十一零点峰值应对
9.1 2024 年双十一时间线
以下是 2024 年双十一零点前后的关键操作时间线(基于公开技术分享还原):
T-72h(10月29日)
├── 完成最后一轮全链路压测,峰值达到 60 万笔/秒
├── 压测报告确认各服务水位均在安全线以下
└── 锁定所有代码变更,进入封网期
T-24h(10月30日)
├── 弹性扩容完成:在线服务器从日常 5 万台扩至 12 万台
├── CDN 预热完成:热点商品详情页命中率达 99.8%
├── 全部降级预案就绪,完成一轮空跑验证
└── 数据库只读副本扩至日常的 3 倍
T-4h(10月31日 20:00)
├── 运维作战室集合,各业务线负责人就位
├── 启动实时监控大盘,各指标基线校准
└── 关闭非核心定时任务和离线计算作业
T-1h(10月31日 23:00)
├── 启动 L0 预降级:关闭个性化推荐、评价展示
├── 开启秒杀商品本地库存预加载
└── 消息队列预创建额外分区
T-10min(10月31日 23:50)
├── 切换至大促限流配置
├── 启动流量预热:逐步放入预约用户流量
└── 确认所有 RZone 状态正常
T-0(11月1日 00:00:00)
├── 峰值瞬间到达:58.3 万笔/秒
├── 各服务 CPU 水位 65%-72%
├── 数据库主库 IOPS 达到 95% 预分配容量
├── 零错误率,RT P99 = 380ms
└── 消息堆积在 10 秒内消化完毕
T+5min
├── 流量回落至峰值的 60%
├── 关闭 L0 预降级
└── 恢复个性化推荐
T+30min
├── 流量稳定在日常的 8 倍
├── 开始弹性缩容第一批机器
└── 离线计算作业逐步恢复
T+24h
├── 弹性缩容完成,恢复日常规模
├── 全量数据校验:订单和库存一致性 100%
└── 压测影子数据清理完成
9.2 零点峰值的技术挑战
双十一零点的流量特征与日常完全不同:
- 瞬时脉冲:从零到峰值的爬升时间不到 1 秒,远超常规限流算法的滑动窗口粒度
- 热点集中:前 100 个爆款商品承担了 30% 以上的访问量
- 强关联性:下单、扣库存、支付三个操作紧密耦合,任何一个环节出问题都会导致用户体验崩塌
- 不可重来:双十一只有一次,没有”明天再试”的机会
9.3 核心应对策略详解
策略一:库存预分桶
将热点商品的库存提前按 RZone 分桶,避免所有扣减请求打到同一行数据:
/**
* 库存预分桶方案
* 将一件商品的 10000 件库存分散到 8 个 RZone
*/
public class InventoryBucketService {
private static final int BUCKET_COUNT = 8;
/**
* 初始化库存分桶
* 将总库存均匀分配到各个桶
*/
public void initBuckets(String itemId, int totalStock) {
int perBucket = totalStock / BUCKET_COUNT;
int remainder = totalStock % BUCKET_COUNT;
for (int i = 0; i < BUCKET_COUNT; i++) {
int bucketStock = perBucket + (i < remainder ? 1 : 0);
inventoryMapper.insertBucket(new InventoryBucket(
itemId,
i,
bucketStock,
bucketStock
));
}
}
/**
* 扣减库存
* 先尝试本地桶,不足时向其他桶借调
*/
public boolean deductStock(String itemId, int quantity, int localBucketId) {
// 尝试本地桶扣减
int affected = inventoryMapper.deductBucket(itemId, localBucketId, quantity);
if (affected > 0) {
return true;
}
// 本地桶不足,尝试从其他桶借调
for (int i = 0; i < BUCKET_COUNT; i++) {
if (i == localBucketId) {
continue;
}
affected = inventoryMapper.deductBucket(itemId, i, quantity);
if (affected > 0) {
return true;
}
}
return false;
}
}策略二:异步化下单链路
将下单流程从同步改为异步排队,削平峰值写入压力:
/**
* 异步下单队列
* 用户点击"立即购买"后进入排队
* 后端按照数据库写入能力匀速处理
*/
public class AsyncOrderProcessor {
// 内存队列容量
private static final int QUEUE_CAPACITY = 100000;
private final BlockingQueue<OrderRequest> orderQueue =
new LinkedBlockingQueue<>(QUEUE_CAPACITY);
// 消费线程池
private final ExecutorService executor =
Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
/**
* 接收下单请求,放入队列
* 如果队列已满,直接返回"系统繁忙"
*/
public OrderResponse submitOrder(OrderRequest request) {
boolean offered = orderQueue.offer(request);
if (!offered) {
return OrderResponse.busy("系统繁忙,请稍后重试");
}
return OrderResponse.queued(request.getRequestId());
}
/**
* 消费线程:持续从队列取出请求并处理
*/
public void startConsumers() {
for (int i = 0; i < executor.toString().length(); i++) {
executor.submit(() -> {
while (!Thread.currentThread().isInterrupted()) {
try {
OrderRequest request = orderQueue.poll(100, TimeUnit.MILLISECONDS);
if (request != null) {
processOrder(request);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
});
}
}
private void processOrder(OrderRequest request) {
try {
OrderResult result = orderService.createOrder(request);
// 通过长连接推送结果给前端
pushService.pushOrderResult(request.getUserId(), result);
} catch (Exception e) {
pushService.pushOrderResult(
request.getUserId(),
OrderResult.failed(request.getRequestId(), e.getMessage())
);
}
}
}策略三:多级缓存体系
请求进入
↓
浏览器本地缓存(LocalStorage,5 分钟有效)
↓ 未命中
CDN 边缘缓存(全球 2800+ 节点,缓存商品详情页)
↓ 未命中
Nginx 本地缓存(Lua 脚本 + Shared Dict,热点商品 10s 缓存)
↓ 未命中
Tair 分布式缓存(集群模式,毫秒级响应)
↓ 未命中
数据库(MySQL / OceanBase)
9.4 故障复盘:2015 年双十一的一次惊险事故
2015 年双十一,阿里巴巴经历了一次未公开的惊险事故。根据事后技术分享中的线索还原:
事故现象:零点后约 3 分钟,某核心服务的 GC(Garbage Collection)时间突然从 50ms 飙升至 2s,导致该服务的所有下游调用超时。
根因分析:该服务使用了一个本地缓存组件,缓存淘汰策略是 LRU(Least Recently Used)。零点流量涌入后,缓存淘汰速度远超预期,大量短生命周期的对象被创建和销毁,触发了 JVM 的 Full GC。
应急处理:
- T+3min:监控告警,值班 SRE 收到告警
- T+5min:确认故障范围,该服务的 RT 从 20ms 涨到 3s
- T+7min:执行预案,将受影响 RZone 的流量切换到备用 RZone
- T+10min:流量切换完成,用户无感
- T+15min:对故障实例做 JVM 参数调整,重启服务
- T+30min:流量切回,系统恢复正常
事后改进:
- 将本地缓存的淘汰策略从 LRU 改为 W-TinyLFU,降低缓存抖动
- JVM 参数中增加
-XX:+UseG1GC和-XX:MaxGCPauseMillis=100,限制 GC 停顿时间 - 在全链路压测中增加”缓存冷启动”场景,模拟缓存空载时的流量冲击
- 每个服务增加 GC 时间的 P99 监控项,超过 500ms 自动触发告警
十、流量工程的核心经验
10.1 十条原则
经过十余年双十一的锤炼,阿里巴巴总结出流量工程的十条核心原则:
第一,可预见的峰值用容量解决,不可预见的峰值用弹性解决。 双十一的峰值是已知的,提前扩容是最直接的手段。但日常运营中的突发流量(如直播带货的瞬时爆发)需要弹性伸缩机制来应对。
第二,没有经过验证的容量等于没有容量。 扩容后必须通过全链路压测验证实际承载能力。曾经出现过扩容后因网络带宽不足导致实际容量未达预期的案例。
第三,故障是常态,容错是底线。 在数万台服务器的规模下,每天都有机器故障。架构设计必须假定任何组件随时可能失败。
第四,限流是保护系统的最后一道防线。 当所有优化手段都无法应对流量时,限流确保系统不会被压垮。宁可拒绝部分用户,也不能让所有用户都无法使用。
第五,异步化是提升吞吐量的核心手段。 能异步处理的业务尽量异步化,减少同步调用链的长度和耦合度。
第六,缓存是性能优化的第一选择。 多级缓存体系将大部分读请求拦截在离用户最近的地方,大幅降低后端压力。
第七,数据分片是水平扩展的基础。 无论是数据库分库分表还是服务单元化,本质都是通过数据分片将负载分散到多个节点。
第八,可观测性是问题定位的前提。 完善的监控、日志和链路追踪系统,是快速发现和定位问题的基础。阿里的全链路追踪系统 EagleEye(鹰眼)可以在秒级定位到问题节点。
第九,预案演练比预案本身更重要。 写在文档里的预案如果没有演练过,在真正故障时大概率无法顺利执行。阿里每年会进行数十次故障演练。
第十,技术架构服务于业务目标。 所有架构决策最终都要回归到业务价值。过度设计和设计不足一样有害。
10.2 不同规模的流量工程方案选择
| 日均 QPS | 建议架构 | 数据库方案 | 缓存方案 | 消息队列 |
|---|---|---|---|---|
| < 1 万 | 单体应用 | 单实例 MySQL 主从 | 本地缓存(Caffeine) | 可选 |
| 1-10 万 | 微服务 | 读写分离 + 分表 | Redis Cluster | Kafka / RocketMQ |
| 10-100 万 | 微服务 + 服务网格 | 分库分表 + 读写分离 | 多级缓存 | RocketMQ 集群 |
| > 100 万 | 单元化架构 | 异地多活分库分表 | CDN + 本地 + 分布式缓存 | 多集群消息 |
10.3 从阿里实践中可以复用的设计模式
即使不是阿里的体量,以下设计模式在中小规模系统中也有实用价值:
- 影子流量测试:在生产环境中复制一份流量到测试环境,验证新版本的正确性
- 分桶计数器:将热点计数器分散到多个桶,降低锁竞争
- 预案自动化:将常见故障场景的处理流程编排成自动化脚本
- 渐进式发布:灰度发布从 1% -> 5% -> 20% -> 50% -> 100% 逐步放量
- 熔断器模式:当下游服务故障率超过阈值时自动断开调用,快速失败
/**
* 分桶计数器实现
* 适用于高并发场景下的计数需求(如库存、秒杀)
* 将单一计数器拆分为多个桶,降低 CAS 竞争
*/
public class BucketCounter {
private final AtomicLong[] buckets;
private final int bucketCount;
public BucketCounter(int bucketCount) {
this.bucketCount = bucketCount;
this.buckets = new AtomicLong[bucketCount];
for (int i = 0; i < bucketCount; i++) {
buckets[i] = new AtomicLong(0);
}
}
/**
* 递增计数
* 使用线程 ID 哈希选择桶,分散竞争
*/
public void increment() {
int index = (int) (Thread.currentThread().getId() % bucketCount);
buckets[index].incrementAndGet();
}
/**
* 递减计数
*/
public boolean decrement() {
int index = (int) (Thread.currentThread().getId() % bucketCount);
long current = buckets[index].get();
if (current > 0) {
return buckets[index].compareAndSet(current, current - 1);
}
// 本桶不足,尝试其他桶
for (int i = 0; i < bucketCount; i++) {
if (i == index) continue;
current = buckets[i].get();
if (current > 0 && buckets[i].compareAndSet(current, current - 1)) {
return true;
}
}
return false;
}
/**
* 获取总计数
*/
public long getTotal() {
long total = 0;
for (AtomicLong bucket : buckets) {
total += bucket.get();
}
return total;
}
/**
* 设置总计数(均匀分配到各桶)
*/
public void setTotal(long total) {
long perBucket = total / bucketCount;
long remainder = total % bucketCount;
for (int i = 0; i < bucketCount; i++) {
buckets[i].set(perBucket + (i < remainder ? 1 : 0));
}
}
}10.4 流量工程的技术演进方向
展望未来,阿里巴巴的流量工程正在向以下方向演进:
- Serverless 化:将更多业务逻辑迁移到函数计算(FC)平台,实现真正的按需弹性
- AI 驱动的容量规划:使用机器学习模型预测流量,自动生成扩缩容计划
- Service Mesh 统一流量治理:通过 Sidecar 代理统一实现限流、熔断、路由,与业务代码彻底解耦
- 混合云弹性:利用公有云的弹性资源应对峰值,日常使用自有数据中心
参考资料
- 林昊.《大规模分布式存储系统:原理解析与架构实践》. 机械工业出版社,2013.
- 阿里巴巴中间件团队.《阿里巴巴中间件技术发展史》. InfoQ 中国,2019.
- 阿里巴巴技术团队.《双 11 技术全景:全链路压测实践》. 阿里技术公众号,2020.
- 李运华.《从零开始学架构》. 电子工业出版社,2018.
- Apache RocketMQ 官方文档. https://rocketmq.apache.org/docs/
- Seata 官方文档. https://seata.io/zh-cn/docs/overview/what-is-seata.html
- 阿里巴巴技术团队.《单元化架构实践》. ArchSummit 全球架构师峰会演讲,2017.
- 毕玄.《阿里技术架构演进》. QCon 全球软件开发大会,2016.
- 阿里云开发者社区.《TDDL 分库分表原理与实践》. 2019.
- 阿里巴巴技术团队.《双十一背后的弹性伸缩实践》. 阿里技术公众号,2023.
上一篇: 微信架构 下一篇: Google 基础设施
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【系统架构设计百科】架构质量属性:不只是"高可用高性能"
需求评审时写下的'高可用、高性能、高并发',到了架构设计阶段几乎无法落地——因为它们不是可执行的需求。本文从 SEI/CMU 的质量属性理论出发,用 stimulus-response 场景模型把模糊需求变成可量化、可验证的架构约束,并拆解属性之间的冲突与联动关系。
【系统架构设计百科】告警策略:如何避免"狼来了"
大多数团队的告警系统都在制造噪声而不是传递信号。阈值告警看似直观,实则产生大量误报和漏报,值班工程师在凌晨三点被叫醒,却发现只是一次无害的毛刺。本文从告警疲劳的工业数据出发,拆解基于 SLO 的多窗口燃烧率告警算法,深入 Alertmanager 的路由、抑制与分组机制,结合 PagerDuty 的告警疲劳研究和真实工程案例,给出一套可落地的告警策略设计方法。
【系统架构设计百科】复杂性管理:架构的核心战场
系统复杂性是架构腐化的根源——本文从 Brooks 的本质复杂性与偶然复杂性划分出发,结合认知负荷理论与 Parnas 的信息隐藏原则,系统阐述复杂性的来源、度量与控制手段,并给出可操作的架构策略
【系统架构设计百科】微服务架构深度审视:优势、代价与适用边界
微服务不是免费的午餐。本文从分布式系统八大谬误出发,拆解微服务真正解决的问题与引入的代价,梳理服务边界划分的工程方法论,还原 Amazon 和 Netflix 从单体到微服务的真实演进时间线,给出微服务适用与不适用的判断框架。