尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

淘宝架构演进:从单体到千万级并发的实战演进与核心设计思想

淘宝架构演进:从单体到千万级并发的实战演进与核心设计思想 1. 项目概述从“小作坊”到“航空母舰”的蜕变聊到淘宝的架构演进这几乎是中国互联网技术发展史上最经典的案例之一。我作为一个经历过从单体应用到分布式、再到微服务化浪潮的老兵每次复盘淘宝这14次架构升级都像在看一部波澜壮阔的技术史诗。它不是一个简单的技术堆砌而是一场围绕“业务驱动”和“流量洪峰”展开的、持续十余年的自我革命。核心目标始终如一在用户无感知的情况下支撑起从零到千万级乃至更高并发的平滑过渡。这背后是无数次在深夜进行的压测、熔断、扩容和重构。今天我们不谈那些宏大的概念就从一个一线工程师的视角拆解这艘“航空母舰”是如何一块钢板一块钢板焊接起来的。你会发现很多你正在面对或即将面对的技术选型难题淘宝的架构师们在十年前就已经踩过坑、填过土了。2. 淘宝架构演进的底层逻辑与核心驱动力2.1 业务爆炸式增长是唯一不变的变量淘宝架构升级的根本驱动力从来不是技术人的炫技而是业务发展的“倒逼”。早期的淘宝就是一个典型的LAMPLinuxApacheMySQLPHP单体应用。所有功能模块——用户、商品、交易、支付——都耦合在一个巨大的代码仓库里部署在一台或几台服务器上。这种架构在流量很小的时候开发效率高部署简单。但问题也随之而来任何一个模块的BUG都可能导致整个网站宕机上线新功能需要全站发布风险极高数据库成为绝对的单点瓶颈。随着用户量和商品量的指数级增长第一个尖锐的矛盾出现了数据库扛不住。最初的解决方案是“垂直拆分”也叫“分库”。这不是微服务而是把不同业务的数据放到不同的物理数据库实例上。比如用户库、商品库、交易库分开。这缓解了单一数据库的CPU、IO和连接数压力。但应用层还是那个庞然大物它需要连接多个数据库复杂度开始上升。紧接着第二个矛盾爆发应用服务器成为瓶颈。即使数据库拆了那个巨大的单体应用在流量面前也开始力不从心。这时候“水平拆分”登场了。首先是对应用服务器本身做集群前面挂上负载均衡器比如早期的Nginx或硬件F5把流量分散到多台机器上。但这只是权宜之计因为应用本身的复杂性没有降低。于是更彻底的“服务化”思想开始萌芽这就是后来微服务的前身。淘宝内部称之为“HSF”其核心就是把那个单体应用按业务领域拆分成一个个独立的、可以单独部署和伸缩的服务单元。2.2 应对“双十一”的技术预演与常态化“双十一”购物节是淘宝架构的“终极压力测试场”也是技术升级的“催化剂”。早期的双十一技术团队如临大敌通宵值守手动扩容。但这种方式不可持续。他们意识到必须把应对脉冲式流量的能力沉淀到平时的架构中使之“常态化”。这就引出了几个核心架构原则弹性伸缩系统必须能根据实时流量自动增加或减少计算资源。这依赖于对服务进行无状态化改造并建设强大的资源调度平台如后来的阿里云弹性计算。柔性可用允许系统在部分受损时降级服务而非完全不可用。比如当商品详情系统压力过大时可以暂时关闭复杂的推荐模块保证核心的“查看商品”和“下单”路径畅通。这需要强大的服务治理能力包括熔断、降级、限流。数据分片单一数据库无论如何优化都有极限。必须对数据进行水平分片Sharding比如把10亿用户数据按用户ID哈希后分散到1000个数据库实例中。淘宝的TDDLTaobao Distributed Data Layer就是干这个的它对应用层屏蔽了分库分表的复杂性。缓存无处不在内存的访问速度比磁盘快几个数量级。淘宝构建了多级缓存体系从客户端浏览器缓存、CDN缓存、到应用层本地缓存如Ehcache、再到分布式缓存如自研的Tair类似Redis。将热点数据如爆款商品信息、秒杀库存尽可能前置到离用户最近的地方。注意很多团队一上来就想搞微服务、搞分库分表这是本末倒置。淘宝的演进路径清晰地告诉我们架构升级是“被迫”的是业务量增长到现有架构的临界点时才采取的针对性措施。在QPS每秒查询率不到1000时一个精心设计的单体应用配合数据库读写分离和缓存可能是性价比最高、最易于维护的选择。3. 核心架构升级节点与技术选型深度解析淘宝的14次升级并非一蹴而就我们可以将其归纳为几个关键阶段每个阶段都解决了当时最突出的矛盾。3.1 第一阶段摆脱“巨石应用”服务化与分布式中间件当单体应用成为瓶颈时淘宝选择了面向服务的架构SOA并自主研发了核心中间件。HSF高性能服务框架你可以把它理解为淘宝版的Dubbo或Spring Cloud。它解决了服务之间的注册、发现、路由和远程调用RPC问题。HSF的设计非常注重性能因为电商场景下一次页面展示可能背后涉及数十次RPC调用任何一点延迟都会被放大。它的序列化协议、网络通信模型都经过了极致优化。TDDL分布式数据访问层这是应对数据库瓶颈的利器。应用代码写SQL时仿佛还在操作一个数据库。但TDDL在底层透明地完成了SQL解析、路由到正确的分片、结果合并等复杂操作。它支持读写分离、分库分表规则配置、数据库主备切换等。它的存在让业务开发人员可以更专注于业务逻辑而不必深陷分布式数据访问的泥潭。Tair分布式缓存/存储对标Redis和Memcached但针对电商场景做了大量定制。例如支持多数据结构并对“秒杀”场景下的库存扣减提供了原子操作支持避免了超卖问题。Tair的集群管理、数据迁移、容灾能力都非常强大。实操心得自研中间件是一把双刃剑。好处是能完全贴合自身业务做深度定制和性能优化。但代价是极高的研发和维护成本以及团队学习曲线陡峭。对于绝大多数公司在开源方案如Spring Cloud Alibaba生态、ShardingSphere、Redis成熟度已经很高的情况下优先采用开源方案是更明智的选择。淘宝走自研路线是因为当时很多开源方案还不存在或不成熟。3.2 第二阶段应对“数据洪流”异步化与消息队列随着系统拆分成微服务服务之间的同步调用RPC虽然解耦了部署但带来了新的问题链路依赖和性能瓶颈。用户下单这个动作需要调用订单服务、扣减库存、更新用户积分、发送短信通知等。如果全部同步调用任何一个下游服务慢都会导致整个下单接口超时用户体验极差。引入消息队列是解决此问题的关键。淘宝早期使用了Notify后来逐渐过渡到更强大的RocketMQ阿里开源。下单成功后订单服务只需向MQ发送一条“订单已创建”的消息就可以立即返回给用户。库存服务、积分服务、通知服务作为消费者异步地从MQ拉取消息进行处理。好处1削峰填谷。双十一零点瞬间的流量洪峰可以被MQ缓冲住下游服务按照自身处理能力消费避免被压垮。好处2系统解耦。订单服务不需要知道有多少个下游服务关心“订单创建”这个事件新增一个下游服务比如数据分析服务只需订阅该消息即可无需订单服务修改代码和上线。好处3最终一致性对于不需要强一致性的业务场景如发短信、更新排行榜异步消息是保证系统整体吞吐量的利器。关于“超买”和“并发锁”这是电商核心难题。在秒杀场景下纯靠数据库的行锁SELECT ... FOR UPDATE会在高并发下导致数据库连接耗尽、性能骤降。淘宝的解决方案是“分层校验”和“缓存原子操作”。前端限流在点击“立即购买”按钮时通过JS进行频率限制。缓存预扣库存数量提前预热到Tair这样的分布式缓存中。扣减库存时使用缓存的原子递减命令如DECR。因为缓存操作是内存级的速度极快能扛住极高并发。这一步决定了“有”或“没有”库存。异步落库缓存扣减成功后发送异步消息由后台服务将库存扣减结果持久化到数据库。即使这一步失败也可以通过定时对账任务来修复缓存和数据库之间的数据一致性。3.3 第三阶段拥抱“云原生”容器化、服务网格与数据中台最近的几次架构升级淘宝/阿里集团的重点转向了云原生。容器化与Kubernetes将所有的应用服务打包成Docker容器由Kubernetes统一调度和管理。这带来了极致的弹性伸缩能力监控系统发现某个服务的CPU使用率超过80%自动触发K8s的HPA水平Pod自动伸缩策略在几十秒内扩容出新的实例。服务网格将服务治理能力熔断、限流、路由、观测从HSF这样的SDK中剥离出来下沉到基础设施层由Sidecar代理如IstioEnvoy来实现。这使得业务代码更加轻量纯净且服务治理策略可以动态配置无需重启应用。数据中台与业务中台这是组织架构和业务架构的升级。将各业务线共用的用户、商品、交易等数据能力和业务能力沉淀成统一的“中台”向前台的各类创新业务淘宝、天猫、闲鱼等提供标准化、组件化的服务。避免每个业务线都从头建设一套用户系统造成数据孤岛和重复建设。你提到的“淘宝茶叶销售数据可视化系统”其底层数据很可能就来源于数据中台提供的统一数据服务。负载均衡的演进从最初的硬件F5到软件Nginx/LVS再到如今云原生时代的服务网格内的智能路由和Kubernetes Service。负载均衡的粒度从机器级别细化到了容器/Pod级别策略也从简单的轮询、加权发展到基于内容、基于地域、基于实时健康检查的智能路由。4. 千万并发架构下的关键组件实战配置思路理解了演进脉络我们来看看如果要设计一个能应对高并发的系统关键组件该如何思考和配置。这里以开源技术栈为例。4.1 负载均衡层从入口到服务的流量指挥棒现代的负载均衡是分层级的全局负载均衡使用DNS或HTTP DNS将用户请求智能解析到离他最近或最空闲的机房入口。这解决了跨地域访问的问题。入口层负载均衡在机房入口使用Nginx或LVS。Nginx更擅长处理HTTP/HTTPS协议配置灵活LVS工作在更底层网络4层性能极高常用来做Nginx集群的负载均衡。Nginx关键配置示例upstream backend_servers { # 使用一致性哈希解决会话保持或缓存命中问题 hash $request_uri consistent; server 10.0.1.101:8080 weight5; #权重 server 10.0.1.102:8080 weight3; server 10.0.1.103:8080 backup; #备份节点 } server { listen 80; location / { proxy_pass http://backend_servers; # 以下超时配置对高并发场景至关重要 proxy_connect_timeout 2s; proxy_read_timeout 5s; proxy_send_timeout 3s; # 启用缓冲减轻后端压力但会略微增加延迟 proxy_buffering on; proxy_buffer_size 4k; proxy_buffers 8 4k; } }服务层负载均衡在微服务内部由服务发现客户端如Nacos Client或服务网格Sidecar来实现。它从注册中心获取所有健康实例的列表并根据策略如轮询、随机、最小连接数选择一台进行RPC调用。这里必须实现客户端负载均衡以避免单点故障。4.2 缓存策略设计不当就是“核弹”缓存是性能的银弹也是复杂性的根源。多级缓存架构CDN存放静态资源图片、JS、CSS和很少变化的动态页面。分布式缓存存放热点业务数据如商品详情、用户会话、秒杀库存。关键点在于缓存键的设计要避免大Key单个Key存储巨大Value和热Key某个Key被极高频率访问。本地缓存在应用服务器内存中如Caffeine、Guava Cache存放极少变化的数据如配置信息、城市列表。它能避免网络开销速度最快。缓存更新策略Cache-Aside最常用。应用先读缓存未命中则读数据库再写入缓存。更新数据时先更新数据库再删除缓存。注意是删除而非更新以避免并发更新导致的数据不一致。这里有一个经典的“先更新数据库还是先删除缓存”的争论通常“先更新数据库再删除缓存”是更稳妥的选择虽然仍有极小概率的不一致窗口。Write-Through/Write-Behind由缓存组件负责同步或异步地将数据写入数据库。对一致性要求高但实现复杂。4.3 数据库抗压读写分离与分库分表当单表数据超过千万或QPS超过数千时就必须考虑拆分。读写分离这是第一步。利用数据库的主从复制将写操作指向主库读操作分散到多个从库。应用层通过TDDL或ShardingSphere这样的中间件来透明路由。注意主从延迟对于刚写入就要读取的场景可能需要强制走主库“写后读主”。垂直分库按业务将表拆分到不同的数据库如用户库、订单库、商品库。水平分表这是应对大数据量的终极手段。选择一个稳定的分片键如user_id通过哈希或取模算法决定数据落在哪个物理表。分片键的选择至关重要要保证数据均匀分布并且大部分核心查询都能带上分片键避免跨分片查询。分表后的问题全局唯一ID生成雪花算法、跨分片查询尽量避免或通过中间件聚合、分布式事务尽量最终一致性避免强一致。这些都需要中间件或业务设计来解决。5. 高并发系统常见问题排查与稳定性保障构建高并发系统就像驾驶一辆高速赛车不仅要能跑得快更要知道刹车和维修在哪里。5.1 典型问题速查与根因分析问题现象可能原因排查思路与解决方案接口响应慢TP99飙升1. 下游服务RT响应时间变慢。2. 自身应用Full GC频繁。3. 数据库慢查询。4. 缓存未命中穿透到DB。1.链路追踪通过SkyWalking、Zipkin查看调用链定位慢节点。2.监控指标检查应用JVM GC日志、CPU使用率检查数据库监控慢SQL日志、连接数、锁等待。3.缓存分析查看缓存集群命中率检查是否有大Key或热Key。服务间歇性超时或报错1. 网络抖动或机房故障。2. 某个服务实例不健康但未及时从注册中心剔除。3. 线程池耗尽。4. 依赖的第三方服务不稳定。1.检查基础设施网络监控、宿主机状态。2.检查服务治理确认服务发现与健康检查机制是否正常检查熔断器如Hystrix、Sentinel是否已触发。3.检查资源应用线程池、数据库连接池使用情况。4.实施降级对非核心依赖配置降级策略。数据库CPU持续100%1. 出现未走索引的慢SQL。2. 遭遇锁等待行锁、表锁。3. 连接数爆满大量慢查询堆积。1.紧急止血通过SHOW PROCESSLIST找到耗时最长的会话必要时KILL。2.分析慢日志使用mysqldumpslow或Pt-query-digest工具分析。3.优化SQL/索引这是根本解决之道。缓存雪崩大量缓存Key在同一时间大面积失效导致所有请求瞬间打到数据库。1.设置不同的过期时间在基础过期时间上增加一个随机值。2.热点数据永不过期通过后台任务异步更新。3.实施熔断限流当数据库压力过大时快速失败部分请求保护DB。缓存穿透查询一个数据库中一定不存在的数据如不存在的商品ID导致每次请求都穿透缓存查DB。1.缓存空值即使数据库没有也将这个Key缓存一个短时间的空值或特殊标记。2.布隆过滤器在查询缓存前先用布隆过滤器判断Key是否存在不存在则直接返回。5.2 稳定性保障的“三板斧”限流、熔断与降级这是保证系统在极端流量下不崩溃的最后防线。限流控制单位时间内通过的请求数量。可以在多个层面做网关层限流如Nginx的limit_req模块对整个入口进行限流。服务层限流如使用Sentinel对某个具体的API接口进行QPS限制。实操心得限流值需要通过全链路压测来精确评估。设置过低会影响正常业务设置过高则失去保护意义。通常先设置一个保守值再根据监控逐步调整。熔断当下游服务失败率如超时、异常达到一定阈值时熔断器会“跳闸”在一段时间内直接拒绝所有对该服务的请求快速失败避免资源被拖垮。一段时间后进入“半开”状态试探性放一个请求过去如果成功则关闭熔断器。这类似于电路中的保险丝。降级当系统压力过大时主动关闭一些非核心功能释放资源保障核心链路。比如在双十一期间关闭商品评价的复杂排序、关闭非实时的推荐算法只展示默认列表。全链路压测这是淘宝保障双十一的“核武器”。在线上环境构造和生产环境一样的流量和数据模拟真实的峰值场景来验证系统的容量、发现瓶颈、演练预案。对于普通公司可以在业务低峰期利用影子表、流量隔离等技术进行小规模的压测。淘宝的架构演进史本质上是一部应对复杂性增长的历史。从一台服务器到全球数据中心从一行PHP代码到成千上万的微服务每一次升级都是为了在“快速响应业务变化”和“保障系统稳定高效”之间寻找新的平衡点。对于我们而言最重要的不是照搬淘宝的具体技术而是理解其背后的设计思想以业务为驱动以解决当前主要矛盾为目标小步快跑持续演进。在技术选型上拥抱成熟的开源生态在架构设计上时刻为扩展和容错留有余地。记住没有最好的架构只有最适合当前和可预见未来业务的架构。
返回列表