MySQL
数据库原理
一、优势
MySQL : 互联网企业使用第一
Oracle : 互联网之外企业使用第一
- 体积小、速度快
- 开源免费、维护成本低
- 易扩展、高可用
二、架构演进
1. 单机单库
瓶颈
- 数据量 过大
- 读/写操作量 过大
- 可用性 差
2. 主从架构
解决 高可用、读压力 问题
瓶颈
- 数据量 过大
- 写操作量 过大
3. 分库分表
解决 数据量、写压力 问题
4. 云数据库
服务提供商 负责解决 可配置性、可扩展性、多用户存储结构设计 问题
三、体系架构
1. 服务层
- 连接池 Connection Pool - 保存、管理 客户端与数据库的连接,一个线程管理一个连接
- 系统管理和控制工具 Management Services & Utilities - 备份恢复、安全管理、集群管理
- SQL 接口 SQL Interface - 接收来自客户端的 SQL 命令,返回结果给客户端
- 解析器 Parser - 将 SQL 生成解析树,并检查是否合法
- 查找优化器 Optimizer - 将解析树转换成运行计划
- 缓存 Cache&Buffer - 将 SQL 语句与结果进行缓存,若下次查找有命中缓存则直接返回结果
2. 存储引擎层
- 负责数据的存储与提取
- 插件式的存储引擎,屏蔽不同引擎间的差异
3. 系统文档层
负责将 数据、日志 存储在操作系统上
-
日志文档
-
错误日志 -【默认】开启 - show variables like '%log_error%';
-
通用日志 - 记录 SQL 查找语句 - show variables like '%general%';
-
二进制日志 - 纪录 SQL 增删改语句 - 用于 数据库恢复、主从复制
- 是否开启 - show variables like '%log_bin%';
- 查看参数 - show variables like '%binlog%';
- 查看日志 - show binary logs;
-
慢查找日志 - 纪录超时 SQL 查找语句 - 【默认】10 秒
-
是否开启 - show variables like '%slow_query%';
-
查看时长设置 - show variables like '%long_query_time%';
-
-
-
配置文档
-
my.cnf
-
my.ini
-
-
数据文档
-
db.opt - 库默认字符集、校验规则
-
frm - 与表相关的元数据(表结构) - 每张表都有一个
-
ibd - InnoDB 表的索引和数据 - 每张 InnoDB 表都有一个
-
MYI - MyISAM 表的索引 - 每张 MyISAM 表都有一个
-
MYD - MyISAM 表的数据 - 每张 MyISAM 表都有一个
-
ibdata1 - 系统表数据、存储表元数据、Undo日志
-
ib_logfile0、ib_logfile1 - Redo 日志
-
-
pid 文档
- 存储自己进程的 ID
四、查找运行机制
-
创建连接 - 客户端与 MySQL 创建半双工连接
-
查看线程状态 - show processlist;
全双工 : 能同时 发送 和 接收 数据 - 打电话
半双工 : 同一时刻,要么发送数据,要么接收数据,不能同时 - 无线电对讲机
单工 : 只能发送【或】只能接收数据 - 单行道
-
-
查找缓存 - 当缓存命中则直接返回结果,否则将调用语法解析器
- SQL 语句和参数必须完全相同,才能命中缓存
- 不能缓存情况
- 查找语句使用 SQL_NO_CACHE
- 查找结果数量大于 query_cache_limit
- SQL 语句中有动态参数 - now()
- 查找 缓存启用、大小、限制 - show variables like '%query_cache%';
- 查找 详细缓存参数、空间 - show status like 'Qcache%';
-
语法解析
- 使用 解析器(Parser) 将 SQL 语句生成 解析树
- 使用 预处理器 检查 解析树 是否合法 - 数据表、数据字段 是否存在
- 生成 新解析树
-
查找优化 - 使用 查找优化器(Optimizer) 根据 解析树 生成最优计划
- 等价变换
- 5=5 and a>5 → a > 5
- a < b and a = 5 → b > 5 and a = 5
- count、min、max 函数优化
- InnoDB引擎
- min 函数只需要找索引最左边
- max 函数只需要找索引最右边
- MyISAM引擎
- count(*) 不需要计算,直接返回
- InnoDB引擎
- 提前终止查找
- limit 获取到所需的数据,就不再往后遍历
- in 函数排序
- where id in (2,1,3) → where id in (1,2,3)
- 等价变换
-
运行查找 - 调用查找引擎,查找引擎 调用 存储引擎 进行 SQL 查找
- 若返回结果过多,采增量模式返回
五、存储引擎
- InnoDB【默认】
- 支持 事务、外键 且 事务安全
- 行级锁 - 支持高并发
- 适合大量 insert、update 操作
- 使用 聚簇索引 - 将 索引 和 数据 一同存储
- 两个存储文档 - .frm 表结构、.ibd 索引&数据 - 单表最大支持 64 TB
- MyISAM
- 不支持 事务、外键
- 访问速度快
- 表级锁 - 并发能力低
- 适合大量 select 操作
- 使用 非聚簇索引 - 索引 和 数据 分开存储
- 三个存储文档 - .frm 表结构、.MYI 表索引、.MYD 表数据 - 单表默认支持 256 TB
- Memory
- 利用内存创建表 - 访问速度非常快
- 应用关闭,数据丢失
- Csv
- 以 CSV 文档存储数据
- 所有 Column 必须 非null
- 不支持 索引、分区
- 适合做 数据交换的中间表
- BlackHole
- 数据只进不出,所有插入的数据都不会保存
六、InnoDB 结构
1. 内存
-
Buffer Pool (BP) 缓冲池
当有新的数据要写入到 Buffer Pool 时,InnoDB 会判断 Free Page 是否足够
如果足够,就将 Free Page 从 Free List 中删除,加到 Lru List 中
如果不足,淘汰 Lru List 末尾的 Page,释放内存空间给新的 Page
-
使用链表结构管理 Page
-
Page 类型
- 默认大小 16 K
- Free Page - 未被使用过
- Clean Page - 已被使用,但数据还未被修改
- Dirty Page - 已被使用,数据也被修改,导致 Page数据 与 磁盘数据 产生不一致
-
链表类型
- Free List 空闲缓冲区 - 管理 Free Page
- Flush List 刷盘缓冲区 - 管理 Dirty Page,按 Page 修改时间排序
- Lru List 使用中缓冲区 - 以 midpoint 为基点,管理 Clean Page 与 Dirty Page
-
前 63% 为 new 列表,存放常用数据
-
后 37% 为 old 列表,存放少用数据
-
脏页 既存在于 Flush List 也存在于 Lru List,链表间互不影响
-
LRU 算法
- 普通 LRU - 末位淘汰,新数据从链表头部加入,释放时从末位淘汰
- 改进 LRU - 新数据从 midpoint 插入,数据被访问时,将向链表头部移动,否则将逐渐向尾部移动,等待淘汰
-
参数
-
查看 Page 大小 - show variables like '%innodb_page_size%';
-
查看 Buffer Pool 参数 - show variables like '%innodb_buffer%';
【建议】innodb_buffer_pool_size 设为总内存的 60% ~ 80%
【建议】innodb_buffer_pool_instances 设为多个,避免缓存争夺
-
-
-
Change Buffer (CB) 写缓冲区 - 进行增删改操作时,若 BP 中没有对应的 Page 数据,将会在 CB 中做纪录,待未来数据被读取时,再将数据合并恢复到 BP 中;若 BP 中有对应数据,则直接在 BP 中更改
- 默认占用 BP 空间 25%,最大允许 50%
- 仅适用 非唯一普通索引 Page - 因为做唯一性校验,必须查找硬盘
-
Adaptive Hash Index 自适应哈希索引 - 优化对 BP 查找
- InnoDB 引擎会自动根据访问频率和模式创建 Hash 索引
-
Log Buffer 日志缓冲区 - 保存 Redo/Undo 数据
- Redo Log 刷盘模式 innodb_flush_log_at_trx_commit
- 0 : 每隔 1 秒 写日志、刷盘 - 最多丢失 1 秒数据
- 【默认】1 : 事务提交,立刻写日志、刷盘,不丢失数据 - 最安全、性能差
- 【建议】2 : 事务提交,将 Log 写入 OS Cache,OS Cache 每隔 1 秒 刷盘
- Redo Log 刷盘模式 innodb_flush_log_at_trx_commit
2. 硬盘
-
Redo Log 重做日志
-
在崩溃恢复期间,用于修复不完整的事务数据
-
当事务开始,产生 Redo Log,事务提交时将 Redo Log 写入 Log Buffer
-
采用顺序循环方式写入文档,写满则回溯到第一个文档,进行覆盖
-
当事务的 Dirty Page 被写入磁盘,Redo Log 占用的空间即可被重用
-
Redo Log 为顺序写入效率高,直接将纪录写入 ibd 属于非顺序写入,效率低
-
show variables like '%innodb_log%';
-
-
Undo Log 撤销日志
-
在事务开始前,保存数据被修改前的状态,用于回滚事务
-
逻辑日志,纪录相反的运行过程
- delete ←→ insert
- update → 原始数据的 update
-
实现 MVCC(多版本并发控制) - 为其他并发事务提供旧数据进行快照读
-
show variables like '%innodb_undo%';
-
-
Binlog 二进制日志
-
纪录 表结构变更、表数据修改
-
用于 主从复制、mysqlbinlog 工具数据恢复
-
纪录模式
- ROW
- 日志记录每一行的修改【结果】
- 优点 - 完全实现主从同步
- 缺点 - 日志暴涨
- STATMENT
- 日志将 SQL 语句复制
- 优点 - 日志量小
- 缺点 - 少数情况导致数据不一致 - last_insert_id()、now()
- MIXED
- 根据 SQL 语句将以上两种模式混合使用
- ROW
-
show variables like 'log_bin';
Redo Log 与 BinLog 区别
- Redo Log 专属于 InnoDB;Binlog 是 MySQL 自带
- Redo Log 是用二进制存储的物理日志,纪录更新【结果】;Binlog 是 逻辑日志,纪录更新【过程】
- Redo Log 是循环写,大小固定;Binlog 追加写,不会覆盖
-
3. 线程
IO Thread
使用大量的 AIO 做读写处理,提高数据库性能
-
Read Thread - 负责将数据从磁盘加载到 Page - 4 个
-
Write Thread - 负责将 Dirty Page 刷新到磁盘 - 4 个
-
Log Thread - 负责将 Log Buffer(日志缓冲区) 内容刷新到磁盘 - 1 个
-
Insert Buffer Thread - 负责将 Chage Buffer(写缓冲区) 内容刷新到磁盘 - 1 个
Purge Thread
- 回收不需要的 Undo Page (事务已提交完成)
- show variables like '%innodb_purge_threads%';
Page Cleaner Thread
- 负责调用 Write Thread 将 Dirty Page 进行刷盘
- show variables like '%innodb_page_cleaners%';
Master Thread
- InnoDB 主线程,负责调度其他线程,优先级最高
- 每 1 秒操作
- 调用 Log Thread,将 Log Buffer 刷新到磁盘
- 判断 IO 压力,决定是否合并 Chage Buffer(写缓冲区)
- 判断 Dirty Page 比例(75%),决定是否调用 Write Thread 刷新 Dirty Page 到磁盘
- 每 10 秒操作
- 调用 Write Thread 刷新 Dirty Page 到磁盘
- 合并 Change Buffer(写缓冲区)
- 调用 Purge Thread,回收 Undo Page
4. ibd 文档
Tablespace(表空间) → ibd文档 → Segment(段) → Extent(区) → Page(页) → Row(行)
Tablespace
- 保存多个 ibd 文档
ibd 文档
- 保存 索引 和 表纪录
- 一个文档包含多个 Segment(段)
Segment
- 管理多个 Extent(区)
- 分为 Leaf node segment(数据段)、Non-leaf node segment(索引段)、Rollback segment(回滚段)
- 一张表至少会有 1 个数据段、1 个索引段
- 每多创建 1 个索引,就会多 2 个 Segment
Extent
- 大小为 1M
- 包含 64 个 Page
- 当需要分配新资源,最小的分配单元为 Extent,而非 Page
Page
- 大小为 16 K
- 保存多个 Row 纪录
- 多种类型,数据页、Undo页、系统页、事务数据页、BLOB对象页
Row
- 字段值
- 事务 ID (Trx id) - 与事务有关,对一条纪录有不同版本的备份
- 字段指针 (Field pointers) - 方便获取字段值
七、索引
可以加快查找速度,但会降低增、删、改速度
InnoDB 是以 主键聚簇索引 为 叶子节点 来构建出 B+Tree 结构
InnoDB 的表必须要有聚簇索引;表没有主键,则以第一个非空 unique 字段作为聚簇索引;否则创建一个隐藏的 row-id 作为聚簇索引
1. 类型划分
- 存储结构
- B Tree 索引
- Hash 索引
- 全文索引
- R Tree 索引
- 应用层次
- 普通索引
- 唯一索引
- 主键索引
- 复合索引
- 键值类型
- 主键索引 - 索引字段 中有包含 主键 与 所有字段
- 辅助索引(二级索引) - 索引字段中只包含 主键 与 索引字段
- 索引与数据关系
- 聚簇索引 - 索引 和 数据 存放在一起 - InnoDB
- 非聚簇索引 - 索引 和 数据 未存放在一起 - MyISAM
2. 应用类型
-
普通索引
-
在普通字段创建索引,没有限制
-
CREATE INDEX <索引名> ON tablename (字段名);
-
ALTER TABLE tablename ADD INDEX [索引名] (字段名);
-
CREATE TABLE tablename ( [...], INDEX [索引名] (字段名));
-
-
唯一索引
- 与普通索引类似,但字段必须唯一,允许空值
- CREATE UNIQUE INDEX <索引名> ON tablename (字段名);
- ALTER TABLE tablename ADD UNIQUE INDEX [索引名] (字段名);
- CREATE TABLE tablename ( [...], UNIQUE [索引名] (字段名)) ;
-
主键索引
- 特殊的唯一索引,不允许空值
- 每张表只能有一个主键
- CREATE TABLE tablename ( [...], PRIMARY KEY (字段名));
- ALTER TABLE tablename ADD PRIMARY KEY (字段名);
-
复合索引
- 使用多个字段创建的索引
- 遵循最左前缀原则
- 复合索引相比多个单一索引开销更小
- CREATE INDEX <索引名> ON tablename (字段名1,字段名2...);
- ALTER TABLE tablename ADD INDEX [索引名] (字段名1,字段名2...);
- CREATE TABLE tablename ( [...], INDEX [索引名] (字段名1,字段名2... ));
3. 原理
-
二分查找法
-
有序数组中,透过对半,查找目标值
-
优点 : 等值、范围查找优秀
-
缺点 : 更新、添加、删除 成本高
-
-
Hash 结构
-
等值查找快速
-
范围查找全表扫描
-
-
B Tree 结构
- 索引 和 数据 分布在整棵树
- 每个节点可以存放多个 索引 和 数据
- 节点中 索引 从左到右升序排列
- 搜索 - 节点内采二分查找,未命中则进入子节点重复查找,直到叶子节点结束
-
B+ Tree 结构【InnoDB采用】
- 非叶子节点只保存索引
- 叶子节点包含 索引 和 数据
- 叶子节点间使用指针连接,提升区间访问性能
- 进行范围查找只需定位两个节点的索引值,然后利用叶子节点指针遍历即可
八、索引分析与优化
应该关心索引是否减少需扫描的行数,而非是否使用索引
LIKE 查找时,% 在后面索引才生效
不建议在含有 NULL 的字段上使用索引,建议将字段设置默认值
1. Explain
-
select_type 查找类型
-
SIMPLE : 不包含 子查找 或 union
-
PRIMARY : 最外层查找
-
UNION : union 关键字之后的查找
-
DEPENDENT UNION : union 关键字之后的查找 且 使用外层的查找结果
-
UNION RESULT : union 的结果
-
SUBQUERY : select 的 子查找
-
DEPENDENT SUBQUERY : select 的 子查找 且 使用外层的查找结果
-
-
type 查找采用方式
效率由上到下增强
-
ALL : 全表扫描
-
index : 先利用索引获取顺序,再做全表扫描
-
range : 利用索引进行范围查找
-
ref : 使用普通索引查找
-
eq_ref : 多表查找时,前表的一条纪录只能匹配后表的一条结果(表关系为一对一)
-
const : 使用 主键 或 唯一索引 做 等值查找
-
NULL : 不需访问表
-
-
possible_keys - 可能用到的索引
-
key - 真正用到的索引
-
row -【估算】需要扫描多少行,越少效率越高
-
key-len - 使用索引的字节数量,用于判断是否使用了全部的复合索引
-
extra
- Using where - 回表查找
- Using index - 查找索引即可满足需求,不用回表(覆盖索引)
- Using filesort - 查找结果需要额外排序 - 建议优化,使用覆盖索引,直接利用索引进行排序
- Using temprorary - 使用了临时表(涉及去重、分组)
2. 慢查找日志
开启
- SHOW VARIABLES LIKE 'slow_query_log%'
- SET global slow_query_log = ON;
- SET global slow_query_log_file = 'OAK-slow.log';
- SET global log_queries_not_using_indexes = ON; - 纪录未使用索引的 SQL,但是 slow_query_log 必须为 ON
- SET long_query_time = 10; - 单位 秒,查找超过该时间就纪录
3. 优化
-
提高索引过滤性 - 避免使用索引后,需扫描的行数仍然过多
-
尽量使用覆盖索引 - 避免回表查找
-
分页查找利用 子查找覆盖索引 优化
-
从全表扫描变成全索引扫描
-
遍历时不用回表
select * from user where id>= (select id from user limit 10000,1) limit 100;
-
九、事务
存储引擎事务已提交,但 Dirty Page 未刷盘,靠 Redo 日志恢复事务
事务回滚,但 Dirty Page 已刷盘,靠 Undo 日志回滚事务
WAL (Write-Ahead Logging) : 先写日志,再写磁盘
1. ACID
- 原子性 Atomicity : 操作要么都发生,要么都不发生
- 一致性 Consistency : 数据库从一个一致状态变换到另一个一致状态
- 隔离性 Isolation : 事务不能被其它的事务所干扰
- 持久性 Durability : 数据的改变是永久性的
2. 隔离级别
-
脏读 : 读取到另一个事务未提交的数据 - Read Committed 读已提交 - Oracle、SQLServer 默认
-
不可重复读 : 读到另一个事务 update 的数据,两次读取到的数据【内容】不一样 - Repeatable Read 可重复读 - MySQL 默认
-
幻读 : 读取到另一个事务 insert 或 update 的数据,两次读取到的数据【数量】不一样 - Serializable 串行化
3. 读、写锁的演进
-
全局排队
-
完全顺序运行所有事务操作,不用加锁
-
强一致性
-
性能低
-
-
排他锁
-
不同操作涉及相同的数据项时,先进入的操作使用排他锁独占数据项,阻塞其他操作
-
-
读写锁
-
排他锁的延伸,区分读操作与写操作,读和读之间不加锁,降低阻塞范围
-
读和写、写和读、写和写,仍会加排他锁
-
-
MVCC 多版本控制
- 允许 读和读、读和写、写和读 并行
- 写和写 阻塞
- 在事务运行前,使用 Undo 日志记录当前数据状态与事务号,供其他读操作读取,也能进行回滚
- 读操作分类
- 快照读 : 读取纪录的【快照】(历史)版本 - 不加锁
- 当前读 : 读取纪录的【最新】版本 - 读返回的纪录会加锁,保证其他事务不会并发修改该纪录
- 只能在 Read Commited、Repeatable Read 隔离级别下工作
4. 锁分类
粒度
-
表级锁
- 操作锁住整张表
- 粒度大、冲突概率高、并发度最低
- MyISAM、InnoDB、BDB 引擎
-
页级锁
- 操作锁定相邻的一组纪录
- BDB 引擎
-
行级锁
-
操作锁住一行数据
-
粒度最小、冲突概率低、并发度最高
-
InnoDB 引擎
-
操作
共享锁 和 排他锁 都是【悲观锁】
- 读锁(S锁)
- 又称 共享锁,多个读操作可以同时进行,不会互相影响
- 读操作期间,可以追加 S锁,但不能追加 X锁,如需追加 X锁,需等所有 S锁 释放,才能追加
- 写锁(X锁)
- 又称 排他锁,同时只能存在一个锁,写操作完成前,阻断其他写锁和读锁(其他事务都不能操作)
性能
- 乐观锁
- 在数据【提交更新时】,才进行版本检测
- 谁都可以来,但我成功了,你就成功不了
- 悲观锁
- 在数据【修改前】,就先锁定
- 我认为会出问题,所以先上锁
十、行锁原理
InnoDB 的行锁是通过对【索引】的数据加锁实现的,无索引则全表锁定,可能导致死锁
InnoDB 优先采用 Next-key Lock 锁住数据+范围,但当 SQL 操作含有唯一索引(一个索引只能定位到一条纪录),将降级成 RecordLock,仅锁住数据
1. 实现算法
- RecordLock
- 锁定单行纪录
- 纪录锁,RC、RR 隔离级别支持
- GapLock
- 锁定索引间的【间隙】,确保间隙间距离不变
- 范围锁,RR 隔离级别支持
- Next-key Lock
- 锁住单行纪录,并锁住数据的前后范围
- 纪录锁 + 范围锁,RR 隔离级别支持
2. 情况
加锁都是 先使用 Next-key Lock 处理,如发现唯一索引,则降级为 RecordLock
当事务使用了写锁(排他锁,同时只能存一个锁),只有当前事务可以修改,但允许普通查找,因为普通查找不加锁
- select ... from 语句 : InnoDB 采用 MVCC 实现非阻塞读,所以普通 select【不加锁】
- select ... from lock in share mode 语句 : 追加【读锁】(S锁) (多个读操作可同时进行)
- select ... from for update 语句 : 追加【写锁】(X锁) (同时只能有一个读操作)
- update ... where 语句 : 追加【写锁】(X锁)
- delete ... where 语句 : 追加【写锁】(X锁)
- insert 语句 : 追加【写锁】(X锁) 的 RecordLock 锁
十一、高可用
1. 主从复制
用途
- 实时灾备,用于故障切换 - 高可用
- 读写分离,分担读压力 - 读扩展
前置条件
- 从库服务器 能连接 主库服务器
- 主库开启 Binlog 日志
- 主从的 server-id 不同
实现原理
- 主库将变更操作纪录到 Binlog 中
- 主库的 BinlogDump Thread 收到从库的请求后,读取 Binlog 信息并推送到从库的 I/O Thread
- 从库的 I/O Thread 读取主库的 Binlog 日志,写入到从库的 Relay Log(中继日志) 中
- 从库的 SQL Thread 检测到 Relay Log 的变更请求,读取 Relay Log 对操作进行回放,更新数据库信息
问题
-
主库当机,数据可能丢失 - 解决 - 半同步复制
主库写入 Binlog 后,等待从库写入 Relay Log 并返回 ACK 后,才进行事务提交
-
主库压力大,复制可能延时
-
解决
-
并行复制
将 SQL Thread 改为多线程对操作进行回放,且基于 组提交(MySQL 5.7 一组事务的提交) 来保证与主库结果一致
-
刚写入的时间段内读主库,之后读从库
-
先去从库读,找不到就读主库 - 注意恶意攻击
-
实时性要求高的读写操作放主库,次要业务进行读写分离
-
-
优化
- 在从库加索引,主库不加,提升写效率
2. 双主模式
- 两台服务器互为主从,任何一台数据变更,都会透过复制,将数据备分到另一台数据库中
- 【建议】使用 双主单写 避免
- ID 冲突
- 当使用主键自动递增时,A、B 主库同步不及时,容易产生问题
- 可以使用自动增长步长解决,A 主库 1,3,5;B 主库 2,4,6 - 对 运维、扩展 不友好
- 更新丢失
- 同一条数据在 A、B 主库都进行更新,会发生纪录覆盖问题
- ID 冲突
- 使用 Keepalived 或 MMM 实施主库故障自动切换
3. MHA 架构
-
30 秒内自动完成故障切换
-
最大程度保证数据一致性
-
支持在线主库切换
-
最少需要 3 台服务器
-
角色
- MHA Manager
- 负责检测 Master 是否当机、控制故障转移、检查 MySQL 复制情况
- 可以 单独布署 或 布署在 Slave 节点
- MHA Node
- 所有的 Master、Slave 节点
- 负责保存、复制 Master 的 Binlog
- MHA Manager
-
优点
- 自动故障转移快
- 主库崩溃不存在数据一致性问题
- 支持 半同步复制、异步复制
- 一个 Manager 可以监控多个集群
-
Master 当机处理
-
将 Master 的 Binlog 保存
-
根据 Binlog 位置找到最新的 Slave
-
用最新 Slave 的 Relay Log 修复其他 Slave
-
将保存下来的 Master 的 Binlog 在最新的 Slave 上修复
-
将最新的 Slave 提升为 Master
-
将其他 Slave 重新指向新 Master,并开启主从复制
-