Redis_高级
分布式缓存
单点Redis的问题:
- 数据丢失问题:实现Redis数据持久化
- 并发能力问题:搭建主从集群,实现读写分离
- 故障恢复问题:利用Redis哨兵,实现健康检测和自动恢复
- 存储能力问题:搭建分片集群,利用插槽机制实现动态扩容
数据丢失问题-数据持久化
- RDB
基本流程
- fork主进程获得一个子进程,共享内存空间
- 子进程读取内存数据并写入新的RDB文件
- 用新的RDB文件替换旧的RDB文件
什么时候执行,save 60 1000什么含义- 默认是服务停止时
- 代表60秒内至少执行1000次修改则触发RDB
RDB的缺点: - RDB执行间隔时间长,两次RDB之间写入数据有丢失的风险。
- fork子进程、压缩、写出RDB文件都比较耗时。
- AOF
AOF默认是关闭的,需要修改redis.conf配置文件来开启AOF,也可以设置记录的频率(always同步刷盘,everysec每秒刷盘,no操作系统控制)
RDB对比AOF
- 持久化方式:定时对整个内存做快照---记录每一次执行的命令
- 数据完整性:不完整,两次备份之间会丢失---相对完整,取决于刷盘策略
- 文件大小:会有压缩,文件体积小---记录命令,文件体积很大
- 宕机恢复速度:很快---慢
- 数据恢复优先级:低,因为数据完整性不如AOF---高,因为数据完整性更高
- 系统资源占用:高,大量CPU和内存消耗---低,主要是磁盘IO资源,但AOF重写时会占用大量CPU和内存资源。
- 使用场景:可以容忍数分钟的数据丢失,追求更快的启动速度---对数据安全性要求较高
并发能力-主从架构
搭建主从架构:
单节点redis的并发能力是有上限的,要进一步提高redis的并发能力,就需要搭建主从集群,实现读写分离。
数据同步原理:
- 全量同步
主从第一次同步是全量同步。主-RDB->从
如何判断slave是否是第一次来同步数据:
- Replication Id:简称replid,是数据集的标记,id一致则说明是同一数据集。每一个master都有唯一的replid,slave则会继承master节点的replid。(判断是否属于同一个主从集群)
- offset:偏移量,随着记录在repl_baklog中的数据增多而逐渐增大。slave完成同步时也会记录当前同步的offset。如果slave的offset洗哦啊雨master的offset,说明slave数据落后于master,需要更新。
因此slave做数据同步,必须向master声明自己的replivation id 和offset,master才可以判断到底需要同步哪些数据
简述全量同步的流程
- slave节点请求增量同步
- master节点判断replid,发现不一致,拒绝增量同步
- master将完整内存数据生成RDB,发送RDB到slave
- slave清空本地数据,加载master的RDB
- master将RDB期间的命令记录在repl_baklog,并持续将log中的命令发送给slave
- slave执行接收到的命令,保持与master之间的同步
- 增量同步
主从第一次同步是全量同步,但如果slave重启后同步,则执行增量同步。
注意:repl_baklog大小有上限,写满后会覆盖最早的数据。如果slave断开时间过久,导致数据被覆盖,则无法实现增量同步,只能再次全量同步。
可以从以下几个方面优化redis主从集群
- 在mater中配置repl-diskless-sync yes启用无磁盘复制,避免全量同步时的磁盘IO
- redis单节点上的内存占用不要太大,减少RDB导致的过多磁盘IO
- 适当提高repl_baklog的大小,发现slave宕机时尽快实现故障恢复,尽可能避免全量同步。
- 限制一个master上的slave节点数量,如果实在是太多slave,则可以采用主-从-从链式结构,减少master压力。
总结:
简化全量同步和增量同步区别
- 全量同步:master将完整内存数据生成RDB,发送RDB到slave,后续命令则记录在repl_baklog,逐个发送给slave
- 增量同步:slave提交自己的offset给master,master获取repl_baklog中从offset子后的命令给slave
什么时候执行全量同步
- slave节点第一次连接master节点时
- slave节点断开时间太久,repl_baklog中的offset已经被覆盖时
什么时候执行增量同步
- slave节点断开又恢复,并且在repl_baklog中能找到offset时。
故障恢复-哨兵机制
sentinel的3个作用是什么
- 监控
- 故障转移
- 通知
sentinel如何判断一个redis实例是否健康
- 每隔1s发送一次ping命令,如果超过一定时间没有响应则认为是主观下线。
- 如果大多数sentinel都认为实例主观下线,则判定服务下线。
故障转移步骤有哪些
- 首先选定一个slave作为新的master
- 然后让所有节点都执行slaveof 新master
- 修改故障节点配置,添加slaveof 新master
存储能力-分片集群
主从&哨兵解决高可用、高并发问题,但仍有2个问题没有解决:
- 海量数据存储问题
- 高并发写的问题
使用分片集群可以解决上述问题,分片集群特征:
- 集群中有多个master,每个master保存不同数据
- 每个master都可以有多个slave节点
- master之间通过ping监测彼此健康状态
- 客户端请求可以访问集群任意节点,最终都会被转发到正确节点
散列插槽
redis会把每一个master节点映射到0~16383共16384个插槽(hash slot)上。
数据key不是与节点绑定,而是与插槽绑定。redis会根据key的有效部分计算插槽值,分2种情况:
- key中包含{},且{}中至少包含1个字符,{}中的部分是有效部分
- key中不包含{},整个key都是有效部分
计算方式:
利用CRC16算法得到一个hash值,然后对16384取余,得到的结果就是slot值。
redis如何判断某个key应该在哪个实例
- 将16384个插槽分配到不同的实例
- 根据key的有效部分计算哈希值,对16384取余
- 余数作为插槽,寻找插槽所在实例即可
如何将同一类数据固定的保存在同一个redis实例
- 这一类数据使用相同的有效部分,例如key都以{typeid}为前缀
集群伸缩:
增加or减少节点
故障转移
当集群中有一个master宕机会发生什么:
- 首先是该实例与其它实例失去连接
- 然后是疑似宕机
- 最后是确认下线,自动提升一个slave为新的master
数据迁移
利用cluster failover命令可以手动让集群中的某个master宕机,切换到执行cluster failover命令的这个slave节点,实现无感知的数据迁移。其流程如下:
- slave节点告诉master节点拒绝任何客户端请求
- master返回当前的数据offset给slave
- 等待该slave数据offset与master一致
- 开始故障转移
- 该slave标记自己为master,广播故障转移的结果
- master收到广播,开始处理客户端读请求
多级缓存
传统缓存的问题:
传统的缓存策略一般是请求到达Tomcat后,先查询redis,如果未命中则查询数据库,存在以下问题:
- 请求要经过tomcat处理,tomcat的性能成为整个系统的瓶颈
- redis缓存失效时,会对数据库产生冲击
多级缓存方案:
用作缓存的nginx是业务nginx,需要部署为集群,再有专门的nginx用来做反向代理: