redis


什么是Redis?

Redis是一个使用C语言开发的内存数据库,读写速度很快,它除了可以做缓存还可以做分布式锁、消息队列。它提供了多种数据类型来支持不同的业务场景。它支持事务、持久化、多种集群方案

1. Redis 和 Memcached 的区别和共同点?

共同点:

  • 都是内存数据库,一般都用来当作缓存使用
  • 都有过期策略
  • 两者的性能都很高

不同点:

  • Redis支持更丰富的数据类型(支持更复杂的应用场景)
  • Redis支持数据的持久化,可以把内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用,而Mecached数据全部存在内存中
  • Redis有灾难恢复机制,因为可以把数据持久化到磁盘
  • Redis在服务器内存使用完之后,会把不用的数据存储到磁盘,而Mecached会直接报异常
  • Mecached不支持原生集群模式,Redis目前是原生支持cluter模式
  • Mecached多线程。非阻塞IO复用的网络模型;Redis使用单线程的多路IO复用模型
  • Redis支持发布订阅模型、lua脚本、事务等功能,Mecached不支持,Redis支持更多的编程语言
  • Mecached过期数据的删除策略只有惰性删除,而Redis有惰性删除和定期删除

1.1 缓存数据的处理流程

  1. 用户请求数据如果在缓存当中就直接返回
  2. 当缓存中不存在就查看数据库是否存在
  3. 数据库存在就更新缓存数据并返回数据
  4. 如果数据库不存在就返回空数据

1.2 为什么要用redis/缓存?

  • 高性能:读取速度快,因为redis是内存数据库,如果访问的是mysql它的数据是存储在磁盘的
  • 高并发:可以承受更大的访问量

1.3 Redis的常见数据结构和应用场景

  • String:一般用在需要计数的场景,比如用户的访问次数、热点文章的点赞或者转发数量等
  • list:发布与订阅或者消息队列、慢查询
  • hash:系统中对象数据的存储
  • set:需要存放的数据不能重复以及需要获取多个数据源交集和并集等场景
  • Zset:需要对数据根据某个权重进行排序。例如直播中的排行,用户在线列表,礼物排行榜,弹幕消息

1.4 Redis没有使用多线程?为什么不使用多线程?

Redis4.0之后的版本已经加入对多线程的支持,但Redis6.0之前主要是单线程处理

Redis6.0之前不使用多线程的原因:

  • 单线程变成容易维护
  • Redis的性能瓶颈不在CPU,而是在内存和网络
  • 多线程存在死锁,线程上下文切换等问题,可能会影响性能

Redis6.0之后引入多线程主要为了提高网络IO的读写性能(瓶颈中的一个,但主要是内存和网络瓶颈)

1.5 Redis设置缓存过期时间有什么用?

内存空间大小是有限制的,如果缓存所有的数据,会造成内存溢出

exp key 60 #设置数据60s过期时间
setex key 60 value #设置键值的同时设置过期时间
ttl key #查询过期时间剩余多少
persist key #取消设置的过期时间

除了String类型拥有独有的设置过期时间的命令,其他的数据类型都需要通过exp

应用场景:短信有效期,用户token有效期

1.6 Redis如何判断数据是否过期?

Redis维护了一个过期字典,key值指向了设置了过期时间的key

1.7 过期的数据的删除策略

惰性删除(懒汉删除):对CPU更加友好

定期删除:对内存更加友好

Redis采用惰性删除+定期删除,但是依旧会存在漏掉过期键的情况以至于导致Out of Memory,这时候我们通过内存淘汰机制解决这个问题

1.8 Redis的内存淘汰机制

Redis提供六种淘汰机制:

  • volatile-lru:从已设置过期时间的数据集中,选取最近最少使用的数据淘汰
  • volatile-ttl:从已设置过期时间的数据集中,选取即将过期的数据淘汰
  • volatitle-random:从已设置过期时间的数据集中,随机选取数据淘汰
  • allkeys-lru(最常用):在内存空间不足以写入新数据时,从键空间中,淘汰最近最少使用的key
  • allkeys-random:在内存空间不足以写入新数据时,从所有数据集中随机淘汰数据
  • no-eviction:在内存空间不足以写入新数据时,写入数据报错
  • volatitle-lfu:从已设置过期时间的数据集中,选取最少使用的key淘汰
  • allkeys-lfu:在内存空间不足以写入新数据时,在所有键空间中,淘汰最近最少使用的key

1.9 Redis持久化机制(怎么保证Redis挂掉之后在重启数据可以进行恢复)?

RDB(Redis默认持久化方式):满足一定条件后,更适合用来做备份

save 900 1           #在900秒(15分钟)之后,如果至少有1个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

save 300 10          #在300秒(5分钟)之后,如果至少有10个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

save 60 10000        #在60秒(1分钟)之后,如果至少有10000个key发生变化,Redis就会自动触发BGSAVE命令创建快照。

AOF: 每秒都会同步一次Redis数据库

appendonly yes #默认是关闭AOF 配置文件更改成yes开启

2.0 Redis事务

> MULTI
OK
> INCR foo
QUEUED
> INCR bar
QUEUED
> EXEC
1) (integer) 1
2) (integer) 1

通过MULTI开启事务,后面的命令都将被放入队列,通过EXEC提交事务在顺序执行

通过WATCH可以来监听事务 DISCARD放弃事务,Redis数据库支持事务但是不支持原子性

2.1 缓存穿透(查不到数据)

用户发起请求—>缓存—>数据库,当用户请求的数据不在缓存当中时,接着会去访问数据库,如果一个人向缓存和数据库中不存在的key发起大量请求就会造成缓存穿透

解决方案:

  • 布隆过滤器:(小概率误判)布隆过滤器判断某个元素存在那么就存在,布隆过滤器说不存在的key一定不存在
  • 缓存无效key

2.2 缓存击穿

缓存过期,在热点数据key值过期的瞬间,大量的并发访问同一个热点数据,就可能造成缓存击穿,好像子弹打在一面墙的同一个点

2.3 缓存雪崩

Redis服务器宕机或者Redis热点数据大面积失效,所有的请求短时间全部落到了数据库上,造成数据库短时间承受大量的请求导致雪崩,场景:双11秒杀。这也是为什么双11会出现服务降级的情况:暂停退款服务

解决方案:

针对Redis服务不可用的情况:

  • 采用Redis集群,避免单机出现问题整个缓存服务无法使用
  • 限流,避免同时处理大量的请求

针对热点缓存失效:

  • 设置不同的失效时间,随机设置缓存失效时间
  • 缓存永不失效

文章作者: Z.Wfeng
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Z.Wfeng !
  目录