前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

参考文章

阿里云 https://developer.aliyun.com/article/982802

shardingSphere https://shardingsphere.apache.org/document/current/cn/features/shadow/

B 站全链路压测实践 https://www.6aiq.com/article/1658063147425

美团 https://tech.meituan.com/2018/09/27/quake-introduction.html

一、全链路压测

1、全链路压测是什么

全链路压测通过在生产环境对业务大流量场景进行高仿真模拟,获取最真实的线上实际承载能力执行精准的容量规划,确保系统可用性。 但是分布式架构和业务快速发展给业务系统带来了不确定性。分布式环境的任意节点都可能成为瓶颈/短板/问题,同时系统可用性随着业务的快速增长,面临更严峻的挑战和不确定性。

1)单链路压测局限

  • 单链路压测局限性:单链路压测缺少外部干扰和各种资源竞争,系统之间都是通过一些基础服务进行串联,如 NginxRedis 缓存、数据库、磁盘、网络等等,而基础服务问题在单服务压测中往往不能被暴露出来,因此不能反映真实的系统承载能力。

  • 场景环节覆盖不全:只关注涉及的核心服务,无法覆盖到所有的环节。

  • 大流量场景的特殊价值:某些问题只有在真正的大流量下才会暴露,比如网络带宽、系统间影响、基础依赖等等。

  • 全链路压测的意义:全链路压测不仅仅是做压测,更多的是进行一次真实的大促预演,预案演练、限流验证、破坏性演练等高可用方案的统一验收。

2)全链路压测-数据问题

全链路压测的常见问题就是如何做到生产环境的数据隔离:在生产环境进行写压测时,需要保证在压测进行的同时不影响线上业务的正常运行,那么就需要考虑将压测产生的数据与生产的真实数据隔离存储,避免脏数据对线上业务产生影响。

目前方案:有2种,影子库、影子表

3)全链路压测目标

1、数据隔离:压测数据与生产数据隔离;

2、压测结果准确:压测环境尽量与生产环境一致(高保真);

3、无影响:压测时降低对线上生产业务的影响;

4)全链路需要的能力

全链路压测能力是我们的压测目标对象和压测平台需要同时具备的一种能力,其核心在于全链路这三个字,进一步讲是全链路标识传递和数据隔离这两种能力。

问题:为什么是全链路标识传递和数据隔离这两种能力?

答案:回到全链路压测的定义(在生产环境的实施的场景化压测)避免不了用户写入场景的压测,这会对生产环境产生脏数据。为了解决这个问题引入了压测标识传递和数据隔离这两种能力的需求。

2、开展全链路压测

全链路压测在业内已经有了广泛的实践,如阿里的 AmazonPTS,美团的 Quake ,京东的的 ForceBOT ,高德的 TestPG 等等,

1)梳理业务场景

锁定系统中对性能影响较大的关键业务场景,这些场景是后续压测工作的核心关注点

  • 重要性区分:先对核心业务和非核心业务加以区分,明确流量高峰集中的业务场景,让压测重点更加突出。

  • 明确改造范围: 依据业务场景整理出接口清单,标注各接口的 “读”“写” 属性以及所运用的中间件,进而确定系统需要改造的范围。
  • 数据隔离:细致梳理数据处理的各个环节,严格确保压测数据与线上数据相互隔离,防止出现干扰情况。

2)制定压测目标

明确系统在吞吐量、响应时间、并发用户数等方面要达成的性能指标

  • 压测范围:确定要测试的业务流程,如用户注册登录、商品下单支付等核心链路。例如为大规模拉新做准备的用户注册加登录流程

  • 压测策略:选择适合的压测方式,如高仿真生产环境压测,提前经历真实的业务高峰

  • 压测目的:明确要通过压测验证或发现的问题,如探测业务吞吐极限、验证架构能力、发现性能瓶颈等

3)确定压测环境

在生产环境进行全链路压测,最核心的是线上写操作不能污染正常的业务数据。

4)准备测试数据

传统的数据构造,一般由测试人员自己维护一批压测数据。但这种方式存在很大的弊端,一方面维护成本相对较高,另一方面,其构造出的数据多样性也不足够。在真实业务场景中,我们需要的是能直接回放业务高峰期产生的流量,只有面对这样的流量冲击,才能真实的反映系统可能会产生的问题。

