美文网首页
Redis事务机制和缓存穿透、雪崩、击穿

Redis事务机制和缓存穿透、雪崩、击穿

作者: JBryan | 来源:发表于2020-04-17 11:11 被阅读0次
    1、常用命令

    MULTIEXEC命令
    以 MULTI 开始一个事务,然后将多个命令入队到事务中, 最后由 EXEC 命令触发事务, 一并执行事务中的所有命令

    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379> set members 36
    QUEUED
    127.0.0.1:6379> get members
    QUEUED
    127.0.0.1:6379> exec
    1) OK
    2) "36"
    127.0.0.1:6379>
    

    DISCARD命令
    DISCARD 命令用于取消一个事务, 它清空客户端的整个事务队列, 然后将客户端从事务状态调整回非事务状态, 最后返回字符串 OK 给客户端, 说明事务已被取消。

    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379> set username root
    QUEUED
    127.0.0.1:6379> get username
    QUEUED
    127.0.0.1:6379> DISCARD
    OK
    127.0.0.1:6379> get username
    (nil)
    127.0.0.1:6379>
    

    WATCH命令
    WATCH 命令用于在事务开始之前监视任意数量的键: 当调用 EXEC 命令执行事务时, 如果任意一个被监视的键已经被其他客户端修改了, 那么整个事务不再执行, 直接返回失败。
    在窗口一watch password,然后set password

    127.0.0.1:6379> WATCH password
    OK
    127.0.0.1:6379> MULTI 
    OK
    127.0.0.1:6379> set password 123456
    QUEUED
    127.0.0.1:6379> get password
    QUEUED
    

    在窗口二修改password

    127.0.0.1:6379> set password 456789
    OK
    127.0.0.1:6379>
    

    此时回到窗口一,提交事务,执行失败

    127.0.0.1:6379> EXEC
    (nil)
    127.0.0.1:6379>
    

    2、Redis事务ACID

    原子性(Atomicity)
    单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。如果一个事务队列中的所有命令都被成功地执行,那么称这个事务执行成功。

    一致性(Consistency)
    在正常状态下一个事务的所有命令是能按照原子性的原则执行的,但是执行的中途遇到错误,不会回滚,而是继续执行后续命令, 如下:

    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379> set key1 value1
    QUEUED
    127.0.0.1:6379> sadd key1 value2
    QUEUED
    127.0.0.1:6379> set key2 value2
    QUEUED
    127.0.0.1:6379> exec
    1) OK
    2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
    3) OK
    127.0.0.1:6379> get key1
    "value1"
    127.0.0.1:6379> get key2
    "value2"
    127.0.0.1:6379>
    

    在set key1 value1之后,执行了一条错误的命令sadd key1 value2,第一条指令并不会回滚,而是继续执行下面一条set key2 value2指令。

    隔离性(Isolation)
    WATCH 命令用于在事务开始之前监视任意数量的键: 当调用 EXEC 命令执行事务时, 如果任意一个被监视的键已经被其他客户端修改了, 那么整个事务不再执行, 直接返回失败。

    持久性(Durability
    因为事务不过是用队列包裹起了一组 Redis 命令,并没有提供任何额外的持久性功能,所以事务的持久性由 Redis 所使用的持久化模式决定。

    3、缓存穿透、雪崩、击穿

    3.1、缓存穿透

    什么是缓存穿透?
    缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候, 在缓存中找不到对应key的value,每次都要去数据库再查询一遍,然后返回空(相当于进行了两次 无用的查询)。这样请求就绕过缓存直接查数据库。

    有什么解决方案来防止缓存穿透?
    采用布隆过滤器BloomFilter:将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力。
    缓存空值:如果一个查询返回的数据为空(不管是数据不 存在,还是系统故障)我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。 通过这个直接设置的默认值存放到缓存,这样第二次到缓冲中获取就有值了,而不会继续访问数据库。

    3.2、缓存雪崩

    什么是缓存雪崩?
    如果缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,造成了缓存雪崩。 由于原有缓存失效,新缓存未存储,期间所有原本应该访问缓存的请求都去查询数据库了,而对数据库CPU 和内存造成巨大压力,严重的会造成数据库宕机。

    有什么解决方案来防止缓存雪崩?
    1、加锁排队
    互斥锁解决,Redis的SETNX去set一个mutex key, 当操作返回成功时,再去数据库读取数据并回设缓存; 否则,就重试整个get缓存的方法

    2、数据预热
    缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!可以通过缓存reload机制,预先去更新缓存,再即将发生大并发访问前手动触发加载缓存不同的key

    3、双层缓存策略
    C1为原始缓存,C2为拷贝缓存,C1失效时,可以访问C2,C1缓存失效时间设置为短期,C2设置为长期。

    4、设置不同的过期时间,让缓存失效的时间点尽量均匀

    3.3、缓存击穿

    什么是缓存击穿
    缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力

    解决方案
    1、设置热点数据永远不过期。
    2、加互斥锁,保证同一时刻,只能有一个线程去访问数据库。类似线程安全的懒汉单例模式实现。

    相关文章

      网友评论

          本文标题:Redis事务机制和缓存穿透、雪崩、击穿

          本文链接:https://www.haomeiwen.com/subject/leasvhtx.html