写点什么

稳定性全系列(二):如何做线上全链路压测

  • 2020-03-25
  • 本文字数:3164 字

    阅读完需:约 10 分钟

稳定性全系列(二):如何做线上全链路压测

1. 背景介绍

如今,在微服务架构盛行的互联网时代,微服务架构下模块(本文指可独立部署的服务)之间的关系错综复杂(哪怕是避免模块之间的直接循环依赖都很变得困难),评估一整套业务系统(集群)的容量已经不像评估单机系统那样容易,而系统的容量评估,是稳定性建设的核心内容之一,是我们绕不开的主题。


有了系统容量评估,配合今年的业务目标,我们才知道应该申请多少预算、什么时候需要扩容、系统瓶颈在哪、哪些服务(模块)需要扩容。评估系统容量或者准确的说 评估线上系统的容量现阶段最优效也是最准确的方式就是进行线上全链路压测

2. 准备工作

你要问实现线上全链路压测难不难?当然难(现阶段稳定性工作哪一项不难?),但依然有迹可循。而且和当前技术体系的系统化建设程度以及各团队之间协作有关系。想实现线上全链路压测,我们需要做如下三个方面的准备工作(为了描述简单,本文的“全压”指的是线上全链路压测):


  • 确定需要哪些团队参与

  • 确定全压技术方案

  • 设定全压目标和计划

3. 拆分详情

确定需要哪些团队参与

全压绝对是一项耗时耗力的工程,特别是刚开始的时候。首当其冲的当然是得到老大的支持,一般需要参与进来的至少有 研发测试运维 三个团队。研发团队主要负责技术方案的设定和实施(当然如果有架构组或中间件团队,技术方案的设定可以交给他们),测试团队负责验证全压方案和数据的正确性以及真正的施压,而运维团队需要关注压测对线上集群的影响以及一些辅助工作(例如提前调整网关的限流阈值)。

确定全压技术方案

这一步应该是难度最大的,不同技术体系具体实施方案当然不一样,但可以相互参考,就拿我的业务部门举例,我们服务端是 Java 栈,整个业务流量符合如下链路:



上图最左边的 App 指的是用户手机中装的 App,从后面的链路我们可以看出,业务网关后面就是我们的服务端系统,各模块之间使用 Dubbo 来进行交互,当然异步用的是 DDMQ,而当模块需要使用集团的中台服务时,我们使用的是 HTTP。模块内部还使用了线程池,也使用了 MySQL、Redis 等外部服务。


第一步,确定“全链路”应该包含链路(或顶级接口),所谓的全链路,它其实是一个相对的概念,在刚开始做全压时,我们主要是把线上的核心链路找出来,找到这些链路的顶级接口,这其实就是发压的主要入口。


第二步,确保压测标识在这些链路中传递以及处理,第二步是最难的也是最复杂的,我们要分析第一步中这些链路中如何有效安全的传递压测标识,压测标识是系统中用来区分压测流量还是线上正常流量的标识,我们要保证压测标识正确的传递和清除,否则可能导致严重的线上事故。这里将给出我们的做法,供大家参考,主要分四大部分:


  • 尽可能的对模块无侵入或低侵入


微服务架构下可独立你部署的模块数可能会非常惊人,任何能成功实时的技术方案都应该要求是对业务模块是无侵入或者是低侵入的,否则将影响方案的推广以及实施成本,我们为了做到这一点,打算直接在我们的基础组件(内部使用的公共库和中间件)动刀子,尽可能的对用户透明。


  • 压测标识安全的传递和处理


这个要分模块内、模块间、模块外三个部分来考虑:


模块内:假如模块内部已经知道该流量是压测流量,我们如何保证该压测流量能在模块内部复杂的逻辑处理中不丢失?模块内主要考虑的是线程中和跨线程执行的时候,压测标识容易丢失,线程中,我们使用的是对 ThreadLocal 的包装类(我们没使用阿里开源的 TransmittableThreadLocal)。而为了能够跨线程传递,我们修改了 taxi-thread 公共库,将其中的 TaxiThreadPoolExecutor 等类进行了修改,加入了压测标识的传递(这里补充下背景,我们为了 traceId 能跨线程传递,在 taxi-thread 公共库中包装了 JDK 线程池相关的类,并在开发规范中要求研发同学不能直接使用 JDK 原生的线程池)。还有一块,就是日志打印,为了能准确区分压测流量和正常流量,也为了压测流量不污染线上数据(比如线上很多模块有埋点日志),我们修改了 taxi-log(我们这边没有直接使用 SLF4J,而是使用包装过的日志公共库 taxi-log),将压测流量所有的日志打在原日志目录下的 shadow 影子目录下,这一切对用户也是透明的。