5)执行压测和监控

利用性能测试工具,按照设计好的场景和脚本进行压力测试,记录关键的性能指标和系统行为。同时,实时监控测试过程中的各项性能指标和系统表现,如响应时间、吞吐量、错误率等,并对监测结果进行分析和对比

  • 施压策略

    • 阶梯增压:初始20%流量预热,每5分钟提升20%至目标峰值

    • 瞬时发压:瞬时流量突增 200% 验证熔断机制(某快递公司双十一演练)

  • 多维监控体系:构建覆盖全服务链路的监控体系至关重要

6)压测复盘

根据测试结果和分析情况,找出系统存在的性能短板和问题,进而提出有针对性的优化和改进措施,不断提升系统的性能和稳定性,输出报告:瓶颈分析(如数据库慢SQL)、优化建议(如分库分表)

二、全链路能力

1、标识传递

1)全链路标识传递

定义一种压测标识,并将这个标识在压测过程中沿着请求链路一直传递下去。这就是全链路标识传递需要实现的功能。我们将压测标识定义为字符串,其取值为压测场景 ID。场景 ID 关联了一个特定的压测场景,因为我们发现不同的场景下压测所需要覆盖的服务范围、压测配置会存在差异。

2)请求间的标识传递

请求间的标识传递属于 RPC 协议规范的一部分,需要在服务框架中实现 客户端设置标识、请求传递标识、服务端读取标识三部分。

3)服务内的标识传递

业务服务在收到携带标识的请求后,在业务逻辑处理中需要将标识一直携带下去,如业务逻辑中的 RPC 请求、数据库访问、缓存访问、日志写入等等。

跨线程间的透传:对于涉及多线程调用的服务来说,要保证测试标识在跨线程的情况下不丢失。这里以 Java 应用为例,主线程根据压测请求,将测试标识写入当前线程的 ThreadLocal 对象中(ThreadLocal 会为每个线程创建一个副本,用来保存线程自身的副本变量),利用 InheritableThreadLocal 的特性,对于父线程 ThreadLocal 中的变量会传递给子线程,保证了压测标识的传递。而对于采用线程池的情况,同样对线程池进行了封装,在往线程池中添加线程任务时,额外保存了 ThreadLocal 中的变量,执行任务时再进行替换 ThreadLocal 中的变量。

4)JMQ 的标识传递

方法1:影子队列模式:即在应用程序中识别到压测标识后将消息投递到另一个队列中。消息本身不再携带压测标识,而是通过队列名称进行区分。消费者需要同时消费正常队列和影子队列,对于影子队列使用上文提到的 服务内标识传递技术进行传递。

方法2:在消息数据结构中封装 metadata 信息:并通过 metadata 传递压测标识。对于消费者而言将会在同一个队列收到正常业务消息和携带压测标识的业务消息。业务服务在读取到携带压测标识的消息后需要构建携带标识的 Context 用于应用内标识传递。

5)定时任务的标识传递

定时任务不同于业务请求,是通过时间触发而不是一个外部请求,因此无法传入标识。对于定时任务需要业务程序同时创建两个定时任务,一个是普通的业务任务,一个是用于处理压测数据的影子任务,对于影子任务可以通过配置文件管理需要注入上下文的压测标识。

2、数据隔离

规则类型 处理方式 数据影响 适用场景
Passthrough 直接透传,不做隔离 可能污染生产数据 下游服务已支持压测,无需隔离
Drop 丢弃请求,返回模拟结果 无数据写入 不需要参与压测的服务或节点
Mock 替换为模拟服务 / 数据 不触及真实资源 第三方服务、需控制压测范围的内部服务
Mirror 隔离存储压测数据 生产与压测数据分离 需要完整验证业务流程,但不能污染生产数据的场景(如数据库、缓存、消息队列)

1)Passthrough(透传)

核心逻辑:不对压测流量做特殊处理,直接透传到下游服务。

适用场景:下游服务已完全支持压测(如内部服务已改造),无需额外隔离。

2)Drop(丢弃)

核心逻辑:直接丢弃压测流量,不执行任何业务逻辑。

适用场景

  • 某些服务暂时不需要参与压测(如非核心依赖、第三方服务)。
  • 压测流量到达特定节点后无需继续向下传递。

3)Mock(模拟)

