Redis:高级特性和底层工作原理
高级特性
简单消息队列
可以用list的rpush+lpop实现简单的消息队列功能(用blpop可以阻塞连接直到有消息时才返回)
发布订阅模式
消费者通过subscribe订阅一个频道,生产者通过publish发布消息到频道,实现多条发布。
通过unsubscribe取消订阅。
订阅的频道可以用通配符,比如(*)。
Redis事务
事务:保证指令一次性执行,和传统事务的区别是假如执行了,中途有错误也无法回滚(语法错误例外,语法错误会导致都不能执行)
指令
- MULTI:开启事务(不能嵌套)
- EXEC:执行事务
- DISCARD:中途放弃事务的执行
- WATCH:类似乐观锁的实现,监视一个KEY,假如KEY的值中途有修改,会阻止这个事务的执行
- UNWATCH
多条命令一次性执行,只保证执行的"原子性"
Lua脚本
好处
- 一次发送多个命令,减少网络开销
- 原子性
- lua file 实现命令集的复用
使用
- redis中调用脚本:eval script (参数key) (参数value)
- lua脚本中执行redis:redis.call(command, key [param1, param2...]),command是命令,key是键,param代表给key的参数
- 设置lua脚本命令执行超时时间,避免出现意想不到的bug(redis是单线程的),但是超时以后也是只接受不执行,为了保证原子性,这时候需要执行script kill命令,但是假如脚本中已经有数据变更了,执行script kill命令也杀不掉。这时候只能shutdown了。。。。。所以使用lua脚本要注意脚本的稳健性。
案例
限流令牌桶
Redis为什么这么快
1、纯内存操作,KV结构(时间复杂度O1)
2、单线程:没有创建、销毁线程的开销,也不需要上下文的切换
3、多路复用I/O
为什么不用多线程?Redis的瓶颈在于内存,用多线程会提高复杂度,所以使用了单线程。
虚拟内存
- 物理内存共享出现不安全的问题,使用空间有限
- 使用虚拟内存可以提高使用空间,划分用户使用空间
用户空间user space和内核空间kernel space
- 内核态:进程运行在内核空间
- 用户态:进程运行在用户空间
上下文切换
CPU分时间片运行时,需要保存程序计数器等信息,然后切换,就叫上下文切换,比较耗资源。
多路复用I/O
传统I/O阻塞
非阻塞I/O(NIO)少了准备数据的阻塞过程,等待数据准备过程中是非阻塞的。
异步I/O(AIO)少了自己主动拷贝数据的过程,拷贝过程中也是非阻塞的。
多路复用I/O:服务端会和多个客户端socket连接,使用轮询的方式轮询访问socket,任意一个socket的数据准备好了都执行读取该socket的数据。使得一个进程可以快速的保持多个连接,优点是连接多。
Redis的过期策略
定时过期:每个key创建一个定时器,但是key很多的时候定时器很多。
惰性过期:下次访问key的时候,判断key是否已过期,过期则删除。(对内存不友好,过期的还在占用内存)
set memory到达上限时,调用activeExpireCycle()释放内存
定期过期:每次扫描一定数量,采样删除。
redis中使用了惰性过期(访问键)和定期过期(一定时间扫描)。
全都没有过期时间怎么办
淘汰策略
-
allkeys-lru 最近最少使用
-
allkeys-random
-
(exception)noeviction 不淘汰
-
allkeys-lfu 一段时间内使用最少
-
volatile-lfu 一段时间内使用最少 (只针对ttl)
-
volatile-lru
-
volatile-ttl 把最快过期的删除
-
volatile-random
-
lru算法通过对象里使用一个缓存的lru时间戳来比较,当前缓存时间与对象lru时间戳距离越久,说明热度越低。
-
lfu算法和lru同一个字段,分位统计,高16位记录访问时间,低8位记录访问频率
持久化机制
RDB redis database
默认的持久化方案,生成快照dump.rdb到磁盘中,重启时根据该文件恢复,
触发机制:save seconds changes
save 900 1
save 300 10
save 60 10000
手动触发:save命令(会阻塞),redis自身是异步持久化数据,bgsave,fork子进程生成快照,并替换原来的rdb文件。
- 优点:恢复速度快;rdb文件紧凑,适合备份
- 缺点:有一定延迟,不能非常精准的备份。
AOF append only file
默认不开启,需要通过配置开启
保存操作指令,也有触发机制:appendfsync
appendfsync always(每次操作都存储)
appendfsync everysecond(每秒同步一次,最常用)
appendfsync no(由系统自行决定什么时候同步)
文件特别大时可以通过rewrite指令压缩,bgrewriteaof,系统根据配置参数(上次重写比例和最小大小)来重写。
重写的时候假如有新指令过来会缓存新指令,AOF重写结束后将缓存命令追加到AOF里面中。
- 优点:安全性高
- 缺点:恢复速度慢
同时有AOF和RDB的时候恢复会优先用AOF。