流量回放的数据隔离
流量回放的数据处理是决定流量回放的基础,流量回放中的流量都是在之前录制下来的。往往录制下来的流量并不能直接回放,这有两个原因,其一是录制下来的流量很难回放就能成功,很多有状态的数据已经被消费掉了,想要回放成功必须对流量进行处理,才能保证回放能够成功;其二是录制下来的流量往往也会将其放大几倍进行回放,从而达到一定压力测试的目的。那么无论怎么样的回放,数据都不能和真实用户的数据混为一谈,必须有相应的处理技术进行处理,这样既保证流量回放的压力不会影响现有服务的服务能力,也能避免回放数据污染生产数据库,在后续的数仓、数据分析、大数据等的应用产生结果的影响。
流量回放的数据隔离方法有两种一种是逻辑隔离,一种是物理隔离。逻辑隔离是通过数据实体中置入一些流量回放的标记,从而在逻辑上只要有标记的就是回放数据,没有的就是真实流量的数据。物理隔离就是真实数据和流量回放数据放到不同的数据区域,从而到的回放数据和真实数据在物理上就完全的隔离。无论是逻辑隔离还是物理隔离都需要项目的技术改造。
数据隔离的分类
逻辑隔离
逻辑隔离就是在数据上做标记,从而可以区分哪些是流量回放的数据,哪些是那些事真实的数据。这个标记可以是专门的一个数据字段作为标记,假设有一个流量回放的标记type,1是回放数据,0是真实用户数据;也可以通过某些特殊的ID进行标记,例如订单号9开头的都是回放数据,其他的都是真实用户数据等等这样的方法,在数据逻辑上进行区分,数据存储上真实用户的数据和回放的数据都在一起混存。逻辑隔离实现简单,理解容易,对于中间件层无需任何改造,但是对于业务系统是需要代码改造的,是有代码入侵的,对于原来的数据结构,数据表都需要进行更改,因此在设计中必须要谨慎评价标记能力,任何遗漏的标记都会导致原始数据的污染。
物理隔离
物理隔离是将所回放数据写入独立的区域,回放数据和真实用户的数据在不同的物理服务器上完全隔离,要做到物理隔离需要的流量染色、影子库表等的处理。物理隔离的相对投入技术改造成本高,理解起来相对复杂,很多改造细节需要充分论证,需要改造中间件,对于业务代码的入侵较少,如果隔离是为了压测服务的,那么数据的脱敏、偏移也需要充分设计,任何一个细节的都可能导致测试的失败。如果是服务压测的数据隔离,在完成影子库表建设后,需要进行小批量的压力测试,确定影子库表、影子库表上数据是有效的。
数据隔离的技术
流量染色
流量染色也叫做流量打标,常规做法是在自定义头中加入一个流量回放的标记,在HTTP协议中我们会通过自定义头加入流量回放的标记,自定专用消息头可通过X-前缀来添加(但是这种用法被IETF在2012年6月发布的 RFC5548 中明确弃用,原因是其会在非标准字段成为标准时造成不便,但是到今天还有很多团队在应用。)自定义HTTP headers 通常意味着提供一些对 web 开发者有用的附加信息,或者是方便故障排除(troubleshooting)。在HTTP协议中的流量回放的标记就可以通过自定义头来实现,比如我们在HTTP中定义一个头是Test-Flag,流量回放的标记是1,正式用户是0。使用自定义头部的时候, 命名是时候记得要绕开浏览器的标准key-name就好了, 具体的标准名可以参考MDN(https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers)。
在一个访问需要协议转换的时候,就需要格外小心,要保证染色标记能够传递下去,例如HTTP协议公网转到RPC内网的时候,自定义头Test-Flag要转成RPC的标记,那么具体RPC怎么标记要看对应的RPC的框架。
影子库表
影子库,就是建立一个新的数据库,新的数据库中的表结构和生产数据库一致,在识别流量染色标记的方法常规会封装到组织级的开发框架中,从而可以达到最小的代码改动就完成回放流量的识别。影子库比较建议单独运行在一个数据库实例上,以防止影子库压力过大影响真实用户系统访问性能。影子表和真实库中数据结构完全一致的新数据表,在流量过来的时候,需要按照回放标记进行流量识别,然后判断存入真实表还是影子表。那么这个识别存储数据的过程可以在ORM框架中定制路由逻辑完成,Mybatis可以使用Interceptor拦截器,在SQL语句执行前对路由进行动态修改。
如果是为了全链路压测而做的影子库、影子表,需要包装影子库表中的数据规模和生产真实数据规模一致,然后将生产库或者生产表的部分相关数据脱敏、偏移后存入影子库,也可以按照手工生成一部分数据,但是一定要保证回放的流量的依赖数据都是经过脱敏、偏移处理的而不是手工生成的。
MQ和Redis
消息中间件MQ最关键的就是需要将回放标记能存入消息队列中,然后还能读取出来具体就写一层意义,那么MQ是否需要做一个专门为流量回放而做的服务呢?这其实是业务决定的,如果业务上没有完全的业务安全性、监管要求,并且MQ的压力也不大,那么流量回放和真实访问用一个就可以了,例如RobbitMQ就可以setHeader回放标记,和自定义协议头的最好一致,比较建议在定义流量回放标记的时候保持一致,这样比较容易保障处理的方式的统一。如果是创建一个影子的消息中间件,那么就需要在生产者代码逻辑修改可以识别回放标记,消费者就需要有专门消费影子消息中间件的服务。
Redis和MQ类似,没有业务上的要求就可以共用服务,在key上加入一些回放标记,例如加一个前缀或者加一个后缀,进行回放流量和真实流量的识别,这个的识别就是在流量转换的时候,通过逻辑代码完成转换。
日志的隔离
应用服务在对于流量回放的处理过程中的日志最好单独保存,也就是实现日志的隔离,这样既可以保证不会因为回放的大量日志而导致生产中真实用户访问的日志被污染,也能方便通过回放的应用服务日志排查回放中的问题。常规的处理方法就是在业务逻辑写日志部分进行一项区分,有回放标记的流量存入一个日志文件,没有标记的存入另外一个日志文件。
总结
流量回放的数据隔离是回放得以实施的重要部分,如果没有做好数据隔离,回放后对于数据的污染会是一个灾难性的后果。那么除了上面说的隔离方案外,要成功实施流量回放还需要完成一些外部依赖系统的解耦,还有一些内部资格验证的逻辑约束,这是因为有时候流量回放是通过录制后放大的流量进行的回放,因此有些用户、优惠券、活动资格等都是有约束的,这些对于流量回放标记的数据应该有一些豁免权。