磁盘I/O速度慢
,给数据库加Redis缓存(参考CPU缓存),将数据缓存在内存中,省略了I/O操作定时删除+惰性删除+内存淘汰
问题1:内存也是有空间限制的
方案1:加超时时间
问题2:超时数据量大,无法一次性删除
方案2:随机
算法删除(惰性删除)
问题3:有些超时数据运气好,一直没有被随机匹配到
方案3:在查询
时判断是否过期,确认为过期的数据被动式触发删除
问题4:没有被随机删除也没有被查询的数据越来越多
方案4:内存淘汰策略
缓存穿透:查询不存在
的数据
方案:缓存空结果null+过期时间
缓存雪崩:大量缓存同时失效
(大量不同的请求打到数据库)
方案:原有失效时间上增加随机值,即过期时间均匀分布+热点数据永不过期
缓存击穿:超高并发访问
一个正好失效的Key(大量相同的请求打到数据库)
方案:加锁(用户出现大并发访问的时候,在查询缓存的时候和查询数据库的过程加锁,只能第一个进来的请求进行执行,当第一个请求把该数据放进缓存中,接下来的访问就会直接集中缓存)
热点数据永不过期,不设置热点key的失效时间
热key:在极短的时间内访问频次非常高的key
提前预测
实时收集
本地缓存(guava cache或caffeine)
发现热点key后将其加载到JVM中,不用到DB或Redis中查询
理解:
1 请求访问热点key,先经过负载均衡器
,到达Nginx
集群,
2 再由Nginx通过负载均衡到达应用网关
,
3 网关转发到后端微服务
,
4 准备热key检测系统
5 计算得到的热key
通过SDK传入系统并写入本地缓存
,
6 请求访问本地缓存,如果存在热点key,则读取Redis并写入
本地缓存,
7 此时,前端再次访问时就可以直接从本地缓存拿到数据
冗余存储备份key
设计思想:将热key分成不同的小key
(比如key拼接节点ID),存储在不同的Redis节点上,降低数据的倾斜,通过小key分流
,分散请求到Redis节点,
将热点key拼接节点ID,去当前访问的Redis判断是否有值,如果没有则读取数据库,存入Redis并返回数据
限流熔断(兜底方案)
限流(Nginx-集成lua脚本插件、网关、微服务-hystrix或sentinel对服务接口限流)
内存
,内存的访问速度是磁盘的上千倍数据结构
实现,性能高事件处理模型
(单线程事件循环,IO多路复用,类似netty网络通信)Redis数据持久化
快照
(理解:数据备份,不同时间段的数据都放在一个RDB文件中)未保存到快照
中的那些数据。写操作命令
(理解:参考了MySQL的Binlog日志),命令会暂存在Redis的aof_buf
中,从缓存中写入AOF。子进程
进行处理指令合并重写期间
,如果进行了数据修改
,就会出现数据不一致
,aof_rewrite_buf
,从fork子进程起后面写入的命令也copy到重写缓存区,等子线程重写结束,将重写缓存区的命令写入AOF主节点
负责写,从节点
负责读数据同步
缓存区
,并设置复制偏移量
(目的:确认缺失的信息范围)解决:主节点宕机
问题,实现高可用
sentinel哨兵
负责统筹协调,监控主节点(定时去确认其响应能力)加入集群:需要和其中一个Redis(IP+端口)建立联系(类似TCP三次握手),Redis原集群内部进行同步确认
数据存储任务分配:槽位slot(类似哈希表),内存空间大的占更多的槽位。
信息同步:redis节点之间要同步自己所负责的槽位信息
问题1:数据量大,
方案1:每个槽位用1bit表示,自己负责的为1,不负责的为0
问题2:定位节点麻烦
方案2:用一个超大的数组
存储每个槽位,空间换时间
struct clusterNode *slots[16384/8];
集群工作:确认
请求的位置是不是自己负责,如果不是则返回一个moved错误给请求端,同时发出对应的负责节点的IP和端口