Redis 集群缓存测试要点--关于 线上 token 失效 BUG 的总结
在测试账户系统过程中遇到了线上大面积用户登录态失效的严重问题,事后对于其原因及测试盲点做了一些总结记录以便以后查阅,总结分为以下7点,其中原理性的解释有些摘自网络。
1.账户系统token失效问题复盘
2.Redis 经典流程
3.Redis分片部署方式
4.Redis扩容导致缓存数据失效
5.Redis Sharding一致性hash算法
6.缓存失效,缓存击穿,缓存穿透
7.Redis缓存测试总结
账户系统token失效问题复盘
现象:redis扩容后线上大量用户登录态失效,需要重新登录。由于登录态可以持续保持,部分用户忘记密码,需要修改密码后再次登录。在测试验证中,由于切换环境、登录登出导致这个问题难以发现和注意。
原因:sharded-redis-pool分片规则中有域名因子(框架源码中),扩容修改了redis域名,导致redis中数据虽然存在,概率性获取不到。
PS:失效问题复盘中有较多关于BUG修复前后代码差异的片段由于保密未贴出,一般来说测试复盘过程中对于代码的解析是很重要的一环。
Redis经典流程
前端测试盲点:
1.有些应用临时数据都存储在redis里,不存储在DB里
2.上面流程中redis的数据不管有没有生效,程序都可以正常进行,且功能正常
3.redis如果是集群的方式,缓存数据的读取和写入有没有进入正确的分片
Redis分片部署方式
(1)在客户端(jedis)做分片(Redis Sharding);这种方式在客户端确定要连接的redis实例,然后直接访问相应的redis实例(目前系统使用的方式)。
(2)在代理中做分片;这种方式中,客户端并不直接访问redis实例,它也不知道自己要访问的具体是哪个redis实例,而是由代理转发请求和结果;其工作过程为:客户端先将请求发送给代理,代理通过分片算法确定要访问的是哪个redis实例,然后将请求发送给相应的redis实例,redis实例将结果返回给代理,代理最后将结果返回给客户端。
(3)在redis服务器端做分片(Redis Cluster);这种方式被称为“查询路由”,在这种方式中客户端随机选择一个redis实例发送请求,如果所请求的内容不再当前redis实例中它会负责将请求转交给正确的redis实例,也有的实现中,redis实例不会转发请求,而是将正确redis的信息发给客户端,由客户端再去向正确的redis实例发送请求。
Redis扩容导致缓存数据失效
假设有三台缓存服务器,缓存tokenkey,希望tokenkey被均匀的缓存到这三台服务器上,原始的做法是对缓存项的键进行哈希,将哈希后的结果对缓存服务器的数量进行取模操作。
假设三台缓存服务器已经不能满足业务缓存需求,需要增加机器,就会出现一些缺陷。假设增加一台服务器,缓存服务器的数量由三台变为四台,此时,如果仍用取模的方法对同一tokenkey进行缓存,那么这个tokenkey所在的服务器编号就肯定与原来三台服务器时所在的编号不同。这就导致了缓存在一定时间内是失效的,当应用无法从缓存中获取数据,则会向后端服务请求数据,由于大量缓存同一时间失效,造成缓存的雪崩,可能导致系统被压垮。
Redis Sharding一致性hash算法
一致性hash:一致性哈希算法也是使用取模的方法,只是一致性哈希算法是对232取模。
我们有ABC三台服务器,使用各自的IP地址进行哈希计算,使用哈希后的结果对232取模,计算结果映射到一个由232个点组成的哈希圆环上,可以得到如下的示意图:
假设有4个tokenkey,1234需要缓存,根据hash(tokenkey)% 232得到的映射图如下,tokenkey1、2存储到A中,tokenkey3存储到B中,tokenkey4存储到C中。
假设机器B出现故障,需要移除服务器B,那么移除后的示意图如下。
当服务器移除以后,按照之前的一致性哈希算法的规则,tokenkey3应该被缓存到服务器C中,tokenkey3的缓存位置发生了改变。但是tokenkey1、2仍被缓存到服务器A中,tokenkey4仍被缓存到服务器C中,这就是一致性哈希算法的优点,当服务器数量发生改变,并不是缓存都会失效,而是只有部分缓存会失效,前端的缓存仍能分担整个系统的压力,不至于所有压力在同一时间集中到后端服务器上。
Hash环的偏斜及虚拟结点:
在实际的映射中,服务器可能会被映射成如下图:
虚拟节点是实际节点在hash环上的复制品,一个实际节点可以对应多个虚拟节点。虚拟节点可以解决hash环的偏斜以及缓存雪崩的问题。
缓存失效、缓存击穿、缓存穿透
缓存穿透
缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击我们的应用,这就是漏洞。
解决方案
有很多种方法可以有效地解决缓存穿透问题,最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。另外也有一个更为简单粗暴的方法(我们采用的就是这种),如果一个查询返回的数据为空(不管是数 据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。
缓存雪崩
缓存雪崩是指在我们设置缓存时采用了相同的过期时间或者其他情况,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩。
解决方案
缓存失效时的雪崩效应对底层系统的冲击非常可怕。大多数系统设计者考虑用加锁或者队列的方式保证缓存的单线 程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上。这里分享一个简单方案就时讲缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
缓存击穿
对于一些设置了过期时间的key,如果这些key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。这个时候,需要考虑一个问题:缓存被“击穿”的问题,这个和缓存雪崩的区别在于这里针对某一key缓存,前者则是很多key。
缓存在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。
解决方案
使用互斥锁(mutex key)
简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的方法。
Redis集群缓存测试总结
功能:
1.系统运行过程中,redis缓存数据生效。缓存的数据读取正确、数据写入落地正确,数据有效期设置合理。
2.redis集群分片策略验证正确。
3.缓存与数据库的数据一致性检测。
4.DB事务性导致回滚,缓存是否回滚,有没有产生脏数据。
5.注意测试环境与线上环境的区别,尤其是单例与集群分片、读写分离。尽量保持测试环境与线上一致或者是其缩小版。
自动化:
1.自动化用例中断言部分设计缓存层断言并且自动化框架本身对于断层层次可配置。
性能及稳定性:
1.关注业务本身应用场景及缓存结构,是否使用缓存。
2.预防缓存穿透、缓存雪崩、缓存击穿引发的系统风险。
扩容:
1.关注扩容方案设计、老数据备份策略、回滚方案
2.关注扩容后分片策略的变化
3.扩容后热点数据失效率或命中率以及对后端DB带来的压力
Redis 集群缓存测试要点--关于 线上 token 失效 BUG 的总结的更多相关文章
- C#使用Redis集群缓存
C#使用Redis集群缓存 本文介绍系统缓存组件,采用NOSQL之Redis作为系统缓存层. 一.背景 系统考虑到高并发的使用场景.对于并发提交场景,通过上一章节介绍的RabbitMQ组件解决.对于系 ...
- <正则吃饺子> :关于redis集群的测试demo
redis集群的测试demo,来自网络,具体不详. 1.下载地址,如下:http://download.csdn.net/detail/u012543819/9729291 2.项目是java项目,结 ...
- Net分布式系统之五:C#使用Redis集群缓存
本文介绍系统缓存组件,采用NOSQL之Redis作为系统缓存层. 一.背景 系统考虑到高并发的使用场景.对于并发提交场景,通过上一章节介绍的RabbitMQ组件解决.对于系统高并发查询,为了提供性能减 ...
- redis集群的测试
原文:http://blog.sina.com.cn/s/blog_53b45c4d0102wg10.html 1.测试存取值 客户端连接集群redis-cli需要带上 -c ,redis-cli - ...
- 带你自行搭建虚拟机和Redis集群环境,值得收藏!
前言: 我们看到分析 Redis 使用或原理的文章不少,但是完整搭建一套独立的 redis 集群环境的介绍,并不是很多或者说还不够详细. 那么,本文会手把手带着大家搭建一套 Redis 集群环境,Re ...
- Docker镜像配置redis集群
redis版本:3.2.3 架构: 3节点redis集群,并为每个节点设置一个备用节点,共6个节点 1.安装redis镜像 docker load < docker.redis.tar.gz 2 ...
- redis集群与分片(2)-Redis Cluster集群的搭建与实践
Redis Cluster集群 一.redis-cluster设计 Redis集群搭建的方式有多种,例如使用zookeeper等,但从redis 3.0之后版本支持redis-cluster集群,Re ...
- phpredis Redis集群 Redis Cluster
官方url: https://github.com/phpredis/phpredis/blob/develop/cluster.markdown#readme 2017年10月29日20:44:25 ...
- (转)高性能网站架构之缓存篇—Redis集群搭建
看过 高性能网站架构之缓存篇--Redis安装配置和高性能网站架构之缓存篇--Redis使用配置端口转发 这两篇文章的,相信你已经对redis有一定的了解,并能够安装上,进行简单的使用了,但是在咱们的 ...
随机推荐
- Jquery动画操作的stop()函数
今天做一个点击动画时,遇到了当快速连续点击时,动画效果会乱,并不是我们想要达到的效果. 查询了一下,确认是动画累积的原因.网上搜了一下,发现jquery 的stop()函数刚好能解决. stop(cl ...
- MySQL在创建数据表的时候创建索引
转载:http://www.baike369.com/content/?id=5478 MySQL在创建数据表的时候创建索引 在MySQL中创建表的时候,可以直接创建索引.基本的语法格式如下: CRE ...
- msyql int(x) 中的x
先看一个mysql表结构 Sql代码 CREATE TABLE `test` ( `TYPEID` int (2) ) ENGINE=MyISAM CHARSET=latin1; Sql代码 ...
- Android组件--意图(Intent)
1. 隐示调用和显示调用 参考资料:http://blog.csdn.net/harvic880925/article/details/38399723 1.概念 1). 显式意图: 能从intent ...
- Azure 应用服务中的 API 应用、ASP.NET 和 Swagger 入门
学习内容: 如何通过 Visual Studio 2015 中的内置工具在 Azure 应用服务中创建和部署 API 应用. 如何使用 Swashbuckle NuGet 包动态生成 Swagger ...
- 标准Trie字典树学习一:原理解析
特别声明: 博文主要是学习过程中的知识整理,以便之后的查阅回顾.部分内容来源于网络(如有摘录未标注请指出).内容如有差错,也欢迎指正! 系列文章: 1. 字典树Trie学习一:原理解析 2.字典树Tr ...
- sql sever 执行较大的文件脚本
1.用管理员身份打开cmd工具 2.执行命令 osql -S localhost -U sa -P 123456 -i D:/test.sql -S 服务器地址 本地可简写 . -U 用户名 -P ...
- 13、IO (File、递归)
File File类的概述和作用 * A:File类的概述和作用 * a: File的概念 * File类是文件和目录路径名的抽象表示形式 * Java中把文件或者目录(文件夹)都封装成File对象 ...
- Linux下一个最简单的不依赖第三库的的C程序(2)
一个最简单的C程序,如下: main.c: int main() { char *str = "Hello World"; ; } 在64位平台上编译一个32位的程序,如下:(32 ...
- 分布式时序数据库InfluxDB
我们内部的监控系统用到分布式时序数据库InfluxDB http://www.ttlsa.com/monitor-safe/monitor/distributed-time-series-databa ...