核心逻辑:用模拟数据 / 服务替代真实依赖,使压测流程完整但不触及真实资源。

适用场景

  • 第三方服务无法支持压测(如支付、短信、物流接口)。
  • 控制压测范围,避免影响某些关键服务(如数据库写操作)。

实现方式

  • 修改业务代码:修改服务调用为空转代码。
    • 优点:实现成本低。
    • 缺点:返回值固定,代码 &业务入侵高,推动困难。
  • 通用 Mock 服务:通用 MockServer,会根据不同用户配置不同 Mock 规则,执行对应的响应延时,并返回对应响应数据。
    • 优点:无代码入侵,业务方无感知。
    • 缺点:实现成本高。

4)Mirror(镜像 / 影子)

核心逻辑:将压测数据与生产数据隔离存储,但保持业务流程不变。

适用场景:需要完整验证业务流程,但不能污染生产数据(如数据库、缓存、消息队列)。

实现方式:如下

a、数据库隔离

  • 影子库:将压测流量路由到独立的数据库实例。

  • 影子表:通过 SQL 解析改写表名(如usershadow_user)。

b、缓存隔离

影子 Key:在缓存 Key 前添加特定前缀(如shadow:user:1)。

// 示例:缓存Key隔离
String originalKey = "user:" + userId;
if (isPressureTestRequest()) {
    key = "shadow:" + originalKey;
}
cache.get(key);

c、消息队列隔离

  • 影子 Topic :将压测消息发送到独立 Topic

    // 示例:消息发送隔离
    String originalTopic = "order-create";
    if (isPressureTestRequest()) {
        topic = "shadow-order-create";
    }
    messageQueue.send(topic, message);
    

四、影子库与影子表

1、方案介绍

1)影子库

针对影子库方案,是在同一个实例上建立对应的影子库。 **用户服务挂载的全链路压测探针获取到流量标之后进行相应的旁路处理,如果是影子流量,那么会从影子连接池中获取影子连接供业务侧使用**,从而将压测流量产生的数据旁路到对应的影子库中,以此达到数据和生产库隔离的效果,从而避免了压测流量产生的数据对生产库造成污染。

image-20250702091907639

2)影子表

影子表方案,是在同一个实例上的同一个数据库上建立对应的影子表。用户服务挂载的全链路压测探针获取到流量标之后进行相应的旁路处理,如果是影子流量,那么,探针会针对本次的 DB 调用进行 SQL 解析和替换,从而将压测流量产生的数据旁路到对应的影子表中。

image-20250702092047875

2、方案对比

具体选择两种方案中的哪一种,其实仅靠一个指标判断是不够的,要结合以上多个指标以及具体的业务场景来进行综合评估的。下面针对两种典型的场景来说明应该如何选择适合自己方案,以下意见仅供参考。

  • 影子表方案:在涉及到的读表比例高于写表、并且整库迁移成本较高的情况下,推荐选择影子表方案,在一定程度上可以减少复杂的数据迁移带来的成本。
  • 影子库方案:在涉及到的写表比例高于读表,同时生产库实例容量较为充足的情况下,推荐选择影子库方案,在一定程度上降低了梳理、配置的成本。
  • 混合方案:部分企业采用混合模式,核心业务用影子库,非核心业务用影子表
横向纬度 纵向纬度 影子库方案 影子表方案
设计思想   根据影子标识区分影子流量,与影子库建立长连接 根据影子标识改写SQL中的表名,访问影子表
成本 改造成本 (中)(库级复制,路由逻辑简单) (高)(需 SQL 解析引擎和动态路由)
  冗余成本 (高)(全库复制,包括只读表)存储容量需要Double (中)(仅复制写表,读表复用)
  数据迁移 (高)(需全量迁移和持续同步结构变更) (中)(仅迁移写表及关联数据)
仿真度   (中)影子库使用自有独立连接池,需保证资源配置与正式环境一致;无背景流量,仿真度不如影子表 (高)压测流量与正式流量共用数据库连接池,资源配置及基础连接数均为线上真实环境
安全性 连接池管理 (中)独立连接池,隔离性好, (中)共享连接池,需比例分配(如生产:压测=2:8)
  连接池安全 (中)压测期间不会影响正式数据库线程池 (中)可能出现压测过大导致线程池被打满,影响线上业务**
  隔离级别 (中)物理隔离(独立数据库实例) (中)逻辑隔离(同一数据库内的独立表)
