流量回放-The Big Picture
一、大背景是什么
微服务架构的同时,服务自身依赖的第三方服务、数据越来越多。
传统的自测/测试方式面临困难
- 被依赖的线下服务不稳定;
- 服务无法提供期望的响应数据;
- 缺少场景构造标准;
传统的解决方式
- 提高环境稳定性:服务不稳定的情况仍无法避免;
- 自己构造数据、改代码注入object:繁杂;
- 想当然的构造场景:场景构造不充分、心里没底;
上述问题导致了代码质量下降、自测/测试困难,在业务越来越复杂,依赖服务越来越多的大环境下,这些问题变得越加严重,已经到了必须要升级解决方案的地步。
二、The big picture
托管被测服务,利用线上流量来测试。
- 服务托管:
服务被托管,其外部依赖被mock,程序的运行环境不再依赖第三方服务,解决环境的不稳定问题;
被托管的服务被提前录制的线上流量测试,第三方依赖也由线上流量mock,解决第三方响应数据难构造、缺少场景构造标准的问题;
- 线上流量:
线上流量被提前录制,请求和对应的第三方交互数据也被正确group起来。
三、技术方案
1、服务托管
- 利用iptables进行托管
利用iptables在系统层面对服务进行托管,服务所有的第三方交互被iptables拦截后mock;好处是通用,对服务的语言无要求,坏处是只能托管网络流量。
- 利用libc、程序网络库等托管
通过hook掉libc中的connect\send\rcv等函数对服务进行托管。好处是可托管网络流量外的如文件读取类流量,坏处是不同的语言hook的方式需要定制,如php用libc方式,go需要修改语言库。
同时,我们会hook掉系统时间调用,让被托管服务回到线上流量的时间。
2、线上流量录制
线上流量,包含服务的请求流量及第三方交互流量。仅有服务的请求流量是不够的,同时,其第三方交互需要被正确的和请求关联,这里要解决的难题是如何在网络层缺少关联id(traceid在应用层,且redis/mysql数据缺少traceid)的情况下,正确的关联请求及其第三方交互。
- 利用时间gap来关联
将一台线上机器服务的请求串行化,请求之间加上一个时间gap,则两个请求之间的第三方交互可以和这个请求正确关联。
好处是通用,不区分程序语言,代码侵入性小;坏处是会增加一些运维成本和机器资源;对于不同协议的服务需要定制不同的串行方案,如http采用nginx+lua,thrift采用服务内转发。
- 利用threadid 来关联
通过hook掉libc中的connect\send\rcv等函数,将相同threadid的流量进行关联。
好处是可以做到并行,录制速度快,case丰富,无资源浪费,对部署架构无影响;坏处是对服务的处理模型有要求,适用于请求、第三方交互都处于同一线程的处理模型,目前在php-fpm处理模型中应用得较好。