浅谈Redis

项目中Redis作为分布式缓存,或作为分布式锁都是会被优先考虑到的一种技术,今天记录一些Redis的基础知识点。

一、为啥要用缓存?

  1. 高性能
    假设一个场景:有一个请求过来查询数据库表,耗时500ms。但是这个结果接下来一天可能都不会改变。
    那么放在缓存中,下次再有请求过来,就不必再花费500ms去查数据库表,直接2ms搞定,性能提升百倍。
  2. 高并发
    mysql这么重的数据库,压根儿设计不是让你玩儿高并发的,虽然也可以玩儿,但是天然支持不好。mysql单机支撑到2000qps也开始容易报警了。
    如果有个系统一秒钟请求有1万,一个mysql单机绝对会挂掉。这时候就需要把数据放缓存中,单机支撑的并发量一秒钟轻松几万几十万,是mysql单机的几十倍。

二、Redis与memcached的区别

  • 相比Memcached来说,Redis拥有更多的数据结构和并支持更丰富的数据操作。
  • Redis比Memcached速度快。
    在Memcached里,你需要将数据拿到客户端来进行类似的修改再set回去。这大大增加了网络IO的次数和数据体积。在Redis中,这些复杂的操作通常和一般的GET/SET一样高效。
  • Redis可以持久化数据
  • Redis原生支持集群模式

三、Redis的持久化

1. RDB持久化机制

Redis默认采用RDB方式。该方式的特点是,定时执行,保证了高性能。

RDB机制的优点:

  • 持久化性能高
  • 基于RDB快照文件,来重启恢复redis非常快速
  • 缓存文件适合做冷备

RDB机制的缺点:

  • 周期性得持久化数据,可能会导致数据的丢失
  • 生成快照文件的时候,如果数据文件非常大,可能会导致服务暂停数毫秒甚至数秒。

2. AOF持久化机制

AOF方式,通过将写命令写入文件,使数据得到持久化,并提供了两个选项:同步写入和每秒异步写入。

同步写入,保证了数据写入文件后,再返回结果,避免了宕机丢失数据的问题。每秒异步写入,保证了一定的性能,也保证了最多只丢失一秒的数据。

AOF机制的优点:

  • AOF可以更好的保护数据不丢失
  • AOF日志文件以append-only模式写入,所以没有任何磁盘寻址的开销,写入性能非常高

AOF机制的缺点

  • 对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大

RDB和AOF到底该如何选择

  • 不要仅仅使用RDB,因为那样会导致丢失很多数据。
  • 也不要仅仅使用AOF,通过AOF做冷备,没有RDB做冷备,来的恢复速度更快
  • 综合使用AOF和RDB两种持久化机制,用AOF来保证数据不丢失,作为数据恢复的第一选择; 用RDB来做不同程度的冷备,在AOF文件都丢失或损坏不可用的时候,还可以使用RDB来进行快速的数据恢复

四、缓存雪崩、穿透、击穿

1. 缓存穿透

缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据,导致数据库压力过大

解决方案:

  • 采用布隆过滤器,使用一个足够大的bitmap,用于存储可能访问的key,不存在的key直接被过滤;
  • 拦截器,id<=0的直接拦截
  • 从cache和db都取不到,可以将key-value写为key-null,设置较短过期时间,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击

2. 缓存击穿

一个热点数据再过期的一瞬间,有大量的请求打到数据库,导致数据库压力巨大。
解决方案:

  • 设置热点数据永远不过期
  • 使用setnx加互斥锁

3. 缓存雪崩

大量的key设置了相同的过期时间,导致在缓存在同一时刻全部失效,造成瞬时DB请求量大、压力骤增,引起雪崩。
解决方案:

  • 过期时间设置成随机
  • 设置热点数据永不过期
  • 如果缓存数据库是分布式部署,将热点数据均匀分布在不同的缓存数据库中

五、缓存过期策略

  • 定期删除:每隔100ms随机抽取一些key检查是否过期,过期了就进行删除
  • 惰性删除:获取某个key的时候,redis会检查一下 ,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除,不会给你返回任何东西。

通过上述两种手段结合起来,确保过期的key一定会被干掉。但是实际上这还是有问题的,如果定期删除漏掉了很多过期key,然后你也没及时去查,也就没走惰性删除,此时会怎么样?如果大量过期key堆积在内存里,导致redis内存块耗尽了,怎么办?

这时候就该使用内存淘汰机制,策略如下

  • noeviction:当内存不足以容纳新写入数据时,新写入操作会报错,不推荐使用
  • allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的)
  • allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key,不推荐使用
  • volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key
  • volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除

六、缓存与数据库的更新顺序

1. Cache Aside Pattern

  • 读的时候,先读缓存,缓存没有的话,那么就读数据库,然后取出数据后放入缓存,同时返回响应

  • 更新的时候,先删除缓存,然后再更新数据库

2. 为什么是删除缓存,而不是更新缓存呢?

有些时候缓存可能并不是直接从数据库表取出来的值,可能需要经过夺标运算或一些复杂的查询,在这种情况下更新缓存的代价是很高的。

如果你频繁修改一个缓存涉及的多个表,那么这个缓存会被频繁的更新,频繁的更新缓存,但是问题在于,这个缓存到底会不会被频繁访问到?

举个例子,一个缓存涉及的表的字段,在1分钟内就修改了20次,那么缓存跟新20次; 但是这个缓存在1分钟内就被读取了1次,那么大量缓存更新的操作是无意义的。

实际上,如果你只是删除缓存的话,那么1分钟内,这个缓存不过就重新计算一次而已,开销大幅度降低。

删除缓存而不是更新缓存其实也是一种懒加载的思想,等到你去使用的时候再去加载。

七、 Redis为啥单线程效率高

  • 纯内存操作
  • 核心是基于非阻塞的IO多路复用机制
  • 单线程反而避免了多线程的频繁上下文切换问题
  • 9
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值