Redis深度历险:核心原理和应用实践(二)

1.分布式锁

分布式应用逻辑处理的并发问题。使用分布式锁来限制程序的并发执行。

分布式锁占用锁,同一时间只能由一个进程使用,先来先得。setnx指令占用。del指令释放。为了避免死锁不释放锁,需要给锁加上一个过期时间。Redis2.8版本加入来set指令的扩展参数,使得setnx和expire指令可以一起执行,解决分布式锁。

Redis分布式锁不要用于较长时间的任务。

可重入性是指线程在持有锁的情况下再次请求加锁,如果一个锁支持同一个线程的多次加锁,那么这个锁就是可重入的。Redis 分 布式锁如果要支持可重入,需要对客户端的 set 方法进行包装,使用线程的Threadlocal变量 存储当前持有锁的计数。不推荐使用可重入锁,它加重了客户端的复杂性,在编写业务方法时注意在逻辑结构上进行调整完全可以不使用可重入锁。

2.延时队列

Redis的list(列表) 数据结构常用来作为异步消息队列使用,使用rpush/lpush操作入队列, 使用 lpop 和 rpop 来出队列。

阻塞读在队列没有数据的时候,会立即进入休眠状态,一旦数据到来,则立刻醒过来。消息的延迟几乎为零。blpop/brpop。

3 种策略来处理加锁失败:(1)直接抛出异常,通知用户稍后重试; (2)sleep 一会再重试; (3)将请求转移至延时队列,过一会再试(将当前冲突的请求扔到另一个队列延后处理以避开冲突)。

延时队列可以通过 Redis 的 zset(有序列表) 来实现。

将消息序列化成一个字符串作 为 zset 的 value,这个消息的到期处理时间作为 score,然后用多个线程轮询 zset 获取到期 的任务进行处理,多个线程是为了保障可用性,万一挂了一个线程还有其它线程可以继续处 理。因为有多个线程,所以需要考虑并发争抢任务,确保任务不能被多次执行。

3.位图

位图不是特殊的数据结构,它的内容其实就是普通的字符串,也就是 byte 数组。可以使用普通的 get/set 直接获取和设置整个位图的内容,也可以使用位图操作 getbit/setbit 等将 byte 数组看成位数组来处理。

Redis 的位数组是自动扩展,如果设置了某个偏移位置超出了现有的内容范围,就会自 动将位数组进行零扩充。

设置 (setbit) 和获取 (getbit) 指定位的值都是单个位的,如果要一次操作多个位,就必须使用管道来处理。Redis 的 3.2 版本以后新增了bitfield指令,有 了这条指令,不用管道也可以一次进行多个位的操作。bitfield 有三个子指令,分别是 get/set/incrby,它们都可以对指定位片段进行读写,但是最多只能处理 64 个连续的位,如果超过 64 位,就得使用多个子指令,bitfield 可以一次执行多个子指令。

4.HyperLogLog

HyperLogLog 提供不精确的去重计数方案,标准误差是 0.81%。

HyperLogLog 提供了两个指令 pfadd 和 pfcount,pfmerge用于将多个 pf 计数值累加在一起形成一个新的 pf 值。

需要占据 12k 的存储空间,不适合统计单个用户相关的数据。

5.布隆过滤器(Bloom Filter)

布隆过滤器可以理解为一个不太确的 set 结构,当使用它的 contains 方法判断某个对象是否存在时,可能会误判。但是只要参数设置合理,它的精确度可以控制的相对足够精确,只会有小小的误判概率。

当布隆过滤器说某个值存在时,这个值可能不存在;当它说不存在时,那就肯定不存在。

布隆过滤器作为一个插件加载到 Redis Server 中,给 Redis 提供了强大的布隆去重功能。

bf.add 添加元素,bf.exists 查询元素是否存在。

原因就在于布隆过滤器对于已经见过的元素肯定不会误判,它只会误判那些没见过的元素。

布隆过滤器的 initial_size 估计的过大,会浪费存储空间,估计的过小,就会影响准确 率。布隆过滤器的 error_rate 越小,需要的存储空间就越大。

爬虫系统中,对 URL 进行去重。邮箱系统的垃圾邮件过滤功能也普遍用到了布隆过滤器。

6.简单限流

限流算法:当系统的处理能力有限时,阻止计划外的请求继续对系统施压。控制用户行为,避免垃圾请求。

7.漏斗限流

漏斗的剩余空间就代表着当前行为可以持续进行的数量,漏嘴的流水速率代表着系统允许该行为的最大频率。

Redis 4.0 提供了一个限流 Redis 模块 redis-cell。该模块使用了漏斗算法,并提供了原子的限流指令。cl.throttle

8.GeoHash

Redis 在 3.2 版本以后增加了地理位置 GEO 模块。

GeoHash 算法将二维的经纬度数据映射到一维的整数,这样所有的元素都将在挂载到一 条线上,距离靠近的二维坐标映射到一维后的点之间距离也会很接近。

在 Redis 里面,经纬度使用 52 位的整数进行编码,放进了 zset 里面,zset 的 value 是元素的 key,score 是 GeoHash 的 52 位整数值。

geoadd,geodist,geopos,geohash 可以获取元素的经纬度编码字符串,georadiusbymember可以用来查询指定元素附近的其它元素。Geo 的数据最好使用单独的 Redis 实例部署,不使用集群环境。

9.Scan

指令 keys 用来列出所有满足特定正则字符串规则的 key。

scan 相比 keys,通过游标分步进行的,不会阻塞线程。提供 limit 参数,可以控制每次返回结果的最大条数。提供模式匹配功能。返回的结果可能会有重复,需要客户端去重。单次返回的结果是空的并不意味着遍历结束,而要看返回的游标值是否为零。

scan 参数提供了三个参数,第一个是 cursor 整数值,第二个是 key 的正则模式,第三个是遍历的 limit hint。

scan 指令是一系列指令,除了可以遍历所有的 key 之外,还可以对指定的容器集合进 行遍历。比如 zscan 遍历 zset 集合元素,hscan 遍历 hash 字典的元素、sscan 遍历 set 集合的元素。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值