Skip to content

Redis

image-20230621143706893

缓存中间件

Memcache和Redis的区别

特性 Redis Memcache
支持的数据类型 数据类型丰富 简单数据对象
数据持久化 支持数据磁盘持久化存储 不支持数据持久化
主从复制 支持主从复制 不支持主从复制
分片 支持分片 不支持分片

Redis为什么快

Redis可以做到100000+QPS(每秒十万+的查询次数)

原因:

  • 完全基于内容,绝大多数请求是纯粹的内存操作,执行效率高
  • 数据结构简单,对数据操作也简单
  • 采用单线程,单线程也能处理高并发请求,想多核也可启动多实例
  • 使用多路IO复用模型,非阻塞IO

多路IO复用模型

FD:文件描述符,一个打开的文件通过唯一的描述符进行引用,该描述符是打开文件的元数据到文件本身的映射

传统的阻塞IO模型

传统的阻塞IO模型是一种同步IO模型,它的工作方式是当应用程序向操作系统请求IO操作时,操作系统会一直等待,直到IO操作完成并返回结果,期间应用程序会被阻塞(即停止运行),无法执行其他任务。在这种模型下,当应用程序需要进行多个IO操作时,必须等待前一个IO操作完成后才能进行下一个IO操作,因此IO操作的效率较低,尤其是在需要进行大量IO操作时,会严重影响应用程序的性能。

多路复用模型

Redis采用的IO多路复用函数:epoll / kqueue / evport / select

如何选用:

  • 因地制宜
  • 优先选择时间复杂度为O(1)的IO多路复用函数作为底层实现
  • 以时间复杂度为O(n)的select作为保底
  • 基于react设计模式监听IO事件

Redis常用数据类型

  • String:最基本的数据类型,二进制安全
  • Hash:String元素组成的字典,适合用于存储对象
  • List:列表,按照String元素插入顺序排序
  • Set:String元素组成的无序集合,通过哈希表实现,不允许重复
  • Sorted Set:通过分数来为集合中的成员进行从小到大的排序

从海量数据中查询某一固定前缀的Key

KEYS pattern:查找所有符合给定模式Pattern的key

使用Scan命令

SCAN cursor [pattern] [count]

  • 基于游标的迭代器,需要基于上一次的游标延续之前的迭代过程
  • 以0作为游标开始一次新的迭代,直到命令返回游标0完成一次遍历
  • 不保证每次执行都返回某个给定数量的元素,支持模糊查询
  • 一次返回的数量不可控,只能是大概率符合count参数

如何使用Redis实现分布式锁

分布式锁需要解决的问题:

  • 互斥性
  • 安全性

  • 死锁

  • 容错

方案一:使用setNX

setNX key value :如果key不存在,则创建并赋值

  • 时间复杂度:O(1)
  • 返回值:成功1;失败0

如何解决setNX长期有效的问题:

expire key seconds:设置key的生存时间,当key过期时,会被自动删除

缺点:原子性得不到满足

方案二:使用set

Set key value [EX seconds] [PX milliseconds] [NX|XX]

  • EX second :设置键的过期时间为second秒
  • PX millisecond:设置键的过期时间为millisecond毫秒
  • NX:只有键不存在时,才对键进行设置
  • XX:只有键已经存在时,才对键进行设置操作
  • Set操作成功完成时,返回ok,否则返回nil

大量的key同时过期的注意事项

集中过期,由于清除大量的key很耗时,会出现短暂的卡顿现象

解决方法:在设置key的过期时间的时候,给每个key加上随机值

如何使用Redis做异步队列

方案一:

使用List作为队列,Rpush生产消息,Lpop消费消息

缺点:没有等待队列里有值就直接消费

弥补:可以通过在应用层引入sleep机制去调用Lpop重试

方案二:

BLpop key [key ...] timeout:阻塞直到队列有消息或者超时

缺点:只能供一个消费者消费

方案三:

使用pub/sub:主题订阅者模式

发送者(pub)发送消息,订阅者(sub)接收消息

缺点:消息的发布时无状态的,无法保证可达

Redis如何持久化