性能影响   (低)(独立连接池,无资源争用) (中)(SQL解析增加5-10% CPU开销,共享连接池可能瓶颈)
环境稳定性 资源占用 (中)占用较多资源及存储,不宜长期留存,存在资源回收、再创建情况。 (高)影子表可以持续留存线上数据库中,只需按需做数据清理
  数据清理 (低) 简单(直接删除影子库) (中)(需按条件清理影子表)
异常场景 数据错乱 存在路由异常场景该如何处理的问题。 存在路由异常场景该如何处理的问题。
    解决方案:①压测开关,非压测期间拒绝压测流量访问;②压测流量跟踪,日志存档。 解决方案:①压测开关,非压测期间拒绝压测流量访问;②压测流量跟踪,日志存档。
维护成本   (需同步生产库结构变更) (仅需同步写表结构变更)
适用场景   写密集型核心业务(如支付、交易),资源充足 读多写少业务(如商品浏览),成本敏感

1)稳定性:选影子库

  • 影子库方案:由于是在同一个实例上建立不同的数据库,所以如果不考虑数据库实例能够达到最大连接数上限,理论上影子连接和正常连接时相互独立的,执行时互不影响。

  • 影子表方案:由于是在同一个实例上的同一个数据库上建立了不同的数据表,那么这里就要考虑业务侧的连接池配置了,因为影子流量涉及到的 DB 操作和正常流量涉及到的 DB 操作,所用的数据库连接,均来源于同一个连接池,所以如果压测量级较大的时候,是比较容易出现连接池连接瓶颈的。

2)冗余成本:选影子表

  • 影子库方案要在同一个数据库实例里,把生产环境的库(含表结构、数据)完整 “复制” 一份做影子库 。哪怕是 “基础只读表”(只有读操作、不会有写入的表),也得单独冗余一份,不能复用生产库已有的。企业规模越大、这类表越多,冗余的数据量和存储成本越高,中大型企业很难接受这种高成本。
  • 影子表方案:基于生产库的同一个数据库实例,只针对 “写表”(有数据写入操作的表)建立影子表 。像 “基础只读表”,直接复用生产库的,不用额外冗余。这样就少了很多不必要的数据复制,降低了存储、维护等冗余成本,比影子库方案更 “省钱”。

3)数据迁移成本:选影子表

影子库方案:全量迁移,范围大、成本高(尤其数据量大、表复杂时)

影子表方案:聚焦写表,复用只读表,范围小但依赖业务梳理清晰,

  • 影子库方案:全量迁移,范围大、成本高(尤其数据量大、表复杂时)
    • 全量库迁移:需要复制整个数据库实例,包括所有表(无论读写)
    • 基础只读表冗余:即使是不变的配置表(如省份编码、商品类目等)也需要完整复制一份,无法复用
    • 存储空间翻倍:对于大型电商系统,TB级数据库的复制会导致存储成本显著增加
  • 影子表方案:聚焦写表,复用只读表,范围小但依赖业务梳理清晰
    • 仅冗余写表:只需为有写操作的表创建影子表,读表(如商品信息表)可直接复用生产表
    • 选择性数据迁移:只需迁移写表及其关联数据(模拟真实场景,必须),基础配置表无需迁移

五、如何负责好一次大促

1、备战前:资源对齐

1)KJ 侧对接(每周会议驱动)

  • 核心动作

    • 参加 KJ 大促周会,同步 BX 业备战进展,获取 KJ 侧资源支持

    • 传递 KJ 侧关键要求:
      • 性能指标CPU 利用率≤ 70%、接口P99 响应时间 ≤ 500ms
      • 发版封板:确认大促前代码冻结时间(如T-3天18:00前完成所有变更)。
    • 更新内部团队:
      • 全链路压测时间(如T-15天20:00-22:00)、大促活动时间(如6月18日0:00-24:00)。
      • 安排值班表:按“核心接口负责人+SRE”组合排班,明确签到方式
  • 交付物

    • KJ- BX 对接纪要(周更)》
    • 《大促值班表(含签到规则)》

