This commit is contained in:
louzefeng
2024-07-09 18:38:56 +00:00
parent 8bafaef34d
commit bf99793fd0
6071 changed files with 1017944 additions and 0 deletions

View File

@@ -0,0 +1,122 @@
<audio id="audio" title="05 | 全链路压测:系统整体容量保障的“核武器”(上)" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/e3/c3/e3a206024ba38726007fb739652a38c3.mp3"></audio>
你好,我是吴骏龙。
通过基础篇的学习相信你对容量保障的相关知识已经有了基础的了解知道了容量测试不能简单定义为压力测试而是验证服务容量的手段知道了容量指标分析不能只看单一指标也学习了分析容量指标的5个经典问题以及了解了容量治理可以采取扩容、限流和降级策略。
从今天开始,我们踏入进阶篇,进阶篇的所有内容都是比较前沿或创新的知识,希望通过大厂前沿经验和我的积累,帮你拓宽视角。在进阶篇,我们从关注度最高的全链路压测开始,与你分享我的实践经验。
你可能会问,到底什么是全链路压测?实施全链路压测要经过几个步骤?有哪些难点坑点?别急,因为内容较多,我会分成两讲,这一讲,先聊聊全链路压测的诞生,以及实施全链路压测前的三项改造工作。下一讲,我们再进一步聊聊两项具体的压测工作,把全链路压测的建设过程完整展示给你。
## 全链路压测的诞生
2013年对阿里巴巴来说有着非凡的意义因为那一年全链路压测诞生了。这可是双11容量保障工作的福音对守在电脑前的程序员们来说流量洪峰终于不再那么可怕了。
虽然当时我还没有进入阿里体系内工作但我作为一名用户亲身参与了从2011年开始的所有双11活动我能深刻感受到双11系统稳定性的变迁。总体来说2011年和2012年给我的体验不太好但2013年就有了很大的改观。
2011年和2012年双11活动的整点系统不可用的问题对我造成了很大的困扰访问网页各种报错连付款都困难当时把我给着急的呀生怕要买的东西被抢完了如果你也经历过那时候的双11应该能够感同身受。
不过从2013年开始虽然每年双11的规模都在大幅增长但除了付款操作偶尔还会被限流以外网页无法访问这种系统不可用的情况几乎碰不到了。直到后来我进入阿里体系内工作后才知道当时的阿里人为此付出了大量的努力和汗水在短短几个月的时间内大刀阔斧地推动各项改造构建压测模型创造性地完成了全链路压测的建设工作才得以保证双11的稳定进行。要知道当年双11的流量峰值已经超过了每秒4万笔交易量放眼全世界也是独树一帜的存在。
阿里的经验证明了一点,那就是对未来可能产生的流量峰值而言,任何预防性的稳定性保障手段,都不如**把实际峰值场景模拟出来“看一看”** 来的有效,这就好比建造三峡大坝,预计能抵挡千年一遇的洪水,但是否能达到这个目标,还是需要经历多次洪水考验才能证明的。全链路压测就是通过模拟这场千年一遇的洪水,来验证服务系统是否能承载预估的流量峰值。
在全链路压测诞生前阿里双11的容量保障工作主要是对业务目标进行拆分对各个服务链路单独进行压测虽然也进行了大量的压测工作但实际发生流量洪峰的时候很多系统的容量还是会有问题。
为什么单链路压测无法排除系统整体容量风险呢,因为整体系统的容量不是由多条“单链路”的容量简单相加而得的。我们看一下下面这张图,它表达的含义是,应用服务的容量除了受自身影响,还受依赖服务的影响,而依赖服务又可能有其他调用方,甚至是一些外部服务,这些影响经过几层累积后,最终的影响面极难判断。
<img src="https://static001.geekbang.org/resource/image/d2/a8/d2055a04f72b5fd8f5248b973144e9a8.png" alt="">
而全链路压测直接从全局视角出发,它的本质是基于线上真实环境和实际业务场景,通过模拟海量的用户请求,来对整个系统的容量进行评估的手段。当然,罗马不是一天建成的,全链路压测也不是一蹴而就的,有很多重点问题需要解决,我们可以从两方面思考。
首先,全链路压测本质上也是一种容量测试的手段,因此容量测试需要解决的问题也是全链路压测面对的重点问题,比如**数据隔离、压测场景置信度、对正常业务的影响**等,其中有些内容我在之前的讲解中也已经涉及到了。
其次,全链路压测的特点决定了它会存在一些独有的重点问题,由于全链路压测遵循与用户访问相同的流量轨迹,因此会涉及大量的服务链路,我们需要保证**压测流量在这些链路中流动时的完整性和可识别性**。此外,有别于单链路压测只需要制造局部流量,全链路压测需要**制造大规模的整体流量**,这也是需要重点考虑的。
<img src="https://static001.geekbang.org/resource/image/77/2a/778a235998568e2754300b804915432a.png" alt="">
可以说,解决了上面这些问题,就具备了全链路压测实施的基本条件,下面我就来具体展开讲解一下全链路压测的建设过程,其中包含三项改造工作和两项压测工作。
三项改造工作包括:数据隔离、中间件改造和应用服务改造,这些改造工作致力于解决上面提到的压测流量的完整性和可识别性、数据隔离以及对正常业务的影响这些重点问题。而两项压测工作则包括:压测模型构建和压测流量构造,对应上面提到的场景置信度和大规模流量制造这两个重点问题。关于两项压测工作,我们下一讲展开。
## 全链路压测应该如何建设
### 三项改造之数据隔离
为了避免环境不对等所造成的压测结果失真,全链路压测一般都是在生产环境展开,而线上压测就一定会涉及到数据隔离的问题,压测数据需要与真实数据有所区分,确保不影响真实用户的体验。因此,数据隔离是全链路压测建设过程中最重要,也是最必不可少的工作。
常见的数据隔离方式有两种,分别是:**逻辑隔离**和**物理隔离**。
逻辑隔离是指通过数据打标的方式区分真实数据和压测数据,在各实体(如用户、商户、订单等)中添加压测类型标识。比如针对用户这个实体,可以设置一个用户类型字段,其他系统或服务可以根据这个字段硬编码走相应的隔离逻辑。
```
enum UserType {
NORMAL = 0, # 普通用户
PERF = 1, # 压测用户
}
```
逻辑隔离实现简单容易理解但难以标准化因为具体的字段设置是由业务技术方决定的。比如上面举例的用户数据中的压测标识字段是UserType但商户数据中的压测标识字段可能就变成了ShopType上游系统如果需要同时识别多种数据的压测标识时会比较困扰。
第二种数据隔离方式是物理隔离,它的做法是先通过在压测流量中进行打标的方式,区分真实请求和压测请求,再将压测请求所涉及的数据存储到另一个与真实表数据结构对等的表中(俗称影子表),使压测数据在物理上与真实数据隔离。这就涉及两个重点工作,一是在压测流量中打标,二是建立影子表。
在压测流量中进行打标该如何做呢通常情况下流量入口大多是HTTP请求压测流量标识可以置于HTTP Header中进入内网后相关中间件需要将HTTP Header中的压测流量标识转移至内部请求如RPC请求的上下文中如遇异步组件如消息队列也需要做特殊处理具体我会在下文“中间件改造”那部分展开。
这个过程要确保压测流量标识能够一路透传(传输过程中不对标识进行改变)至数据层不丢失;最后,数据层,如数据库中间件通过对压测流量标识的识别,将数据写入影子表,完成整个物理隔离的全过程。
<img src="https://static001.geekbang.org/resource/image/72/f2/72cfee8ec07f4dbf683374b904053cf2.png" alt="">
值得一提的是,物理隔离还有一个额外的好处,由于实现物理隔离必须构建统一的压测流量标识,那么分布式链路跟踪系统也可以根据该标识,直观地展示压测链路,这样比较方便监控和排查问题。
那么,影子表如何建立呢?为了使全链路压测对于数据库容量的评估准确,我们需要保证影子表的数据内容和规模与真实表一致,但又不能与真实表数据冲突,你可以参考以下过程建立影子表:
1. 针对某张真实表建立相应的影子表表名可以通过增加前缀或后缀区分比如原表名为User影子表名可以设定为User_T其他影子表也都基于_T这个后缀建立。
1. 将真实表的数据进行脱敏部分id类字段需要进行偏移以免增长后与真实表冲突比如真实的订单号都是以1开头那么影子表中的订单号可以偏移为以9开头。
1. 脱敏和偏移后的数据导入到影子表中。
1. 进行完整性检查(数据量、表结构等内容),确保数据无误。
<img src="https://static001.geekbang.org/resource/image/eb/9d/ebde00beee2b58e6432879374084289d.png" alt=""><br>
逻辑隔离和物理隔离各有千秋,两者对比如下表所示。我的经验是,如果你公司的技术体系比较成熟,技术栈统一,也有固定的中间件团队支持,那么可以尝试使用影子表的方式进行数据的物理隔离;反之,如果技术体系不完整,或大量使用开源框架,二次开发成本高,那么可以采用逻辑隔离的方式。
<img src="https://static001.geekbang.org/resource/image/04/d7/0436754c1fe1120be566e056f6b403d7.png" alt="">
### 三项改造之中间件改造
在数据隔离环节我已经提到,压测流量标识透传以及数据的物理隔离等工作,都需要对中间件进行改造,比较典型的有数据库中间件对影子表的支持,消息队列对压测流量标识传递的支持,等等。
数据库中间件对影子表的支持比较简单,上面也已经提到过,实现的机制是基于压测流量标识,数据库中间件接收到某个带有压测流量标识的请求需要操作数据库时,将这个操作的目的地重定向到影子表上。这些影子表的信息,以及与真实表的映射关系,可以维护在一个统一的地方做管控,同时供数据库中间件调用。
另外一个典型的中间件,消息队列,它是微服务体系中常见的中间件。消息队列对压测流量标识传递的支持,主要目标是保证在生产和消费数据时,压测流量标识不能丢失。具体来说,当有压测请求作为生产者将数据写入消息队列后,这个生产者的使命就完成了,当消费者去消息队列中消费出这条消息时(相当于另一次请求),我们已经无从知晓数据是压测数据还是真实数据了,这破坏了压测流量的可识别性。
因此,对消息队列需要进行改造,当接收到带有压测请求标识的生产者推送消息时,需要将压测标识转存至数据中,以免丢失,当异步服务消费数据时,再将该标识恢复至请求体或上下文中继续传递。
<img src="https://static001.geekbang.org/resource/image/ec/cb/ec041061c9e891607f2c28784e0bd6cb.png" alt="">
通过以上两个例子,你可能也发现了,中间件需要改造的地方基本上都是**与压测数据打交道**的地方,所以在中间件改造方案的制定中,我们需要对数据特别敏感,涉及到数据的地方可能都是潜在的改造点。
### 三项改造之应用服务改造
除了中间件改造,应用服务也需要进行一定的改造,确保压测请求能被反复执行,并且不影响真实场景,常见的应用服务改造点有:
- **绕开限制逻辑:** 比如系统针对短时间内反复下单的用户将进行限制,这个逻辑针对压测流量需要放开。
- **数据隔离前置:** 数据隔离前置能够减轻其他应用服务改造的工作量,比如大数据报表中需要对压测数据进行剔除,如果这些报表的数据源都在数据仓库里,那么我们完全可以在压测数据生成时就隔离掉不进数据仓库,这样大数据服务就无需改造了。
- **Mock逻辑** 有些对外交互的服务是不太方便发起大量真实请求的比如支付和清结算等这些功能可以在识别到压测流量后走Mock服务也就是模拟一个正常的返回而不是直接调用真实服务。
除此之外还有一些如风控拦截等安全性方面的限制也需要适当放开以便压测请求能够重复执行。总之所有可能会限制或阻碍压测请求流动的地方都需要打通如果无法打通那就Mock。
好了,到这里,数据隔离、中间件改造和应用服务改造都完成后,我们已经初步具备了实施全链路压测的条件。接下来就是压测实施层面的工作了。下一讲,我们主要来聊聊压测模型构建和压测流量构造两项工作。
## 总结
在这一讲中我首先与你分享了全链路压测的诞生过程正所谓“预见未来最好的方式就是实现未来”阿里通过将全链路压测成功应用于双11活动的保障工作证明了这一点也为容量保障带来了一个强大的武器。
全链路压测通过模拟海量的用户请求,来对整个系统的容量进行评估,其建设过程涉及到的要点还是比较多的,今天我们主要讲的是三项改造工作,这里面有几个重点你可以关注:
- 数据隔离是全链路压测建设过程中最重要的工作,逻辑隔离和物理隔离是两种常见的数据隔离方式。
- 如果公司的技术体系比较成熟,基础设施统一且有专业团队维护,那么可以尝试使用影子表进行数据的物理隔离,这样数据风险更小;反之,如果基础设施改造成本太大,就建议采用逻辑隔离的方式。
- 在中间件改造方案的制定中,我们需要对数据特别敏感,涉及到数据的地方可能都是潜在的改造点。
- 常见的应用服务改造点有绕开限制逻辑、数据隔离前置、Mock逻辑等这些改造工作能够确保压测请求的正常流动也能更好的配合数据隔离。
## 课后讨论
在中间件改造的版块中,我详细讲解了消息队列的改造工作。如果你要在公司内实施全链路压测,你觉得还有没有其他和数据打交道的中间件需要做改造的?如果有的话,你会怎么设计改造方案?欢迎你给我留言,也欢迎分享给更多的朋友一起阅读。

