Redis专题-必知必会的基础知识

4,322 阅读9分钟

Redis有哪些优缺点?

优点

  • 读写性能优异, Redis能读的速度是110000次/s,写的速度是81000次/s。
  • 支持数据持久化,支持AOF和RDB两种持久化方式。
  • 支持事务,Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性执行。
  • 数据结构丰富,除了支持string类型的value外还支持hash、set、zset、list等数据结构。
  • 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。 缺点
  • 数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。
  • Redis 不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复。
  • 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性。
  • Redis 较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。

Redis为什么这么快?

  • 完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。
  • 数据结构简单,读取速度快。比如SDS、双端链表、压缩链表、跳跃链表。
  • 处理网络请求采用单线程,避免了不必要的上下文切换和竞争条件。

Redis 4.0 开始,用异步线程处理一些耗时操作。如,异步线程实现惰性删除(解决大KEY删除阻塞主线程)、异步 AOF (解决磁盘 IO 紧张时,fsync 执行一次很慢)等等。

  • 使用多路 I/O 复用模型,非阻塞 IO。
  • 使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis 直接自己构建了 VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。

Redis中有多少数据库?

Redis服务器默认会创建16个数据库,可通过配置的database选项修改。默认情况下,Redis客户端的目标数据库为0号数据库。

Redis数据结构?

  • 基本数据类型:string、list、set、zset、hash
  • 高级数据结构: Bitmap、HyperLogLog、GEO

Redis Module:BloomFilter、RedisSearch、Redis-ML、JSON。Stream功能(5.0新增)

Redis使用场景

  • 数据缓存
  • 会话缓存
  • 时效性数据
  • 访问频率
  • 计数器
  • 社交列表
  • 记录用户判定信息
  • 交集、并集和差集
  • 热门列表与排行榜
  • 最新动态
  • 消息队列
  • 分布式锁

Redis持久化

Redis 提供了两种方式,实现数据的持久化到硬盘。Redis启动会优先加载AOF文件,当未开启AOF时,才会加载RDB文件(未开启也不会加载)。

RDB 持久化(全量),fork 一个子进程,将内存中指定时间间隔内的数据集快照写入临时文件,成功后,再替换之前的文件,用二进制压缩存储。通过配置save参数、save(阻塞)、bgsaveshutdownflushall命令触发。

  • 优点:灵活设置备份频率和周期,适合冷备份,数据集的时候易恢复,子进程持久化不会影响主进程IO。

  • 缺点:丢失数据窗口大,当数据集较大时,fork子进程可能会导致整个服务器停止服务几百毫秒,甚至是 1 秒钟

不建议在主 Redis 节点开启 RDB 功能,会带来一定时间的阻塞,特别是数据量大的时候

AOF持久化(增量),以协议格式将被执行的写命令追加到服务器状态的aof_buf缓冲区,然后根据对应的策略向硬盘中同步数据。随着文件越来越大,需要定期对AOF文件进行重写(fork子进程来完成)。配置appendonly yes开启AOF。

AOF文件的加载需要先创建一个伪客户端,然后把命令一条条发送给Redis服务端,服务端再完整执行一遍相应的命令。

  • 写入策略:配置appendsync ,每秒同步(everysec),等到缓冲区满才同步(no),每次发生数据变更立即同步(always)。

  • 重写机制:通过auto-aof-rewrite-min-sizeauto-aof-rewrite-percentage配置重写时机。重写只会保留最终数据,多条写命令会合并为一条,已经超时的数据不会写入文件。重写过程中父进程执行的命令会通过管道按批次发送给子进程,由子进程重写回放。子进程退出后只有少量命令还累计在父进程,父进程只需回放少量命令即可。

  • 优点:更高的数据安全性,采用append模式没有磁盘寻址的开销,写入性能非常高,而且也不会破坏已经保存的数据。

  • 缺点:AOF文件通常要大于RDB文件,大数据集恢复是其速度慢于RDB,AOF这种较为复杂的基于命令日志/merge/回放的方式容易出bug

在 Redis4.0 版本开始,允许使用RDB-AOF混合持久化方式(5.0默认开启)。优化重写机制,重写后新的AOF文件前半段是RDB格式全量数据,后半段是AOF格式增量数据。在 Redis 实例重启时,会使用RDB持久化文件重新构建内存,再使用AOF重放近期的操作指令来实现完整恢复重启之前的状态。

