Redis深度历险:数据结构

这是阅读Redis深度历险读后的总结

String(字符串)

  • 内部是一个动态(可修改)字符数组
  • 内部使用预分配来减少内存频繁分配->类似Java的ArrayList
  • 常见用来缓存用户数据,将数据JSON化后存入redis
  • 如果字符串代表的是一个数字(范围:-263—263-1),则可以对其自增减操作。

List(列表)

  • 内部是链表结构,而不是数组->插入和删除很快,但是索引定位很慢
    • 在列表元素较少时,使用连续的内存存储元素->ziplist
    • 当元素变多后,由多个ziplist组成quicklist
  • 通过索引来定位元素时,索引可以为负数,表示倒数第几个

Hash(字典)

  • 内部结构和Java的HashMap等同,都是数组+链表结构
  • 存储的值只能是字符串
  • 并且扩容的rehash是渐进rehash
    • 保留新旧的hash,在每次查询以及定时任务中,渐进的将旧元素移动到新hash中
    • 在移除旧hash的所有元素后,会被删除
  • 新增存储的值时如果值有空格,需要被""括起来
    • 因为redis的命令会根据空格来分析关键字
  • 也可以使用单个值计数和string类型一样

Set(集合)

  • 和java的HashSet相当,内部键值无序,且唯一
  • 当最后一个元素被移除,就会被自动删除,内存回收

Zset(有序列表)

  • 一方面是set,保证唯一性,一方面每个元素都有一个score来保证排序
    • 可以用来实现排名,比如value为排名的信息,score作为排序字段
  • 内部由跳表实现
    • 一种层级机制的链表结构
  • 当最后一个元素移除后,自身会被删除

位图BitMap

基本用法

  • Redis的位数组是自动扩展的,会自动将位数组进行零补充
  • 对于位图的存取有两个概念:零存零取,整存零取
    • 零存代表是零散的存储,比如一个位一个位的存储
    • 零取代表零散的取,比如一个位一个位的获取位的值
    • 整存代表整个的存,redis的位图存储可以直接存储一个字符串,会自动将其转为二进制

统计用法

  • bitcount [xx] start end ,统计位图xx从start到end的1的个数
    • bitcount w 0 0 #0到0范围中1的个数
    • bitcount w 1 3 #1到3的范围中1的个数
  • bittops [xx] 0或1 start end,统计xx在start和end中出现的第一个0或1
    • bitops w 0或1 #整个位图中0/1第一次出现的位置
    • bitpos w 0或1 1 1 # 从第二个字符出现1或0的位置

适用场景

  • 布隆过滤器
  • 统计过滤,比如点赞id记录

HyperLogLog

  • 类似于set的数据集合,但是误差在0.81%左右,并不是太离谱
  • 相比于Set来说使用一定的误差来换取占据的空间更小,但并不代表可以随意使用和浪费,需要在一定的业务场景中使用:不适用在统计单个用户的数据信息。

使用方法

  • pfadd 增加计数
    • pfadd [kye] [value] 类似于set集合,只需要将value加进去,就可以统计成功
  • pfcount 获取计数
    • pfcount [key] 获取key代表的HyperLogLog的计数值

适用场景

  • 对于一个网站的UV以及PV的统计,对于一个需要去重,但是对精确性要求不是非常严格的场景

Redis限流

限流的作用

  • 控制流量
  • 控制用户行为,避免垃圾请求

Redis-Cell-Redis自己的限流模块~

  • Redis 4.0提供的模块,也是使用的漏斗算法
  • 提供了原子的限流指令。
  • 只有一个命令cl.throttle
    • 但是返回值和参数都比较复杂
  • 参数
    • cl.throttle [key] [漏斗容量] [速率分子] [速率分母] [每次操作需要容量]
    • cl.throttle pangpi:reply 15 30 60 3
    • 胖批的回复行为 当漏斗到15次满了后开始漏水,60秒最多漏30次,也就是两秒漏一次,每次漏3个容量
  • 返回值
    ![[Pasted image 20231101144420.png]]

GEO定位

GeoHash算法

  • 属于业界比较通用的地理位置距离排序算法
  • Redis中也是用了这个算法。
  • 将二维的经纬度数据映射到一维的整数,虽然相对位置的值会变化,但是每个位置的附近节点的距离排序不会发生变化
    • 使用Redis的Geo查询时,可以将其看成内部结构为zset,通过score排序就可以得到坐标附近的元素
    • 具体算法:请看85页

注意事项

  • 使用geo作为应用计算车的数据,餐馆的数据,最好不要使用集群一起存储geo,而是根据不同的区域划分来使用,比如先按国家拆分,按照省市拆分,可以显著降低单个geo的大小

Scan模糊查询

  • keys就是键的模糊查询,但是:
    • 没有offset、limit参数,查多少就吐出多少
    • 是遍历算法,复杂度是O(n),会导致服务卡顿

Scan概念

  • 字典结构
    • redis的key都存在一个很大的字典中,类似java中的hashmap
    • scan指令返回的游标就是key在数组中的位置索引->槽
      • 所以会出现空,肯就是某些槽中是空的
  • 遍历顺序
    • 使用高位进位加法遍历
    • 可以在扩缩容时避免槽位的遍历重复和遗漏
  • 字典扩容
    • 就是扩容hash槽,重新取模运算

Stream消息队列

  • Redis5.0的Stream新数据结构极大借鉴了Kafka的设计
  • 一个Stream对应一个key
  • 每个Stream可以挂多个消费组(Consumer Group)
    • 消费组不会自动创建,需要使用xgroup create进行创建
      • 消费组需要指定Stream的某个消费ID开始消费,用来初始化last_delivered_id
    • 每个消费组有一个游标last_delivered_id在Stream上移动来表示当前消费组消费到哪里了
    • 每个消费组都有Stream内唯一名称
    • 消费组下有多个消费者,共用一个last_delivered_id
      • 消费者内部有一个状态变量(数组)pending_ids->Pending Entries List
        • 记录了当前被客户端读取但是还没ack的消息
  • 消息ID形式是timestampInMillis-sequence
    • 例如1527846880572-5,表示消息是在1527846880572毫秒时间戳时产生,并且是这个时间戳的第5条消息
    • 消息可以由客户端定义,但是格式必须满足整数-整数
  • 24
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值