模块间:我们这边模块间的通讯方式主要是 Dubbo 和 DDMQ,Dubbo 这块的话我们直接通过 Filter 来实现压测标识传递,而 DDMQ 本身就自带压测标识传递方式,可以直接使用。


模块外:这一部分主要是存储、缓存以及一些外部服务(比如上图的中台服务)。


存储例如 MySQL、MongoDB 等,我们必须要隔离压测和线上数据,所以我们会事先建好所谓的 影子表,影子表其实和线上表的区别就是表名,影子表会在真实表名前加一个 shadow_前缀,而我们的 taxi-mybatis、taxi-mongo 等公共库在识别到压测标识时,会给表或者文档名称前也带上 shadow_前缀。之所以只是做表隔离而没有做库级别隔离,考虑到的还是降低侵入性和成本。关于存储,还有一个关键点,假如模块只提供查询服务(比如某些配置中心),如果按照前面说的,存储接入压测标识这块做成无侵入的话,全压流量查询也会走影子表,这也许是我们不希望看到的,所以在 MySQL 这块我们特意做成有侵入的(需要加一个插件配置),否则默认不识别压测标识


对于分布式缓存,我们使用的是 Redis,这一块的处理方式和存储类似,我们修改了我们自己 Redis 包装的公共库,如果是识别到压测标识,默认在操作的 key 上加一个 shadow_前缀,保证压测流量不污染线上缓存数据。


对于外部服务,我们使用的是 HTTP 来调用,所以修改了我们 taxi-util 中的 HTTP 组件,做了压测标识的传递,保证下游外部服务能知道这是压测流量。那肯定有人问,如果下游服务不支持压测流量识别该咋办?所以这里我们借助了 SDS 服务降级系统https://github.com/didi/sds),可以只对压测流量进行拦截,使其不调用下游外部服务。


最后的效果如下:



第三步,确保全压流量能被监控到,这涉及到我们在实际全压中能否直观的感受到压测流量,这一块需要和内部的监控系统来打通,由于能方便的取到压测标识,这一块的实现我们不再阐述。


第四步,准备全压数据,确定接口调用比例,最理想的方式是能对线上流量进行克隆、放大和处理,作为压测输入数据来重放,但这块难度较大,需要有好的平台来支撑,我们目前只能使用更简单的方式来造数据。由于无法使用仿真数据,我们提前在影子表中造了一批用户、设备信息、位置等和业务相关的数据,然后去线上统计了链路上各顶级接口的流量和交易量的比例,来作为压测时流量放大的依据。当然,必不可少的还有一个发压工具或平台,例如滴滴的奥创发压平台。

确定全压目标和计划

全压前我们需要定下全压的目标,比如当前我们交易系统能支撑 100W 订单(现有日单量峰值),而业务今年的目标是冲击 300W 日订单,那按照峰值流量 2 倍来算,我们的交易系统需要支撑 600W 的单量,那么第一次全压的目标可以保守些,定为日订单 200W。因为哪怕线下验证已经充分,全压时也会遇到各种出乎意料的问题,当然发现问题其实也意味着我们发现了系统容量瓶颈,这也是全压的主要目的之一。全压计划也同样重要,因为我们系统一定是在不断的迭代中,上一次的全压结论可能会很快“过期”,所以我们需要定下明确的全压计划和节奏,不断降低全压的人力成本,使这一稳定性建设工作持续有效的进行下去。

4. 总结

截止到目前,我们已经进行过很多轮的全压,也在不断往全压中补充新的链路,加入新的模块,目前全压的人力成本还是较高,我们也在探索全自动化全压方案,到时候有成果将和大伙继续分享。


作者介绍


易振强,滴滴专家工程师


