全链路压测体系

Posted 字节跳动技术质量

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了全链路压测体系相关的知识,希望对你有一定的参考价值。

压测方案

网络架构

  • 目的

理解业务的请求在网络中是如何流转的,整个过程经过了哪些节点。业务请求经过的所有节点,都是压测的对象。在压测过程中,都需要关注其性能表现。

  • 请求流转

下图一个典型的网络架构,用户请求通过CDN溯源,经过TTGW,TLB,AGW,然后才到达业务服务PSM。(TTGW是头条的高性能4层负载均衡网关,TLB是七层负载均衡服务,AGW是头条统一业务Api接入层)

压测目的与方案

在全链路压测体系第一步,压测人员必须明确压测目的,当明确压测目的后才能选择一个合理的压测方案。一个完整合理的方案可以提高全链路压测效率,减少没有意义的工作,节约了时间成本,对后续其他模块的压测或常态化压测提供了一定借鉴。

  • 目的:在结合业务背景前提下,用户清晰把握明确性能测试的目的是什么?根据不同场景分类,有着不同目的,常见的场景如下:


场景分类

主要目的

典型场景

主要特点

能力验证


验证在给定的软硬件条件下,系统能否具有预期表现

当前服务已经部署了n台机器,能否支持50万用户同时在线访问

1、软硬件环境都已经确定
2、有明确的性能目标
3、需要根据业务场景来构造压测数据和请求
容量规划
容量规划
关注如何使系统具有我们要求的性能
春节活动需要X亿人同时在线访问,系统需要如何调试?(性能优化,设计优化,资源预估)
1、它是一种探索性测试
2、常用于了解系统现状
3、需要根据系统现状,对未来系统进行一个预估和规划
性能调优

主要用于对系统性能进行调优

系统响应越来越慢,此时该如何处理?
1、对于代码级的优化,单实例压测即可
2、对于系统整体设计优化,需要集群压测,保证集群负载维持在一定水位
缺陷发现重现
发现/重现性能缺陷
服务线程死锁,内存泄漏等
1、需要对性能问题分类
2、针对每类问题构造对应的数据和压测策略
性能基准比较
系统新版本的性能验证
新版本的代码改动,是否有降低了系统性能,是否符合上线要求
1、有版本性能基准
2、固定环境因素的影响
3、AAB Diff
4、diff置信度

压测目标

在网络架构图中,明确展示了各系统各司其职,它们分别负责将用户请求做相应处理并将请求流转至下游服务。因此,根据压测方案的目的,选择一个合理的压测目标,可以减少大量的压测工作,提高压测效率。


目的
压测目标
典型场景
压测带宽
从CDN、TLB处发压
春节活动需要X亿人同时在线访问,链路带宽是否足够?
压测业务逻辑
从汇聚机房、核心机房、卫星机房的AGW和业务服务发压
用户零点秒杀,是否能够保障商品、订单等系统一切正常?
压测异步消息
从MQ producer处发压
异步消息队列是否能够满足高压力场景?

环境隔离

在字节内部,BOE环境是不允许压测的,由于BOE资源不足,与线上环境差异大,压测出来的结论并不能充分保证线上的性能情况。因此本文指的压测都是在线上环境,或者PPE环境下的压测。下文将重点介绍字节的全链路压测环境。

压测标记

为了区分线上流量与压测流量,使服务可以针对压测流量做定制业务逻辑,服务架构体系在服务框架与服务治理层面设定了压测标记。

目的:

  • 对于框架与服务治理体系而言,压测标记可以用于区分流量属性,并且做相应拒绝/通过操作。

  • 对于业务服务内部而言,压测标记可以让业务方识别压测流量并做相应的业务逻辑处理。

原理:

  • 通过特殊字段stress_tag,对压测流量进行染色,且压测标记对应的value不为空的流量。

  • 服务框架通过解析请求的stress_tag,对接口上下文注入压测标识符,并透传至下游服务,完成全链路压测标记透传。

生效条件:

  • 压测前必须做服务改造。在全链路中,所有服务必须将上下文透传至下游,保证压测标记能被框架识别且透传。

压测开关

为了强化压测流量的管理,服务治理体系引入了压测开关的概念。压测开关作为总控制,所有服务框架必须判断压测开关是否打开,若打开才能允许通过压测流量,若关闭则只能拒绝压测流量。

目的:

  • 保护线上服务,避免线上服务在没有准备好的情况下,或不能压测的情况,受到压测流量的袭击

  • 压测紧急处理,对于线上服务负载过大时,且无法停止压测流量时,可以通过压测开关拦截所有压测流量,避免出现线上故障

原理:

  • 压测开关的表达方式是etcd的配置值,每个服务都会有一个特定的压测开关key,value为on表示打开状态,off为关闭状态。存储服务的压测开关key各有不同。

  • 每个服务每个集群都有一个压测开关(key = psm/cluster),控制该集群的压测流量

  • 计算服务的压测开关状态都是由框架和Mesh来判断的,存储服务的压测开关状态则是由存储服务的SDK来判断的

  • 压测开关没有打开时,压测流量会被服务框架或存储SDK拒绝

