Redis是使用C语言编写的,存储模型是基于键值对的,键始终是一个字符串,而值可以是多种数据类型,每一种数据类型都有专门的命令集。
Redis数据类型和应用场景
先贴一个口诀,再对每个数据类型进行分析。
字列哈,集合位,有序集、基数流。
分别代表字符串、列表、哈希(散列表)、集合、位图、有序集合、HyperLogLog和流八种数据类型。划分数据类型主要是根据Redis的命令集,同一种数据类型对应同一个命令集合。 例如字符串类型的值,可以是字符串、数字或者二进制数据(Redis通过元数据来记录字符串的长度,而不是某个特殊符号),但是它们都属于字符串。
字符串
字符串对象支持字符串、数字和二进制。底层通过C的int和动态字符串(Simple Dynamic String)实现。Redis不会主动区分存储类型,而是根据命令的上下文来决定如何处理,Redis会动态选择合适的编码方式。 值比较长的时候,会把元数据和值分开存储,这一点在其它的类型中亦有体现。字符串Redis对象有三种编码方式:
- int:可以用64位表示的整数对应的字符串,会按整数存储。
- embstr:较短的字符串,会将字符串和元数据存储在连续内存块中。
- raw:较长的字符串,会把字符串和元数据分开存储。(把Redis对象和对象的值分开存储,需要分配两次内存,但是扩展更方便)
字符串Redis对象可以用于缓存(json等类型的键值数据、二进制数据等)、计数(利用整数自增命令)、分布式锁(利用NX实现锁的获取和释放,EX实现锁过期)、统一信息存储(不同服务器共享一个Redis内的session信息)、简单消息队列。
列表
Redis列表对象的每一个元素都是字符串。Redis3.2版本之前,元素数目少和元素比较短的场景,会使用压缩列表,其它的情况会使用双向链表来存储Redis列表对象。3.2版本之后,列表底层实现统一为quicklist。 quicklist是一个由多个压缩列表组成的双向链表,支持从两端进行操作,每一个节点是一个压缩列表,存储多个列表字符串元素。(压缩列表把所有元素紧凑存储在连续内存中)
列表可以用于实现简单消息队列和阻塞队列。
- 简单消息队列:生产者使用LPUSH/RPUSH,消费者使用LPOP/RPOP 轮询。
- 阻塞队列:生产者使用LPUSH/RPUSH,消费者使用BLPOP/BRPOP命令,这些命令会阻塞到消息可用。
列表怎么实现一个可靠的消息队列?
- 消息保序:LPUSH/RPUSH。
- 阻塞读取:BRPOP。
- 重复消息处理:生产者自行实现唯一ID。
- 消息的可靠:使用BRPOPLPUSH,利用备份list。 最后,列表无法支持消费者组这一功能,但是stream可以。
哈希
Redis哈希对象是键值对的集合,适合存储对象的属性和属性值。例如HSET user:1001 name "Alice" age 25 email "[email protected]
。Redis 7.0版本之前,元素数量少和元素长度短的时候,会使用压缩列表实现,数量多和元素长的时候,会使用哈希表实现。7.0版本之后,压缩列表被listpack代替,进一步优化了内存使用和性能。相比字符串,哈希一个键对应一个哈希表,而且直接支持字段级别的操作。
哈希适合用于缓存对象,能够缓存属性和属性值,并且能够快速查找。例如可以用于缓存购物车对象,用户ID为key,商品ID为字段名,商品的数量为字段值。
集合
Redis集合对象是无序的字符串集合,集合中每个元素是唯一的。当元素都是整数而且数目比较少时,使用整数集合,不满足这一条件的话,底层会使用哈希表实现。和List相比,集合是无序的,而且不能存储重复元素。值得注意的是,Redis支持集合之间的交集,并集和差集。
集合无序、不可重复,可以用来实现点赞、关注、共同好友和抽奖等功能。
有序集合
Redis有序集合对象的值,都是一个字符串+一个浮点数类型的分值。Redis7.0之前,元素数目少或者元素值短的时候使用压缩列表实现,其它情况使用跳表实现。7.0版本之后,压缩列表被listpack代替了。(和哈希里面一样)。
有序集合可以用于展示最新列表、排行榜和需要排序展示 的情况。
位图法
Redis bitmap对象是一串连续的二进制数组,底层使用string实现。通过偏移量来定位元素。例如SETBIT key offset value
。
位图很适合二值状态存储,能够节省内存空间,例如记录签到情况、登录状态。
HyperLogLog
HyperLogLog 是 Redis 提供的一种基数估算数据结构,用于快速计算集合中不重复元素的近似数量(基数)。它的核心特点是通过牺牲一定的精确度,极大地降低内存使用量。HyperLogLog 的底层实现基于概率算法,适合处理大规模数据的去重统计场景。
HyperLogLog适合用于海量数据去重统计(统计网站独立访客数、活跃用户数)、大规模数据分析(日志分析、流量监控)、分布式系统(分布式环境中统计全局唯一元素的数量)。
流Stream
Stream是Redis5.0版本引入的,专门用于处理日志、消息队列和实时数据流等场景,支持高效的生产者、消费者模型、能够存储和管理有序的消息流。Stream的键是流的名称,而值是消息ID+键值对的集合,这个消息ID为时间戳-序列号。加入我们向mystream流添加了两条消息:
XADD mystream * key1 value1 key2 value2
XADD mystream * key3 value3 key4 value4
*
告诉Redis要自动生成消息ID,结果如下
1683532800000-0: { key1: value1, key2: value2 }
1683532801000-0: { key3: value3, key4: value4 }
使用流Stream数据结构能够实现一个比较完善的消息队列,但是也有缺陷,这一点放在场景篇里面。
总结
Redis主要支持这八个数据类型,重点要记忆他们的值的类型格式和基本的应用场景。一些比较经典的应用场景会记录在Redis【场景篇】。