先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新软件测试全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上软件测试知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024b (备注软件测试)
正文
redis-cli -h ${host} -p
p
o
r
t
g
e
t
s
m
s
:
v
e
r
i
f
i
c
a
t
i
o
n
:
86
:
{port} get sms:verification:86:
portgetsms:verification:86:{tel}
{“code”:“2294”,“createdAt”:“Jun 14, 2022 10:45:28 AM”,“times”:1,“verifyTimes”:0,“status”:false}
计数器
上图为雪球APP,关注用户功能,业务限制普通用户每天最多允许关注100个用户,超过则提示;
我们可以想象一下,服务端应该是有一个计数器,用户每关注成功一人,计数器+1;每次点击关注按钮,会先判断当前计数器是否超过100,超过则提示「你今天已关注100人,请改天再试」。
在本例中,查询Redis,用户uid1在2023-02-07的日关注数Redis的值,已达到100,所以当天无法继续关注用户。
redis-cli -h ${host} -p ${port} get DAILYFUSER_2023-02-07_uid1
100
如下为Redis计数服务端代码实现,因为是用String数据结构存储的,Redis提供了incr()接口来实现+1操作。
Long followerNum = JedisCluster.master().incr(RelationKeys.createrFollowDailyKey(follower.getId()));
分布式锁
实现分布式锁也是Redis非常常见的使用场景。
下面以雪球的直播业务为例来介绍。用户在雪球直播,需要创建直播间,业务上是一个用户只能创建一个直播间。在测试的过程中,发现存在这么一个问题:多个用户并发创建直播间时会存在Bug,不同的用户会同时创建成功同一个直播间。
如下图:
为了解决这个问题,可以使用Redis分布式锁,优化代码,代码片段如下:
其中实现分布式锁的核心方法是setexnx(),该方法最终调用的是Redis的 set Key Value EX seconds NX 命令,该命令只在Key不存在时才对Key进行设置操作,并返回OK。如上面代码所示如果setexnx返回结果不是OK,则表明锁已存在,那么本次加锁操作失败,业务报错。
这里有一个需要注意的是finally代码块最终会释放锁,那为什么在加锁的时候还要设置过期时间呢?这个主要是为了防止意外发生,程序在走到finally之前,比如程序退出,导致无法释放锁,所以设置了一个兜底的策略,60s后自动释放锁。
三、Redis测试案例
案例一:用户分组查询接口升级
项目背景:用户分组查询从原来的RPC接口升级为gRPC接口,升级前后业务逻辑需保持完全一致。
发现的问题:
在测试过程中,发现分组信息缓存失效后,分组信息无法正常加载。
问题产生原因:
通过分析得知,查询分组信息,首先会从Redis里查询用户的分组成员,当缓存无数据时,会从DB加载数据并回写到缓存。接下来对比下接口升级前后Redis里的数据。
升级前Redis里的分组数据:
/**升级前Redis value格式为:uid -> 创建时间时间戳取负值 **/
redis-cli -h ${host} -p ${port} zrange MEMBER_MEMBERLIST_GROUPID_3615231762_14257441 0 -1 withscores
9485866208 -1669558282413
7371699344 -1663674830000
升级后Redis里的分组数据:
/**升级后Redis value格式为:uid -> 创建时间时间戳 **/
redis-cli -h ${host} -p ${port} zrange MEMBER_MEMBERLIST_GROUPID_3615231762_14257441 0 -1 withscores
7371699344 1663674830000
9485866208 1669558282413
通过对比发现,分组信息的score值不一致。升级前score值为创建时间时间戳取负值,升级后score值为创建时间时间戳,没有对时间戳取负值,最终导致分组信息无法正常加载。
解决方案:
对创建时间戳取负值,保持与原有写入逻辑一致。
总结:对于此类问题,测试过程中不但需要关注Redis值是否写入了,还要保证数据格式的正确性,包括数据结构、字段类型以及各字段的写入格式。
案例二:个股页新帖流数据不更新
问题:
用户反馈,雪球个股页:中天科技(SH600522),新帖流数据不更新。
问题产生原因:
当天雪球内网出现短暂故障,个股页新帖流接口在设置了Redis值后,由于网络错误,导致缓存过期时间设置失败,缓存永不过期(正常情况缓存60s会过期),从而出现部分个股页新帖流下的帖子一直不更新。
参照下图,由于设置Redis值和设置Redis过期时间,不是原子操作,在极端情况下,确实会出现缓存没有过期时间的问题。那从QA的角度,如何避免这种问题呢?
解决方案:
1、Code Review阶段,关注代码里设置Redis值和缓存过期时间,是否使用原子操作,如String结构,可以直接使用setex命令。测试过程中要去关注系统是否会存在缓存过期时间设置失败的问题。
2、一旦发生了缓存过期时间设置失败的问题,是否有相应的应对方案。从测试的角度要多考虑不同场景下系统异常的处理方案,对于极端情况下会出现的缓存无过期时间,系统要增加缓存过期检查机制,对于没有过期时间的缓存,程序要有设置过期时间的机制等。
案例三:行情逐笔Redis大Key优化测试
测试分析:
1、Key读写方式的变化:从原来的读写一级Key变为二级Key,且Key的名称已被改变。
2、二级Key读写必然存在跨Key读写数据的场景,如何进行场景覆盖。 3、由于行情逐笔交易数据量较大,如何验证数据的准确性。
测试覆盖:
1、股票品类覆盖
按照股票品类维度划分,每个品类选择至少一支股票覆盖。
2、Redis Key值覆盖
此次优化,涉及到不同的Redis Key,如盘前:trade:ext_pre:{symbol},盘中:trade:{symbol},盘后:trade:ext_after:{symbol} 等共6类Redis Key。
3、相关业务回归
梳理相关涉及到的此次的Redis Key的相关业务,并进行测试覆盖。
因新老key数据量较大,通过如下脚本来验证数据量是否一致。
#!/bin/bash
key=KaTeX parse error: Expected group after '_' at position 24: …levelkey="shard_̲{key}"
/** 查询老key里的数据量**/
old=$(sh connect_redis.sh zcard ${key} | awk ’ $1>0{print KaTeX parse error: Expected 'EOF', got '}' at position 2: 1}̲') /** 查询新key里的…(sh connect_redis.sh zrange ${levelkey} 0 -1 | grep trade | grep -v zrange)
for var in ${list}
do
i=sh connect_redis.sh zcard ${var} | awk '$1>0{ print $1}'
sum=
(
(
((
((sum+
i
)
)
d
o
n
e
i
f
[
!
−
n
"
i)) done if [ ! -n "
i))doneif[!−n"old" ]
then
old=0
fi
if [ ! -n “$sum” ]
then
sum=0
fi
echo “原KEY数据总数” ${old}
echo “新KEY数据总数” ${sum}
if [ $old -eq $sum ]
then
echo “数据总数一致”
else
echo “数据总数不一致”
fi
风险评估:
测试通过后,接下来就会下掉对老Redis Key的读写。
1、如何确定没有别的业务在调用老的Key?
因行情服务较多,如何保证没有任何服务在调用老的Redis Key了,主要是从两个方面,一方面,开发从代码的角度梳理相关服务调用,测试从业务的角度梳理并进行覆盖;另一方面,为了防止有梳理遗漏的地方,可以通过Redis的访问日志,持续观察老Redis Key还有没有访问量。
2、如何将上线风险降到最低?
一是线上逐步放量,持续观察;二是增加新老服务开关,一旦出问题可以快速的切换到老服务。
通过以上案例,介绍了测试过程中曾踩过的一些比较典型的坑,以及相应的应对方案。总结下Redis测试的一些关注点:
1、缓存数据存储逻辑的合理性。缓存数据写入的正确性以及缓存的写入数据格式是否合理。
2、缓存读取逻辑的合理性。有缓存要优先读缓存,无缓存查询数据库,并回写缓存。
3、缓存更新逻辑的合理性。什么情况下要更新缓存,以及缓存失效后是否会更新缓存内容。
4、缓存时间设置的合理性。缓存时间设置太短,会导致频繁访问数据库;时间设置太长,一方面会占用过多内存,造成资源浪费;另一方面会造成用户访问到的一直是老数据。因此要根据业务数据的实际更新频次,设置合理的过期时间。
5、缓存数据是否会重复。同样的数据,应只存在一条,重复的数据会浪费资源。
四、Redis常见问题
Redis有一些比较经典的问题,如缓存穿透,缓存击穿和缓存雪崩。在介绍这几个概念之前,我们先来看一个正常的缓存模型。
正常缓存模型
正常的请求过程
1、用户通过雪球APP访问雪球后端服务
2、后端服务先请求Redis,检查请求内容是否存在
3、如果有数据,Redis将结果返回给后端服务,并执行7;如果没有则会继续往下执行
4、后端服务从数据库中查询请求的数据
5、数据库将查询的结果返回给后端服务
6、如果数据库有返回数据,则将返回的结果添加到Redis
7、将请求的数据返回给客户端
缓存穿透
在高并发场景下,通过接口访问一个缓存和数据库都不存在的数据,此时缓存起不到保护数据库的作用,就像被穿透了一样,导致数据库存在被打挂的风险。
解决方案:
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注软件测试)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img-blog.csdnimg.cn/direct/664b183a927649e5aaece2045920d5fd.png)
解决方案:
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注软件测试)
[外链图片转存中…(img-KO7cGatV-1713590777148)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!