Reids 数据类型

Reids 数据类型

Posted by vxiaozhi on January 12, 2025

Reids 数据类型

Redis 主要支持以下几种数据类型:

  • string(字符串): 基本的数据存储单元,可以存储字符串、整数或者浮点数。
  • hash(哈希):一个键值对集合,可以存储多个字段。
  • list(列表):一个简单的列表,可以存储一系列的字符串元素。
  • set(集合):一个无序集合,可以存储不重复的字符串元素。
  • zset(sorted set:有序集合): 类似于集合,但是每个元素都有一个分数(score)与之关联。
  • 位图(Bitmaps):基于字符串类型,可以对每个位进行操作。
  • 超日志(HyperLogLogs):用于基数统计,可以估算集合中的唯一元素数量。
  • 地理空间(Geospatial):用于存储地理位置信息。
  • 发布/订阅(Pub/Sub):一种消息通信模式,允许客户端订阅消息通道,并接收发布到该通道的消息。
  • 流(Streams):用于消息队列和日志存储,支持消息的持久化和时间排序。
  • 模块(Modules):Redis 支持动态加载模块,可以扩展 Redis 的功能。

zset(sorted set:有序集合)

Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。 不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。

zset的成员是唯一的,但分数(score)却可以重复。

为什么起名zset, 有两种解释:

  • 前面的Z代表的是XYZ中的Z,zset是在说这是比set有更多一个维度的set 😦
  • Z正好排在单词字母表中的最后一个,表示里面的元素都是类似于…X、Y、Z顺序排来的,所以叫ZSET。

HyperLogLogs

HyperLogLog 是一种基数估算算法。所谓基数估算,就是估算在一批数据中,不重复元素的个数有多少。

从数学上来说,基数估计这个问题的详细描述是:对于一个数据流 {x1,x2,…,xs} 而言,它可能存在重复的元素,用 n 来表示这个数据流的不同元素的个数,并且这个集合可以表示为{e1,…,en}。目标是:使用 m 这个量级的存储单位,可以得到 n 的估计值,其中 m«n 。并且估计值和实际值 n 的误差是可以控制的。

对于上面这个问题,如果是想得到精确的基数,可以使用字典(dictionary)这一个数据结构。对于新来的元素,可以查看它是否属于这个字典;如果属于这个字典,则整体计数保持不变;如果不属于这个字典,则先把这个元素添加进字典,然后把整体计数增加一。当遍历了这个数据流之后,得到的整体计数就是这个数据流的基数了。

这种算法虽然精准度很高,但是使用的空间复杂度却很高。那么是否存在一些近似的方法,可以估算出数据流的基数呢?HyperLogLog 就是这样一种算法,既可以使用较低的空间复杂度,最后估算出的结果误差又是可以接受的。

应用场景举例

HyperLogLog 主要的应用场景就是进行基数统计。这个问题的应用场景其实是十分广泛的。例如:对于 Google 主页面而言,同一个账户可能会访问 Google 主页面多次。于是,在诸多的访问流水中,如何计算出 Google 主页面每天被多少个不同的账户访问过就是一个重要的问题。那么对于 Google 这种访问量巨大的网页而言,其实统计出有十亿 的访问量或者十亿零十万的访问量其实是没有太多的区别的,因此,在这种业务场景下,为了节省成本,其实可以只计算出一个大概的值,而没有必要计算出精准的值。

对于上面的场景,可以使用HashMap、BitMap和HyperLogLog来解决。对于这三种解决方案,这边做下对比:

  • HashMap:算法简单,统计精度高,对于少量数据建议使用,但是对于大量的数据会占用很大内存空间;
  • BitMap:位图算法,具体内容可以参考我的这篇文章,统计精度高,虽然内存占用要比HashMap少,但是对于大量数据还是会占用较大内存;
  • HyperLogLog:存在一定误差,占用内存少,稳定占用 12k 左右内存,可以统计 2^64 个元素,对于上面举例的应用场景,建议使用。

Streams

Redis Stream 是 Redis 5.0 版本新增加的数据结构。

Redis Stream 主要用于消息队列(MQ,Message Queue),Redis 本身是有一个 Redis 发布订阅 (pub/sub) 来实现消息队列的功能,但它有个缺点就是消息无法持久化,如果出现网络断开、Redis 宕机等,消息就会被丢弃。

简单来说发布订阅 (pub/sub) 可以分发消息,但无法记录历史消息。

而 Redis Stream 提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。

Stream 提供的功能可以类比其它消息队列中间件, 如 Kafka。