2)业务需求管控

  • 核心动作
    • 统计大促期间业务上线需求,按优先级分类:
      • P0(必须上线):如监管合规修改、核心功能优化( KJ 侧联合评审)。
      • P1(可延期):如用户体验优化、非核心功能迭代。
    • 封闭期(T-3天~T+1天)上线需邮件审批,抄送 KJ 侧负责人,明确回滚方案。
  • 交付物
    • 《大促需求清单(含优先级标注)》
    • 《封闭期上线审批邮件(含回滚计划)》

3) 内部研发管理(每周例会驱动)

  • 核心动作

    • 压测接口统计:

      • 梳理核心接口清单,标注依赖服务(数据库、缓存、第三方)。

      • 执行单接口压测,记录 TPS、错误率、TP99 响应时间(示例):

        接口名称 当前 QPS 目标 QPS 瓶颈点 优化措施
        核保接口 800 1200 数据库慢查询 添加索引
    • 降级预案:

      • 制定《降级规则表》,明确触发条件(如数据库连接数 >90% 时自动熔断核保接口)。
      • 演练降级流程,验证自动化开关有效性
    • 巡检加固:

      • 检查服务器资源( CPU / 内存/磁盘使用率)、中间件配置( Nginx 超时时间、Redis 内存碎片率)。
      • 修复高危漏洞(如 Log4j2 漏洞补丁升级)。
    • 流量地图:标识上下游接口,以及流量情况,标识问题,

  • 交付物:

    • 《压测接口统计表(周更)》
    • 《降级预案手册(含演练记录)》
    • 《巡检加固报告(含修复项)》
    • 《核心接口流量地图(可视化看板)》
    • 《周例会纪要(含待办事项跟踪)》

2、备战中全链路验证与流程固化

1)KJ 侧协同

  • 核心动作:参加 KJ 侧全链路压测动员会,确认压测范围
  • 交付物:《压测计划》

2)内部研发管理

  • 核心动作:压测执行:

    • 监控关键指标:核保接口TPS是否达标、第三方支付通道超时率是否可控。
    • 记录压测问题:如缓存穿透导致数据库CPU飙升至95%,紧急添加空值缓存。

    • 作战室准备:
      • 部署监控大屏,展示核心接口实时数据(QPS、错误率、响应时间)。
      • 准备应急工具包:降级开关操作指南、 KJ 侧应急联系人清单。
  • 交付物:

    • 《全链路压测报告(含问题修复计划)》
    • 《封板检查清单(所有项勾选通过)》
    • 《作战室物资清单(监控大屏、应急工具包)》

3、大促期:实时响应与动态调控

  • 核心动作:

    • 作战室值班:主班人员实时监控告警,备班人员随时支援突发问题
    • 动态调控:
      • 根据流量地图调整限流阈值(如核保接口从 1200 QPS降至1000 QPS,避免数据库过载)。
      • 记录战时决策:如“因第三方短信通道限流,临时降级为异步发送,业务影响<0.1%”。
    • 战报:通过作战室、实时大屏、战报等手段营造紧张感,同时设置“减压时刻”(如大促后团队聚餐)缓解压力。
  • 交付物:

    • 《实时流量地图(含动态调控记录)》
    • 《战时决策记录(含问题定位-处理-复盘)》

4、备战后:经验沉淀与能力提升

1)KJ 侧复盘

  • 核心动作:参加 KJ 侧大促复盘会,汇报 BX 研发侧贡献:
    • 稳定性成果:出单成功率9 9.98%、0重大事故。
    • 优化案例:通过压测发现核保接口 SQL 缺陷,节省 20% 服务器资源。

2)内部研发复盘

  • 核心动作:输出《大促稳定性战报》,包含:

    • 目标达成率:压测覆盖接口100%、降级预案演练通过率100%。
    • 关键问题:如“缓存穿透导致数据库CPU飙升”的根因(空值未缓存)及改进措施(新增空值过滤中间件)。

    • 更新知识库:将优秀实践(如自动化压测脚本、降级开关操作SOP)录入团队文档。

5、应用考核

  • 应用级:
    • ① ≥ 200CCPU 利用率≥26%;
    • ② ≥ 100C且< 200C,CPU利用率≥20%
  • 备战团队:
    • 大促期间CPU利用率≥32%,
    • 日常标准≥38.5%,、
  • 缓存资源利用率:
    • 缓存利用率大促峰值利用率45%,
    • 日常利用率60%;

ContactAuthor