文章目录
初识Redis
特征:
- 键值型,value支持多种不同数据结构,功能丰富
- 单线程,每个命令具备原子性
- 低延迟,速度快(基于内存,IO多路复用,良好的编码)
- 支持数据持久化
- 支持主从集群,分片集群
Redis通用命令
常见指令:
- KEYS : 查看符合模版的所有KEY,不建议在生产环境设备上使用
- DEL:删除一个指定的KEY
- EXISTS: 判断key是否存在
- EXPIRE: 给一个key设置有效期,有效期到期时key会被自动删除
- TTL: 查看一个KEY的剩余有效期
通过help[command]可以查看一个命令的具体做法,如 help keys
String类型:
Key的层级格式:
Hash类型:
List类型:可看作一个双向链表结构,可支持正向检索和反向检索
Set类型: value为null的HashMap
SortedSet类型: 一个可排序的set集合,每一个元素都带有一个score属性,可基于此属性对元素排序,底层实现是一个跳表(SkipList)+hash表
分布式缓存
单点Redis的问题
持久化
RDB
redis数据备份文件(redis数据快照),内存中所有数据都记录到磁盘中。redis实例故障重启后,从磁盘读取快照文件,恢复数据。
bgsave基本流程
- 开始时会fork主进程得到子进程,子进程共享主进程的内存数据;
- 完成fork后子进程读取内存数据并写入RDB文件;
- 用新RDB文件替换旧的RDB文件;
fork采用的是copy-on-write技术:
- 当主进程执行读操作时,访问共享内存。
- 当主进程执行写操作时,则会拷贝一份数据,执行写操作。
通过虚拟内存 映射实现共享内存数据
RDB执行时机? save 60 1000 ?
默认服务停止时执行,60秒内至少执行1000次i需改则触发RDB
RDB缺点?
RDB执行间隔时间长,两次RDB间写入数据有丢失风险
fork子进程、压缩、写出RDB文件都比较耗时
AOF
追加文件,Redis处理的每一个写命令都会记录在AOF文件,可以看作是命令日志文件
因为记录命令,所以比RDB文件大得多,且会记录对同一个key的多次写操作,但只有最后一次写操作才有意义,通过执行bgewriteaof命令,可让AOF文件执行重写功能,用最少的命令达到相同效果。Redis也会在触发阈值时自动去重写AOF文件。
AOF对比RDB
Redis 主从
搭建主从架构
实现读写分离
数据同步原理
主从第一次同步时全量同步
全量同步流程:
- slave节点请求增量同步
- master节点判断replid,发现不一致,拒绝增量同步
- master将完整内存数据生成RDB,发送RDB到slave
- slave清空本地数据,加载master的RDB
- master将RDB期间的命令记录在repl_baklog, 并持续将log中的命令发送给slave
- slave 执行接收到的命令,保持与master之间的同步
如果slave重启后同步,则执行增量同步
Redis哨兵
Redis 原理
IO多路复用
无论是阻塞IO还是非阻塞IO ,用户应用在一阶段都需要调用recvfrom来获取数据,差别在于无数据时的处理方案:
- 如果调用rcvfrom时,恰好没有数据,阻塞IO会使进程阻塞,非阻塞IO使CPU空转,都不能充分发挥CPU的作用
- 如果调用recvfrom时,恰好有数据,则用户进程可以直接进入第二阶段,读取并处理数据
FD文件描述符:从0开始递增的无符号整数,用来关联linux中的一个文件;
IO多路复用:利用单个线程来同时监听多个FD,并在某个FD可读、可写时得到通知,从而避免无效的等待,充分利用cpu资源
select poll epoll
差异:
- select和poll只会通知用户进程有FD就绪,但不确定具体是哪个FD,需要用户进程逐个遍历FD来确认;
- epoll则会在通知用户进程FD就绪的同时,把已就绪的FD写入用户空间;
poll
-
创建pollfd数组,向其中添加关注的fd信息,数组大小自定义;
-
调用poll函数,将pollfd数组拷贝到内核空间,转链表存储,无上限;
-
内核遍历fd,判断是否就绪;
-
数据就绪或超时后,拷贝pollfd数组到用户空间,返回就绪fd数量n;
-
用户进程判断n是否大于0;
-
大于0则遍历pollfd数组,找到就绪的fd;
对比select: -
select模式中的fd_set大小固定为1024,而pollfd在内核中采用链表,理论上无上限;
-
监听fd越多,每次遍历消耗时间也越久,性能反而会下降;
epoll
总结:
select模式存在的三个问题?
1)能监听的FD最大不超过1024
2)每次select都需要把所有要监听的FD都拷贝到内核空间
3)每次都要遍历所有的FD来判断就绪状态
poll模式的问题?
1)利用链表解决了select中监听FD上限的问题,但依然要遍历所有FD,如果监听较多,性能会下降;
epoll模式中如何解决这些问题?
1)基于epoll实例中的红黑树保存要监听的FD,理论上无上限,而且增删改查效率都非常高,性能不会随监听的FD数量增多而下降
2)每个FD只需要执行一次epoll_ctl添加到红黑树, 以后每次epoll_wait无需传递任何参数,无需重复拷贝FD到内核空间
3)内核会将就绪的FD直接拷贝到用户空间的指定位置,用户进程无需遍历所有FD就能知道就绪的FD是谁
IO多路复用-事件通知机制
FD有数据可读时,调用epoll_wait就可以得到通知,由两种:
- LT,有数据可读时,会重复通知多次,直至数据处理完成,时Epoll的默认模式;
- ET,…………,只会被通知一次,不管数据是否处理完成;
惊群现象(所有进程都被唤醒)
信号驱动IO
信号驱动IO时与内核简历SIGIO的信号关联并设置回调,内核有FD就绪时,会发出SIGIO信号通知用户,期间用户应用可以执行其他业务,无需阻塞等待
异步IO
全部交给内核,然后啥玩意也不管,在高并发下,相当于领导不管下属死活,导致内存过多系统崩溃。
Redis网络模型
reids到底是多线程还是单线程?
仅聊redis的核心业务部分(命令处理): 单线程
聊整个redis: 多线程
为什么redis要选择单线程?
1.抛开持久化不谈,redis时纯内存操作,执行速度很快,性能瓶颈时网络延迟而不是执行速度,因此多线程不会带来很大的性能提升。
2. 多线程导致过多的上下文切换,有不必要的开销
3. 引入多线程面临线程安全问题,必然要引入线程锁这样的安全手段,实现复杂度高,且性能会打折扣
内容均来自B站黑马程序员redis视频,若有侵权,联系删除!