Redis深入历险读书笔记第一章

本文详细介绍了Redis的基础数据结构及其应用场景,包括String、List、Hash、Set和ZSet,并探讨了Redis在分布式锁、延时队列、布隆过滤器和位图等高级用法。此外,还分析了Redis分布式锁的超时和可重入性问题,以及如何利用ZSet实现延时队列。
摘要由CSDN通过智能技术生成

基础和应用篇

Redis可以做什么

  1. 记录帖子的点赞数量、评论数量和点击数。(hash)
  2. 记录用户的帖子ID列表(排序),便于快速显示用户的帖子里表(zset)
  3. 记录帖子的标题、摘要、作者和封面信息,用于列表展示(hash)
  4. 记录帖子的点赞用户I D,评论ID里表,用于显示和驱虫计数(zset)
  5. 缓存近期热帖的内容,减少数据库压力(hash)
  6. 记录帖子的相关文章ID,根据内容推荐相关帖子(list)
  7. 如果帖子ID是整数自增,适宜食用Redis来分配帖子ID。
  8. 收藏集和帖子之间的关系(zset)
  9. 记录热榜帖子ID列表、总热榜和分类热榜(zset)
    10.缓存用户行为历史,过滤恶意行为(zset、hash)

Redis基础数据结构

5种基本数据结构

string
  1. Redis的String是动态字符串,是可以修改的字符串,内部结构的实现类似于ArrayList,采用预分配冗余空间的方式减少内存的频繁配置。扩容每次扩充1MB,最大512MB。
  2. 它是通过key-value的方式存储在Redis中的,但是value的格式是序列化的json字符串。
键值队

通过字典的key和value,支持简单的增删改查操作。

批量键值队

可以对多个字符串进行批量读写,节省网络开销。

过期和Set命令扩展

可以对key设置过期时间,到时见会被自动删除,这个功能用来控制缓存的失效时间。

计数

如果value值是一个整数,还可以对它进行自增操作。自增是由范围的,他的范围在signed Long的最大值和最小值之间,超出这个范围,Redis会报错。

List(列表)
  1. Redis的list是链表不是数据是LinkedList,所以list的插入和删除操作非常快,时间复杂度O(1)。
  2. Redis的列表通常用来做异步队列使用。将需要延后处理的任务结构体序列化成字符串,塞进Redis的列表,另一个线程从这个列表中轮询进行数据处理。5
右边进左边出:队列

常用于消息队列和异步逻辑处理,它会确保元素的访问顺序性。

右边进右边出:栈

栈是先进后出的数据结构,正好和队列相反。

慢操作
快速列表

Redis在列表元素较少的情况下内存会使用一块连续的区间,这个结构叫做zipList,压缩列表。
当数据比较大的时候会使用quicklist。也就是把多个ziplist用指针链接起来。

Hash(字典)
  1. Redis里的Hash相当于Java里的HashMap,它是无序字典存储很多键值对,结构都是数组+链表的结构。不同的是Redis里的value只能是字符串。
  2. rehash时Redis时采用的渐进式的rehash,在rehash时会保留旧的数组,查询时会查询新旧两个数组的内容,当后在后续的定时任务以及Hash操作指令中,循序渐进的把旧Hash内容放到新的Hash中。
  3. Hash也有缺点在存储消耗要高于耽搁字符串。
SET(集合)
  1. Redis的集合相当于JAVA的HashSet,它的内部的键值队是无序、唯一的。
  2. 它相当于一个value都是null的字典,当所有的key都删除是内存会被回收。
ZSET(有序列表)
  1. 它在内部对每个value赋予一个score,代表这个value的排序权重。
  2. 它的排序是通过跳跃列表来实现的。

分布式锁

分布式锁的奥义

  1. 分布式锁本质上要实现的目的就是在Redis中占一个坑,当别的进程也要来占据坑的时候,发现已经被占据了,就会放弃或之后重试。

超时问题

  1. Redis分布式锁不能解决超时问题,如果在加锁和释放锁之间的逻辑执行得太长,以超出锁的超时限制,就会出现问题。因为这时候第一个线程池游的锁会过期,临界区的逻辑还没有执行完,而同时第二个线程就提前重新持有了这个锁,导致临界区代码不能的得到严谨的执行。
  2. 所以Redis的分布式锁不要用于较长时间的业务处理。

