共计 1895 个字符,预计需要花费 5 分钟才能阅读完成。
1. 分布式锁:
实现:用 set key value ex time nx 指令实现,这个指令以及其参数是原子性的操作。释放锁用 del key,释放之前先比较一下 value 是否与当前的 value 一样,原因见后面。key 为锁名。value 为随机数并用一个变量记录这个随机数。ex 是个 set 指令的参数,代表 time 秒后该 key 自动删除。nx 是 set 指令的参数,代表没有该 key 时才设置它的值。
说明:设置过期时间是防止占有锁的线程出现异常,导致一直不释放锁。value 使用随机数的原因:超时后,新的线程获取锁了并为 key 设置了新的随机数,原先的线程还一直在执行逻辑,最后并执行了 del 指令,如果使用了随机数,在删除前比较了,就不会把 key 给删了。防止了其他线程释放了当前线程的锁。
2. 消息队列:
实现:用 list 列表类型去作为消息队列使用。一端 push 加入消息,另一端用阻塞读 brpop 或 blpop 指令去获取消息并执行。还要做一个异常处理,如果阻塞读长时间没有消息,Redis 为了减少空闲资源占用,会断开连接,这时候 br(l)pop 会报错,报错后需要重新去阻塞读。如果需要实现延时队列可以使用 zset,score 作为到期处理时间,然后通过轮询,比较当前时间和 score,到时间了就取出消息去执行。
说明:使用阻塞读而不是轮询是为了防止队列空了,做大量无用的空轮询。
3. 使用位图存储 bool 类型数据:
说明:位图的详细指令可自行搜索。首先解释一下位图,位即 bit 的中文名称,位图的最小存储单位就是 bit,结构属于数组,通过索引设置数据。一个 bit 就是二进制里面的 0 或 1,一个字节 (byte) 等于 8 个 bit。一个英文字母等于一个 byte。汉字就不一定,不同的编码占用不同的字节,有的是两个字节有的是三个字节。可以用 setbit 设置位,比如 setbit key 1 1,意为在第二个位置上设置为 1,0 的话不用设置,默认就是 0。
实现:Redis 提供了 bitcount 和 bitpos 指令来统计和查找位图类型数据,后面可以加 start 和 end 参数选择范围。bool 类型的数据正好只要 0 和 1,在有大量的这种 bool 数据时,使用位图可以节约非常大的空间。应用场景应该类似于登录记录、签到记录等这种纯 bool 类型数据。例如,某人 A 第 3 天时签到了,就执行 setbit Akey 2 1。以此类推,想统计签到天数时就执行 bitcount Akey。返回的是 1 的个数,也就是签到天数。bitpos 获取的是第一次出现 1 的位置,如 bitpos Akey 1. 返回的是第一次出现 1 的位置,也就是 A 第一天签到是什么时候。
4.HyperLogLog 统计 UV:
说明:HyperLogLog 是 Redis 的高级数据结构,作用是统计基数,比如元素有 1,2,3,4,5,5,6。HyperLogLog 只会统计基数 6,即 1,2,3,4,5,6 不重复的元素的个数,最重要的是,即使元素非常大,它所占有的内存也是固定的,每个 HyperLogLog 只需花费 12KB。它的指令很少。主要有:pfadd key element 添加元素。pfcount key 统计基数。
实现:在做 UV 时,即统计独立访客数就可以用上他,针对全网站、单独页面都可以。我们只需要把 ip(或用户 id)和日期(精确到天)添加进去就行了,有更多其他信息也行,反正 HyperLogLog 只会统计基数。只要保证当天内一个用户的信息绝对一样就行了,它会自动去重,也就是一天内不管这个用户访问多少次,都只算一次。
5. 用 scan 搜索特定的 key:
说明:在数据量不是很大时,可以直接用 keys 这个简单的指令,按照一定的规则搜索对应 key。但当数据量大了以后显然就不可取了,最主要的是 keys 是阻塞的,它会去遍历所有的 key 直到找出符合条件的 key,时间复杂度是 O(n)。scan 的时间复杂度虽然也是 O(n), 但是它不会阻塞线程,可以限定返回的个数。scan 是一系列的指令,针对不同的基本数据类型都有对应的一些指令,搜索 key 只是最基本的用法,更详细的用法可以查找官方 api 文档。
实现:使用指令 scan start match key* count limit。start 是游标开始的地方,正是因为使用的是游标,所以不会造成线程阻塞。match 后面接正则表达式。count 后面接限定的返回数量。比如:scan 0 match person* count 1000,游标从 0 开始,返回最多 1000 条 person 开头的 key。会返回两个结果,一个是游标停止的地方,是个整数,下次就把 0 换成这个整数接着找。另一个就是找到的 key 了。
: