斗智斗勇之redis

数据结构 redis 支持的数据结构:Redis中的value支持string(字符串)、hash(哈希)、 list(列表)、set(集合)、zset(有序集合)、Bitmaps(位图)、 HyperLogLog、GEO(地理信息定位)等多种数据结构。
抗压能力: redis 基于内存的单线程非关系型数据库,每秒支持十万并发
经典问题: 1.redis缓存穿透,缓存击穿,缓存雪崩原因+解决方案:

缓存穿透:

key对应的数据在数据源并不存在,每次针对此key的请求从缓存获取不到,请求都会到数据源,从而可能压垮数据库。比如用一个不存在的用户id获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。

缓存穿透解决方案:

1.采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。

2.如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。

缓存击穿:

key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从数据库加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把数据库压垮。

缓存击穿解决方案:

1.事先和业务或运营部门了解,预先设置热点key,在redis高峰访问之前,把一些热门数据提前存入到redis里面,加大这些热门数据key的时长。

2.实时调整:现场监控哪些数据热门,调整key的过期时长

3.设置锁:

(1)在缓存失效的时候(判断拿出来的值为空),不是立刻去加载数据库
(2)先使用缓存工具来设置下锁
(3)当操作返回成功时,再进行加载数据库的操作,并回设缓存,最后删除锁
(4)当操作返回失败时,证明有线程在加载数据库,当前现程睡眠一段时间再重试整个get缓存的方法

设置锁的缺点:影响效率
 

使用互斥锁(mutex key),在缓存失效时,不是立即去查询数据库,先使用缓存工具来设置下锁,当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的方法。

SETNX,是「SET if Not eXists」的缩写,也就是只有不存在的时候才设置,可以利用它来实现锁的效果。

缓存雪崩:

当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给数据库带来很大压力。

缓存雪崩解决方案:

1.可以考虑用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。

2.将缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

Redis大key和热key:

大key和

热key简介:

1byte = 8bit  

1k = 1024byte

1M = 1024k

1G = 1024M

bit = 字节

一个汉字占2个bit,一个英文(不区分大小写)占1bit,中文标点占3个bit,英文占1个bit

在Redis中,一个字符串最大512MB,一个二级数据结构hash、list、set、zset可以存储大约40亿个(2^32-1)个元素。

判定维度:
大Key通常都会以数据大小与成员数量来判定,而热Key则以其接收到的请求频率、数量来判定。

造成影响:大Key与热Key如果未能及时发现并进行处理,很可能会使服务性能下降、用户体验变差,甚至引发大面积故障。

大key

大key的定义:一般我们会将含有较大数据或含有大量成员、列表数的Key称之为大Key,主要体现在:字符串类型它的big体现在单个value值很大;非字符串类型:哈希、列表、集合、有序集合,它们的big体现在元素个数太多。

Redis的大Key评判标准:

1.一个string类型的Key,它的值为5MB(数据过大)

2.一个List类型的Key,它的列表数量为20000个(列表数量过多)

3.一个ZSet类型的Key,它的成员数量为10000个(成员数量过多)

4.一个Hash格式的Key,它的成员数量虽然只有1000个但这些成员的value总大小为100MB(成员体积过大)

带来的问题:

1、阻塞请求【Redis客户端Client发现Redis变慢】:大Key对应的value较大,对其进行读写需要耗费较长的时间,这样就可能阻塞后续的请求处理。Redis的核心线程是单线程,单线程中请求任务的处理是串行的,前面的任务完不成,后面的任务就处理不了[表象就是Client发现Redis变慢]。执行大key命令的客户端本身,耗时明显增加,甚至超时

2、内存增大:读取大Key耗费的内存比正常Key会有所增大,如果不断变大,可能会引发内存溢出OOM,或达到redis的最大内存Max Memory设置值引发写阻塞或重要Key被逐出。

3、阻塞网络:读取或删除value较大时会占用服务器网卡较多带宽,自身变慢的同时可能会影响该服务器上的其他Redis实例或者应用服务。

4、影响主从同步、主从切换:删除一个大Key造成主库较长时间的阻塞并引发同步中断或主从切换

5.负载均衡受到影响:Redis集群中的某个节点内存远超其余节点,但因Redis集群的数据迁移最小粒度为Key而无法将node上的内存均衡化;大key本身的存储带来分布式系统中分片数据不平衡,CPU使用率也不平衡。

6.大key有时候也是热key,读取操作频繁,影响面会很大

7.执行大key删除时,在低版本redis中可能阻塞线程

热key

热key的定义:在某个Key接收到的访问次数、显著高于其它Key时称热Key

举例:

1.某Redis实例的每秒总访问量为10000,而其中一个Key的每秒访问量达到了7000,这个key访问次数显著高于其它Key。

2.对一个拥有上千个成员且总大小为1MB的HASH Key每秒发送大量的HGetAll,带宽占用显著高于其它Key。

3.对一个拥有数万个成员的ZSet Key每秒发送大量的ZRange,CPU时间占用显著高于其它Key。

带来的问题:

1.热Key占用大量的Redis CPU时间使其性能变差并影响其它请求;

2.Redis集群中各节点流量不均衡造成Redis集群的分布式优势无法被Client利用,一个分片负载很高而其它分片十分空闲从而产生读/写热点问题;

3.在抢购、秒杀活动中,由于商品对应库存Key的请求量过大超出Redis处理能力造成超卖;

4.热Key的请求压力数量超出Redis的承受能力造成缓存击穿,此时大量强求将直接指向后端存储将其打挂并影响到其它业务;

产生

原因:

1、redis数据结构使用不当/redis使用场景不对:将Redis用在并不适合其能力的场景,造成Key的value过大,如使用String类型的Key存放大体积二进制文件型数据。

