Redis知识整理(八) – 事务&布隆过滤器
事务
特点
Redis事务没有回滚
选用redis的本质就是因为速度快,所以作者设计的事务的时候依然是考虑到执行的速度问题
使用
主要命令:
DISCARD:取消事务
EXEC:执行事务
MULTI:开启事务
WATCH:查看事务,类似于乐观锁,CAS(compare and set)
细节点:
两个事务,事务A和事务B,事务A先开启,然后事务B开启,事务A get k1,事务B del k1,事务B先提交,则k1被删除,事务A提交的时候获取不到结果
证明:
-
先exec的事务,先执行。执行前,multi的事务指令放在各自的缓冲区。
-
如果事务A watch k1,则事务B exec之后,事务A会discard。
# 开启事务
> MULTI
OK
> set k1 aaa
QUEUED
> set k2 bbb
QUEUED
> exec
1) OK
2) OK
#=================事务执行先后顺序问题=================
# client1
> MULTI
OK
> get k1
QUEUED
# client2
> MULTI
OK
> del k1
QUEUED
> exec
1) (integer) 1
# client1
# client1后提交 此时k1已经被client2的事务del
> exec
1) (nil)
#=================WATCH命令=================
> WATCH k1
OK
> get k1
QUEUED
> keys *
QUEUED
# 此时k1的值被更改
# 由于已经WATCH,所以提交事务直接nil
> exec
(nil)
为什么 Redis 不支持回滚(roll back)
如果你有使用关系式数据库的经验, 那么 “Redis 在事务失败时不进行回滚,而是继续执行余下的命令”这种做法可能会让你觉得有点奇怪。
以下是这种做法的优点:
- Redis 命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面:这也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。
- 因为不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速。
有种观点认为 Redis 处理事务的做法会产生 bug , 然而需要注意的是, 在通常情况下, 回滚并不能解决编程错误带来的问题。 举个例子, 如果你本来想通过 INCR 命令将键的值加上 1 , 却不小心加上了 2 , 又或者对错误类型的键执行了 INCR , 回滚是没有办法处理这些情况的。
布隆过滤器(RedisBloom)
redisbloom.so 扩展库
redis-server --loadmodule /opt/redis/redisbloom.so /etc/redis/6379.conf
添加布隆过滤器主要目的
解决缓存穿透/缓存击穿
即频繁访问redis库中不存在的key,从而频繁访问rdb
基本原理:
- 利用bitmap+hash算法,记录rdb中存在的数据,对应偏移位。
- 请求进来通过同样的hash算法,计算当前是否存在数据。
- 效果取决于 bitmap的size 和 hash算法的数量
效果:
- 概率性解决问题
- 不可能达到百分之百的效果
- bloom.so的效果可以达到阻挡 > 99% 以上的请求
操作
> BF.add xxoo abc
(integer) 1
> BF.EXISTS xxoo abc
(integer) 1
> BF.EXISTS xxoo bbb
(integer) 0
- BF.add 将rdb中的数据 录入redis
- BF.EXISTS 判断是否存在,判断所有二进制位,只要有一个为0,不需要查询rdb,直接返回即可。
特点
bloom过滤器复用的bitmap的好处在于,多个二进制位代表一个查询的元素。
比如:“iPad” 对应的 1&5&7下标的二进制位偏移,输入“小米”经过hash算法,返回的1&3&5&7 二进制位,其中3对应的值为0,此时代表rdb中不存在“小米”的检索结果。
特殊处理
- 如果没有被bloom过滤器拦截,但是实际上rbd中没有数据
- 可以在redis中存一个kv value做标记位,减少对于rbd的访问
- 数据库增加了元素
- 必须要做对bloom过滤器的元素的添加