Redis数据类型

文章目录

  • Redis介绍
  • RedisObject的结构
    • 1. type
    • 2. enconding
    • 3. lru
    • 4. refcount
    • 5. *prt
  • Redis源码结构
    • 1. 基本数据结构
    • 2. Redis数据类型的底层实现
    • 3. Redis数据库的实现
    • 4. Redis服务端和客户端实现
    • 5. 其他
  • Redis数据类型
    • String
      • 使用场景
      • 使用示例
    • List
      • 使用场景
      • 使用示例
    • Set
      • 使用场景
      • 使用示例
    • Zset
      • 使用场景
      • 使用示例
    • Hash
      • 使用场景
      • 使用示例
    • Stream
      • 使用场景
      • 使用示例
    • Bloom Filter
      • 使用场景
      • 使用示例
    • Bitmap
      • 使用场景
      • 使用示例
    • HyperLogLog
      • 使用场景
      • 使用示例
    • Geospatial
      • 使用场景
      • 使用示例


Redis介绍

Redis全称REmote DIctionary Server,由Salvatore Sanfilippo写的高性能key-value存储系统,完全开源免费,遵守BSD协议。

Redis是key-value存储系统,其中key类型一般为字符串,value类型则为RedisObject对象。

RedisObject的结构

RedisObject定义了5个属性:type、enconding、lru、refcount和*prt
Redis数据类型_第1张图片

Redis数据类型_第2张图片

属性 描述
type value值的数据类型
enconding value值的编码方式
lru 记录此对象最后一次访问的时间
refcount 记录对象的引用次数
*prt 数据指针

1. type

value值的数据类型。

常见数据类型:

类型常量 类型描述
REDIS_STRING 字符串对象
REDIS_LIST 列表对象
REDIS_HASH 哈希对象
REDIS_SET 集合对象
REDIS_ZSET 有序集合对象

2. enconding

value值的编码方式

常见编码方式:

编码常量 编码描述
REDIS_ENCODING_INT long 类型的整数
REDIS_ENCODING_EMBSTR embstr 编码的简单动态字符串
REDIS_ENCODING_RAW 简单动态字符串
REDIS_ENCODING_HT 字典
REDIS_ENCODING_LINKEDLIST 双端链表
REDIS_ENCODING_ZIPLIST 压缩列表
REDIS_ENCODING_INTSET 整数集合
REDIS_ENCODING_SKIPLIST 跳跃表和字典

不同数据类型支持的编码方式

数据类型 编码方式 描述
REDIS_STRING REDIS_ENCODING_INT 使用整数值实现的字符串对象
REDIS_STRING REDIS_ENCODING_EMBSTR 使用 embstr 编码的简单动态字符串实现的字符串对象
REDIS_STRING REDIS_ENCODING_RAW 使用简单动态字符串实现的字符串对象
REDIS_LIST REDIS_ENCODING_ZIPLIST 使用压缩列表实现的列表对象
REDIS_LIST REDIS_ENCODING_LINKEDLIST 使用双端链表实现的列表对象
REDIS_HASH REDIS_ENCODING_ZIPLIST 使用压缩列表实现的哈希对象
REDIS_HASH REDIS_ENCODING_HT 使用字典实现的哈希对象
REDIS_SET REDIS_ENCODING_INTSET 使用整数集合实现的集合对象
REDIS_SET REDIS_ENCODING_HT 使用字典实现的集合对象
REDIS_ZSET REDIS_ENCODING_ZIPLIST 使用压缩列表实现的有序集合对象
REDIS_ZSET REDIS_ENCODING_SKIPLIST 使用跳跃表和字典实现的有序集合对象

3. lru

记录此对象最后一次访问的时间。

当redis内存回收算法设置为volatile-lru或者allkeys-lru时候redis会优先释放最久没有被访问的数据。

4. refcount

记录对象的引用次数,类似于jvm的引用计数垃圾回收算法,当refcount为0时,表示没有其它对象引用,可以进行释放此对象。

5. *prt

数据指针,指向底层真正的数据结构。

Redis源码结构

redis源码主要放在src目录里。

主要核心部分分类如下:

1. 基本数据结构

  • 动态字符串 :sds.c
  • 整数集合 :intset.c
  • 压缩列表 :ziplist.c
  • 快速链表 :quicklist.c
  • 字典 :dict.c
  • Streams :底层实现结构为listpack.c和rax.c