生效条件:

  • 压测前必须打开整条调用链中所有服务的压测开关,否则压测流量会被框架/SDK拒绝。(开关可以在Rhino压测平台打开)

存储隔离方案

对于压测数据的存储,必须将线上数据与压测数据做隔离,否则会导致压测数据量过大影响线上数据正常存取。

目的:

  • 将压测过程中产生的测试脏数据与线上真实数据做隔离,防止污染线上真实存储。

  • 存储隔离后,可以测试出预期存储条件下的性能。

原理:

  • 各存储系统的SDK会对输入的上下文识别压测标识符,若存在压测标记,则走影子表存储,否则走线上存储。

  • 部分SDK另外提供压测开关判断,用户需打开存储服务的压测开关方可存到影子表中。

生效条件:

  • 压测前必须对代码做相应改造,并升级至最新版本的存储SDK

平台搭建

Rhino压测平台

它是一个多功能压测平台,支持多种场景、模式的发压。Rhino统一管理了压测任务、压测数据、发压机、压测结果。集成了Bytemesh、User、Trace、Bytemock、Bytecopy等多个系统。

全链路压测体系

字节压测平台对比

Rhino压测平台 vs Holmes压测平台


Homles压测平台
Rhnio压测平台
压测协议 支持
thrift
http/https/protobuf/thrift/其他所有(plugin)
发压能力
目前发压机数量<10,MaxQPS<10W
发压机水平扩容能力?
目前发压实例<400,MaxQPS<400w
发压机理论上可以无限水平 扩容
多机房支撑
自己搭建压测环境,不存在多机房
CN/Alisg/Maliva
压测环境搭建
平台自动拉取scm,自动搭建压测环境
链路拓扑: 压测环境->线上环境
不支持,统一线上压测
压测数据
线上流量录制,保存最近2个小时内录制数据,直接回放
用户构造fake数据
csv文件数据
流量录制回放:录制数据保存在hdfs,可以多次改写,回放。不受时间限制
研发流量整合
已经接入CI,每次CI后,自动拉取代码编译,并搭建压测环境,进行性能diff
接入Devops,发布前,对stress集群进行压测
性能diff
支持多种指标、以及自定义指标的diff
支持多版本的性能diff
只支持不同压测结果的diff
压测报告
只提供被压测服务的性能指标监控
客户端监控、服务端监控、下游监控、性能profile,告警监控
压测风险
将压测流量打到非被测服务,引发问题
发压数据的schema版本与线上服务不一致,引发问题
压力太大,有将服务及下游打挂的风险
压测链路中存在写接口,如果没有改造,有数据污染的风险
风险控制

压测标记 & 压测开关
链路梳理&压测周知
告警监控
压测方式
流量录制回放
Fake数据压测
流量录制回放
线上单实例流量调度

压测方式

根据不同业务的场景、以及压测的方案,业务方需要制定不同的发压方式,以达到压测预期效果。下面将介绍Rhino平台提供的四种发压方式,业务方需根据自身业务特点,选择适合的方式发压。

Fake流量

Fake流量压测是指用户自行构造压测请求进行压测。Rhino平台支持HTTP、Thrift两种协议的Fake流量发压。

原理:

全链路压测体系

Fake流量模式适合针对请求参数简单的接口压测,同时也适合针对特定请求进行压测。Rhino平台会为每个请求注入压测标记。

典型场景:

  • 新服务上线之前进行压测。

  • 为了重现某种场景下造成的性能问题,构造特定参数的请求发压。

  • 线上http/thrift服务已经在运行,且接口参数比较单一,快速压测接口

  • 接入公司passport lib后,使用压测账号进行压测

自定义插件发压

为了支持更多的协议与更复杂的压测场景,Rhino平台支持了GoPlugin发压模式。

原理:

依赖golang的plugin功能,运行时加载plugin文件,并加以执行

全链路压测体系

GoPlugin发压模式适合灵活构造请求数据、支持自定义协议、支持自定义发压场景,相当于所有发压场景都可以通过代码实现。注意Rhino平台对于GoPlugin模式不会注入压测标记,用户需在插件内加上压测标记。

典型场景:

  • 压测自定义协议的服务,如websocket、gRPC等

  • 压测自定义的场景,如请求一个接口后等待2s再次请求第二个接口、请求第一个接口对返回值做相应的计算转换再请求第二个接口等

  • 自定义的压测数据构造,比如从DB、服务等获取压测请求数据

  • 自定义的压测目标:比如要压测消息队列,可以通过构造一个GoPlugin对producer发压

流量录制回放

为了使压测更贴近线上请求,Rhino平台支持了流量录制回放的发压模式,平台经过线上流量采集、线上流量改写为压测请求、压测流量回放三个步骤,将线上请求回放到压测目标中。

