什么是redis redis是一种基于内存的键值存储系统 常用于作为缓存 消息队列 分布式锁 排行榜等场景 最大的特点就是快 为了这一特点redis本身基于内存 底层的数据结构也有优化 对于String来说使用了SDS编码 而不是c语言的string类型 其次有ziplist跳表等高效的数据结构 除此之外redis也通过IO多路复用提高性能 那如果redis挂了怎么办 这就提到了redis的持久化机制通过RDB和AOF机制来保证redis的持久化 那如果说一个节点的redis不够用怎么办或者一个节点的压力太大了怎么办 我们又引入了redis主从模式 redis集群模式
每个主节点都有属于自己的槽位 通过命令行也可以看到 不同的节点有属于自己的槽位 总共有16384个槽位这里均分给了三个主节点

从插入操作来看看 如果请求发送错节点的时候 节点返回目标节点地址 通过-c能自动让redis-cli自动处理这一过程

Redis Cluster 没有中心元数据节点,所有节点通过 Gossip 协议 定期随机交换节点状态

|--------------------------------------------------------------------------------------------------------------------------|
| Redis 集群会出现脑裂问题吗? |

从上面的图片可以看出 我们一开始有三个主节点三个从节点 然后手动断连了一个 可以看到由于哨兵机制的存在 从节点升级为主节点了 在我们尝试给断联的旧主节点添加的时候可以看到这里触发了默认的自我保护机制 因为可以看到172.22.0.4这个节点已经被标记为故障节点了 因为在redis中 如果一个主节点无法联系到半数以上的主节点,它会拒绝写入 每个节点基于本地视角独立决策 而不是其他节点尝试连接判断该节点是否能够联系上

旧主能联系到的 master 且状态为 connected 的节点:只有它自己 (myself 那行),集群总主节点数(cluster_size)为 3,多数派阈值:3 / 2 + 1 = 2, 实际联系数:1 < 2,因此处于少数派分区,触发写入保护。
再我们关闭相关配置过后 在恢复节点的期间如果有数据插入 然后后续如果节点恢复了 旧主节点发现原来自己断联了会自动降级并清空数据
从上面也能看出来就是对于脑裂这种现象redis本身已经做了不少相关的措施了 一是默认情况下一个主节点状态为fail是无法写入数据的 又和谈数据丢失呢 二是主节点网络恢复后 因 epoch 落后自动降级为 slave 并清空数据 进一步减少了脑裂带来的影响
|------------------------------------------------------------------------------------------------------------------------|
| Redis 中如何实现分布式锁? |
考虑的点比较多 说到锁我们就能够想到只有一个线程能够获取到锁 也就是天然具有排他性 那在redis中有哪些操作或者说结构是这样的呢 自然而然能够想到set nx 对于set key value nx 来说如果key不存在则设置成功并返回OK 如果key已经存在 命令直接失败返回nil
对于我们之前学习的锁比如ReentrantLock来说是有超时锁的 那对于分布式这样的场景来说 也该有超时锁 所以自然而然能够想到通过设置超时时间 set key value NX EX 30
加完锁之后我们就需要考虑释放锁了 考虑多线程下的情况 如果A线程获取到锁 然后锁过期了 B线程拿到了锁 然后A线程释放锁 那么此时就将B线程的锁释放了 所以我们在释放锁的时候需要判断这把锁是不是自己的 但是也有可能A线程刚判断完成了 阻塞了一段时间 锁过期了 然后B线程拿到锁然后A线程释放了B线程的锁
所以我们引入了Lua脚本 对于判断锁是否是自己的和解锁操作需要保证原子性
那就引出了Redisson 刚才说的那么多其实Redission已经帮我们实现了
|----------------------------------------------------------------------------------------------------------------------------------------|
| Redis 实现分布式锁时可能遇到的问题有哪些? |
如上
|--------------------------------------------------------------------------------------------------------------------------------|
| 说说 Redisson 分布式锁的原理? |
万字解析Redission ---深入理解Redission上锁过程_redission的trylock-CSDN博客
|------------------------------------------------------------------------------------------------------------------------------|
| 如何使用 Redis 快速实现排行榜? |
通过Zset数据结构 通过得分来进行排序

考虑第一种方案 先更新数据库再更新redis 那如果说mysql更新成功了但是redis还未更新请求来了读到的是redis更新之前的数据 如果redis更新失败读取到的也是之前的数据
第二种 先更新redis再更新数据库 如果redis更新成功 但是msyql更新失败 如果redis删除操作还未进行那么此时回去读到未生效的数据
第三种 先更新数据库再删除redis 依旧有问题 和方案一一样如果读取到了删除之前的数据 如果删除redis失败了 后续读取到的都是删除之前的数据
第四种 先删除redis再删除数据库 线程A删除了redis数据 然后线程B读取发现redis没有数据从数据库读取并写入到redis种 线程A更新数据库 此时redsi和数据库种的数据不一致
对于第四种来说 正是因为执行数据修改的时候中间被其他线程操作了共享变量才导致数据不一致问题 那能不能将其他线程的影响干掉呢 我们通过等待一段时间再次删除redis种的数据 就可以保证在线程A删除redis到更新数据库的这段时间内 其他线程的操作给他干掉