2. Redis数据类型的底层实现

  • redis对象 :object.c
  • 字符串 :t_string.c
  • 列表 :t_list.c
  • 字典 :t_hash.c
  • 集合及有序集合 :t_set.c 和 t_zset.c
  • 数据流 :t_stream.c

3. Redis数据库的实现

  • 数据库的底层实现 :db.c
  • 持久化 :rdb.c 和 aof.c

4. Redis服务端和客户端实现

  • 事件驱动 :ae.c 和 ae_epoll.c
  • 网络连接 :anet.c 和 networking.c
  • 服务端程序 :server.c
  • 客户端程序 :redis-cli.c

5. 其他

  • 主从复制 :replication.c
  • 哨兵 :sentinel.c
  • 集群 :cluster.c
  • 其他数据结构 :hyperloglog.c 、 geo.c 等
  • 其他功能 :pub/sub 【发布/订阅】、 Lua脚本等

Redis数据类型

  1. 一般认为Redis的数据类型有:String、List、Set、Zset、Hash、Stream
  2. HyperLogLog、Bitmap、Bloom Filter的底层是String数据类型
  3. Geospatial的底层是Zset数据类型
数据类型 描述 使用场景
String 最基本的数据类型,可以存储任意数据,如文本、整数、二进制数据等,最大512M 用于缓存、计数器、分布式锁等场景
List 按照插入顺序排序的字符串元素集合,支持头尾插入、弹出等操作 用于实现队列、栈、消息队列等场景
Set 无序的字符串元素集合,其中元素不可重复,支持交集、并集、差集等操作 用于进行唯一性判定、求多个集合的交集、并集等场景
Zset 带有分数排序的字符串元素集合,支持根据分数范围来获取元素等操作 用于需要排序并保持唯一性的场景
Hash 存储多个键值对的字典,支持对单个字段进行增删查改等操作 用于表示对象、存储属性等场景
Stream 异步消息传输机制,基于多个消费者以广播模式接收生产者发送的消息 用于消息队列、事件驱动等场景
Bloom Filter 底层是String,概率型的数据结构(布隆过滤器),用于快速判断一个元素是否存在于一个集合中 用于判重、URL 去重、邮箱黑名单过滤等场景
Bitmap 底层是String,位图,用于存储一系列只有 0 和 1 的值,支持位运算等操作 用于标记、统计等场景
HyperLogLog 底层是String,基数统计算法,用于统计一个集合中不重复元素的数量 用于进行去重、UV 统计等场景
Geospatial 底层是Zset,地理位置数据类型,支持存储经度、纬度等地理信息,且支持根据地理位置信息进行查询 用于 LBS 场景、附近的人、商家等推荐等场景

String

String 类型是最简单、最常用的数据类型之一。它可以存储文本、整数或二进制数据。String 类型在 Redis 中被处理为二进制安全的字节序列。

使用场景

  • 缓存

    String 类型常被用作缓存的存储,可以将频繁读取的数据存储在 Redis 中,以提高数据读取效率。例如存储网页内容、用户信息等。

  • 计数器

    String 类型支持对整数进行原子操作,因此可以用作计数器。可用于实现访问量统计、文章点赞数统计等场景。

  • 分布式锁

    由于 Redis 提供原子操作的特性,可以利用 String 类型实现分布式锁。使用 SETNX 命令尝试加锁,利用 SETEX 命令设置过期时间,实现分布式环境下的互斥访问控制。

  • 分布式 Session

    在分布式系统中,可以借助 String 类型实现分布式 Session 的存储和管理。例如将用户登录信息存储在 Redis 的 String 类型中,实现用户状态的共享和管理。

使用示例

  • 设置和获取值:

    SET key value   # 设置字符串键的值
    GET key         # 获取字符串键的值
    
  • 字符串拼接:

    APPEND key value         # 将字符串追加到键值的末尾
    STRLEN key               # 获取指定键值的长度
    
  • 数值操作:

    INCR key                 # 将键值作为整数增加 1
    DECR key                 # 将键值作为整数减少 1
    INCRBY key increment     # 将键值作为整数增加指定值
    DECRBY key decrement     # 将键值作为整数减少指定值
    
  • 原子操作和过期:

    SETNX key value          # 如果键不存在,设置键的值
    SETEX key seconds value  # 设置键的值和过期时间
    

总结来说,Redis 的 String 类型是一个灵活而强大的数据类型,适用于缓存、计数器、分布式锁和分布式 Session 等各种常见用例。通过原子操作和丰富的命令集,可以充分发挥 String 类型的优势。

List

List(列表)是一个有序的字符串元素集合,插入顺序按照元素的加入顺序排列。List 可以存储各种类型的元素(如字符串、整数),在 Redis 中被处理为双向链表。List 具备头部插入、尾部插入、头部弹出、尾部弹出等操作,并支持通过索引访问和修改元素。

使用场景

  • 队列

    List 可以方便地实现队列数据结构,支持在列表头部插入元素和在列表尾部弹出元素。它可以用于任务队列、消息队列等场景,例如在一个多线程或分布式环境中,通过 List 来存储待处理的任务,各个消费者可以从队列尾部取出任务进行处理。

  • List 也可以作为栈(后进先出,LIFO)来使用。通过在列表头部插入元素和从列表头部弹出元素可以实现栈的功能,比如实现一些撤销操作。

使用示例

  • 插入和删除操作:

    LPUSH key value1 [value2 ...]   # 在列表头部插入一个或多个值
    RPUSH key value1 [value2 ...]   # 在列表尾部插入一个或多个值
    LPOP key                        # 弹出并返回列表的头部元素
    RPOP key                        # 弹出并返回列表的尾部元素
    
  • 获取列表元素:

    LINDEX key index    # 获取指定索引处的元素值
    LRANGE key start stop   # 获取指定范围内的元素值
    
  • 获取列表长度:

    LLEN key    # 获取列表的长度
    
  • 修改列表元素:

    LSET key index value   # 设置指定索引处的元素值
    

总结来说,Redis 的 List 数据类型是一个灵活且功能强大的有序集合,适用于队列、栈和消息队列等各种场景。通过多种插入、弹出和访问元素的命令,可以方便地操作和管理列表数据。

Set

Set(集合)是一个无序的、不重复的元素集合。Set 可以存储各种类型的元素(如字符串、整数),在 Redis 中被处理为哈希表结构。Set 提供了添加、删除、判断元素是否存在等常用操作,还支持交集、并集、差集等集合运算。

使用场景

  • 去重

    Set 的最常见用途是消除重复元素。通过将元素添加到 Set 中,可以自动去重,保留唯一的元素。

  • 标签或分类

    Set 可以用于标签或分类的存储。例如,将文章的标签存储在 Set 中,方便根据标签进行搜索和分类。

  • 共同好友

    Set 可以用于存储共同好友关系。通过将用户的好友列表存储在 Set 中,可以方便地查找两个用户的共同好友。

  • 集合运算

    Set 提供了交集、并集、差集等集合运算,可以对多个 Set 进行操作,求得他们之间的交集、并集或差集。

使用示例

  • 添加和删除元素:

    SADD key member1 [member2 ...]   # 向集合中添加一个或多个元素
    SREM key member1 [member2 ...]   # 从集合中删除一个或多个元素
    
  • 检查元素是否存在:

    SISMEMBER key member   # 检查元素是否存在于集合中
    
  • 获取集合中的元素数量:

    SCARD key   # 获取集合的元素数量
    
  • 获取集合中的所有元素:

    SMEMBERS key   # 获取集合中的所有元素
    
  • 集合运算:

    SINTER key1 [key2 ...]   # 返回多个集合的交集
    SUNION key1 [key2 ...]   # 返回多个集合的并集
    SDIFF key1 [key2 ...]    # 返回多个集合的差集
    

总结来说,Redis 的 Set 数据类型提供了一种无序、不重复的集合存储方式,适用于去重、标签或分类、共同好友关系存储以及集合运算等场景。通过多种操作命令,可以方便地对集合进行增删查改以及集合运算。

Zset

Zset(Sorted Set)数据类型(有序集合)是一种基于 Set 的数据类型,其每个元素都会关联一个 double 类型的分数(score)属性。Zset 中的元素是唯一的,但是分数(score)可以重复。Zset 根据元素的分数进行排序,俗称为有序集合。