2.未及时清理垃圾数据:没有对无效数据进行定期清理,造成如HASH类型Key中的成员持续不断的增加。即一直往value塞数据,却没有删除机制,value只会越来越大。

3.对业务预估不准确/不合理:

   3-1.业务上线前规划设计考虑不足没有对Key中的成员进行合理的拆分,造成个别Key中的成员数量过多(大Key)

   3-2.预期外的访问量陡增,如突然出现的爆款商品、访问量暴涨的热点新闻、直播间某大主播搞活动带来的大量刷屏点赞、游戏中某区域发生多个工会间的战斗涉及大量玩家等(热Key);

5.大key的产生往往是业务方设计不合理,没有预见vaule的动态增长问题:

   5-1.一直往value塞数据,没有删除机制,迟早要爆炸

   5-2.数据没有合理做分片,将大key变成小key

找到大key

0.使用Redis内置功能发现大Key及热Key:当你对Redis的大Key热Key已有明确的分析目标时,可以通过Redis内置命令对目标Key进行分析。

方案一:使用debug object命令对Key进行分析:该命令能够根据传入Key的名称来对Key进行分析并返回大量数据,其中serializedLength的值为该Key的序列化长度,但Key的序列化长度并不等同于它在内存空间中的真实长度。

缺点:debug object属于调试命令,运行代价较大,并且在其运行时,进入Redis的其余请求将会被阻塞直到其执行完毕。而该命令的运行的时间长短取决于传入对象(Key名)序列化长度的大小,因此,在线上环境中并不推荐使用该命令来分析大Key,这可能引发故障(在其运行时,进入Redis的其余请求将会被阻塞直到其执行完毕。并且每次只能查找单个key的信息,官方不推荐使用)。

注意事项:

  0-1.debug object bigkey本身可能就会比较慢,它本身就会存在阻塞Redis的可能

  0-2.建议在从节点执行

  0-3.建议在节点本地执行

方案二:Redis自4.0起提供了memory usage命令来帮助分析Key的内存占用相对debug object它的执行代价更低,但由于其时间复杂度为O(N)因此在分析大Key时仍有阻塞风险。

1.通过Redis官方客户端redis-cli的BigKeys参数发现大Key:使用BigKeys命令以遍历的方式分析Redis实例中的所有Key,并返回整体统计信息与每个数据类型中Top1的大Key(可以找到某个实例下的5种数据类型(String、hash、list、set、zset)的最大key)。

优点:是可以在线扫描,不阻塞服务;缺点是信息较少,内容不够精确。

缺点:BigKeys仅能分别输出Redis五种数据结构中的最大Key,如果你想只分析String类型或是找出全部成员数量超过10的Hash Key,那么bigkeys在此类需求场景下将无能为力。

注意事项:

  1-1.建议在从节点执行,因为--bigkeys也是通过scan完成的。
  1-2.建议在节点本机执行,这样可以减少网络开销。
  1-3.如果没有从节点,可以使用--i参数,例如(--i 0.1 代表100毫秒执行一次)

2.通过Redis官方客户端redis-cli的hotkeys参数发现热KeyRedis自4.0起提供了hotkeys参数来方便用户进行实例级的热Key分析功,该参数能够返回所有Key的被访问次数。

缺点:同样为不可定制化输出报告,大量的信息会使你在分析结果时复杂度较大。使用该方案的前提条件是将redis-server的maxmemory-policy参数设置为LFU

3.redis-rdb-tools工具以定制化方式找出大Key:在redis实例上执行bgsave,bgsave会触发redis的快照备份,生成rdb持久化文件,然后对dump出来的rdb文件进行分析,找到其中的大key(使用redis-rdb-tools离线分析工具来扫描RDB持久化文件,虽然实时性略差,但是完全离线对性能无影响。)。

优点:按照自己的标准精确的分析一个Redis实例中所有Key的真实内存占用并避免影响线上服务,在分析结束后得到一份简洁易懂的报告(获取的key信息详细、可选参数多、支持定制化需求,结果信息可选择json或csv格式,后续处理方便

缺点:由于分析RDB文件为离线工作,因此对线上服务不会有任何影响,但离线分析代表着分析结果的较差时效性。对于一个较大的RDB文件,它的分析可能会持续很久很久。

4.依靠公有云的Redis分析服务发现大Key及热Key:公有云的Redis控制台能满足实时的对Redis实例中的所有Key进行分析并发现当前存在的大Key和热Key。了解Redis在运行中曾出现过哪些大Key热Key,使自己对整个Redis实例的运行状态有一个全面而又准确的判断。

举例:阿里云Redis控制台中的CloudDBA,它支持Redis大Key与热Key的实时分析、发现。大Key及热Key分析底层为阿里云Redis内核的Key分析功能,该功能通过Redis内核直接发现并输出大Key热Key的相关信息,因此,该功能的分析结果准确性高效且对性能几乎无任何影响,你可以通过点击CloudDBA中的“Key分析”进入该功能。

Key分析功能共有两个页面,它们允许在不同的时间维度对对应Redis实例中的Key进行分析:

1.实时:对当前实例立即开始分析当前实例,展示当前存在的所有大Key及热Key。

2.历史:展示该实例近期曾出现过的大Key及热Key,在历史页面中,所有出现过的大Key及热Key都会被记录,哪怕这些Key当前已经不存在。该功能能够很好的反映Redis的历史Key状态,帮助追溯过去或现场已遭破坏的问题。

解决

方案

对于String数据结构的话,减少存储的字符串的长度;对于List、Hash、Set、ZSet数据结构是减少集合中元素的个数:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值