为什么redis能这么快
100000+qps
- 完全基于内存,绝大部分请求是纯粹的内存操作
- 数据结构简单,键值对,查找的时间复杂度是O(1)
- 采用单线程,单线程也能处理高并发请求,想多核也可启动多实例(单线程只是处理网络请求的时候是单线程)
- 使用多路I/O复用模型,非阻塞IO
多路IO复用模型
FD:File Descriptor,文件描述符
一个打开的文件通过唯一的描述符进行引用,该描述符是打开文件的元数据到文件本身的映射
传统的阻塞I/O模型
当对某个文件进行读写时,如果当前FD不可读或者不可写,redis就不会对其他操作进行响应,导致服务不可用
select系统调用:监听文件是否可读写
redis采用的IO多路复用函数:epoll/kqueue/evport/select
- 因地制宜
- 优先选择时间复杂度为O(1)的函数
- select时间复杂度为O(n)作为保底
- 基于react设计模式监听I/O事件
redis使用的数据类型
从海量Key查询出某一固定前缀的Key
- 问清数据规模
使用keys对线上业务的影响
keys指令一次性返回所有匹配的key,key的数量过大会使服务卡顿
使用scan指令:无阻塞
scan 0 k1* count 10(返回 游标1232 和匹配的元素)
scan 1232 k1* count 10
java可以将结果放入set去重
如何通过redis实现分布式锁
分布式锁需要解决的问题
- 互斥性:只能由一个客户端获取到锁
- 安全性:只能由获取锁的客户端删除锁
- 死锁:获取到锁的客户端宕机,需要由机制防止
- 容错:部分节点宕机,仍然可以获取锁
setnx key val
解决setnx长期有效
如果大量的key同时过期需要注意什么
集中过期,由于删除大量key需要时间,会出现卡顿现象
解决:设置key的过期时间时,给每个key加上随机值
如何使用redis做异步队列
使用List作为队列,rpush生产消息,lpop消费消息.
缺点:没有等待队列里有值才去消费,可以在程序中引入sleep机制去调用lpop重试
blpop key timeout:阻塞直到队列有消息或者超时
缺点:只能提供给一个消费者
pub/sub:主题订阅者模式-一对多
缺点:消息的发布无状态,无法保证被接收到
redis如何做持久化
RDB(快照)持久化:保存某个时间节点的全量数据快照
- sava:阻塞服务进程,直到RDB创建完成
- bgsave:fork出一个子进程来创建RDB文件,不阻塞服务器进程
自动化触发RDB持久化
bgsave原理
RDB持久化的缺点
- 全量同步,数据量大会由于IO而严重影响性能
- 可能会因为redis挂掉而丢失从当前至最近一次快照期间的数据
AOF(Append-Only-File)持久化:保存写状态
- 记录下除了查询以外的所有变更数据库状态的命令
- 以append的形式追加到AOF文件中
RDB和AOF共存的情况下的恢复流程
RDB和AOF的优缺点
RDB-AOF混合持久化
bgsave做镜像全量持久化,aof做增量持久化
使用Pipeline的好处
Redis的主从同步
主从同步原理
- 全同步
- 增量同步
主从同步Master宕机后的主从切换问题
留言协议Gossip
在杂乱无章中寻求一致
Redis的集群原理
如何从海量数据中快速找到所需
- 分片:按照某种规则去划分数据,分散存储在多个节点上
- 常规的哈希划分无法实现节点的动态增减
- 一致性哈希算法:对2^32取模,将哈希值空间组织成虚拟的圆环.一致性哈希算法对于节点的增减都只需重新定位环中的一小部分数据.
- 一致性哈希算法缺点:节点少的时候会发生数据倾斜.解决:引入虚拟节点