1、布隆过滤器
1.1、布隆过滤器是什么?(判断某个key一定不存在)
- 本质上布隆过滤器是一种数据结构,比较巧妙的概率型数据结构
- 特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”。
- 相比于传统的 List、Set、Map 等数据结构,它更高效、占用空间更少,但是缺点是其返回的结果是概率性的,而不是确切的。
使用:
- 布隆过滤器在NoSQL数据库领域中应用的非常广泛
- 当用户来查询某一个row时,可以先通过内存中的布隆过滤器过滤掉大量不存在的row请求,然后去再磁盘进行查询
- 布隆过滤器说某个值不存在时,那肯定就是不存在,可以显著降低数据库IO请求数量
1.2、应用场景
1)场景1(给用户推荐新闻)
- 当用户看过的新闻,肯定会被过滤掉,对于没有看多的新闻,可能会过滤极少的一部分(误判)。这样可以完全保证推送给用户的新闻都是无重复的。
2)场景2(爬虫url去重)
- 在爬虫系统中,我们需要对url去重,已经爬取的页面不再爬取
- 当url高达几千万时,如果一个集合去装下这些URL地址非常浪费空间
- 使用布隆过滤器可以大幅降低去重存储消耗,只不过也会使爬虫系统错过少量页面
1.3、布隆过滤器原理
- 每个布隆过滤器对应到Redis的数据结构是一个大型的数组和几个不一样的无偏hash函数
- 如下图:f、g、h就是这样的hash函数(无偏差指让hash映射到数组的位置比较随机)
添加:值到布隆过滤器
- 1)向布隆过滤器添加key,会使用 f、g、h hash函数对key算出一个整数索引,然后对长度取余
- 2)每个hash函数都会算出一个不同的位置,把算出的位置都设置成1就完成了布隆过滤器添加过程
查询:布隆过滤器值
- 1)当查询某个key时,先用hash函数算出一个整数索引,然后对长度取余
- 2)当你有一个不为1时肯定不存在这个key,当全部都为1时可能有这个key
- 3)这样内存中的布隆过滤器过滤掉大量不存在的row请求,然后去再磁盘进行查询,减少IO操作
删除:不支持
- 1)目前我们知道布隆过滤器可以支持 add 和 isExist 操作
- 2)如何解决这个问题,答案是计数删除,但是计数删除需要存储一个数值,而不是原先的 bit 位,会增大占用的内存大小。
- 3)增加一个值就是将对应索引槽上存储的值加一,删除则是减一,判断是否存在则是看值是否大于0。
2、redis事物
2.1、redis事物介绍
- redis事物是可以一次执行多个命令,本质是一组命令的集合。
- 一个事务中的所有命令都会序列化,按顺序串行化的执行而不会被其他命令插入
作用:一个队列中,一次性、顺序性、排他性的执行一系列命令
2.2、redis事物基本使用
- 下面指令演示了一个完整的事物过程,所有指令在exec前不执行,而是缓存在服务器的一个事物队列中
- 服务器一旦收到exec指令才开始执行事物队列,执行完毕后一次性返回所有结果
- 因为redis是单线程的,所以不必担心自己在执行队列是被打断,可以保证这样的“原子性”
注:redis事物在遇到指令失败后,后面的指令会继续执行
- mysql的rollback与redis的discard的区别:
- mysql回滚为sql全部成功才执行,一条sql失败则全部失败,执行rollback后所有语句造成的影响消失
- redis的discard只是结束本次事务,正确命令造成的影响仍然还在.
# Multi 命令用于标记一个事务块的开始事务块内的多条命令会按照先后顺序被放进一个队列当中,最后由 EXEC 命令原子性( atomic )地执行
> multi(开始一个redis事物)
incr books
incr books
> exec (执行事物)
> discard (丢弃事物)
#在命令行测试redis事物
[root@redis ~]# redis-cli
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set test 123
QUEUED
127.0.0.1:6379> exec
1) OK
127.0.0.1:6379> get test
"123"
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set test 456
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> get test
"123"
127.0.0.1:6379>
# 使用python测试redis事物
#定义ip
host = 'localhost'
#建立服务连接
r = redis.Redis(host=host)
pipe = r.pipeline()
#开启事务
pipe.multi()
#存储子命令
pipe.set('key2', 4)
#执行事务
pipe.execute()
print(r.get('key2'))
3、watch指令
实质:WATCH 只会在数据被其他客户端抢先修改了的情况下通知执行命令的这个客户端(通过 WatchError 异常)但不会阻止其他客户端对数据的修改
- watch其实就是redis提供的一种乐观锁,可以解决并发修改问题
- watch会在事物开始前盯住一个或多个关键变量,当服务器收到exec指令要顺序执行缓存中的事物队列时
- redis会检查关键变量自watch后是否被修改(包括当前事物所在的客户端)
- 如果关键变量被人改动过,exec指令就会返回null回复告知客户端事物执行失败,这个时候客户端会选择重试
注:redis禁用在multi和exec之间执行watch指令,必须在multi之前盯住关键变量,否则会出错