使用场景

  • 排行榜:

    Zset 常被用于实现排行榜功能,例如音乐网站的歌曲播放次数排行榜、积分排行榜等,分数可以表示播放次数或者积分,元素即为歌曲或用户。

  • 范围查询:

    由于有序集合中元素按照分数排序,因此可以方便进行范围查询。例如,可以使用 ZRANGEBYSCORE 命令获取指定分数范围内的元素列表。

  • 任务调度:

    Zset 可以用于任务调度,分数可以表示任务的执行时间,通过定时将分数符合条件的任务提取出来执行。

  • 实时榜单:

    Zset 可以用于实时热门数据统计,例如统计最近一段时间内的热门搜索关键词或热门商品。

使用示例

  • 添加和删除元素:

    ZADD key score1 member1 [score2 member2 ...]   # 向有序集合中添加一个或多个元素
    ZREM key member1 [member2 ...]                 # 从有序集合中删除一个或多个元素
    
  • 查看元素排名:

    ZRANK key member   # 获取指定成员的排名
    
  • 查看元素分数:

    ZSCORE key member   # 获取指定成员的分数
    
  • 获取集合中的元素数量:

    ZCARD key   # 获取有序集合的元素数量
    
  • 获取指定分数范围内的元素:

    ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]   # 获取指定分数范围内的元素
    

总结来说,Redis 的 Zset 数据类型提供了一种根据分数进行排序的有序集合存储方式,适用于排行榜、范围查询、任务调度和实时榜单等场景。通过多种操作命令,可以方便地对有序集合中的元素进行增删查改以及范围查询。

Hash

Hash 是一个键值对集合,类似于关联数组或者对象。在 Redis 中,每个 Hash 可以存储多个键值对,其中键与值都是字符串类型的。Hash 常用于存储对象的属性和值,特别适合用来存储对象的多个属性,比如用户、商品等。

使用场景

  • 存储对象属性:

    Hash 可以用于存储对象的多个属性和对应的值,比如用户对象的属性(用户名、年龄、性别等)、商品对象的属性(名称、价格、库存等)。

  • 缓存存储:

    Hash 可以用于存储缓存信息,例如将数据库查询结果缓存为 Hash 类型,字段名作为缓存的唯一标识,字段值存储查询结果。

  • 计数器:

    Hash 可以用于实现计数器功能,例如网站的文章点赞数、评论数等,可以以文章 ID 为键,以点赞数和评论数为字段值存储在 Hash 中。

  • 对象存储:

    Hash 适合于存储较为复杂的对象结构,比如存储 JSON 数据时,可以将不同属性存储为 Hash 的不同字段,方便操作和检索。

使用示例

  • 添加和修改字段:

    HSET key field value      # 设置指定字段的值
    HMSET key field1 value1 field2 value2 ...   # 设置多个字段的值
    
  • 获取字段值:

    HGET key field   # 获取指定字段的值
    HMGET key field1 field2 ...   # 获取多个字段的值
    
  • 删除字段:

    HDEL key field1 [field2 ...]   # 删除一个或多个字段
    
  • 获取所有字段名:

    HKEYS key   # 获取所有字段名
    
  • 获取所有字段值:

    HVALS key   # 获取所有字段的值
    
  • 获取字段数量:

    HLEN key   # 获取字段的数量
    

总结来说,Redis 的 Hash 数据类型提供了一种存储对象属性的键值对集合存储方式,适用于对象属性存储、缓存存储、计数器和对象存储等场景。通过多种操作命令,可以方便地对 Hash 中的字段进行增删查改操作。

Stream

Stream(流)是一个有序、持久化的消息流数据结构,类似于消息队列。Stream 以时间顺序存储消息,并为每个消息分配一个唯一的、递增的 ID。Stream 中的消息称为条目(entry),每个条目包含一个字段的键值对集合。Stream 提供了多种操作来添加、读取和删除条目,并可以根据条件进行过滤。

使用场景

  • 消息队列:

    Stream 可以作为轻量级的消息队列使用,用于发布订阅模式、异步任务处理、实时处理等场景。

  • 日志收集:

    Stream 可以用于实时收集和存储系统日志,方便后续检索和分析。

  • 事件溯源:

    Stream 可以用于记录和回放事件流,实现事件溯源机制。

  • 实时数据处理:

    Stream 可以用于实时数据处理,对实时数据进行监控、处理、聚合等操作。

