最近在刷面经,正好这几天补redis这块。把我这几天的整理版发下,不再面面俱到,而是偏需要理解记忆的内容。
我们只做知识的搬运工 -鲁迅
1.五种数据结构及其应用场景(重要)
类型 | 简介 | 特性 | 场景 |
string(字符串) | 二进制安全 | 可以包含任何数据,比如jpg图片或者序列化对象 | --- |
Hash(字典) | 键值对集合,即编程语言中的map类型 | 适合存储对象,并且可以像数据库中的update一个属性一样只修改某一项属性值 | 存储、读取、修改用户属性 |
List(列表) | 链表(双向链表) | 增删快,提供了操作某一元素的api | 最新消息排行;消息队列 |
set(集合) | hash表实现,元素不重复 | 添加、删除、查找的复杂度都是O(1),提供了求交集、并集、差集的操作 | 共同好友;利用唯一性,统计访问网站的所有Ip |
sorted set(有序集合) | 将set中的元素增加一个权重参数score,元素按score有序排列 | 数据插入集合时,已经进行了天然排序 | 排行榜;带权重的消息队列 |
2.分布式锁(重要)
分布式锁的解决的问题: 效率性,正确性
对锁的要求:
-
互斥性。在任意时刻,只有一个客户端能持有锁。
-
不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
-
具有容错性。只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。
-
解铃还须系铃人
至于 单机加锁的坑 ,这一块有基础的都应该了解,不再絮叨
3.引入redLock算法
问题1 :单master挂掉锁丢失 -----
问题2 :redlock 解决了单master,主从下主从替换时,锁复制可能丢失的情况,无法根本解决大延迟的情况(任务处理时间过长) 。
大延迟的情况主要通过锁的续期。 设置守护线程/watchdog 一定时间去续期,一定要续自己
启动一个watch dog看门狗,他是一个后台线程,会每隔10秒检查一下,如果客户端1还持有锁key,那么就会不断的延长锁key的生存时间
redis master-slave架构的主从异步复制导致的redis分布式锁的最大缺陷:在redis master实例宕机的时候,可能导致多个客户端同时完成加锁。无法从根本上解决,可查看国外两个大神的辩论。文末附连接。
4. 雪崩,穿透,击穿
雪崩- 缓存有数据但是同一时间失效 , Key的失效时间都加个随机值就好了,这样可以保证数据不会再同一时间大面积失效
穿透 -缓存无数据,恶意请求直接打到数据库, 接口层增加校验,比如用户鉴权,参数做校验,不合法的校验直接 ,或者使用布龙过滤器
击穿- 缓存有数据,但是单个热点Key 失效, 请求打到数据库。 缓存击穿的话,设置热点数据永不过期,或者加上互斥锁就搞定了
5. 了解持久化的方式,RDB的过程
记忆点 :fork 和 copy-on-write
-
Redis使用fork函数创建子进程;
-
父进程继续接收并处理命令请求,子进程将内存数据写入临时文件;
-
子进程写入所有数据后会用临时文件替换旧RDB文件;
6.策略淘汰机制
Redis 中数据过期策略采用定期删除+惰性删除策略。
定期删除策略:Redis 启用一个定时器定时监视所有的 key,判断key是否过期,过期的话就删除。这种策略可以保证过期的 key 最终都会被删除,但是也存在严重的缺点:每次都遍历内存中所有的数据,非常消耗 CPU 资源 。 redis 默认是每隔 100ms 就随机抽取一些设置了过期时间的 key
惰性删除策略:在获取 key 时,先判断 key 是否过期,如果过期则删除。这种方式存在一个缺点:如果这个 key 一直未被使用,那么它一直在内存中,其实它已经过期了,会浪费大量的空间。
如果经过上两种策略还会有没有清除的数据
那么内存淘汰机制相当于男人的最后一条底裤
Redis 3.0 内存淘汰机制有以下几种策略:记忆法: 1+2+3,通过英文名规律可记忆。
-
noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。(Redis 默认策略)
-
allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 Key。(推荐使用)
-
allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个 Key。
-
volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的 Key。这种情况一般是把 Redis 既当缓存,又做持久化存储的时候才用。
-
volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个 Key。
-
volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的 Key 优先移除。
配置内存淘汰机制只需要在 redis.conf 配置文件中配置 maxmemory-policy 参数即可。
7 .数据同步
主从复制的过程 记忆法:快照+缓存+增量
Redis的全量复制过程主要分三个阶段:
-
快照阶段:从结点向主结点发起SYNC全量复制命令,主节点执行bgsave将内存中全部数据生成快照并发送给从结点,从结点释放旧内存载入并解析新快照,主节点同时将此阶段所产生的新的写命令存储到缓冲区。
-
缓冲阶段:主节点向从节点同步存储在缓冲区的操作命令,这部分命令主节点是bgsave之后到从结点载入快照这个时间段内的新增命令,需要记录要不然就出现数据丢失。
-
增量阶段:缓冲区同步完成之后,主节点正常向从结点同步增量操作命令,至此主从保持基本一致的步调
增量复制是个典型的生产者-消费者模型,使用定长环形数组(队列)来实现,如果buffer满了那么新数据将覆盖老数据,因此从结点在复制数据的同时向主节点反馈自己的偏移量,从而确保数据不缺失。
无盘复制,也就是避免了生成的RDB文件落盘再加载再网络传输的过程,而是流式的遍历发送过程,主节点一边遍历内存数据,一边将数据序列化发送给从结点。
8.哨兵工作原理(故障转移的方式)
1、每个Sentinel节点都需要定期执行以下任务:每个Sentinel以每秒一次的频率,向它所知的主服务器、从服务器以及其他的Sentinel实例发送一个PING命令
2、如果一个实例距离最后一次有效回复PING命令的时间超过down-after-milliseconds所指定的值,那么这个实例会被Sentinel标记为主观下线
3、如果一个主服务器被标记为主观下线,那么正在监视这个服务器的所有Sentinel节点,要以每秒一次的频率确认主服务器的确进入了主观下线状态
4、如果一个主服务器被标记为主观下线,并且有足够数量的Sentinel(至少要达到配置文件指定的数量)在指定的时间范围内同意这一判断,那么这个主服务器被标记为客观下线
5、一般情况下,每个Sentinel会以每10秒一次的频率向它已知的所有主服务器和从服务器发送INFO命令,当一个主服务器被标记为客观下线时,Sentinel向下线主服务器的所有从服务器发送INFO命令的频率,会从10秒一次改为每秒一次
6、Sentinel和其他Sentinel协商客观下线的主节点的状态,如果处于SDOWN状态,则投票自动选出新的主节点,将剩余从节点指向新的主节点进行数据复制
7、当没有足够数量的Sentinel同意主服务器下线时,主服务器的客观下线状态就会被移除。当主服务器重新向Sentinel的PING命令返回有效回复时,主服务器的主观下线状态就会被移除。
补充:
记忆轴线:故障发现+从节点选举
-数量不够,客移除,ping 有效,主移除。
ping -time -主观下线 -所有s再次确认-(足够多s同意)客观下线-INFO 命令10s到1s一次-选主,数据复制
info 命令:主节点会返回自己的run_id和自己的从节点信息
9.集群的工作流程
文章是根据我自己的知识结构作为查漏补缺而用,不能照顾到每个读者,多包涵。
比较全的redis讲解:https://juejin.im/post/5e520c0b6fb9a07ca5303bf5
守护线程分布式锁+锁的续期:https://juejin.im/post/5c457f5a6fb9a049d37f6b55
锁的续期1: https://juejin.im/post/5d122f516fb9a07ed911d08c
大神分布式锁的辩论:https://juejin.im/post/5e6df710e51d4526fc74b4ec