摘要:设计一个线上压测系统能让我们学习到多少东西?这 13 个问题看你能否搞定。
本文分享自华为云社区《设计一个线上压测系统能让我们学习到多少东西?13 个问题看你能否搞定》,作者:breakDawn。
Q: 为什么需要线上压测?
A:
- 需要在某些活动、大促前,评估机器扩容数量,验证系统能否有效支撑流量峰值。
- 线下测试环境的机器资源有限, 无法完全模拟现网。 同时很多配置可能配置不相同,如果没对上导致机器数量估计错误,可能引发重大故事。所以必须要在线上做压测。
Q: 全链路压测和接口压测的区别?
A:
在特定的业务场景下,将相关的链路完整地串联起来同时施压,尽可能模拟出真实的用户行为。
接口 A 做接口压测,可能是 1w/s 的 QPS, 但是 A 和 B 同时压测,可能因为数据库连接等共享资源,导致实际 QPS 下降。
Q: 业务系统如何区分压测流量?即判断哪些是压测的请求,哪些是正常的请求?
A:
- url 上加上打标参数, 例如 http://xx?st=true
- hearder 中打标
Q: 这个压测打标的改造和适配要中间所有服务参与吗? 改造成本会不会有点大?
A:
不需要全部参与。
如果设计过链路跟踪系统, 则每个服务都有中间件团队提供的拦截器, 因此直接通过公共拦截器来做压测标记的识别。
Q: 识别到压测标记后, 如何保证往下游发请求时,仍然是压测标记的形式?
即发请求的时候已经不是同一段拦截器的代码了。 但是也要保证尽可能不改动原有的业务逻辑代码。
A:
如果处理请求和发下游请求是在一个线程中完成的, 那么可以使用 threadLocal。
即拦截到请求时, 将压测标记 set 进 threadLocal 中。
发送下游请求的代码中,如果能从 threadLocal 中拿到压测标记,则改造 url,设置进往下发的请求中
Q: 如果我不在同一个线程中处理和发请求, 怎么办?
即我的业务代码中 做了 new Thread 或者 ExectorPool.submit 提交异步请求, 这时候业务逻辑里肯定不会涉及到 threadLocal 的代码, 而此时压测标记就会丢失了。
threadLocal 可以用 InheriableThreadLocal, 这样如果在线程中 new 新的线程,则标记可以被传递下来。
如果是线程池创建异步请求, 可以用阿里的 TransmittableThreadLocal。
Q: 如果我的压测链路中 包含了外部服务的接口怎么办? 例如第三方支付、第三方短信等。
A:
链路跟踪系统中发请求的 filter 中, 新增 MockFilter, 如果判断是压测请求, 则直接返回 mock 逻辑(不建议部署 mock 服务, 因为部署 mock 服务的话,服务器成本又得考虑,不如直接封装到 mockFilter 代码中)
Q: 会对数据库产生影响的压测请求怎么办?
如果直接落库,可能会影响正常用户的请求访问, 也可能污染线上数据。
A:
为每个生产库 生成一个影子库, 专门用来存储压测数据。
然后做过分库分表的话, 肯定有数据库的 proxy,在 proxy 里都往压测库插入和读写。
如果没有,就扩展 Spring 的 AbstactRoutngDataSource 类, 实现一个动态的数据源,让里面可以根据压测标记进行切换。
Q: redis、kafka 等中间件对压测有什么特殊处理?
A:
除了添加统一特点的压测标记(中间件和业务不是强相关,所以可以进行特定改造)
还要注意缓存的存活时间要设置短一点。
Q: 压测结束时,如何避免对数据库继续产生影响?
A:
注意不要触发 数据源的 init-method 方法, 当真正执行压测的时候再建议会话连接。
各种超期时间也要注意设置, 尽快接触压测对组件的影响。
Q: 压测数据怎么构造?一个个手动拼数据参数,然后让测试同学发送吗?
A:
不行,如果业务有改动,参数很容易对不上,同时组装过程耗时也会非常久。
建议从线上直接 dump 最近的请求数据,这样可保证参数没有变化。
同时做一些脱敏和修正处理。
Q: 怎么完整设计这个压测系统的架构?包含哪些角色
A:
该问题参考《超大流量分布式系统架构解决方案》一书中给出的方案,也可以有其他方案。
- 压测 manager 服务, 提供给压测控制者查看和使用的。可以读取 mysql 数据库获取压测结果情况,或者进行调度指令的下发等。
- taskService 服务,用于处理调度指令,执行定时调度、即时调度等行为。
- Agent 压测请求发送客户端。根据 taskService 的指令进行发送
- DataFactoy,给 agent 提供脱敏、修改后的压测数据。
- MQ, 接收 agent 压测请求的结果,堆积到队列里提供给 DataCollect 消费。
- DataCollect, 压测结果消费者, 将结果写入到数据库 MYSQL。
- 注册中心,用于管理和注册上面这些服务。
- Detecotr, 流量检测和干预器,可以根据情况即时调整 agent 的发送速率。
Q: 怎么模拟实际用户的请求发送? 因为实际场景应该是多个不同 ip 的用户访问进来才对。
A:
- apache HttpComponents 的 httpclient 包
- Java11 的异步 httpclient, 支持 HTTP/2, 支持用 reactive stream。