Redis数据过期策略

  • 定时删除:在设置键的过期时间的同时,创建一个定时器(timer),让定时器在键的过期时间来临时,立即执行对键的删除操作。对CPU不友好。
  • 惰性删除:放任键过期不管,但是每次从键空间中获取键时,都检查取得的键是否过期,如果过期的话,就删除该键;如果没有过期,就返回该键。
  • 定期删除:在规定的时间内,分多次遍历服务器中的各个数据库,从数据库的expires字典中随机检查一部分键的过期时间,并删除其中的过期键。

expires字典会保存所有设置了过期时间的key的过期时间数据,其中,key是指向键空间中的某个键的指针,value是该键的毫秒精度的UNIX时间戳表示的过期时间。Redis中同时使用了惰性过期和定期过期两种过期策略。

Redis数据淘汰策略

Redis内存数据集大小上升到一定大小的时候,就会进行数据淘汰策略。Redis 提供了以下8种数据淘汰策略:

  • 全局的键空间选择性移除
    • noeviction:新写入操作会报错。(默认)
    • allkeys-lru:在键空间中,移除最久未使用的key。(这个是最常用的)
    • allkeys-random:在键空间中,随机移除某个key。
    • allkeys-lfu:在键空间中,移除最少使用频次的key(4.0的)
  • 设置过期时间的键空间选择性移除
    • volatile-lru:在设置了过期时间的键空间中,移除最久未使用的key。
    • volatile-random:在设置了过期时间的键空间中,随机移除某个key。
    • volatile-ttl:在设置了过期时间的键空间中,有更早过期时间的key优先移除。
    • volatile-lfu:在设置了过期时间的键空间中,移除最少使用频次的key(4.0的)

LRU:并不是一个严格的 LRU 实现,通过采样一小部分键,然后在采样键中回收最适合(拥有最久未被访问时间)的那个。

MySQL里有2000w数据,Redis中只存20w的数据,如何保证Redis中的数据都是热点数据?选择 allkeys-lru 策略。如果在 Redis 4.0 版本,可以考虑使用 volatile-lfu

如果有大量的 key 需要设置同一时间过期,一般需要注意什么?

如果大量的 key 过期时间设置的过于集中,一般需要在时间上加一个随机值,使得过期时间分散一些。调大 hz 参数。

Redis事务

Redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。没有隔离级别的概念。事务中任意命令执行失败,其余命令仍会被执行。

通过MULTI命令开启一个事务,在该语句之后执行的命令,都将被视为事务之内的操作,最后我们可以通过执行 EXEC/DISCARD命令来提交/回滚该事务内的所有操作。开启事务后,所有语句,发送给 Redis Server ,都会暂存在 Server 中。在事务开启之前,如果客户端与服务器之间出现通讯故障并导致网络断开,其后所有待执行的语句都将不会被服务器执行。

如何实现 Redis CAS 操作?

在 Redis 的事务中,WATCH命令可用于提供CAS功能。

Redis主从同步

image.png

psync命令实现全量复制和增量复制。增量复制通过主服务器id、复制偏移量以及主服务器复制积压缓冲区实现。

Redis哨兵

image.png

Redis集群

redis cluster采用数据分片的哈希槽来进行数据存储和数据的读取。redis cluster的新增和删除节点都需要手动来分配槽区。redis cluster执行读写操作的都是master节点。

image.png

Redis实现分布式锁

image.png

高频面试题

image.png

如何使用 Redis 实现消息队列?

一般使用 list 结构作为队列,rpush 生产消息,lpop 消费消息。当 lpop 没有消息的时候,要适当 sleep 一会再重试。还可使用blpop,在没有消息的时候,它会阻塞住直到消息到来。使用 pub / sub 主题订阅者模式,可以实现 1:N 的消息队列。但是在消费者下线的情况下,生产的消息会丢失。

延时队列: 使用 sortedset ,拿时间戳作为 score ,消息内容作为 key 调用 zadd 来生产消息,消费者用 zrangebyscore 指令获取 N 秒之前的数据轮询进行处理。

参考