背景
最近,公司接手了个新项目,系统会涉及到客户订单信息。一开始,客户量并不多,一切都运行正常。后来有大批客户订单导入系统,线上便出现用户反馈订单加载慢的情况,类似图中这种场景。经过排查,开发人员优化了慢sql查询,并加入了Redis缓存,经过我们测试人员验证上线,问题得到解决。在测试过程中,还发现订单查询速度甚至比之前还快,这主要归功于Redis缓存。那今天,我们就来讲讲测试Redis缓存需要注意什么。
什么是Redis缓存
我们知道redis是基于内存的数据库,读写数据快。利用这一点,将频繁访问的数据存储在内存中,当应用程序需要这些数据时,可以直接从 Redis 中快速获取,而无需每次都从后端的慢速存储(如数据库)中读取。
缓存命中逻辑的处理机制
-
不做缓存,直接查询数据源
-
只查询缓存,缓存不命中直接返回空结果,定时查询数据源更新缓存
-
查询缓存,缓存不命中,查询数据源再返回结果
-
查询缓存,缓存不命中,查询数据源先返回结果 异步更新缓存
Redis缓存测试策略
- 测试对象:被测服务和redis的交互场景。而不是redis本身
- 测试核心:围绕数据源的增删查改,校验被测服务和redis增删查改的正确性。
下面介绍几个常见缓存测试的场景
新增缓存场景
- 场景模拟方式:通过文档描述或开发描述模拟对应场景,比方说请求生成订单接口就会缓存订单数据。
- 校验方法:
- 直接和redis交互,通过redis提供的get方法直接查询订单缓存数据是否存储在redis当中。
- 可能需要相信开发实现的代码逻辑,查询接口会查询redis,也可以通过删减mysql的数据确保结果是redis返回的,通过请求查询接口校验订单结果是否能正常获取。
查询缓存场景
- 场景模拟方式:前置设计缓存数据,比方说直接写入redis数据或者通过外部某些接口生成缓存数据,通过外部的查询接口再校验查询结果。
- 校验方法:通过外部的查询接口校验,对齐文档内容或研发口径定义期望值,校验结果输出满足期望。
- 需要设计的缓存数据场景:
- 无缓存(空内容)、mysql有数据
- 无缓存(空内容)、mysql无数据
- 有缓存(有内容)、mysql有数据
- 有缓存(有内容)、mysql无数据
缓存更新场景
本质上是数据存在缓存时,校验正常的业务更新。但对某单一数据的处理同时存在多个数据源时,也就是mysql和redis需要同时更新这条数据,会存在先后顺序的问题,在高并发的场景下,就有可能产生数据不一致的情况。
- 场景模拟方式:前置存在缓存数据时,通过服务提供所有的数据更新方式(接口),再通过服务对外的查询方式校验结果是否是更新后的结果。
- 数据一致性的解决方案:
1)先更新数据库,再删除缓存。 更新数据库的速度比删除缓存的速度要慢得多。因为更新 MySQL 是磁盘 IO 操作,而 Redis 是内存操作。内存操作比磁盘 IO 快得多。如果先删除缓存,缓存中不存在,数据库又没有完成更新,此时有请求进来读取数据,并写入到缓存,那么在更新完缓存后,缓存中这个 key 就成了一个脏数据。
2)延时双删防止脏数据。 就是在第一次删除缓存之后,过一段时间之后,再次删除缓存。主要针对缓存不存在,但写入了脏数据的情况。在先删缓存,再写数据库的更新策略下发生的比较多。
3)数据上锁。 确保在当前服务下同一条数据同一时间只允许一个事务在处理,如果有其他事务介入直接拒绝。
缓存淘汰场景
- 直接delete
- 校验方法:直接校验对外的查询结果是否查询不到当前数据
- 缓存超时
- 校验方法:校验过期时间的正确性,校验时间的边界值。
- 需要设计的模拟场景:判断缓存时间的配置和机制是否符合预期
1)未淘汰前几秒查询
2)淘汰后的几秒查询
- 自定义的淘汰机制
比方说保障redis数据只存储100条数据,如果数据存在超过100条,会把离淘汰时间最近的数据直接delete
- 校验方法:校验机制是否符合业务预期,可能需要前置构建数据模拟场景
评论区