1. 背景
- 一直都希望自己能更多的去深入了解系统的实现,看到产品原型,就能知道背后要用什么技术栈.这样跟技术聊逻辑设计的时候,会比较多共同语言,别人也不会觉得你就是个功能测试,啥事不找你商量。之前面试过一个测试者,我看简历写了测试过订单模块,我就问他:订单如果发起了,但是未支付,几分钟失效,她就回答是10分钟,我就问她是什么技术栈实现的,她就说这个是开发关心的问题,测试一般不需要去了解这些。做测试不仅仅是功能测试,还要了解系统背后用的技术栈,这样可以更全面和深入保障系统的质量。
- 如果开发去了解Redis的话,更多是了解它的应用和设计,如果是测试的话,我是从二个方面去了解的,1个Redis的应用,这样我再看到一些原型业务的时候,我就知道这个地方可能会用到Redis,比如分布式系统Session的存储,比如会员活动抢红包等业务场景。
2 分布式系统
- 分布式系统凭借高吞吐,强扩展,高并发,低延迟以及灵活部署等特点,大大促进了互联网的飞速发展,给企业带来了巨大的利益,而作为分布式系统中的中间件,也起到了了必不可少的作用。目前互联网公司中主流的系统架构结构如下:
3 Redis的应用
3.1 数据存储
- 字符串String
分布式系统中存储用户的SessionId
- 列表List
- 集合Set (Redis中的集合类型可以保证存储的数据是唯一的,不重复的,Redis的Set类型常用于解决重复提交,剔除重复ID等业务场景),
实战经验:之前有个需求就是记录用户的快递地址,用户的快递地址肯定是唯一的,发现存储的时候,同一个用户是会存储多条快递地址的,程序员用的是List的存储,改成Set就好了,或者有些业务,程序员没有判断接口的幂等性,通过接口测试,也可能造成存储多条数据,这个时候测试如果走查代码的时候,确定程序员用的是Set存储结构就好,就不需要去考虑前端是否重复请求,接口是否有做幂等性检测,当你了解更多的技术实现,某种程序也是提高自己的测试效率,提高自己对质量保障的自信力。
- 有序集合SortedSet(包含了List和集合Set的特性,在此基础上又实现了有序)
实战经验:经常用于排行榜
- 哈希Hash存储(底层数据结果是Key_Value构成,value又是由Filed-Vlue构成)
实际应用:当需要存入缓存中的对象信息具有某种共性的时候,为了减少缓存中key的数量,应该采用Hash哈希存储,如果程序员吐槽key太多了,浪费存储空间,不妨就可以用这个存储结构
3.2 监听器
- 将数据压入缓存队列中,并设置一定的TTL时间,当TTL时间一到,将触发监听事件,从而处理相应的业务逻辑
实战经验:下完订单以后,如果用户10分钟没有确认收货地址,推送消息提示用户
3.3 分布式锁
- 同一时刻多个并发的线程对共享资源进行访问操作,导致最终出现数据不一致的问题,其实就是多线程高并发出现的并发安全问题,比如多人抢一个红包业务场景
解决方案:单机时代,即加Synchronized关键字可以解决这个问题。在微服务,分布式系统架构时代,如果出现高并发请求的时候,Synchronized同步操作将显得"力不从心"。 由于Redis底层架构是采用单线程的,操作具备原子性,当有其它进程请求过来的时候,如果前面没有处理完毕,当前线程会进入等待状态,一直到前面的线程处理完毕
4 Redis的弱点
4.1 缓存穿透
- 前端用户访问获取数据时,后端会先在缓存Redis中查询,如果能查到数据,则直接将数据返回给用户,如果缓存中没有查到数据,则前往数据库中查询,如果数据库中没有查到数据,则返回Null,流程结束。如果前端频繁发起访问请问时,恶意提供数据库不存在的key,每次访问请求时将查询数据库,如果此时有恶意攻击,发起大量请求,会对数据库造成大量压力,这个过程就是缓存穿透
解决方案:当数据库没有查到这个数据的时候,则将Null返回给前端用户,同时将Null数据塞入缓冲中,并设置一定的过期时间,可以减少数据库频繁查询压力
4.2 缓存雪崩
- 指的是某个时间点,缓存中的key集体发生过期失效,导致大量查询数据库的请求都落在了数据库上,导致数据库负载过高
解决方法:为这些Key设置不同的随机的过期时间,从而错开缓存中key的失效时间点,可以在某种程度上较少数据库的查询压力
4.3 缓存击穿
- 指缓存中某个频繁被访问的Key,这个Key在某个瞬间过期失效,直接访问数据库,比如微博热搜应用场景
解决方案:设置这个Key永不过时
不管是缓存穿透,缓存雪崩,还是缓存击穿,都是功能测试不出来的,实际测试中,我们要了解各个中间件的特性,对此进行有效测试,才能健全的保障质量
5 应用业务场景
- 热点数据的存储与展示
- 最近访问的数据
- 并发访问
- 排名