redis进阶


一、发布订阅

场景一:(实时性)

直播间中会话,进入直播间之前的消息你是接收不到的,只能接收到进入直播间之后的消息

订阅者只能接收到连接发布者之后发布者发布的消息

场景二:(历史性)

登陆微信之后可以查看历史聊天记录,数据库中肯定存放全量的数据

但是不能全部查库,n天之前的可以查库(请求量特别低),三天内的呢?

  zset可以去实现,把时间作为记录的分值,把消息作为元素,按照时间去将数据从redis中删除

左边redis充当发布订阅,当消息来了后讲消息放到右侧redis的zset中。需要查询过往消息的时候从右侧redis读取

 二、事务

watch为监听某些key的操作,mutli为开启事务标志

如上图,client1开启了watch监听k1,若client2发送的删除先执行了exec,watch1监听到k1发生了变化,此时client1之后的命令是不执行的

redis是单进程的,client1和client2两个客户端同时发送命令时,会将命令分组放到队列中,哪组命令先出现exec命令就先执行哪组命令,不论事务是否开启 

三、布隆过滤器

作用:防止数据穿透

数据穿透了怎么办?在redis中新增一个key,value标记不存在,下次请求再来的时候redis直接返回不存在,避免再次穿透

使用bitmap,如上图:

将数据库中现有的商品依次通过映射函数进行计算,在bitmap中将一些位置标记为1(具体哪些位置进行标记暂不研究)。所有映射函数计算完毕后,bitmap中相应位置都会被进行标记。

元素3为用户请求,当redis中没有该请求的时候使用布隆过滤器,通过映射函数进行计算,当所有计算结果在bitmap中都为1时,放行请求到数据库。

但是此时会有一个问题:请求计算后所有在bitmap中的数字可能都为1(如上图),但是这些被标记为1的bitmap对应的位置可能不是数据库中一个商品计算后修改为1的,这时也会请求到数据库。这种概率很小

四、redis作为缓存和作为数据库的区别

缓存不是全量数据,缓存应该随着访问变化,应该存放热数据

有时会对redis中某一key值设置过期时间,需要明确当查询这一key值时不会延长过期时间,当重新set这一key值时会剔除过期时间

 五、管道

1、衔接前一个命令的输出作为后一个命令的输入

2、管道会触发创建子进程

使用linux的时候有父子进程的概念:父类进程的数据子类进程能不能看到?

  父子进程修改数据对方看不到。子进程的修改不会破坏父进程,父进程的修改也不会破坏子进程

六、RDB

1、时点性:redis中数据持久化会有一个时间

2、RDB会创建一个子进程,调用fork进行拷贝+copy on write

  fork(系统调用)并不是真正的拷贝数据,仅仅是指针指向

 进行数据持久化时,父进程(上图fork左下)先通过fork创建一个子进程(上图fork右下),子进程将数据落地到磁盘,子进程创建的时间即为数据落地时间

 父进程针对客户端进行操作,子进程进行数据落地

3、命令触发RDB

  save触发前台阻塞,不允许对外提供服务,如读写(应用场景比如关机维护)

  bgsave触发子进程fork

 4、弊端:时点与时点之间容易丢失数据相对多一些

      优点:数据写入磁盘,恢复数据速度更快

 七、AOF

1、AOF:向文件追加,追加的内容为redis的写操作记录到文件中,类似于mysql中binlog

2、redis中可以同时开启AOF和RDB,如果开启了AOF,只会用AOF恢复

好处:很少丢失数据

弊端:体量无限变大,恢复慢

3、AOF在4.0以后将老的数据RDB到aof文件中,将增量的数据以指令的方式追加到AOF中

  AOF是一个混合体,利用了RDB的快

4、redis是内存级别的数据库,写操作会触发IO,写操作有三种级别:

  always:每次写入数据都会立即写入磁盘

  everysec:redis每秒调一次flush向磁盘中写

  no:当redis中数据在内核buffer中满了,会向磁盘中写入

 八、AFK原理

1、单机、单节点、单实例的缺陷:

  单点故障、容量有限、多线程打进来后压力大

2、AKF从x、y、z三个维度去解决问题

  x:解决单点问题,x轴可以创建多个备机,进行数据备份

  y:y轴可以将不同的模块数据存放到不同redis中

  z:z轴可以建立在同一模块的数据中按照id进行划分出多个redis

 3、redis集群保证数据一致性的方案

 4、redis一般用主从不用主备,用主从客户端可以访问主节点也可以访问从节点

  主备的话客户端是不能访问备机

 九、redis主从复制

1、redis主从复制为弱一致性,容易丢失数据

 十、redis击穿

redis作为缓存,key过期,或redis中数据被当作冷数据删除,这时高并发过来请求穿过了redis到达数据库

1、解决方案

  每一个请求首先get key发现没有,get失败的请求都去setnx,set成功的人去数据库操作,set失败的人睡眠

2、如果set成功的线程挂掉?  可以设置锁的过期时间

3、线程在操作数据库,但是锁过期了?  一个线程取db,一个线程监控是否取回来了,更新锁时间

十一、穿透

业务查询的是数据库中不存在的数据

使用布隆过滤器

十二、雪崩

短时间内大量的key同时失效,间接造成大量请求到达db

可以在业务层加判断进行延时,延时之后随机到达redis