Redis进阶
发布订阅
一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
命令 | 描述 |
---|---|
SUBSCRIBE channel [channel ...] | 订阅给定的一个或多个频道的信息。(创建频道) |
UNSUBSCRIBE [channel [channel ...]] | 指退订给定的频道。 |
PSUBSCRIBE pattern [pattern ...] | 订阅一个或多个符合给定模式的频道。 |
PUNSUBSCRIBE [pattern [pattern ...]] | 退订所有给定模式的频道。 |
PUBSUB subcommand [argument [argument ...]] | 查看订阅与发布系统状态。 |
PUBLISH channel message | 将信息发送到指定的频道。 |
事务
隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
原子操作:事务中的命令要么全部被执行,要么全部都不执行。
三个阶段:
-
开始事务。MULTI
-
命令入队(FIFO)。
-
执行事务。EXEC
命令 | 描述 |
---|---|
MULTI | 标记一个事务块的开始。 |
EXEC | 执行所有事务块内的命令。 |
WATCH key [key ...] | 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。 |
UNWATCH | 取消 WATCH 命令对所有 key 的监视。 |
DISCARD | 取消事务,放弃执行事务块内的所有命令。 |
WATCH命令是一个乐观锁
Redis持久化机制
RDB
-
RDB(Redis Database)持久化是把当前进程数据生成快照保存在RDB文件的过程。
-
RDB持久化生成的RDB文件是一个经过压缩的二进制文件。
-
触发RDB持久化过程分为手动触发和自动触发。
手动触发
命令 | 描述 |
---|---|
SAVE | 异步保存数据到硬盘(备份,将rdb文件移动到安装目录并重启服务集合恢复) |
BGSAVE | 在后台异步保存当前数据库的数据到磁盘 |
自动触发
Redis会判断是否满足持久化的条件,满足则自动执行bgsave命令进行持久化。是否满足则是通过Redis核心配置文件redis.conf来配置的。比如:
1 # RDB 保存的条件 2 save 900 1 # 表示 900 秒内如果至少有 1 个 key 值变化,则把数据持久化到硬盘 3 save 300 10 4 save 60 10000 5 6 # bgsave 失败之后,是否停止持久化数据到磁盘,yes 表示停止持久化,no 表示忽略错误继续写文件。 7 stop-writes-on-bgsave-error yes 8 9 # RDB 文件压缩 10 rdbcompression yes 11 12 # 写入文件和读取文件时是否开启 RDB 文件检查,检查是否有无损坏,如果在启动是检查发现损坏,则停止启动。 13 rdbchecksum yes 14 15 # RDB 文件名 16 dbfilename dump.rdb 17 18 # RDB 文件目录 19 dir ./
载入
-
如果Redis开启了AOF持久化功能,就会优先使用AOF文件来还原数据库状态,因为AOF文件的更新频率比RDB文件的更新频率高。
-
只有在AOF持久化关闭的状态时,服务器才会使用RDB文件来还原数据库状态。
-
服务器在载入RDB文件期间,会一直处于阻塞状态,直到载入工作完成为止。
优缺点
-
优点:RDB文件是一个紧凑的二进制文件,适用备份、全量复制的场景。加载RDB文件恢复数据远远快于AOF文件。
-
缺点:不能实时持久化,数据丢失的风险高。每次BGSAVE创建子进程属于重量级操作,频繁执行成本高。
AOF
-
AOF(Append Only File)持久化以独立日志方式记录每次写命令,重启时再重新执行AOF文件中的命令达到恢复数据的目的。
-
AOF的主要作用就是解决了数据持久化的实时性。
-
被写入AOF文件的所有命令都是以Redis的命令请求协议格式保存的,因为Redis命令请求协议格式是纯文本格式,所以我们可以直接打开一个AOF文件观察里面的内容。
-
默认情况下AOF功能是关闭的。我们需要修改配置文件:appendonly no改为appendonly yes。
工作流程
-
命令追加:服务器执行完一个写命令后,会以协议格式将被执行的写命令追加到服务器状态的aof_buf缓冲区末尾。
-
文件同步:AOF缓冲区根据对应的策略向硬盘做同步操作。
-
文件重写:随着AOF越来越大,需要定期对AOF文件进行重写,达到压缩的目的。
-
重启加载:当Redis重启时,可以加载AOF文件进行数据恢复。
文件同步策略
-
appendfsync always:每次写入都要同步AOF文件,从效率上看,是最慢的,从安全性上看,是最安全的。
-
appendfsync everysec:每1秒钟同步一次,该策略为AOF的缺省策略。
-
appendfsync no:从不同步。高效但是数据不会被持久化
Redis明明是单线程,为什么性能还那么高?
-
纯内存访问,所有数据放在内存中,内存响应的速度非常快。
-
非阻塞I/O,Redis使用epoll作为I/O多路复用技术的实现的,再加上Redis自身的事件处理模型将epoll中的连接、读写、关闭都转换为事件,不在网络I/O上浪费过多事件。
-
单线程避免了线程切换和竞态产生的消耗。
单线程优缺点
-
单线程可以简化数据结构和算法的实现。
-
单线程可以避免竞态产生的消耗,锁和线程切换通常是性能杀手。
-
对于每个命令的执行时间有要求,如果某个命令执行过长,会造成其他命令阻塞,对于Redis这种高性能的服务来说是致命的。
Redis流水线(管道)
-
在一般情况下,用户每执行一个Redis命令,客户端和服务器都需要进行一次通信:客户端向服务器发送命令请求,而服务器则会将执行命令所得的结果返回给客户端。
-
减少客户端和服务器之间的通信次数,可以有效提高程序的执行效率。
-
流水线功能可以将多条命令打包一起发送,并且在一次命令回复中包含所有被执行命令的结果,使用这个功能可以有效提升程序在执行多条命令时的效率。
1 import redis 2 3 #创建连接池获取连接 4 pool = redis.ConnectionPool(host='wykd', port=6379,password='123456', decode_responses=True) 5 rp1 = redis.Redis(connection_pool=pool) 6 7 #创建管道,可以选择开启或关闭事务,这里的事务与Redis事务一样是弱事务型 8 pipe = rp1.pipeline(transaction=True) 9 #在管道中添加命令 10 pipe.set('new','123') 11 pipe.set('name', 'wyk2') 12 pipe.set('company', 'csdn2') 13 pipe.hincrby('hage','wyk',1) 14 15 #这个命令会报错,因为hage为hash类型不能使用get命令,此时无论开启关闭事务,管道中的其他命令也依然会正常执行 16 #pipe.get('hage') 17 18 #也可以用下面的语法将多个命令拼接到一起 19 # pipe.set('name', 'wyk').set('company', 'csdn').hset('hage', 'wyk',28).hincrby('hage','wyk',1) 20 21 #执行pipeline里的脚本 22 pipe.execute()