Redis:我大哥是mysql
Redis:我大哥是mysql
本文说明:简单梳理redis的设计
redis某种角度上只是mysql的手下的工具人
1.缓存管理
redis的出现:作为缓冲区、以免mysql被大量请求冲烂宕机
如果同时有很多请求、对mysql进行查询,就会造成mysql服务器的压力。而其中往往有一部分是进行重复的操作、多次查询同一内容,如果类比cpu设计一个缓存区、把近期用到的数据都存入内存中,就可以减轻mysql的处理压力。
1.1.定期删除
而随着时间的积累,单纯把近期查询的数据、直接放入内存,会使内存容量爆满,需要定期删除。
如果每执行一次删除操作就要遍历一遍数据、检查是否过期,则会花费太多资源,所以用随机检查,随机到的数据一旦过期就删除。
1.2.惰性删除
如果有数据特别侥幸,随机算法并不能抽到,依旧会长久的留存。所以检查每次请求的数据是否过期,过期数据直接删除。(被查询到才检查、然后执行删除 -> 被动行为,所以叫惰性删除)
1.3.内存淘汰
redis提供八种机制,让上层应用自行选择(可以更好的适配机器内存大小、业务需求)
- noeviction:使用的内存超过配置则return err,不会删除任何key
- allkeys-lru:新增key时过限,优先用LRU算法删除最久没有使用的key
- volatile-lru:新增key时过限,从设置过期时间的key中删除最久没有使用的key
- allkeys-random:新增key时过限,全局随机删除key
- volatile-random:新增key时过限,从过期集合中随机删除key
- volatiole-ttl:从设置过期时间的key中删除即将要过期的key
- volatile-lfu:从设置过期时间的key中删除使用频率最少的key
- allkeys-lfu:全局删除使用频率最少的key
1.4.可能出现的问题
-
缓存击穿(穿透)
一句话概括:跳过redis,查询mysql中不存在的数据
大量的业务请求发送过来,而redis中没有记录相关数据,请求们就会直接发到mysql、给mysql施加极大的压力。
-
缓存雪崩
一句话概括:大量数据热点同事过期、又被嘎嘎请求访问,越过redis查询mysql造成mysql宕机;也可能是redis故障、缓存系统异常导致。
解决方案:
- 热点问题设为永不过期、普通key过期时间随机设置
- 缓存空值:请求的数据不在redis里,设置缺省值(None),后续再次查询直接返回缺省值(空值)
- 布隆过滤器:同步数据库中存储的数据ID,如果请求的id不存在过滤器里,说明数据库里就没有该数据,别继续查询了
- 接口限流
- 服务熔断:从缓存获取数据发现异常,就直接返回错误数据给前端、避免所有的流量都挤到mysql
2.数据持久化
要是因为电路问题导致服务器意外宕机,则把数据存到内存的redis就会丢失所有内容,请求压力又会来到mysql身上;所以需要进行redis缓存文件备份。
2.1.rdb备份文件
采用rdb文件记录每一次的文件,并把数据备份到硬盘上;但是每一次完整的扫描、备份都将花费大量的时间,同时占用过多的硬盘资源。
2.2.AOF记录文件
采用AOF文件记录近期redis每一次执行的操作、同时把近似的指令合并(比如请求1“查询学生小张的年龄”,请求2“查询学生小张的班级” -> 合并为“查询学生小张”+“年龄”+“班级”),以免AOF文件过于冗杂。
- 如果每一次执行的操作都直接对AOF文件进行一次读写,则大量请求导致大量redis操作会在AOF的I/O交互上花费过多的时间
- 用增加一个临时缓冲区(AOF-buf)来放置一定量的操作指令,避免高频读写AOF
3.哨兵
避免redis宕机、恢复数据需要花费的时间,考虑多个服务器协作。区分为主-从节点,主节点直接缓存请求,从节点负责接收主节点的消息,存储、同步主节点的数据。
为了确保从节点上的内容跟主节点同步,可以用数据游标(复制偏移量)记录当前节点执行的操作次数,比较游标值即可。
当主节点宕机,立马用从节点顶上来作为新的主节点,等到原主节点修复以后,再被分配到现主节点下同步数据。
哨兵的工作就是:
- 定时ping节点,检查有无宕机
- 哨兵有多个、内部可进行通信,当有一个哨兵检测到a机子宕机,则发请求让其余哨兵也测试a机子,都无法连通时认为该机凉了
- 选定新的主节点上位、等原主节点修复后并入当前主节点手下,避免人为操作
4.集群
集群就是一堆redis服务器一起工作。链接远程节点:类比tcp三次握手
为了扩大存储空间,让每个服务器都存储一部分数据,类比hash表,先把所有数据用hash划分为n个槽位,再分配每个槽位的数据由哪台服务器来负责。
可以简单的用bit表示,0和1来记录每个槽位是否由自己负责的;不过一次遍历还是要花时间、那就用空间换时间,直接数组记录某个槽位的节点是哪台机子。