redis知识总结


前言


一、redis事务

Redis 事务的本质是一组命令的集合 

事务支持一次执行多个命令,一个事务中所有命令都会被序列化。

在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。

所以说:Redis 事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。

Redis 事务没有隔离级别的概念

Redis 事务不保证原子性 

Redis中,单条命令是原子性执行的,但事务不保证原子性,且没有回滚

Redis事务的三个阶段

  1. 开始事务

  2. 命令入队

  3. 执行事务

watch 格式watch key1 key2 ...
监视一或多个 key,如果在事务执行之前,被监视的 key 被其他命令改动,则事务被打断(类似乐观锁)。

unwatch  取消监听

multi 标记一个事务块的开始,形成队列(queued)。
exec 执行所有事务块(一旦执行 exec 后,之前加的监控锁都会被取消掉)。
discard 取消事务,放弃事务块中的所有命令。

127.0.0.1:6379> multi # 开启事务
OK
127.0.0.1:6379(TX)> set k1 v1 # 命令入队
QUEUED
127.0.0.1:6379(TX)> set k2 v2 # 命令入队
QUEUED
127.0.0.1:6379(TX)> get k2 # 命令入队
QUEUED
127.0.0.1:6379(TX)> set k3 v3 # 命令入队
QUEUED
127.0.0.1:6379(TX)> exec # 执行事务
1) OK
2) OK
3) "v2"
4) OK
127.0.0.1:6379> get k1 # set命令执行成功
"v1"
127.0.0.1:6379> get k2 # set命令执行成功
"v2"

事务中存在命令性错误  若在事务队列中存在命令性错误(类似于java编译性错误),则执行 exec 命令时,所有命令都不会执行。

事务中存在语法性错误  若在事务队列中存在语法性错误(类似于 Java 的的运行时异常),则执行 exec 命令时,其他正确命令会被执行,错误命令抛出异常。

  • 一旦执行 exec 开启事务后,无论事务是否执行成功, watch 对变量的监听都将被取消。

  • 当事务执行失败后,需重新执行 watch 命令对变量进行监听,并开启新的事务进行操作。

  • watch 指令类似于乐观锁,在事务提交时,如果 watch 监控的多个 key 中任何 key 的值已经被其他客户端更改。

    则使用 exec 执行事务时,事务队列将不会被执行,同时返回 (nil) 应答以通知调用者事务执行失败。

二、发布订阅

 Redis 发布订阅(pub / sub)是一种消息通信模式发送者(pub)发送消息,订阅者(sub)接收消息。

这些命令被广泛用于构建即时通信应用,比如网络聊天室(chat room)和实时广播、实时提醒等。

Redis 通过 publish 、subscribe 和 psubscribe 等命令实现发布和订阅功能。

通过 subscribe 命令订阅某频道后,redis-server 里维护了一个字典,字典的键就是一个个 channel。

而字典的值则是一个链表,链表中保存了所有订阅这个 channel 的客户端。

subscribe 命令的关键,就是将客户端添加到给定 channel 的订阅链表中。

通过 publish 命令向订阅者发送消息,redis-server 会使用给定的频道作为键,在它所维护的 channel 字典中查找记录了订阅这个频道的所有客户端的链表,遍历这个链表,将消息发布给所有订阅者。

pub / sub 从字面上理解就是发布(Publish)与订阅(Subscribe),在 Redis 中,你可以设定对某一个 key 值进行消息发布及消息订阅,当一个 key 值上进行了消息发布后,所有订阅它的客户端都会收到相应的消息。

这一功能最明显的用法就是用作实时消息系统,比如普通的即时聊天,群聊等功能


订阅频道
subscribe Chat
发布信息
 publish Chat "Hello,world"

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

缓存雪崩

在使用缓存时,通常会对缓存设置过期时间,一方面目的是保持缓存与数据库数据的一致性,另一方面是减少冷缓存占用过多的内存空间。

但当缓存中大量热点缓存采用了==相同的实效时间==,就会导致缓存在某一个时刻同时实效,请求全部转发到数据库,从而导致数据库压力骤增,甚至宕机。从而形成一系列的连锁反应,造成系统崩溃等情况,这就是缓存雪崩(Cache Avalanche)。

解决方法

1.通常的解决方案是将key的过期时间后面加上一个随机数(比如随机1-5分钟),让key均匀的失效。
2. 可以把一些热点数据提前放入缓存。
3. 构建缓存高可用集群(针对缓存服务故障情况)。 

缓存穿透 

缓存穿透(cache penetration)是用户访问的数据既不在缓存当中,也不在数据库中。出于容错的考虑,如果从底层数据库查询不到数据,则不写入缓存。这就导致每次请求都会到底层数据库进行查询,缓存也失去了意义。当高并发或有人利用不存在的Key频繁攻击时,数据库的压力骤增,甚至崩溃,这就是缓存穿透问题。

如何解决

0.业务层校验不合法的数据.比如id=负数。

1. 如果查询的结果为null,也往缓存中存入一个Null对象。而且该对象的存放时间不要太长。

2. 使用布隆过滤器。 把表中存在的所有id存入到布隆过滤器中,查询时,先经过布隆过滤器,如果不存在则直接返回null,如果存在则查询缓存和数据库。

布隆过滤器 

布隆过滤器是一种数据结构,对所有可能查询的参数以 hash 形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力。

布隆过滤器(Bloom Filter)的核心实现是一个==超大的位数组==和==几个哈希函数==。假设位数组的长度为m,哈希函数的个数为k

以上图为例,具体的操作流程:假设集合里面有3个元素{x, y, z},哈希函数的个数为3。首先将位数组进行初始化,将里面每个位都设置位0。对于集合里面的每一个元素,将元素依次通过3个哈希函数进行映射,每次映射都会产生一个哈希值,这个值对应位数组上面的一个点,然后将位数组对应的位置标记为1。查询W元素是否存在集合中的时候,同样的方法将W通过哈希映射到位数组上的3个点。如果3个点的其中有一个点不为1,则可以判断该元素==一定不存在集合中==。反之,如果3个点都为1,则该元素==可能存在集合中==。注意:此处不能判断该元素是否一定存在集合中,可能存在一定的误判率。可以从图中可以看到:假设某个元素通过映射对应下标为4,5,6这3个点。虽然这3个点都为1,但是很明显这3个点是不同元素经过哈希得到的位置,因此这种情况说明元素虽然不在集合中,也可能对应的都是1,这是误判率存在的原因。  

缓存击穿 

缓存击穿,是指一个 key 非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问。

当这个 key 在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。

当某个 key 在过期的瞬间,有大量的请求并发访问,这类数据一般是热点数据。

由于缓存过期,会同时访问数据库来查询最新数据,并且回写缓存,会导使数据库瞬间压力过大。

解决

第一种设置热点永远不过期

从缓存层面来看,没有设置过期时间,所以不会出现热点 key 过期后产生的问题。

第二种解决加互斥锁

分布式锁:使用分布式锁,保证对于每个 key 同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只能等待。

这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大。

四、 Redis淘汰策略有哪些?

使用就是通过修改配置文件来实现


总结

笔记

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值