Redis 类型

1.9K
0
0
最后修改于
String#

String,作为一种最常用的数据类型之一,不同编程语言的底层实现都做了优化或拓展。Redis 则重新拓展了其中 String 类型所涵盖的范围。
包括一般意义上的字符串字面量、数值、图片、音频、序列化后的对象等任何二进制数据。

可以用于简单的存储需求(如 Session,Token),也可以基于此实现一些特定功能,如 RateLimit,小数量 PV,分布式锁。用途

List#

Redis 中实现的双链表

  • 实现栈 / 队列,构建后台任务系统
  • 可以记住用户在社交网络上发布的最新更新。(Twitter 将其用于最新推文)
  • 实现基于共享内存的 IPC 进程通信(生产消费模式)如resque/resque
    基于这些用例,Redis 给出了一些常用 API
  • LTRIM
  • push(LPUSH/RPUSH)
  • POP(LPOP / RPOP)返回元素
  • LLEN
  • LMOVE,原子化在 list 间移动
  • LTRIM,移除多余元素
    此外,List 还支持阻塞操作。并为阻塞等待附加一个 timeout。
    Redis 列表最大长为2^32-1 。其头尾操作时间复杂度为 O (1),但是 LLINDEX,LINSERT,LSET,等链表中元素操作的时间复杂度为 O (n)。
Hash#

Hash 是 KV 键值对,类似于 HashMap,可以直接修改某些键值对。
可以用于存储一些常用且复杂的对象:用户信息、商品信息、文章信息、购物车信息。
给出的常用 API 包括:
HSET
HGET
HMGET
HINCRBY
大部分是 O (1) 的,HKEYSHVALS, and HGETALL是 O (N) 的。

Set#

集合,无序但唯一。
提供的通用 API,支持常见的集合运算,交并差补。
常用于:

  • 跟踪唯一项(访问某篇文章的所有 IP)
  • 关系运算(好友推荐)
  • 集合运算(如共同关注)
    基于这些用例给出的常用 API
  • SADD 将新成员添加到集合中。
  • SREM 从集中删除指定的成员。
  • SISMEMBER 测试是否为集合成员。
  • SINTER 返回两个或多个集合的交集。
  • SCARD 返回集合的大小(又称基数)。
    大多数集合命令是 O (1) 的,但是 SMEMBERS 是 O (n) 的(因此在大数据集中,应该使用 SSCAN)
    此外,对于大数据集的进行 SISMEMBER 这样的操作,可能占用大量内存。因此可以考虑使用 bloom 过滤器
SortedSet#

有序集合,相比于 Set, 多了一个 Score 数值参数。
常用于排行榜,基于滑动窗口的限流。
SetKey [SetItemKey, SetItemScore]
常用命令:

  • ZADD 将新成员和关联的分数添加到排序集中。如果成员已存在,则会更新分数。
  • ZRANGE 返回在给定范围内排序的排序集合的成员。
  • ZRANK 返回所提供成员的等级,假设排序按升序排列。
  • ZREVRANK 返回所提供成员的排名,假设排序的集合按降序排列。

但是相比于 Set,大多数命令是 O (log (n)),而非 O (1)
对于部分命令,如 ZRANGE,复杂度为 O (log (n)+m),其中 m 为结果集大小,因此当结果集很大时,应当小心。

Stream#

Stream 是一种类似于日志文件的只增数据流。克服了只增日志文件的一些问题。

  • O (1) 时间的随机存取
  • 复杂度消费策略(如消费组)
    常用于实现轻量级的 MQ。但是对于事件溯源也可起到一定的效果。
    loading...
BitMap/BitField#

位图,0 / 1 表示。
可用于用户签到情况、活跃用户情况、用户行为统计(比如是否点赞过某个视频),操作权限。
通过 BIT 操作,可以方便的计算出
Redis 建议使用分片存储,每个 key 对应 1M 的 BitMap。
对于 BitMap 还有一个 BitField,可以在一个 BitMap 中方便的存储操作多个字段。
BITFIELD key <ops> <data-type> <offset> [data] [<ops> <data-type> <offset> [data]]
loading...
其中 offset 除了直接表示外,还可以通过 # 符号。
其 offset 是通过 data-type 指定的位数,乘以 #所指示的值。
比如 GET u3 #2 GET u5 #1 得到结果为 [6, 28]
loading...
同时还提供了 BITFIELD 的溢出控制能力
相关用例:

  • Reddit 2017 愚人节涂鸦 How We Built r/Place - Upvoted (redditinc.com)
    另外值得注意的是位在字节中的排布。当设定的位置与字节边界对齐时,其行为与大端对齐一致。
    而当不与字节边界对齐时,比如SET u5 7
    在字节中的结果如下
+--------+--------+
|00000001|01110000|
+--------+--------+
Geospatial index#

地理信息索引,存储地理位置,基于 Sorted Set 实现。
可以实现常见基于地理位置的查询,
比如找出的距离某点最近的一批点(附近的人 / 面对面建群)。

概率类型#

HyperLogLog#

一种基于概率的用于估计计数的数据结构。允许少量误差。
适用于数量量巨大(百万、千万级别以上)的计数场景。
热门网站每日/每周/每月访问 ip 数统计、热门帖子 uv 统计,视频播放量等。

Bloom Filter#

一种基于概率的,用于判断集合中是否存在某元素。
对于一个问询,结果可能有四种。
布隆过滤器判断可以保证,当集合中不存在该元素时,则对该元素的问询一定时不存在。

如下表所示:

集合中存在集合中不存在
认为存在于集合中true不会发生
认为不存在posibbletrue
因此适用于允许丢失,但倾向于不重复的情况。
比如:
信息推送系统。
大量用户检查用户名 / 域名是否已占用。
从实现上看,仅存储元素的哈希表示,从而牺牲了一些精度。因此 Bloom Filter 节省空间且速度快。
Cuckoo Filter#

与 Bloom 过滤器类似,基于概率的用于判断集合中是否存在某元素。相较于 Bloom FIlter,允许删除并在某些情况下有着更好的性能,但是在插入数据时不及布隆过滤器。
允许删除的特性使得能够比 Bloom Filter 有着更广泛的使用场景。
除了布隆过滤器的 usecase 之外,还可以对需要变更集合数据的情况进行处理。
比如:
优惠券使用活动,当某用户未使用某优惠券时,其 id 在过滤器中。
当用户使用后,便从过滤器中删除。
如下:

集合中存在(未使用)集合中不存在(使用)
认为用户存在于集合中(未使用)true不会发生
认为不存在(使用)posibbletrue
T-digest#

该数据结构主要回答问题

  • 对于一个给定的数据,数据流中有多少数据时小于 / 大于这个数值的,百分比是多少?
  • 对于一个给定的数据,数据流中有多少数据时小于 / 大于这个数值的,个数是多少?
  • 小于数据流中 p 百分比的最高值是多少?比如当前段位。
Top-K#

用于估计数据流中排名最高的元素。比如分析访问的峰值 IP,以分析 DDOS 攻击。
它摒弃了一些较旧的方法,如 “计数全部” 和 “承认所有计数”,转而采用计数指数衰减策略,该策略偏向于小流,对大流的影响有限。
用例:

  • 在过去 3 天内提到最多的 10 个 topic 是什么?
  • 今天阅读 / 浏览次数最多的 10 个帖子新闻是什么?
Count-Min Sketch#

可用于估计数据流中事件的频率。
可能会重复计数。且对低频计数不友好,反而适用于高频计数。
适用于:产品销量

Time Series#

RedisTimeSeries/RedisTimeSeries: Time Series data structure for Redis (github.com)