可重入性

  1. Redis的分布式锁默认是不支持重入的,如果想要支持需要封装set方法,增加一个变量用来计算持有锁的计数。

延时队列

  1. 注意Redis不是专注于处理消息的中间件,没有一般消息中间件的多种功能,如不支持ACK验证,所以如果是对权限要求比较高的它并不适用。

异步消息队列

  1. Redis的list可以用来做异步消息队列使用,通过rpush和lpush操作入队列,通过lpop和rpop操作来出队列。
  2. 它可以支持多个消费者和生产者兵法进出消息,每个消费者拿到的消息都是不同的列表元素。

队列空了怎么办

客户端通过队列的pop操作来获取消息,然后进行处理,当消息都处理完成之后,客户端就会陷入pop循环,这是Redis的QPS就会被拉高,我们通常用sleep来解决这个问题

阻塞度

空闲链接自动断开

如果线程一直阻塞,Redis的客户端链接就成了闲置链接,闲置过久,服务器一般会主动断开链接,减少闲置资源的使用,这时候如果Blpop/brpop就会报错,所以在设计的时候治理需要在捕获到异常后继续重试。

锁冲突

指在获取分布式锁没有获取到时具体实现

  1. 直接抛出异常,通知用户稍后重试。
    这种方式比价适合由用户发起的请求。
  2. sleep一会,然后重试。
    sleep会阻塞当前线程,会导致队列的后续消息出现延迟。如果碰撞的比较厉害,就会出现严重的延迟,如果个别死锁,会导致之后的消息永远得不到处理。
  3. 将请求转移至延时队列,过一会再试。
    这种方式比较适合用于异步消息处理。

延时队列的实现

延时队列可以通过Redis的zset来实现。我们将消息序列化成一个字符串作为zset的value,这个消息的到期处理时间作为score(排序权重),然后用多个线程轮询zset获取到期的任务进行处理。
需要注意的是因为是多个线程,所以要注意不被重复消费。

节衣缩食——位图

  1. 使用场景如存储bool型数据,比如用户一年的签到记录。

基本用法

  1. Redis的位数组是自动扩展的,如果设置了某个便宜位置超出了现有的内容范围,就会自动将位数组进行0扩充。
零存整取

使用单个位操作设置位值,使用单个位操作获取具体位值。

整存零取

使用字符串操作符批量设置位值,使用单个位操作获取具体位值。

统计和查找

Redis提供了位图统计指令bitcount和位图查找指令bitpos。

HyperLogLog

提供不精确的去重技术方案,虽然不精确,但是也不是非常离谱,标准误差在0.81%。

使用方法

  1. pfadd添加计数
  2. pfcount获取计数

布隆过滤器

布隆过滤器是什么

  1. 布隆过滤器是一个不精确的set结构,当你使用它的contains方法判断某个对象是否存在是,它可能会误判。

布隆过滤器的基本用法

  1. bf.add 添加元素
  2. bf.exists 判断元素是否存在
  3. bf.madd添加多个
  4. bf.mexists 判断多个是否存在

注意事项

  1. 布隆过滤器的initial_size不能太大,如果太大会浪费存储空间,过小会影响准确率。

布隆过滤器的原理

布隆过滤器的数据结构

布隆过滤器的数据结构是一个大型的位数组和几个不一样的无偏hash函数。

使用原理
add
  1. 添加key时,通过多个hash函数对key进行hash,获得一个整数索引值。
  2. 对位数组长度进行取模运算得到一个位置,每个hash函数都会算的一个不同的位置。
  3. 再把位数组的这几个位置都设置成1,完成添加操作。
判断
  1. 根据key计算hash
  2. 判断位数组的位置是否都是1,如果有不是1的那么说明容器中这个key不存在。

空间占用计算

公式
  1. k=0.7*(l/n)
  2. f=0.6185^(l/n)
    n 是预计元素的数量
    f是错误率
    l是位数组的长度
    k是最佳数量
公式结论
  1. 位数组相对越长(l/n),误差f越低
  2. 位数组相对越长,hash函数需要的最佳数量越多
  3. 当一个元素平均需要1个字节的指纹空间时,错误率大约位2%
  4. 错误率为10%时,一个元素需要的平均指纹空间为4.792个bit,大约位5
  5. 错误率1%时,9.585个bit大于10
  6. 错误率0.1时,14.377,大约15

其他应用

  1. URL去重
  2. 降低IO请求
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值