使用示例

  • 添加条目:

    XADD mystream * field1 value1 field2 value2   # 添加条目,并生成递增的唯一 ID
    
  • 读取条目:

    XREAD STREAMS mystream 0   # 从指定位置读取条目,0 表示从最旧的条目开始读取
    
  • 删除条目:

    XDEL mystream id1 id2 ...   # 删除一个或多个指定的条目
    
  • 获取条目数量:

    XLEN mystream   # 获取条目的数量
    
  • 根据条件过滤条目:

    XREAD STREAMS mystream id0-0 COUNT 10   # 根据 ID 过滤条目,从指定 ID 位置开始读取指定数量的条目
    

总结来说,Redis 的 Stream 是一种用于处理实时流式数据的日志数据结构。作为高性能的消息队列,Stream 支持添加、读取、消费和管理消息,适用于消息队列、日志处理和流式计算等场景。通过使用 Stream 提供的命令,可以实现高效、可持久化的实时数据处理。

为什么不使用Redis发布订阅 (pub/sub) 来实现消息队列:

Redis 本身是有一个 Redis 发布订阅 (pub/sub) 来实现消息队列的功能,支持发布 / 订阅,支持多组生产者、消费者处理消息。但是存在很多问题:

  1. 消费者下线,数据会丢失。

  2. 不支持数据持久化,Redis 宕机,数据也会丢失,Pub/Sub 没有基于任何数据类型实现,不会写入到 RDB 和 AOF 中,当 Redis 宕机重启,Pub/Sub 的数据也会全部丢失。

  3. 消息堆积,缓冲区溢出,消费者会被强制踢下线,数据也会丢失。

    缓冲区的默认配置:client-output-buffer-limit pubsub 32mb 8mb 60。它的参数含义如下:

    • 32mb:缓冲区一旦超过 32MB,Redis 直接强制把消费者踢下线。
    • 8mb + 60:缓冲区超过 8MB,并且持续 60 秒,Redis 也会把消费者踢下线。

Bloom Filter

Bloom Filter 是一种概率型数据结构,用于快速判断一个元素是否在集合中,具有快速查询和占用空间少的特点。Bloom Filter 使用一系列哈希函数和位数组,通过将元素映射到位数组的多个位置,并将相应位置的值置为 1,来表示元素存在的可能性。

但需注意:Bloom Filter 在存在一定的误判率(false positive)的情况下使用,因此适用于对错误率要求不高的场景。

使用场景

  • 缓存穿透:

    Bloom Filter 可以用于缓存穿透场景,当请求的数据在缓存中不存在时,可以通过 Bloom Filter 快速判断请求的数据是否一定不存在,从而避免无效的数据库查询操作。

  • 去重判断:

    Bloom Filter 可以用于去重场景,例如判断一个 URL 是否已经访问过,判断一个用户是否已经参与过某个活动等。

  • 数据集合判断:

    Bloom Filter 可以用于判断元素是否属于一个大数据集合,避免对庞大的数据集合进行昂贵的查询操作。

使用示例

  • 添加元素:

    BFADD key item   # 向 Bloom Filter 中添加一个元素
    
  • 判断元素是否存在:

    BFMEXISTS key item1 item2 ...   # 判断一个或多个元素是否存在于 Bloom Filter 中
    
  • 获取 Bloom Filter 的错误率:

    BFINFO key   # 获取 Bloom Filter 的相关信息,包括错误率、哈希函数数等
    

总结来说,Redis 的 Bloom Filter 是一种快速判断元素是否存在的概率型数据结构,适用于缓存穿透、去重判断和数据集合判断等场景。通过添加元素和判断元素是否存在的操作,可以实现快速而低成本的元素存在性判断。需要注意的是,Bloom Filter 在存在一定的误判率(false positive)的情况下使用,因此适用于对错误率要求不高的场景。

Bitmap

Bitmap(位图)是一种稀疏压缩的数据结构,用于存储和操作二进制位的集合。每个位可以表示一个索引或标记,BitMap 中的位数由用户指定,一般用于表示布尔值或者计数器。