View File

@@ -0,0 +1,94 @@
<audio id="audio" title="06 | 全链路压测:系统整体容量保障的“核武器”(下)" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/d2/51/d2848e6d40f3fe6703a074f8c58ea151.mp3"></audio>
你好,我是吴骏龙。
上一讲,我为你讲解了在正式实施全链路压测前,我们要做的三项改造工作,包括数据隔离、中间件改造和应用服务改造。这一讲,我们就正式进入两项压测工作:压测模型构建和压测流量构造,把全链路压测的建设过程完整展示给你。除了技术工作之外,在这一讲中我还会与你分享全链路压测的组织协调和运营工作,它们对全链路压测的完整落地同样起到至关重要的作用。
我们先看看如何构建压测模型。
## 两项压测工作:压测模型构建
构建压测模型的重点是准确度,如果模型与真实场景相差过大,那么压测结果的可参考性将会大打折扣,下面是一些典型的由于压测模型不准确导致压测结果无效的反面教材:
- 下单链路中,压测用户没有使用红包,导致对营销服务的压测结果偏优。
- 压测用户数据未考虑sharding分布导致数据库单片过热。
- 压测用户数量过少,使用有限的压测用户反复下单后,导致单个用户订单量过多。
- 压测商户数量过少,压测时针对单个商户的操作过于密集,导致菜品扣减库存的锁争抢激烈。
压测模型包含业务模型和数据两部分,我再来通过几个实例讲解一下如何构建尽可能真实的场景。
**实例一: 读请求**
读请求由于不会对数据造成污染,因此可以直接使用真实请求和数据进行回放。
- 压测场景:商家列表及关键词查询。
- 业务模型:拉取线上日志,根据真实接口比例关系进行回放。
- 数据:拉取线上日志,使用真实数据。
**实例二: 写请求**
写请求一般需要单独构造压测模型,并做好数据隔离和清理工作。
- 压测场景:用户下单
- 业务模型根据生产监控或日志获取下单场景的链路信息观察接口调用情况和上下游依赖当然你也可以写一个系统帮你做这个事。产品、研发和测试共同评审链路的完整性。另外评估业务改造点比如需要对支付和短信等环节进行Mock。
- 数据:构建测试用户、测试商户、测试菜品等数据,数量上与线上真实情况等比例缩放;及时对压测数据进行清理,或使用影子表。
归纳一下,压测模型构建的核心要点是,要利用好生产环境的各种信息来帮助我们**构建贴近真实业务的压测模型**。生产环境是个聚宝盆,请求的依赖关系、调用比例、数据特征都是我们构建压测模型的素材,将这些数据抽取出来再进行精加工,即可得到贴合实际的压测模型。
## 两项压测工作:压测流量构造
有了压测模型和数据最后临门一脚就是构造压测流量进行施压。全链路压测对于压测流量构造的技术选型主要取决于流量的规模如果规模不大传统的压测工具是可以支持的如JMeter、Locust、nGrinder等如果是大规模流量乃至超大规模流量百万请求量级成本就会比较高。对于后者可以考虑自研一套压测平台这也是很多大厂的做法我在下一讲会专门展开这部分内容敬请关注。
我们来总结一下,全链路压测的建设过程可以归纳为两个重点:首先,通过中间件改造和应用服务改造,保证压测流量的完整性和可识别性,并保证压测数据与真实数据隔离开;其次,利用生产环境的各类信息,构建贴近真实场景的压测模型,并通过构造大规模压测流量实施全链路压测。
这些工作都完成后,全链路压测在技术层面的建设就基本告一段落了。
## 全链路压测的组织协调和运营工作
说了那么多,也许你会觉得建设全链路压测的技术难度还是挺高的,但我想告诉你的是,除了技术工作,组织协调和运营工作其实更难。这就好比新冠肺炎疫情的防控,全世界都知道中国的成功经验,但有几个国家能成功复制中国的防疫举措呢?
关于全链路压测建设时会涉及到的组织协调工作,通过全链路压测的建设过程相信你也看到了,其中光中间件改造和业务改造两项工作,就几乎覆盖了大半个技术团队,要同时协调那么多团队的工作安排,难度不小吧?
我认为,推动全链路压测这样的“航空母舰”项目,是需要自上而下的,但不一定非要强推。我在阿里本地生活工作时,技术团队建立了 **“Program机制”**这是一种针对跨团队大型项目的推动机制由CTO直接牵头和授权对公司内部需要推动的技术改造类项目进行必要性和优先级评定。
从项目跟进的角度来说所有公共团队如基础设施团队、大数据团队等和业务团队的技术Leader需要定期参加会议在会议上对这些项目的进展和风险进行讨论业务团队必须在约定时间内完成公共团队的技术改造需求而公共团队则需要提供合理的方案并提供足够的支持。
Program机制为基础设施团队推动技术改造类项目提供了一个强有力的抓手**动态平衡了业务实现与技术改造之间的关系**,使得业务团队必须腾出一部分时间进行技术升级,而不是埋头沉迷于业务迭代。
全链路压测就是众多技术改造类项目的一员。在我目前所在的这家创业公司同样是依托于类似的机制仅仅2个多月的时间便从0到1推动完成了全链路压测的核心改造工作所以你也大可不必把全链路压测想的很难可以尝试用类似的思路去推动它。
组织协调很难,另一个更有难度的问题是,在全链路压测建设完成后,如何将其有效地运营起来,明确每个参与团队要做什么事,做这些事的规范是什么,做的不好的后果是什么等等,这样才能将全链路压测的价值最大化地固化下来。
我的经验是,全链路压测是需要有一个集中式的团队去管理的,这个团队不需要很多人,但是需要被充分授权。可能你会问,光授权也没用啊,别人不听你的怎么办?**这时候就需要通过一些规范去约束和管控了**。
我在做全链路压测运营工作时,建立了两项规范,首先是**全链路压测的常态化执行制度**,每周三晚间低峰期执行全链路压测,核心链路的技术人员和运维人员必须现场值守,其余技术人员可以远程值守。值守人员需要严密关注业务指标,如果出现服务可用性问题或资损问题,及时报告压测团队暂停压测。
如果压测过程中出现服务瓶颈,我们有时候会执行一些降级操作以观察效果,这时候值守人员也应配合操作,如果因为未有效值守导致线上问题,需要承担连带责任。
此外,全链路压测能够暴露出整体系统的容量隐患,但仅仅将问题暴露出来还是不够的,我们需要确认这些问题得到重视和解决,才是真真正正地消除了容量风险,我建立的第二项规范,就是用来驱动全链路压测时所发现问题的及时改进,称之为**容量问题分级规范**。
这项规范根据容量风险的严重程度划定了不同的等级,每个等级对应不同的解决时限要求,越严重的风险,越是需要快速解决,或至少有临时措施。我们会定期统计问题解决的时长达标率,以此作为所有技术团队绩效考评的一个参考标准。
<img src="https://static001.geekbang.org/resource/image/47/20/478fc13efa7546918cedbd549e441520.jpg" alt="">
总结一下,推动全链路压测的落地,不仅仅是一项技术工作,组织协调和运营工作同样重要,否则还是很容易失败的。我比较倡导通过建立机制和流程规范的方式,自上而下去联动和管理多个团队之间的工作,定好的规范要及时跟进并督促执行,尽早暴露风险。
## 总结
关于全链路压测的内容比较多,我们来好好总结一下。全链路压测通过模拟未来流量峰值提前发生,将不确定问题转化为确定性问题,从而达到提前暴露系统整体容量问题的目的。
全链路压测的建设过程,涉及到数据隔离、中间件改造、业务服务改造、压测模型构建和压测流量构造这五项工作,有一定的技术难度和改造量,虽然我在讲解中提供了多种方案,但你在制定技术方案时还是需要平衡好投入产出比。
例如公司大量采用开源技术作为基础设施业务场景也比较简单这时候完全可以不用去动这些基础设施可以直接在业务层进行压测数据的逻辑隔离。构造流量也可以直接使用成熟的开源工具JMeter、Locust等。一句话适合的才是最好的。
全链路压测不是单一的技术问题组织协调和运营工作也需要重点考虑建立一支强有力的全链路压测团队通过流程和机制的制定去管理和规范各个团队的工作是我给到的经验之谈。Program机制、全链路压测常态化执行制度和容量问题分级规范是我给出的三项具体可操作的方法也是我推动或利用的比较成功的例子希望能够给你带来一些启发。
最后,河有两岸,事有两面,全链路压测也不是银弹,无法解决所有问题,将所有容量问题全部交给全链路压测兜底,不再做单链路压测或单服务压测,是错误的实践。全链路压测的实施成本较高,因此其实施频率一般是远远低于业务变更频率的。
全链路压测的擅长点是定期摸底系统整体容量,而常态的容量保障工作应当覆盖每个业务各个接口,这些毛细血管依然需要单链路压测和单服务压测去保障。
<img src="https://static001.geekbang.org/resource/image/b6/a0/b6e09f87aa7ba731471de4e0477e53a0.png" alt="">
## 课后讨论
假设我们通过全链路压测得到结论系统整体能够承载1000TPS每秒下1000单的负载但实际业务达到这个负载时系统却出现了不稳定的情况你觉得在全链路压测工作中可能有哪些地方我们考虑的不够周全从而导致了这一问题欢迎在评论区与我交流你的想法。