5548 字
28 分钟
MySQL与Redis核心知识点
MySQL与Redis核心知识点
一、MySQL日志系统
1.1 MySQL日志分类
1.1.1 Server层日志
-
Error Log(错误日志)
- 记录MySQL服务器启动、运行和关闭过程中遇到的问题
- 包括启动参数、服务器异常、崩溃恢复、表损坏等
- 用于诊断MySQL服务器的问题
-
Slow Query Log(慢查询日志)
- 记录执行时间超过指定阈值的SQL查询
- 用于分析慢查询,使用mysqldumpslow工具分析
-
General Query Log(通用查询日志)
- 记录连接ID、IP地址、用户名、执行的SQL语句等
- 用于诊断问题、审计和性能分析
-
Binary Log(二进制日志)
- Server层生成的二进制日志
- 记录对MySQL数据库进行更改的所有操作
- 用于数据备份、数据恢复以及主从集群数据同步
1.1.2 InnoDB引擎层日志
-
Redo Log(重做日志)
- 物理日志,记录在某个数据页上做了什么修改
- 用于数据崩溃恢复,保证事务持久性
- 大小固定,循环写入
-
Undo Log(回滚日志)
- 逻辑日志,记录数据在被事务修改之前的旧值
- 实现事务原子性,主要用于事务回滚和MVCC
1.1.3 复制相关日志
-
Relay Log(中继日志)
- MySQL从库从主库同步的binlog日志
- 实现MySQL的主从异步复制
-
审计日志
- 记录数据库操作活动的日志
- 用于审计、安全和合规检查
1.2 Redo Log vs Binary Log
特性 | Redo Log | Binary Log |
---|---|---|
层次 | InnoDB引擎层 | Server层 |
用途 | 崩溃恢复,保证事务ACID | 数据备份、恢复、主从同步 |
记录内容 | 物理日志,记录数据页修改 | 逻辑日志,记录SQL语句或行变更 |
写入时机 | 事务执行过程中 | 事务提交时 |
写入方式 | 循环写入(空间固定) | 追加写入 |
持久化 | WAL机制,先写日志再写数据 | 事务提交时写入 |
1.3 Undo Log工作机制
1.3.1 事务回滚实现
- 事务之间通过链表结构记录:A → B → C
- 回滚时根据链表查找前一个状态
- 回滚后,清除或标记已回滚的undo log记录
1.3.2 Undo Log清理时机
- 当某个版本不会被任何现有和未来的事务看到时
- 读事务在ReadView中记录自己开始时看到的最大事务编号
- 如果一个事务编号小于所有当前活跃的读事务,就可以被清理
二、MySQL架构
2.1 MySQL Server架构分层
┌─────────────────────────────────┐│ 客户端连接层 │├─────────────────────────────────┤│ 服务层 ││ ┌────────────────────────┐ ││ │ NoSQL接口 │ SQL接口 │ ││ ├────────────────────────┤ ││ │ 解析器 │ 查询优化器 │ 缓存 │ ││ └────────────────────────┘ │├─────────────────────────────────┤│ 存储引擎层 ││ InnoDB │ MyISAM │ Memory │├─────────────────────────────────┤│ 系统文件层 ││ 数据文件 │ 日志文件 │ 配置文件 │└─────────────────────────────────┘
2.1.1 网络连接层
- 客户端连接器
- MySQL 8.0默认最大连接数:151
- 长连接问题:
- 临时使用的内存资源在断开时才会释放
- 长期积累可能导致内存占用过大
- 解决方案:
- 定期断开长连接
- MySQL 5.7+:执行mysql_reset_connection重置连接资源
2.1.2 服务层
- NoSQL接口:负责JSON字段的增删改查
- SQL接口:接收客户端SQL命令,响应查询结果
- 解析器:将SQL解析成解析树,检查语法和语义
- 查询优化器:
- 将解析树转换成执行计划
- 评估优化性能,选择合适索引,确定连接顺序
- 优化器局限性:
- 统计信息不准确
- 最小执行成本≠最快速度
- IO估算未考虑缓存
- 某些操作无法准确估算
2.1.3 存储引擎层
- 本质上是表处理器
- 管理表创建、数据检索、索引创建
- 支持自定义存储引擎开发
2.2 SQL语句执行过程
客户端发送SQL ↓连接器验证身份和权限 ↓[MySQL 8.0前] 查询缓存? ↓解析器:语法分析 + 语义分析 ↓优化器:生成执行计划 ↓执行器:调用存储引擎接口 ↓存储引擎:数据读写 ↓返回结果给客户端
三、MySQL索引
3.1 索引分类
3.1.1 按数据结构分
- B+ Tree索引(InnoDB默认)
- Hash索引
- Full-text全文索引
3.1.2 按物理存储分
- 聚簇索引(主键索引)
- 二级索引(辅助索引)
3.1.3 按字段特性分
- 主键索引(PRIMARY KEY)
- 唯一索引(UNIQUE)
- 普通索引(INDEX)
- 前缀索引
3.1.4 按字段个数分
- 单列索引
- 联合索引(复合索引)
3.2 B树 vs B+树
特性 | B树 | B+树 |
---|---|---|
数据存储 | 所有节点都存储数据 | 只有叶子节点存储数据 |
叶子连接 | 叶子节点间无连接 | 叶子节点双向链表连接 |
查询效率 | 不稳定(1~h次) | 稳定(始终h次) |
范围查询 | 需要中序遍历 | 直接遍历叶子链表 |
空间利用 | 较低 | 较高(非叶子节点只存索引) |
树高度 | 相对较高 | 相对较矮 |
3.2.1 为什么MySQL选择B+树
B+树结构示例: [10|20] <- 只存索引 / | \[5|10] [15|20] [25|30] <- 只存索引 ↓ ↓ ↓[5]←→[10]←→[15]←→[20]←→[25]←→[30] <- 数据+双向链表
优势:
- 磁盘I/O友好:非叶子节点不存数据,单节点可存更多索引
- 范围查询高效:通过叶子节点链表顺序访问
- 查询性能稳定:所有查询路径长度相同
- 更高的扇出:树更矮,减少I/O次数
3.3 InnoDB三大特性
- 自适应Hash索引:自动为热点数据建立Hash索引
- Buffer Pool:缓冲池,减少磁盘I/O
- 双写缓冲区:保证数据页的可靠性
3.4 索引失效场景
3.4.1 索引生效条件
- 全值匹配(=、<、>、IN等)
- 最左前缀原则
- 范围查询
- ORDER BY排序
- GROUP BY分组
3.4.2 索引失效场景
- 违反最左前缀原则:联合索引未从第一个字段开始
- 使用函数或运算:
WHERE DATE(create_time) = '2024-01-01'
- 隐式类型转换:字符串字段与数字比较
- 索引选择性差:如性别字段
- OR条件:存在非索引字段
- 索引碎片过多:需要重建索引
- 数据量太小:优化器选择全表扫描
- 优化器估算错误:统计信息不准确
3.5 索引优化口诀
- 全值匹配我最爱,最左前缀要遵守
- 带头大哥不能死,中间兄弟不能断
- 索引列上少计算,范围之后全失效
- LIKE百分写最右,覆盖索引不要星
- 不等空值还有OR,索引影响要注意
- 字符引号不能丢,SQL优化有诀窍
四、MySQL事务
4.1 事务隔离级别
4.1.1 并发问题
- 脏读:读到其他事务未提交的数据
- 不可重复读:同一事务内两次读取同一行数据结果不同
- 幻读:同一事务内两次查询结果集行数不同
4.1.2 隔离级别与解决方案
隔离级别 | 脏读 | 不可重复读 | 幻读 | 实现机制 |
---|---|---|---|---|
读未提交 | ✗ | ✗ | ✗ | 无隔离 |
读已提交 | ✓ | ✗ | ✗ | MVCC(每次SELECT生成ReadView) |
可重复读 | ✓ | ✓ | ✓* | MVCC(首次SELECT生成ReadView)+ Next-Key Lock |
串行化 | ✓ | ✓ | ✓ | 所有SELECT自动加共享锁 |
*注:MySQL InnoDB的可重复读通过Next-Key Lock解决了幻读问题
MySQL默认隔离级别:可重复读(REPEATABLE READ)
4.2 MVCC机制
4.2.1 版本链
每行数据在InnoDB中有隐藏列:
DB_TRX_ID
:最后修改的事务IDDB_ROLL_PTR
:回滚指针,指向undo logDB_ROW_ID
:隐藏主键(无主键时使用)
4.2.2 ReadView
ReadView包含:
m_ids
:活跃事务ID列表min_trx_id
:最小活跃事务IDmax_trx_id
:下一个要分配的事务IDcreator_trx_id
:创建该ReadView的事务ID
4.2.3 可见性判断
if (DB_TRX_ID < min_trx_id) return 可见; // 事务已提交else if (DB_TRX_ID >= max_trx_id) return 不可见; // 事务在ReadView后开始else if (DB_TRX_ID in m_ids) return 不可见; // 事务未提交else return 可见; // 事务已提交
4.3 当前读 vs 快照读
4.3.1 快照读(Snapshot Read)
- 普通SELECT(不加锁)
- 基于MVCC读取快照版本
- 不加任何锁
SELECT * FROM table WHERE id = 1;
4.3.2 当前读(Current Read)
- 读取最新版本并加锁
- 触发场景:
-- SELECT加锁SELECT ... FOR UPDATE; -- 加X锁SELECT ... FOR SHARE; -- 加S锁
-- DML操作(都是当前读)UPDATE table SET ...; -- 加X锁DELETE FROM table WHERE ...; -- 加X锁INSERT INTO table VALUES ...; -- 加插入意向锁
4.3.3 UPDATE的特殊性
-- 事务ASTART TRANSACTION;SELECT * FROM user WHERE id = 1; -- 快照读,age = 20
-- 事务BUPDATE user SET age = 21 WHERE id = 1;COMMIT;
-- 事务A继续SELECT * FROM user WHERE id = 1; -- 快照读,仍是age = 20UPDATE user SET name = 'Tom' WHERE id = 1; -- 当前读,读到age = 21
UPDATE必须是当前读的原因:
- 保证数据一致性
- 避免丢失更新
- 通过锁机制防止并发问题
4.4 InnoDB串行化实现
InnoDB的串行化不是物理串行执行,而是通过锁机制实现:
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
-- 所有SELECT自动转换为SELECT ... FOR SHARE; -- 自动加S锁 + Next-Key Lock
-- DML操作UPDATE/DELETE/INSERT; -- 加X锁 + Next-Key Lock
锁策略:
- SELECT:自动加共享锁 + Next-Key Lock(行锁+间隙锁)
- DML:加排他锁 + Next-Key Lock
- 范围查询:锁定整个范围,完全防止幻读
五、MySQL锁机制
5.1 锁分类
5.1.1 按操作类型
- 共享锁(S锁):读锁,不阻塞读,阻塞写
- 排他锁(X锁):写锁,阻塞其他读写
5.1.2 按粒度分类
表级锁:
- 表锁:锁整张表,粒度大,并发低
- 元数据锁(MDL):Server层表锁,DDL时阻塞DML
- 自增锁(AUTO-INC):保证自增值并发安全
- 意向锁:
- 意向共享锁(IS):事务想获取S锁
- 意向排他锁(IX):事务想获取X锁
- 作用:快速判断表中是否有行锁
行级锁:
- 记录锁(Record Lock):锁定单行记录
- 间隙锁(Gap Lock):锁定范围,防止插入
- 临键锁(Next-Key Lock):记录锁+间隙锁
- 插入意向锁:INSERT专用,间隙锁的特殊类型
5.1.3 按态度分类
- 乐观锁:提交时检测冲突(版本号/CAS)
- 悲观锁:操作前加锁(InnoDB各种锁)
5.2 加锁规则
- DELETE:当前读,加X锁
- INSERT:加插入意向锁
- UPDATE:当前读,加X锁
六、MySQL优化
6.1 深度分页优化
问题:LIMIT 1000000, 10
需要扫描100万条数据
优化方案:
-- 1. 使用子查询(延迟关联)SELECT * FROM table t1JOIN (SELECT id FROM table LIMIT 1000000, 10) t2ON t1.id = t2.id;
-- 2. 记录上次位置SELECT * FROM table WHERE id > last_id LIMIT 10;
-- 3. 使用覆盖索引SELECT id, name FROM table LIMIT 1000000, 10; -- (id,name)建立联合索引
6.2 表设计优化
- 选择合适的数据类型(定长用CHAR)
- 字段设置NOT NULL + 默认值
- 只创建必要的索引
- 日期比较存储为UNSIGNED INT
6.3 SQL优化建议
- 小表驱动大表
- 避免SELECT *
- 使用TRUNCATE代替DELETE FROM
- 合理使用索引覆盖
- 避免在索引列上计算
6.4 常用SQL技巧
-- 自定义排序SELECT * FROM t1 WHERE id IN (7,3,1,4,5,8,10)ORDER BY FIELD(id, 7,3,1,4,5,8,10);
-- NULL值排最后SELECT * FROM t1ORDER BY IF(ISNULL(k3), 1, 0), k1, k2 LIMIT 10;
-- 统计分析SELECT COUNT(DISTINCT user_id) as total_users, SUM(quantity * price) as total_sales, SUM(quantity * price) / COUNT(DISTINCT user_id) as avg_priceFROM orders;
-- 分组汇总SELECT product_id, SUM(quantity * price) as sales, CASE WHEN SUM(quantity * price) < 100 THEN '低' WHEN SUM(quantity * price) < 200 THEN '中' ELSE '高' END as levelFROM ordersGROUP BY product_id WITH ROLLUP;
-- 多条件筛选示例SELECT DISTINCT user_idFROM ordersWHERE user_id IN ( SELECT user_id FROM orders WHERE product_id = 101)AND user_id IN ( SELECT user_id FROM orders WHERE product_id = 102)AND user_id NOT IN ( SELECT user_id FROM orders WHERE product_id = 103);
七、Redis数据类型
7.1 五大基础数据类型
7.1.1 String(字符串)
- 底层实现:SDS(Simple Dynamic String)
- 应用场景:
- 缓存对象(JSON序列化)
- 计数器(INCR/DECR)
- 分布式锁(SET NX EX)
- Session共享
7.1.2 List(列表)
- 底层实现:quicklist(双向链表+压缩列表)
- 应用场景:
- 消息队列(LPUSH/BRPOP)
- 文章列表、Timeline
- 关键命令:LPUSH/RPUSH、LPOP/RPOP、LRANGE、BRPOP(阻塞)
7.1.3 Hash(哈希)
- 底层实现:ziplist → hashtable(元素增多时转换)
- 应用场景:
- 对象存储(用户信息、商品信息)
- 购物车(用户ID为key,商品ID为field)
- 优势:可以只修改对象的某个字段
7.1.4 Set(集合)
- 底层实现:intset → hashtable
- 应用场景:
- 共同好友(SINTER交集)
- 点赞用户(去重)
- 抽奖系统(SRANDMEMBER)
- 集合操作:交集(SINTER)、并集(SUNION)、差集(SDIFF)
7.1.5 ZSet(有序集合/Sorted Set)
- 底层实现:
- ziplist(元素少时)
- skiplist(跳表)+ hashtable(元素多时)
- 特点:每个成员关联一个score分数,按分数排序
- 核心应用场景:
- 排行榜系统:游戏排行、热搜榜单
- 延迟队列:score存储执行时间戳
- 滑动窗口限流:score存储时间戳,统计时间窗口内请求数
- 优先级队列:score表示优先级
面试重点:ZSet为什么用跳表而不用红黑树?
- 范围查询效率高:跳表遍历更简单,红黑树需要中序遍历
- 实现简单:跳表比红黑树的实现和调试更简单
- 内存占用灵活:可以通过调整索引构建概率来平衡内存和性能
- 并发友好:跳表更容易实现无锁操作
7.2 三大特殊数据类型(面试常考)
7.2.1 Bitmap(位图)
- 本质:String的位操作
- 典型应用:
- 用户签到(一年365天仅需46字节)
- 在线状态统计
- 布隆过滤器基础
- 优势:极度节省内存
7.2.2 HyperLogLog
- 用途:基数统计(去重计数)
- 特点:固定12KB内存,误差率0.81%
- 应用:UV统计(独立访客数)
7.2.3 GEO(地理位置)
- 底层:基于ZSet实现(GeoHash编码作为score)
- 应用:附近的人、距离计算
7.3 数据类型选择(面试必备)
场景 | 数据类型 | 选择理由 |
---|---|---|
缓存用户信息 | String/Hash | String简单;Hash可部分更新 |
排行榜 | ZSet | 自动排序,支持范围查询 |
消息队列 | List/Stream | List简单;Stream功能完整 |
共同好友 | Set | 交集运算 |
用户签到 | Bitmap | 节省内存 |
UV统计 | HyperLogLog | 固定内存消耗 |
附近的人 | GEO | 原生地理位置支持 |
分布式锁 | String | SET NX EX原子操作 |
八、Redis持久化
8.1 RDB(快照)
8.1.1 触发条件
默认配置:
- 900秒内有1次修改
- 300秒内有10次修改
- 60秒内有10000次修改
8.1.2 特点
- 优点:
- 压缩的二进制文件,体积小
- 恢复速度快
- 适合备份和灾难恢复
- 缺点:
- 可能丢失最后一次快照后的数据
- fork子进程时可能阻塞
8.2 AOF(追加日志)
8.2.1 写入流程
命令执行 → AOF缓冲区 → 系统调用write → 内核缓冲区 → fsync → 磁盘
8.2.2 同步策略
- always:每个命令都同步,最安全但性能最差
- everysec:每秒同步一次(默认)
- no:由操作系统决定
8.2.3 AOF重写
- 目的:解决AOF文件过大问题
- 机制:创建新AOF文件,合并命令,只保留最终状态
8.3 混合持久化(4.0+)
- RDB快照 + AOF增量日志写入同一文件
- 结合两者优势:快速恢复 + 低数据丢失风险
九、Redis缓存问题
9.1 缓存穿透
问题:大量请求不存在的数据,直接打到数据库
解决方案:
- 参数校验:拦截非法请求
- 缓存空值:将NULL结果缓存短时间
- 布隆过滤器:快速判断数据是否存在
- 注意:标准布隆过滤器不支持删除
- 可用Counting Bloom Filter支持删除
9.2 缓存击穿
问题:热点数据过期,大量请求打到数据库
解决方案:
- 热点数据永不过期
- 分布式锁:只允许一个请求查询数据库
- 双Key策略:主Key过期时间短,备Key过期时间长
- 缓存预热:定时更新热点数据
9.3 缓存雪崩
问题:大量缓存同时过期或Redis宕机
解决方案:
避免同时过期:
- 随机过期时间:基础时间 + 随机值
- 互斥锁:使用singleflight等工具
- 二级缓存:本地缓存 + Redis
- 缓存预热:提前加载热点数据
避免Redis宕机影响:
- 高可用集群:主从、哨兵、Cluster
- 限流降级:保护数据库
- 熔断机制:快速失败
十、缓存与数据库一致性
10.1 一致性问题的本质
缓存一致性问题通常发生在”缓存数据存在业务更新”的场景,核心问题是:缓存删除前旧数据被查询到,并在删除后旧数据执行了覆盖。
10.2 更新策略对比
10.2.1 Cache Aside Pattern(旁路缓存)
主流方案,分为读写两个流程:
写操作:
1. 更新数据库2. 删除缓存
读操作:
1. 读缓存,命中返回2. 未命中,读数据库3. 写入缓存
10.2.2 各种更新策略的问题
策略 | 操作顺序 | 主要问题 | 发生条件 |
---|---|---|---|
先删缓存,后更新DB | redis.delete() → db.update() | 旧数据回填 | 并发读在删除后、更新前查询DB |
先更新DB,后删缓存 | db.update() → redis.delete() | 短暂不一致 | 删除失败或延迟 |
先更新缓存,后更新DB | redis.set() → db.update() | DB更新失败导致不一致 | 缓存有新值,DB是旧值 |
10.3 延迟双删策略
10.3.1 核心思想
删除缓存 → 更新数据库 → 延迟N秒 → 再次删除缓存
延迟时间计算公式:
延迟时间 = 1.5 * TP99( 数据主从同步时间 + 数据库查询时间 + 写入缓存时间)
10.3.2 实现方式演进
1. 同步延迟双删
// 问题:阻塞业务线程,增加接口RTredis.delete(key);db.update();Thread.sleep(100); // 阻塞当前线程redis.delete(key);
2. 异步延迟双删
// 优点:不阻塞主线程// 问题:重启时丢失延迟任务redis.delete(key);db.update();executorService.schedule(() -> { redis.delete(key);}, 100, TimeUnit.MILLISECONDS);
3. MQ延迟双删
// 优点:持久化,重启不丢失// 问题:增加系统复杂度redis.delete(key);db.update();mq.sendDelay("DELETE_CACHE_TOPIC", key, 100);
4. 监听Binlog异步删除
// 优点:无代码侵入,解耦业务// 实现:Canal监听MySQL binlog业务代码: db.update(); // 仅更新数据库
Canal系统: 监听binlog → 删除缓存 → 延迟删除
10.4 最佳实践建议
10.4.1 方案选择
- 简单系统:使用”先更新DB,后删缓存”
- 中等复杂度:使用MQ异步延迟双删
- 复杂系统:使用Binlog + Canal方案
10.4.2 注意事项
- 延迟双删不是万能的:只能大概率解决问题
- 读写分离场景:必须考虑主从延迟
- 不要过度设计:根据业务容忍度选择方案
- 分布式锁谨慎使用:
- 串行化会严重影响性能
- 增加Redis强依赖
- 可能导致雪崩效应
10.4.3 核心原则
- 最终一致性:接受短暂不一致,保证最终一致
- 业务优先:根据业务对一致性的要求选择方案
- 避免强一致:如果要求强一致,不应使用缓存
- 监控告警:建立完善的监控体系
10.5 一致性问题总结
问题根源:
- 缓存和数据库是两个独立系统
- 无法保证原子性操作
- 网络延迟和故障
解决思路:
- 尽量避免不一致(合理的更新策略)
- 降低不一致影响(缩短时间窗口)
- 接受最终一致性(合理的业务预期)
十一、Redis内存管理
11.1 过期删除策略
Redis采用惰性删除 + 定期删除组合策略:
- 惰性删除:访问时检查是否过期
- 定期删除:定时任务随机抽样删除
- 过期字典:Hash表存储key和过期时间
11.2 内存淘汰策略
当内存不足时(maxmemory限制):
策略 | 说明 |
---|---|
noeviction | 不淘汰,拒绝写入(默认) |
allkeys-lru | 所有key中淘汰最近最少使用 |
allkeys-lfu | 所有key中淘汰最不频繁使用 |
allkeys-random | 所有key中随机淘汰 |
volatile-lru | 过期key中淘汰最近最少使用 |
volatile-lfu | 过期key中淘汰最不频繁使用 |
volatile-random | 过期key中随机淘汰 |
volatile-ttl | 淘汰TTL最短的key |
11.3 LRU vs LFU
11.3.1 LRU(Least Recently Used)
传统LRU:
- 双向链表实现
- 访问移到头部
- 淘汰尾部
Redis近似LRU:
- 随机采样(默认5个)
- 记录最后访问时间戳
- 淘汰最久未访问的
- 问题:缓存污染(大量数据一次性读取)
11.3.2 LFU(Least Frequently Used)
Redis LFU实现:
- 24位字段:16位时间戳 + 8位访问频率
- 访问频率采用对数增长
- 解决了LRU的缓存污染问题
11.4 大Key问题
11.4.1 判断标准
- String类型:value > 1MB
- 集合类型:元素数 > 10000
11.4.2 影响
- 内存占用过多
- 网络传输阻塞
- 主从同步延迟
- 集群数据倾斜
- 影响持久化性能
11.4.3 解决方案
- 拆分:大Key拆分为多个小Key
- 异步删除:使用UNLINK代替DEL
- 过期时间:设置更短的TTL
- 定期扫描:及时发现并处理
十二、Redis高可用
12.1 主从复制
12.1.1 同步方式
-
全量同步:
- 主节点生成RDB快照
- 发送RDB文件给从节点
- 发送缓冲区命令
-
增量同步:
- 基于复制缓冲区(repl_backlog_buffer)
- 使用PSYNC命令实现部分重同步
- 通过offset判断同步位置
12.1.2 一致性判断
通过复制偏移量(replication offset)判断主从是否一致
12.2 哨兵模式
12.2.1 故障检测
- 组建哨兵集群:通过发布/订阅机制来监控主从节点
- 监控节点:
- 定期发送PING命令
- 通过INFO命令获取从节点信息
- 故障判定:
- 主观下线:单个哨兵判定
- 客观下线:达到quorum数量哨兵同意
12.2.2 故障转移
- 选举Leader哨兵:
- 需要majority(超过半数)票数
- 注意:quorum和majority是不同的值
- 选择新主节点:
- 优先级(replica-priority)
- 复制偏移量(数据最新)
- Run ID(最小者胜出)
- 执行切换:
- 被选出的从节点执行SLAVEOF NO ONE
- 其他从节点指向新主
- 通知客户端新主节点信息
12.3 Redis Cluster
- 16384个槽位(slots)
- 数据分片存储
- 去中心化架构
- 自动故障转移
MySQL与Redis核心知识点
https://fuwari.vercel.app/posts/database_and_redis/