使用场景

  • 布尔值表示:

    Bitmap 可以用来表示布尔值(0 或 1),例如标记用户是否在线、是否已读等状态。

  • 计数器:

    Bitmap 可以用于实现计数器功能,例如统计用户登录次数、点击次数等。

  • 位操作:

    Bitmap 提供了位操作的功能,例如与、或、非、异或等操作,可以用于集合运算、位运算等应用。

使用示例

  • 将指定位置的位设置为 1:

    SETBIT key offset value   # 将 key 的 offset 位置的位设置为 value (0 或 1)
    
  • 获取指定位置的位的值:

    GETBIT key offset   # 获取 key 的 offset 位置的位的值 (0 或 1)
    
  • 统计指定范围内值为 1 的位的数量:

    BITCOUNT key [start end]   # 统计 key 中指定范围内的值为 1 的位的数量
    
  • 对多个 key 进行位操作并将结果保存到新的 key 中:

    BITOP operation destkey key1 [key2 ...]   # 对多个 key 进行位操作(与、或、非、异或)并将结果保存到 destkey 中
    

总结来说,Redis 的 Bitmap 是一种稀疏压缩的位集合数据结构,适用于表示布尔值、计数器和位操作等场景。通过设置位、获取位的值、统计位数量和位操作等操作,可以对二进制位进行存储、操作和查询。Bitmap 在实现简单功能时占用的内存较小且性能较高,适合处理大量位操作的需求。

HyperLogLog

HyperLogLog(超级日志日志)是一种基数估计算法,用于统计唯一元素的数量。HyperLogLog 使用非常小的固定空间来估计大型集合的基数,同时引入了一定的误差。

使用场景

  • 基数统计:

    HyperLogLog 主要用于统计大型集合的基数(即唯一元素的数量),例如统计网站的独立访客数、统计 IP 地址数量等。

使用示例

  • 添加元素到 HyperLogLog:

    PFADD key element1 element2 ...   # 将元素添加到 HyperLogLog 中
    
  • 获取 HyperLogLog 的基数估计:

    PFCOUNT key   # 获取 HyperLogLog 的基数估计值
    
  • 合并多个 HyperLogLog:

    PFMERGE destkey sourcekey1 sourcekey2 ...   # 合并多个 HyperLogLog,并将结果保存到 destkey 中
    

总结来说,Redis 的 HyperLogLog 是一种基数估计算法,用于统计大型集合的基数。通过添加元素到 HyperLogLog,获取基数估计值,以及合并多个 HyperLogLog 等操作,可以实现高效的基数统计。需要注意的是,HyperLogLog 在提供基数估计的同时,会引入一定的误差(通常为 0.81%),因此适用于对精确度要求不高的基数统计场景。

Geospatial

Geospatial(地理空间)功能是通过 Geohash 算法实现的,它允许在 Redis 中存储和查询具有地理位置信息的数据。Geospatial 提供了一系列的命令和数据结构,可以进行地理位置坐标的存储、距离计算、位置查询等操作。

使用场景

  • 地理位置存储

    Geospatial 可以用于存储具有地理位置信息的数据,例如存储地标、商家或用户的地理坐标、地理区域等。

  • 位置查询与距离计算

    Geospatial 提供了查询附近位置、计算两地距离等功能,例如在地理半径范围内查找附近的商家、计算两点之间的距离等。

  • 地理位置可视化

    通过 Geospatial 可以将地理位置信息存储到 Redis 中,然后配合其他工具实现地理信息的可视化,例如在地图上展示商家的分布情况、绘制用户的移动轨迹等。

使用示例

  • 添加地理位置坐标:

    GEOADD key longitude latitude member   # 将指定的经度、纬度和成员添加到指定的 key 中
    
  • 查询指定位置的地理信息:

    GEOPOS key member1 [member2 ...]   # 获取指定成员的地理位置坐标信息
    
  • 查询指定位置附近的其他成员:

    GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [COUNT count] [ASC|DESC]   # 获取指定半径范围内的成员信息
    

总结来说,Redis 的 Geospatial 功能通过 Geohash 算法实现对地理位置的存储和查询,适用于地理位置存储、位置查询与距离计算以及地理位置可视化等场景。使用 Geospatial 提供的命令,可以进行地理位置坐标的存储、查询和距离计算等操作,方便实现与地理信息相关的功能。

参考文章:https://zhuanlan.zhihu.com/p/382296964

你可能感兴趣的:(Redis,redis,数据库,缓存)