【本人秃顶程序员】Redis的n种妙用,不单单是缓存

←←←←←←←←←←←← 快,点关注!redis

介绍

redis是键值对的数据库,经常使用的五种数据类型为字符串类型(string),散列类型(hash),列表类型(list),集合类型(set),有序集合类型(zset)数据库

Redis用做缓存,主要两个用途:高性能,高并发,由于内存自然支持高并发浏览器

应用场景

分布式锁(string)

setnx key value,当key不存在时,将 key 的值设为 value ,返回1。若给定的 key 已经存在,则setnx不作任何动做,返回0。缓存

当setnx返回1时,表示获取锁,作完操做之后del key,表示释放锁,若是setnx返回0表示获取锁失败,总体思路大概就是这样,细节仍是比较多的,有时间单开一篇来说解服务器

计数器(string)

如知乎每一个问题的被浏览器次数并发

set key 0
incr key // incr readcount::{帖子id} 每阅读一次
get key // get readcount::{帖子id} 获取阅读量

分布式全局惟一id(string) 分布式全局惟一id的实现方式有不少,这里只介绍用redis实现dom

每次获取userId的时候,对userId加1再获取,能够改进为以下形式分布式

直接获取一段userId的最大值,缓存到本地慢慢累加,快到了userId的最大值时,再去获取一段,一个用户服务宕机了,也顶多一小段userId没有用到高并发

set userId 0
incr usrId //返回1
incrby userId 1000 //返回10001
消息队列(list)

在list里面一边进,一边出便可性能

# 实现方式一
# 一直往list左边放
lpush key value 
# key这个list有元素时,直接弹出,没有元素被阻塞,直到等待超时或发现可弹出元素为止,上面例子超时时间为10s
brpop key value 10 

# 实现方式二
rpush key value
blpop key value 10

过时策略

按期删除

redis 会将每一个设置了过时时间的 key 放入到一个独立的字典中,之后会按期遍历这个字典来删除到期的 key。

按期删除策略

Redis 默认会每秒进行十次过时扫描(100ms一次),过时扫描不会遍历过时字典中全部的 key,而是采用了一种简单的贪心策略。

从过时字典中随机 20 个 key; 删除这 20 个 key 中已通过期的 key; 若是过时的 key 比率超过 1/4,那就重复步骤 1;

惰性删除

除了按期遍历以外,它还会使用惰性策略来删除过时的 key,所谓惰性策略就是在客户端访问这个 key 的时候,redis 对 key 的过时时间进行检查,若是过时了就当即删除,不会给你返回任何东西。

按期删除是集中处理,惰性删除是零散处理。

为何要采用按期删除+惰性删除2种策略呢?

若是过时就删除。假设redis里放了10万个key,都设置了过时时间,你每隔几百毫秒,就检查10万个key,那redis基本上就死了,cpu负载会很高的,消耗在你的检查过时key上了

可是问题是,按期删除可能会致使不少过时key到了时间并无被删除掉,那咋整呢?因此就是惰性删除了。这就是说,在你获取某个key的时候,redis会检查一下 ,这个key若是设置了过时时间那么是否过时了?若是过时了此时就会删除,不会给你返回任何东西。

并非key到时间就被删除掉,而是你查询这个key的时候,redis再懒惰的检查一下

经过上述两种手段结合起来,保证过时的key必定会被干掉。

因此说用了上述2种策略后,下面这种现象就不难解释了:数据明明都过时了,可是还占有着内存

内存淘汰策略

这个问题可能有小伙伴们遇到过,放到Redis中的数据怎么没了?

由于Redis将数据放到内存中,内存是有限的,好比redis就只能用10个G,你要是往里面写了20个G的数据,会咋办?固然会干掉10个G的数据,而后就保留10个G的数据了。那干掉哪些数据?保留哪些数据?固然是干掉不经常使用的数据,保留经常使用的数据了

