阿里架构
2003 年 5 月 10 日,一个叫「淘宝」的网站悄然上线。那时候,eBay 已经收购了中国最大的 C2C 电商网站易趣(Eachnet),占据了超过 90% 的市场份额。eBay 的中国区负责人信心满满地宣称:「淘宝不可能活过 18 个月。」
马云的回答是:「eBay 是大海里的鲨鱼,而我们是长江里的扬子鳄。如果我们还竞争不过大海里的鲨鱼,就到长江里去生存。」
淘宝用了三年时间,从零做到了中国市场第一。它做对了几件事:免费(eBay 收上架费,淘宝不收);担保交易(支付宝,解决信任问题);本土化运营。技术上的秘密武器是:阿里技术团队自己写了一个完全不同于 eBay 的分布式架构,能够用远低于 eBay 的成本支撑更高的交易量。
这个故事的背景是:阿里的技术挑战,是全球电商领域里最极端的场景之一——双十一的峰值流量,是平时的数十倍甚至上百倍。这种量级的流量波动,在全球任何其他电商平台都不存在。
公司画像
阿里巴巴集团(Alibaba Group)由马云于 1999 年在杭州创立,最初是一个 B2B(企业对企业)批发平台(Alibaba.com),帮助中国制造商对接海外买家。2003 年推出 C2C 平台淘宝(Taobao.com),2008 年推出 B2C 平台天猫(Tmall.com),2014 年在美国纽交所上市。
理解阿里技术挑战的关键,在于两个数字:
- 双十一峰值:2021 年,天猫双十一订单创建峰值达到 54.4 万笔/秒,支付峰值 10.5 万笔/秒
- 日常规模:淘宝日活用户超过 3 亿,每秒处理的搜索请求超过 100 万次
阿里与其他大厂的区别在于:Google、Netflix、Uber 的技术挑战是「如何让系统更稳定、更快」,而阿里的核心挑战是「如何在流量暴涨 100 倍时,系统不崩溃,事后还能正常缩回去」。
每年双十一,阿里的技术团队要做的事情就像:把一个只能容纳 1000 人的场馆,改造成能容纳 10 万人的场地——然后在活动结束后,用一个小时把它恢复到原来的状态。这中间任何一个环节出错,都可能造成灾难性的后果。
架构演进时间线
第一阶段:淘宝时代的 LAMP 架构(2003-2008)
以小博大的技术选择
2003 年的淘宝,技术栈简单到不能再简单:一台 Sun 小型机,几个 PC 服务器,跑着 Apache + PHP + MySQL。这个配置在当时跟 eBay 的 Oracle RAC 集群比起来,简直是蚂蚁对大象。
但阿里团队做出了一个关键决策:用应用层的扩展来弥补数据库的不足。
传统的扩容思路是纵向扩展(升级更大的数据库服务器),但阿里选择了横向扩展——把数据按用户 ID 分片(Sharding),每个分片独立数据库。这样即使单个 MySQL 实例的容量有限,整个系统的容量也可以通过增加分片来线性扩展。
// 淘宝早期数据分片策略(示意)
public class OrderShardingStrategy {
// 按用户 ID 哈希分片:userId % 分片数
public int getShardIndex(Long userId, int shardCount) {
return (int) (userId % shardCount);
}
// 路由到具体的数据库连接
public DataSource getDataSource(Long userId) {
int shardIndex = getShardIndex(userId, shardCount);
return dataSources[shardIndex];
}
// 查询订单
public List<Order> findOrdersByUser(Long userId, int offset, int limit) {
DataSource ds = getDataSource(userId);
try (Connection conn = ds.getConnection()) {
// 分片内分页查询
String sql = "SELECT * FROM orders WHERE user_id = ? LIMIT ? OFFSET ?";
return query(conn, sql, userId, limit, offset);
}
}
}
这个阶段淘宝面临的真正问题不是架构有多先进,而是增长速度太快。2004 年双十一,淘宝的访问量是平时的 10 倍,服务器差点撑不住。团队连夜从其他部门借服务器,才勉强扛过去。从那之后,双十一备战成了阿里的年度惯例。
支付宝与担保交易
2004 年底,支付宝上线,解决了 C2C 交易中最核心的信任问题——买家先把钱打给支付宝,收到货确认没问题后,支付宝再把钱打给卖家。这个看起来简单的流程,背后是一套完整的资金托管和清结算系统。
// 支付宝担保交易核心流程
public class EscrowPaymentService {
// 1. 买家付款:资金进入支付宝托管账户
public PaymentResult buyerPay(Long orderId, BigDecimal amount) {
Order order = orderService.findById(orderId);
// 创建托管交易
EscrowTransaction tx = new EscrowTransaction();
tx.setOrderId(orderId);
tx.setBuyerId(order.getBuyerId());
tx.setSellerId(order.getSellerId());
tx.setAmount(amount);
tx.setStatus(TransactionStatus.IN_ESCROW); // 资金在托管中
tx.setCreatedAt(now());
escrowRepo.save(tx);
// 冻结买家账户相应金额
accountService.freeze(order.getBuyerId(), amount);
return PaymentResult.success(tx.getId());
}
// 2. 买家确认收货:资金解冻给卖家
public SettlementResult confirmReceipt(Long orderId) {
Order order = orderService.findById(orderId);
// 验证:只有买家才能确认收货
if (!currentUserId().equals(order.getBuyerId())) {
throw new UnauthorizedException();
}
EscrowTransaction tx = escrowRepo.findByOrderId(orderId);
// 解冻买家资金,并转入卖家账户
accountService.unfreeze(tx.getBuyerId(), tx.getAmount());
accountService.credit(tx.getSellerId(), tx.getAmount());
tx.setStatus(TransactionStatus.RELEASED);
escrowRepo.save(tx);
// 更新订单状态
orderService.updateStatus(orderId, OrderStatus.COMPLETED);
return SettlementResult.success();
}
// 3. 退款:资金退回买家
public RefundResult refund(Long orderId, BigDecimal amount, String reason) {
EscrowTransaction tx = escrowRepo.findByOrderId(orderId);
// 从卖家账户扣款,退回买家
accountService.debit(tx.getSellerId(), amount);
accountService.unfreezeAndCredit(tx.getBuyerId(), amount);
tx.setStatus(TransactionStatus.REFUNDED);
tx.setRefundAmount(amount);
tx.setRefundReason(reason);
escrowRepo.save(tx);
return RefundResult.success();
}
}
第二阶段:去 IOE 运动(2008-2013)
为什么阿里要去 IOE
2008 年,阿里巴巴集团内部喊出了著名的「去 IOE」口号:
- 去 IBM:不再使用 IBM 小型机(当时用 RISC 架构的 IBM Power 系列,每台数百万美元)
- 去 Oracle:不再使用 Oracle 商业数据库( licence 费用极高,扩展性受限于单机)
- 去 EMC:不再使用 EMC 高端存储(成本高,扩展不灵活)
背后的直接原因是:Oracle 数据库的成本已经高到无法承受。据阿里内部数据,到 2008 年,阿里每年花在 Oracle license 和维护上的费用已经超过数亿人民币。更要命的是,即使花了这么多钱,Oracle 在高峰期依然会撑不住——阿里每年双十一都会提前给 Oracle 原厂打电话,请求他们派工程师驻场应急。
阿里工程师调研后发现:淘宝双十一的实际 workload(访问模式和数据特征),跟 Oracle 设计的目标场景差异很大。Oracle 的优化方向是强一致性事务处理,而淘宝 90% 以上的数据库操作是读操作,而且读操作可以接受一定程度的数据延迟(最终一致性)。
OceanBase:自研分布式数据库
2009 年,阿里巴巴开始自研分布式数据库 OceanBase,核心设计目标是:用 MySQL 的语法和生态,享受分布式数据库的扩展性,同时保证强一致性事务。
OceanBase 的关键设计:
LSM-Tree 存储引擎:写入时先写内存(MemTable),定期刷盘生成 SSTable 文件,按时间线组织。这样写入是顺序写磁盘,性能极高。读取时需要合并内存和磁盘的多层数据。
准内存数据库 + 持久化:热点数据尽量放在内存,减少磁盘访问。对于强一致性要求高的场景,通过 Paxos/Raft 协议保证多数派写入成功。
-- OceanBase 的 SQL 语法跟 MySQL 兼容
-- 淘宝订单表分库分表示例
CREATE TABLE orders (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
order_no VARCHAR(64) NOT NULL,
user_id BIGINT NOT NULL,
total_amount DECIMAL(12, 2) NOT NULL,
status TINYINT NOT NULL,
created_at DATETIME NOT NULL,
updated_at DATETIME NOT NULL,
INDEX idx_user_id (user_id),
INDEX idx_created_at (created_at)
) PARTITION BY HASH(user_id) PARTITIONS 256;
OceanBase 在 2019 年开源后,被蚂蚁集团和阿里云广泛应用。2021 年,OceanBase 在 TPC-C 基准测试中创下了 7.07 亿 tpmC 的世界纪录,成为全球最快的分布式关系数据库。
迁移的代价
去 IOE 不是一蹴而就的。阿里花了 近 10 年时间,才把核心系统从 Oracle 迁移到 OceanBase + MySQL。这期间遇到了无数问题:
- 应用兼容性:有些 Oracle 特有的 SQL 语法在 MySQL 中不支持,需要逐条改写
- 数据迁移:双十一前夜做数据迁移,风险极高。每次迁移都要精心设计回滚方案
- 团队学习成本:DBA 从 Oracle 专家变成 MySQL/OceanBase 专家,需要持续培训
阿里的经验是:迁移要渐进式推进,不要追求一步到位。可以先在新业务上用新数据库,老业务逐步迁移,等新数据库在生产环境验证稳定后再扩大范围。
第三阶段:云化与中台(2013-2019)
中台战略的诞生
2015 年,马云在阿里内部正式提出「中台战略」,成为阿里技术史上最重要的组织变革之一。
前台:淘宝、天猫、盒马、饿了么等面向用户的业务 App,各自独立运营
中台:共享业务能力(用户中心、商品中心、交易中心、支付中心等),所有前台共用
后台:基础设施(数据库、云平台、安全)
中台的核心目标是复用——如果每个前台业务都要自己开发用户认证、商品管理、订单处理、支付对接,那每个团队都要重复造轮子。中台把这些通用能力抽取出来,作为共享服务供所有前台调用。
Dubbo:高性能 RPC 框架
Dubbo 是阿里巴巴 2011 年开源的高性能 RPC 框架,专注于服务治理,被广泛应用于国内 Java 微服务架构。
Dubbo 的核心能力:
- 远程过程调用:像调用本地方法一样调用远程服务
- 服务注册与发现:基于 ZooKeeper / Nacos 的服务注册中心
- 负载均衡:随机、轮询、最少活跃、一致性哈希
- 熔断降级:Sentinel 提供了 Dubbo 集成能力
- 流量管理:灰度发布、金丝雀、权重调整
// Dubbo 服务提供者
@Service(version = "1.0.0")
public class OrderServiceImpl implements OrderService {
@Autowired private OrderRepository orderRepository;
@Override
public Order createOrder(Long userId, List<Long> productIds) {
Order order = new Order();
order.setUserId(userId);
order.setStatus(OrderStatus.CREATED);
order.setCreatedAt(new Date());
order = orderRepository.save(order);
// 扣减库存(同步调用库存服务)
inventoryService.deductStock(productIds);
// 发送订单创建事件(异步)
orderEventPublisher.publishCreated(order.getId());
return order;
}
}
// Dubbo 服务消费者
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@Reference(version = "1.0.0", loadbalance = "roundrobin")
private OrderService orderService;
@Reference(version = "1.0.0", timeout = 3000, retries = 2)
private StockService stockService;
@PostMapping
public Response createOrder(@RequestBody OrderRequest request) {
// Dubbo 会自动从注册中心获取可用实例,负载均衡分发
Order order = orderService.createOrder(
request.getUserId(),
request.getProductIds()
);
return Response.success(order);
}
}
Dubbo 在 2018 年进入 Apache 孵化器,并于 2021 年毕业成为 Apache 顶级项目。目前国内大多数使用 Dubbo 的公司都是金融、电商、政府等领域的头部企业。
RocketMQ:分布式消息中间件
RocketMQ 是阿里巴巴开源的分布式消息中间件,2017 年捐赠给 Apache 并于同年毕业为 Apache 顶级项目,是国内使用最广泛的 MQ 之一(另一个是 Kafka)。
RocketMQ 的核心能力:
- 事务消息:半消息 + 本地事务回查,解决分布式事务中的消息一致性问题
- 顺序消息:按消息发送顺序消费,适用于需要严格顺序的场景(如订单状态机)
- 延迟消息:消息发送后不立即投递,等待指定时间再投递(如超时未支付自动取消订单)
- 消息过滤:消费者按 tag、key 过滤,不需要消费全量消息
// RocketMQ 事务消息:保证订单服务和库存服务的一致性
@Service
public class OrderService {
@Autowired private RocketMQTemplate rocketMQTemplate;
@Autowired private OrderRepository orderRepository;
public void createOrder(Long userId, List<Long> productIds) {
// 1. 发送半消息(此时消费者看不到这条消息)
// TransactionProducer 负责管理事务状态
rocketMQTemplate.sendMessageInTransaction(
"order-topic:create",
MessageBuilder.withPayload(
new OrderMessage(userId, productIds))
.setHeader("orderId", UUID.randomUUID().toString())
.build(),
// TransactionListener:本地事务 + 事务状态回查
(msg, arg) -> {
try {
// 执行本地事务:创建订单记录
Order order = new Order();
order.setUserId(userId);
order.setStatus(OrderStatus.PENDING);
orderRepository.save(order);
// 扣减库存(同步调用)
boolean deducted = stockService.deduct(productIds);
if (!deducted) {
throw new StockException("库存不足");
}
// 本地事务成功,提交半消息,消费者可以消费
return LocalTransactionState.COMMIT_MESSAGE;
} catch (Exception e) {
// 本地事务失败,回滚半消息
return LocalTransactionState.ROLLBACK_MESSAGE;
}
},
null
);
}
}
// 延迟消息:订单超时未支付自动取消
@Service
public class OrderCancelScheduler {
@Autowired private OrderRepository orderRepository;
@Autowired private RocketMQTemplate rocketMQTemplate;
public void scheduleOrderTimeoutCheck(Long orderId) {
// 订单创建后 15 分钟,检查是否已支付
// 延迟消息:15 分钟后才投递到消费者
rocketMQTemplate.asyncSend("order-topic:timeout-check",
new OrderTimeoutMessage(orderId),
new SendCallback() {
@Override
public void onSuccess(SendResult result) {
// 发送成功,定时器会在 15 分钟后触发
}
@Override
public void onException(Throwable e) {
// 发送失败,记录日志,人工介入
log.error("Failed to schedule timeout check for order {}",
orderId, e);
}
});
}
}
Sentinel:流量控制组件
Sentinel 是阿里开源的流量控制组件,以「流量」为切入点,提供限流、熔断、降级、系统自适应保护等能力。
// Sentinel 限流规则配置
@Configuration
public class SentinelConfig {
@PostConstruct
public void initRules() {
// 流量控制规则
List<FlowRule> flowRules = new ArrayList<>();
FlowRule orderRule = new FlowRule();
orderRule.setResource("order/create");
orderRule.setGrade(RuleConstant.FLOW_GRADE_QPS); // 按 QPS 限流
orderRule.setCount(10000); // 10000 QPS
orderRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
flowRules.add(orderRule);
FlowRuleManager.loadRules(flowRules);
// 熔断规则
List<DegradeRule> degradeRules = new ArrayList<>();
DegradeRule degradeRule = new DegradeRule();
degradeRule.setResource("payment/charge");
degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
degradeRule.setCount(5); // 5 次异常触发熔断
degradeRule.setTimeWindow(10); // 熔断持续 10 秒
degradeRule.setMinRequestAmount(10); // 至少 10 次请求才计算异常率
degradeRules.add(degradeRule);
DegradeRuleManager.loadRules(degradeRules);
}
}
// 使用注解声明资源
@RestController
@RequestMapping("/order")
public class OrderController {
@SentinelResource(value = "order/create",
blockHandler = "createBlockHandler",
fallback = "createFallback")
public Response createOrder(@RequestBody OrderRequest request) {
return orderService.create(request);
}
// 限流处理:超过 QPS 上限时执行
public Response createBlockHandler(OrderRequest request,
BlockException ex) {
log.warn("Order create rate limited: {}", ex.getClass().getSimpleName());
return Response.error("系统繁忙,请稍后再试");
}
// 降级处理:服务异常时执行
public Response createFallback(OrderRequest request, Throwable ex) {
log.error("Order create failed", ex);
return Response.error("服务暂时不可用");
}
}
第四阶段:双十一技术保障体系
全链路压测
2013 年双十一,阿里第一次实现了全链路压测——在生产环境上,用模拟流量对整个系统施压,发现真实的瓶颈点。
为什么要在生产环境压测? 因为测试环境和生产环境的差距太大了。测试环境只有几台机器,而生产环境有几千台。中间件、网络配置、数据库连接池参数,在不同规模下的表现完全不同。只有在生产环境压测,才能发现真实的瓶颈。
全链路压测的核心技术:
- 流量复制:用 TCPCopy 等工具,将历史流量(双十一前一年的真实请求)复制到压测环境
- 数据隔离:压测流量和真实流量使用不同的用户 ID、商品 ID、订单 ID,确保不会污染真实数据
- 流量染色:给压测流量打上特殊标记(header),中间件识别后放行,监控系统区分统计
- 逐级加压:从 10% 流量开始,逐步加压到 100%,观察各项指标的拐点
# 全链路压测的流量控制命令示例
# 1. 启动压测任务
# 2. 逐步加压,观察系统指标
# 压测目标:订单创建接口
target_qps=540000 # 目标 54 万 QPS
current_qps=54000 # 当前 5.4 万 QPS
# 逐步加压:每次增加 10%
while [ $current_qps -lt $target_qps ]; do
echo "Increasing to $current_qps QPS..."
# 调整压测流量
adjust_load --qps $current_qps
# 观察系统指标(延迟、错误率、CPU、DB 连接)
check_metrics
# 如果出现异常拐点,记录瓶颈点
if error_rate > 1%; then
echo "ERROR: Error rate exceeded threshold at $current_qps QPS"
echo "Bottleneck detected: $current_component"
break
fi
current_qps=$((current_qps * 11 / 10)) # 增加 10%
done
预案自动化
双十一期间,阿里会提前准备数百个应急预案(runbook),每个预案对应一种可能的故障场景:
# 预案配置示例
- id: flow-control-orders
name: 订单创建限流预案
trigger:
metric: order_create_qps
condition: "qps > 80000"
duration: 10s # 持续 10 秒才触发
actions:
- type: sentinel-flow-control
resource: order/create
max_qps: 50000
strategy: THROW
- type: disable-promotion
promotion_id: "1111-coupon"
- type: disable-flash-sale
flash_sale_id: "*" # 关闭所有秒杀
rollback:
- type: sentinel-reset
resource: order/create
当某个指标触发阈值时,对应的预案会自动执行,不需要人工干预。这在双十一零点零分流量洪峰来袭时至关重要——那时候根本没时间让人工来判断和操作。
异地多活
阿里采用「两地三中心」的部署架构:
- 杭州两个机房:同时对外服务(active-active),一个机房故障,另一个自动接管
- 上海一个机房:备用,不直接承接流量,故障时快速切换
关键设计是单元化——把业务按照用户 ID 所属的区域,划分到不同的单元(Cell)内。每个单元是一个完整的业务系统,包含自己的应用、数据库、缓存。单元之间相互隔离,一个单元故障不会影响其他单元。
架构启示
启示一:中台战略的代价与收益
中台战略给阿里带来了显著的效率提升:之前每个业务都要重复开发「用户中心」,有了中台后直接调用共享服务,开发周期从几个月缩短到几周。
但中台也有代价:
- 耦合风险:所有前台依赖同一个中台,中台出问题影响所有前台
- 灵活性下降:前台想改一个功能,需要跟中台团队协调,响应速度变慢
- 团队协作复杂:前台和中台属于不同团队,KPI 不同,利益不一致
建议:中台适合业务稳定、团队规模大、公用能力多的公司。小公司、新业务不要盲目追求中台。先让业务跑起来,等真正需要复用的时候再抽取中台。
启示二:全链路压测是必须的
很多公司的压测只在接口级别,无法发现全链路的瓶颈。瓶颈往往出在意想不到的地方——数据库连接池配置太小、中间件线程池不够、缓存穿透导致 DB 被打爆。
建议:即使不做完整的全链路压测,也要进行多服务集成测试。压测要尽可能接近真实环境(使用生产数据的脱敏副本),而不是用假数据跑单元测试。
启示三:技术债务要定期偿还
阿里去 IOE 花了近 10 年,期间持续投入,每年都在做迁移。不是因为技术选型错了,而是因为技术在进步,当年的最佳选择变成了今天的债务。
建议:技术债务不能无限积累。每个季度至少评估一次技术债务的规模,列出 TOP N 需要偿还的债务,按计划逐步还。长期不还的技术债务,会以 bug 的形式找上门来。
术语表
总结
阿里是中国互联网架构的集大成者,它的技术演进始终围绕一个核心命题:如何在极限流量下保证系统稳定。
演进脉络:
- 1999-2003:B2B 起步,LAMP + Oracle
- 2003-2008:淘宝崛起,数据分片 + 支付宝担保交易
- 2008-2013:去 IOE,OceanBase 自研数据库替代 Oracle
- 2013-2019:中台战略,Dubbo + RocketMQ + Nacos + Sentinel 全套中间件体系
- 2019-至今:智能化运营,全链路压测常态化,极致弹性扩缩容
核心技术贡献:
- 去 IOE:用 OceanBase + MySQL 替代 Oracle,节省数十亿 license 费用
- Dubbo:高性能 RPC 框架,Apache 顶级项目,国内微服务主流选型之一
- RocketMQ:分布式消息中间件,Apache 顶级项目,事务消息是其核心差异化能力
- Sentinel:流量控制组件,限流 + 熔断 + 降级三剑客
双十一技术保障体系:
- 全链路压测在生产环境发现真实瓶颈
- 预案自动化减少人工干预时间
- 异地多活保证任何单机房故障不影响业务
- 技术债务定期偿还,保持架构活力
对普通项目的启发:
- 技术选型要考虑团队能力和业务阶段,不要盲目追新技术
- 中台要量力而行,业务稳定、团队规模大才适合做中台
- 压测要尽可能接近真实场景,单元测试无法替代集成压测
- 技术债务要定期偿还,积压越久代价越大