• 是一个开源的key-value存储系统
  • 支持持久化
  • 一般作为缓存
  • 支持多种数据类型
  • 操作都是原子性的(单线程中,能够在单条指令完成的操作都是原子操作,因为中断只能发生在指令之间 多线程中,不能被其他线程或进程打断的操作为原子操作)
  • 支持不同方式排序
  • 可以实现主从同步
  • 默认端口号6379(merz)
  • 默认16个数据库,初始默认使用0号库
  • 命令不区分大小写,key区分大小写

    Redis 为什么快(有待完善)

  • 单线程

  • 多路IO复用

    数据结构(value)类型

    String

  • 最基本的类型,一个key对应一个value

  • 二进制安全,可以包含任意数据,例如图片等
  • 最多512M
  • 数据结构
    • 简单动态字符串,可以修改,内部结构实现类似ArrayList,采用预分配冗余空间的方式减少内存的频繁分配
    • 实际分配的capacity一般都大于实际字符串长度len, 当字符串长度<1M时,都是加倍现有长度,超过1M则只会多扩1M
  • 应用场景

    • 商品编号、订单号,可以incr命令生成
    • 是否喜欢文章

      List列表

  • 单键多值,是简单的字符串链表

  • 底层双向链表
  • 数据结构
    • quickList、ziplist
    • 数据元素较少时是ziplist(它将所有的元素紧挨着一起存储,分配的是一块连续内存,数据较多时变成qiuckList(多个zipList前后相连的双向链表)
  • 应用场景

    • 微信文章订阅

      Set集合

  • 类似于没有重复的列表

  • 无序集合,底层是一个value为null的hash表
  • 数据结构dict字典(hash表实现)
  • 应用场景

    • 抽奖(随机数)
    • 点赞
    • 好友关注社交关系(集合运算,比如共同关注)
    • 可能认识的人(差集)

      hash哈希

  • 键值对集合,适用于存储对象

  • 数据结构
    • ziplist(key-value较短且个数较少的时候)
    • hashtable
  • 应用场景

    • 简单的购物车(中小厂版)

      zset(sortedset)有序集合

  • 没有重复元素

  • 每个成员都关联了一个评分,根据评分从最低分到最高排序
  • 集合的成员唯一,评分可以重复
  • 底层结构:
    • hash,作用是关联元素value和score,保证value的唯一性,可以通过value找到相应的score
    • 跳跃表:目的是给元素vaLue排序,根据score的范围获取元素列表
  • 应用场景

    • 根据商品销量进行排序显示
    • 抖音热搜

      bitmap

      位图,是一个以位为单位的数组,数组中只能存储1或0,数组的下标在Bitmap中叫做偏移量。Bitmap实现统计功能,更省空间。面试中常问的布隆过滤器就有用到这种数据结构,布隆过滤器可以判断出哪些数据一定不在数据库中,所以常被用来解决Redis缓存穿透问题。

      Stream

      Stream 实际上是一个具有消息发布/订阅功能的组件,也就常说的消息队列
      Strean 除了拥有很高的性能和内存利用率外, 它最大的特点就是提供了消息的持久化存储,以及主从复制功能,从而解决了网络断开、Redis 宕机情况下,消息丢失的问题,即便是重启 Redis,存储的内容也会存在

      HyperLogLog

  • HyperLogLog是一种算法,并非redis独有

  • 目的是做基数统计,故不是集合,不会保存元数据,只记录数量而不是数值。
  • 耗空间极小,支持输入非常体积的数据量
  • 核心是基数估算算法,主要表现为计算时内存的使用和数据合并的处理。最终数值存在一定误差
  • redis中每个hyperloglog key占用了12K的内存用于标记基数(官方文档)
  • pfadd命令并不会一次性分配12k内存,而是随着基数的增加而逐渐增加内存分配;而pfmerge操作则会将sourcekey合并后存储在12k大小的key中,这由hyperloglog合并操作的原理(两个hyperloglog合并时需要单独比较每个桶的值)可以很容易理解。
  • 误差说明:基数估计的结果是一个带有 0.81% 标准错误(standard error)的近似值。是可接受的范围
  • Redis 对 HyperLogLog 的存储进行了优化,在计数比较小时,它的存储空间采用稀疏矩阵存储,空间占用很小,仅仅在计数慢慢变大,稀疏矩阵占用空间渐渐超过了阈值时才会一次性转变成稠密矩阵,才会占用 12k 的空间

    GEO

    Redis GEO 主要用于存储地理位置信息,并对存储的信息进行操作,

    事务

  • redis事务是一个单独的隔离操作,事务中的所有命令都会序列化按顺序执行,执行过程中,不会被其他客户端发来的命令请求所打断

  • 主要作用是串联多个命令,防止别的命令插队
  • 输入multi开始组队,输入的命令会进入到队列中,不会执行,直到输入exec,redis会将命令队列里的命令依次执行,输入discard可以放弃组队
  • 组队时出错,整个队列取消
  • 执行时出错,只有出错的命令不被执行,其他正常

    悲观锁

    每次去拿数据时都认为别人会修改,所以每次都在拿数据时上锁

    乐观锁

    拿数据时不上锁,更新的时候去判断有没有更新
    可以使用版本号等机制,适用于多读的应用场景

    持久化

    RDB

  • 在指定的时间间隔内,将内存中的数据集快照写入磁盘

  • 当Redis重启时,RDB程序会通过重载RDB文件来还原数据库
  • redis会单独创建一个子线程来持久化,会将数据写入到一个临时文件,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程,主进程是不进行任何IO操作的,这就确保了性能,如果需要大规模的数据恢复,且对数据恢复的完整性不是非常敏感的,那RDB比aof高效
  • 优势
    • 适合大规模的数据恢复
    • 对数据完整性和一致性要求不高更适合使用
    • 节省磁盘空间
    • 恢复速度快
  • 劣势

    • fork时,大致2倍的膨胀性,数量大时候还是比较消耗性能
    • 可能丢失最后一次快照后的所有修改

      AOF(append only file)

  • 以日志的形式来记录每个写操作,将redis所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件

  • 优势
    • 备份机制更稳健,丢失数据概率低
    • 可读的日志文本,通过操作aof文件,可以处理误操作
  • 劣势
    • 比起rdb占用更多的磁盘空间
    • 恢复备份速度要慢
    • 每次读写都同步,有一定的性能压力
    • 存在个别bug,造成恢复不能
  • 默认不开启
  • AOF和RDB同时开启,系统默认取aof的数据
  • redis启动之初会重新读取该文件重新构建数据库,换言之,redis重启的话,就根据日志文件的内容,将写指令从头到尾执行一次完成数据恢复工作

可以都开启
对数据不敏感可以rdb
不建议单独aof,可能有bug
纯内存缓存,可以都不用

缓存穿透

访问缓存和数据库都不存在的数据

  • 解决方案

    • 对空值缓存
    • 设置白名单
    • 布隆过滤器
    • 实时监控

      缓存击穿

      有热点key过期,短时间大量访问数据库,导致数据库压力增大
  • 解决方案

    • 预先设置热门数据
    • 实时调整
    • 使用锁(只允许一个线程重新缓存,其他线程再重新从缓存里面拿数据)

      缓存雪崩

      短时间内大量key过期
  • 解决方案

    • 构建多级缓存架构:
      • 比如nginx缓存+redis缓存+其他缓存(ehcache等)
    • 使用锁或队列
      • 保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量并发的请求落到底层存储系统上,不适合高并发情况
    • 设置过期标志更新缓存
      • 记录缓存是否过期(设置提前量),如果过期通知另外的线程在后台更新实际key的缓存
    • 将缓存失效时间分散开
      • 比如可以在原有的时间上加一个随机值,这样每一个缓存的过期时间重复了降低,很难发生集体失效的事件了

        分布式锁

        针对于整个分布式集群系统的锁
  • 设置过期时间(上锁的时候同时设置),防止一直不释放锁

  • 使用uuid,防止释放其他的锁
  • 使用Luna脚本保证删除的原子性
  • setnx

    集群

  • 实现了redis的水平扩容,即启动n个redis节点,将整个redis数据库分布在n个节点中,每个节点存储1/N的数据

  • 分摊压力
  • 无中心化配置相对简单
  • 不足
    • 不支持多键操作
    • 不支持多键事务和luna脚本

      通道

      其他

      查看版本的命令
      redis- server -v
      或者在进入redis后输入info