我是易振强,热爱开源,热爱分享,深耕分布式系统和稳定性建设,欢迎关注 SDS 服务降级系统:https://github.com/didi/sds ;也热爱生活,热爱漫画,一拳超人和海贼王都很好看!!


本文转载自公众号普惠出行产品技术(ID:pzcxtech)。


原文链接


https://mp.weixin.qq.com/s/2M9EyCIuT1mZ9drftdMEBA


2020-03-25 10:004349

评论

发布
暂无评论
发现更多内容

MySQL 服务器演化分析

Andy

关于Tensorflow!目标检测预训练模型的迁移学习

北桥苏

Python 深度学习 tensorflow 目标检测

数说热点|社恐人群运动健身指南:不想去健身房,那就在家找面墙

MobTech袤博科技

Java面试通关:阿里内部实战模拟面试精讲题库,竟被上传GitHub!

Java你猿哥

Java redis JVM java面试 Java基础知识点

用 Tensorflow.js 做了一个动漫分类的功能(一)

北桥苏

JavaScript tensorflow

2023企业数智化财务创新峰会西安站圆满举办!

用友BIP

智能会计 价值财务

100万数据,如何快速的导入数据库?

NineData

数据库 开发者 数据导入 数据导出 NineData

用 Tensorflow.js 做了一个动漫分类的功能(二)

北桥苏

JavaScript node.js tensorflow

如何在 Windows10 下运行 Tensorflow 的目标检测?

北桥苏

深度学习 tensorflow 目标检测

智慧工业园三维可视化安全生产管控系统

2D3D前端可视化开发

物联网 可视化 智慧园区 智慧化工园区 工业组态

简单聊聊MySQL索引优化的内容

(-0 , +0)

javaweb脚手架springboot基础入门

(-0 , +0)

springboot整合redis基础示例

(-0 , +0)

Nautilus Chain 或成未来最好的链上隐私生态

西柚子

Prompt工程师指南[高阶篇]:对抗性Prompting、主动prompt、ReAct、GraphPrompts、Multimodal CoT Prompting等

汀丶人工智能

人工智能 自然语言处理 深度学习 ChatGPT prompt learning

分类树,我从2s优化到0.1s

Java你猿哥

Java 算法 ssm 分类树

火山引擎DataLeap数据调度实例的 DAG 优化方案 (一):问题与需求分析

字节跳动数据平台

数据平台 DAG DataLeap

SpringBoot整合MybatisPlus基础教程

(-0 , +0)

springboot Mybatis Plus

eBPF动手实践系列二:构建基于纯C语言的eBPF项目

阿里云大数据AI技术

运维 C语言 ebpf 企业号 5 月 PK 榜

一把王者的时间,带你吃透Java面试八股文(2023最新整理)

Java你猿哥

Java 面试 微服务 Spring Boot mybatis

宝兰德应用服务器软件与华为云GaussDB完成兼容互认证

华为云开发者联盟

数据库 后端 华为云 华为云开发者联盟 企业号 5 月 PK 榜

在GitHub被疯抢的这份阿里内部绝密Java面试八股文手册有多强?

Java你猿哥

Java MySQL 面试 JVM Java八股文

Java中常见集合类核心源码阅读

(-0 , +0)

Java 源码 集合

Java常见集合类型及其异同点,简单使用

(-0 , +0)

Java 集合

什么是策略模式?如何在Java项目中引入策略模式来优化代码结构

(-0 , +0)

MVP发布后,接下来该做什么?

敏捷开发

项目管理 Scrum MVP 最小可用产品

Windows10上CUDA9.0+CUDNN7.0.5的完美安装教程

北桥苏

深度学习 cuda cudnn

火山引擎DataTester:A/B实验平台数据集成技术分享

字节跳动数据平台

Prompt工程师指南[应用篇]:Prompt应用、ChatGPT|Midjouney Prompt Engineering

汀丶人工智能

人工智能 自然语言处理 ChatGPT MidJourney prompt learning

如何将训练好的Python模型给JavaScript使用?

北桥苏

Python tensorflow AI

如何用 ModelScope 实现 “AI 换脸” 视频

北桥苏

Python ModelScope

稳定性全系列(二):如何做线上全链路压测_架构_易振强_InfoQ精选文章