Redis提供的内存淘汰策略有以下几种:
  • noeviction 不会继续服务写请求 (DEL 请求能够继续服务),读请求能够继续进行。这样能够保证不会丢失数据,可是会让线上的业务不能持续进行。这是默认的淘汰策略。
  • volatile-lru 尝试淘汰设置了过时时间的 key,最少使用的 key 优先被淘汰。没有设置过时时间的 key 不会被淘汰,这样能够保证须要持久化的数据不会忽然丢失。(这个是使用最多的)
  • volatile-ttl 跟上面同样,除了淘汰的策略不是 LRU,而是 key 的剩余寿命 ttl 的值,ttl 越小越优先被淘汰。
  • volatile-random 跟上面同样,不过淘汰的 key 是过时 key 集合中随机的 key。
  • allkeys-lru 区别于 volatile-lru,这个策略要淘汰的 key 对象是全体的 key 集合,而不仅是过时的 key 集合。这意味着没有设置过时时间的 key 也会被淘汰。
  • allkeys-random 跟上面同样,不过淘汰的策略是随机的 key。allkeys-random 跟上面同样,不过淘汰的策略是随机的 key。

持久化策略

Redis的数据是存在内存中的,若是Redis发生宕机,那么数据会所有丢失,所以必须提供持久化机制。

Redis 的持久化机制有两种,第一种是快照(RDB),第二种是 AOF 日志。快照是一次全量备份,AOF 日志是连续的增量备份。快照是内存数据的二进制序列化形式,在存储上很是紧凑,而 AOF 日志记录的是内存数据修改的指令记录文本。AOF 日志在长期的运行过程当中会变的无比庞大,数据库重启时须要加载 AOF 日志进行指令重放,这个时间就会无比漫长。因此须要按期进行 AOF 重写,给 AOF 日志进行瘦身。

RDB是经过Redis主进程fork子进程,让子进程执行磁盘 IO 操做来进行 RDB 持久化,AOF 日志存储的是 Redis 服务器的顺序指令序列,AOF 日志只记录对内存进行修改的指令记录。即RDB记录的是数据,AOF记录的是指令

RDB和AOF到底该如何选择?
  • 不要仅仅使用 RDB,由于那样会致使你丢失不少数据,由于RDB是隔一段时间来备份数据
  • 也不要仅仅使用 AOF,由于那样有两个问题,第一,经过 AOF 作冷备没有RDB恢复速度快; 第二,RDB 每次简单粗暴生成数据快照,更加健壮,能够避免 AOF 这种复杂的备份和恢复机制的 bug
  • 用RDB恢复内存状态会丢失不少数据,重放AOP日志又很慢。Redis4.0推出了混合持久化来解决这个问题。将 rdb 文件的内容和增量的 AOF 日志文件存在一块儿。这里的 AOF 日志再也不是全量的日志,而是自持久化开始到持久化结束的这段时间发生的增量 AOF 日志,一般这部分 AOF 日志很小。因而在 Redis 重启的时候,能够先加载 rdb 的内容,而后再重放增量 AOF 日志就能够彻底替代以前的 AOF 全量文件重放,重启效率所以大幅获得提高。

缓存雪崩和缓存穿透

缓存雪崩是什么?

假设有以下一个系统,高峰期请求为5000次/秒,4000次走了缓存,只有1000次落到了数据库上,数据库每秒1000的并发是一个正常的指标,彻底能够正常工做,但若是缓存宕机了,每秒5000次的请求会所有落到数据库上,数据库立马就死掉了,由于数据库一秒最多抗2000个请求,若是DBA重启数据库,立马又会被新的请求打死了,这就是缓存雪崩。

如何解决缓存雪崩

事前:redis高可用,主从+哨兵,redis cluster,避免全盘崩溃 事中:本地ehcache缓存 + hystrix限流&降级,避免MySQL被打死 过后:redis持久化,快速恢复缓存数据

缓存穿透是什么?

假如客户端每秒发送5000个请求,其中4000个为黑客的恶意攻击,即在数据库中也查不到。举个例子,用户id为正数,黑客构造的用户id为负数,

若是黑客每秒一直发送这4000个请求,缓存就不起做用,数据库也很快被打死。

如何解决缓存穿透

查询不到的数据也放到缓存,value为空,如set -999 “”

总而言之,缓存雪崩就是缓存失效,请求所有所有打到数据库,数据库瞬间被打死。缓存穿透就是查询了一个必定不存在的数据,而且从存储层查不到的数据没有写入缓存,这将致使这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。

原文:https://blog.csdn.net/weixin_44175121/article/details/86300688

相关文章
相关标签/搜索