原理:

全链路压测体系

依赖bytecopy的采集流量能力,要求服务已经部署到线上,开启mesh,且有流量可以采集。

典型场景:

  • 构造压测请求比较复杂,且服务已经上线,线上有流量可供采集

  • 压测需要模拟线上请求的分布,避免hot key,如搜索query

  • 希望将线上流量放大N倍,录制线上流量并回放到特定压测目标

  • 希望录制线上流量,同时执行复杂的改写规则用于回放

流量调度

对于服务维度而言,如果想测试服务能承载多少QPS,每个接口的QPS分布情况,流量调度是一个比较合适的压测方式。Rhino平台支持了单实例的流量调度模式压测。

原理:

全链路压测体系

scheduler修改被测实例的consul权重,使流量不断打到目标实例中,而其他实例流量相应的减少,保持服务的总流量不变。压测的请求完全来自线上流量,不使用压测标识,因此压测流量的流转、存储均保持线上模式。同时scheduler会监控目标实例的服务指标,当服务指标到达阈值后将停止压测,将consul权重恢复至初始值。

典型场景:

  • 希望评估当前服务能够承载多少qps,每个接口分别承载多少qps,可将压测结果用于服务容量评估

  • 不希望对代码做压测改造,快速增加单实例的压力

压测方式对比

下面将上述压测方式在压测目标、压测场景、优缺点维度下做对比,方便业务方选择合适的方式用于压测。

全链路压测体系

监控

为了使压测结果更准确、使被测服务在压测过程中更安全,Rhino平台开发了一套压测专用的报警监控体系。分为实时客户端监控、被测服务端监控、ms报警监控。

实时监控

公司的服务监控体系是基于metrics的30s一次聚合,但是对于压测任务而言,意味着观察压测状态需要等待30s的延时,这基本上是不能忍受的。因此Rhino平台支持了发压客户端维度的秒级监控,使用户可以及时观察压测状态,当压测出现异常时可以立即停止压测。

实现方案:

全链路压测体系

服务端监控

Rhino支持服务端角度的全链路监控,包括服务监控、机器资源监控、上下游监控。目前使用的是grafana面板展示,将全链路每个服务metrics、机器influxdb数据聚合展示到grafana中。未来将使用Argos展示服务端监控数据。

ms报警监控

此外,Rhino平台还支持监控ms告警规则,当被测服务或下游服务触发了告警规则后,压测任务便自动停止,防止造成线上事故。

实现方案:

全链路压测体系

分析&优化

最后,压测完成后,如何分析压测问题,并作出相应优化通常是业务方最关注的问题。下文将列举几种分析方法,以及常见的性能问题及优化方式。

分析方法

  1. 监控分析

可以从发压客户端监控、被测服务端监控发现异常,异常主要包括:

  • 尖刺现象,查看错误日志,抓请求重现

全链路压测体系

  • 压力到达瓶颈,性能开始下降,接口延时上升,需要查看pprof对各项指标做相应分析

全链路压测体系

  • 被测服务某一资源被打满,查看cpu耗时统计,找出耗时的模块

全链路压测体系

  • 流量/延时分布不均,查看agw是否正常分配流量,查看存储sharding是否正常

全链路压测体系

  • 协程数量大涨,且没有下降趋势,协程泄漏,检查代码协程使用


  1. Nemo性能分析平台

用户可以通过nemo分析平台做服务的pprof分析,nemo平台支持分析golang、python语言的服务,分析的指标包括cpu使用率、内存使用、协程数、线程数、阻塞时间。一般分析Top使用率,如果TopList展示了不正常的元素,应该关注这个异常元素。

  1. 系统层tracing分析

  • 基于宿主机系统层面的cpu、topN函数分析

常见问题

  1. 服务的 CPU 陡然升高,RPC调用和 consul、etcd 访问频繁超时,以及 goroutine数目大涨。
  • 可能是频繁创建kitc client,每个调用创建一次。正确用法是只初始化一次client,重复使用
  1. 调用http接口,协程泄漏
  • 可能是http connection未释放,常见的代码问题是http.Body未Close
  1. 内存RSS一直升高,没有下降趋势,内存泄漏
  • 内存泄漏可以根据pprof top list查看最高使用的函数/对象,并作出优化调整
  1. 性能瓶颈为写数据库
  • 可以尝试加入写proxy解决
  1. redis连接超时
  • 需要增加redis client连接数
  1. 发压压力很高,但被测服务cpu却一直未跑满
  • 有可能是用到了锁,需要profile排查一下

写在最后:




以上是关于全链路压测体系的主要内容,如果未能解决你的问题,请参考以下文章

全链路压测体系建设方案的思考与实践

全链路压测体系建设方案的思考与实践

全链路压测性能保障体系建设之路

全链路压测最佳实践

全链路压测体系建设方案的思考与实践

全链路压测体系建设方案的思考与实践