Redis全称REmote DIctionary Server,由Salvatore Sanfilippo写的高性能key-value存储系统,完全开源免费,遵守BSD协议。
Redis是key-value存储系统,其中key类型一般为字符串,value类型则为RedisObject对象。
RedisObject定义了5个属性:type、enconding、lru、refcount和*prt
属性 | 描述 |
---|---|
type | value值的数据类型 |
enconding | value值的编码方式 |
lru | 记录此对象最后一次访问的时间 |
refcount | 记录对象的引用次数 |
*prt | 数据指针 |
value值的数据类型。
常见数据类型:
类型常量 | 类型描述 |
---|---|
REDIS_STRING | 字符串对象 |
REDIS_LIST | 列表对象 |
REDIS_HASH | 哈希对象 |
REDIS_SET | 集合对象 |
REDIS_ZSET | 有序集合对象 |
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 | 使用跳跃表和字典实现的有序集合对象 |
记录此对象最后一次访问的时间。
当redis内存回收算法设置为volatile-lru或者allkeys-lru时候redis会优先释放最久没有被访问的数据。
记录对象的引用次数,类似于jvm的引用计数垃圾回收算法,当refcount为0时,表示没有其它对象引用,可以进行释放此对象。
数据指针,指向底层真正的数据结构。
redis源码主要放在src目录里。
主要核心部分分类如下:
数据类型 | 描述 | 使用场景 |
---|---|---|
String | 最基本的数据类型,可以存储任意数据,如文本、整数、二进制数据等,最大512M | 用于缓存、计数器、分布式锁等场景 |
List | 按照插入顺序排序的字符串元素集合,支持头尾插入、弹出等操作 | 用于实现队列、栈、消息队列等场景 |
Set | 无序的字符串元素集合,其中元素不可重复,支持交集、并集、差集等操作 | 用于进行唯一性判定、求多个集合的交集、并集等场景 |
Zset | 带有分数排序的字符串元素集合,支持根据分数范围来获取元素等操作 | 用于需要排序并保持唯一性的场景 |
Hash | 存储多个键值对的字典,支持对单个字段进行增删查改等操作 | 用于表示对象、存储属性等场景 |
Stream | 异步消息传输机制,基于多个消费者以广播模式接收生产者发送的消息 | 用于消息队列、事件驱动等场景 |
Bloom Filter | 底层是String,概率型的数据结构(布隆过滤器),用于快速判断一个元素是否存在于一个集合中 | 用于判重、URL 去重、邮箱黑名单过滤等场景 |
Bitmap | 底层是String,位图,用于存储一系列只有 0 和 1 的值,支持位运算等操作 | 用于标记、统计等场景 |
HyperLogLog | 底层是String,基数统计算法,用于统计一个集合中不重复元素的数量 | 用于进行去重、UV 统计等场景 |
Geospatial | 底层是Zset,地理位置数据类型,支持存储经度、纬度等地理信息,且支持根据地理位置信息进行查询 | 用于 LBS 场景、附近的人、商家等推荐等场景 |
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 可以存储各种类型的元素(如字符串、整数),在 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 可以存储各种类型的元素(如字符串、整数),在 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(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 是一个键值对集合,类似于关联数组或者对象。在 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 以时间顺序存储消息,并为每个消息分配一个唯一的、递增的 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) 来实现消息队列的功能,支持发布 / 订阅,支持多组生产者、消费者处理消息。但是存在很多问题:
消费者下线,数据会丢失。
不支持数据持久化,Redis 宕机,数据也会丢失,Pub/Sub 没有基于任何数据类型实现,不会写入到 RDB 和 AOF 中,当 Redis 宕机重启,Pub/Sub 的数据也会全部丢失。
消息堆积,缓冲区溢出,消费者会被强制踢下线,数据也会丢失。
缓冲区的默认配置:client-output-buffer-limit pubsub 32mb 8mb 60。它的参数含义如下:
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 可以用来表示布尔值(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 主要用于统计大型集合的基数(即唯一元素的数量),例如统计网站的独立访客数、统计 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(地理空间)功能是通过 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