🚀 Database
1、数据库基础
1.1 事务的概念和特性
1.2 锁
1.3 锁协议
1.4 事务日志
1.5 MVCC实现原理
1.6 基础知识
1.6.1 三范式
1.6.2 多表连接方式
1.6.3 存储过程
1.6.4 TRUNCATE和DROP的区别
1.6.5 触发器
1.6.6 视图
2、MySQL
2.1 索引
2.2 索引组织表
2.3 InnoDB和MyISAM的区别
2.4 Checkpoint技术
2.5 宕机恢复原理
2.6 数据库优化
2.7 分库分表
2.8 一致性哈希算法
2.9 主从复制
3、Redis
3.1 概述
3.1.1 为什么Redis单线程还这么快
3.1.2 Redis数据类型
3.1.3 持久化机制
3.1.4 过期机制和内存淘汰策略
3.2 线程模型
3.3 分布式问题
3.3.1 Redis实现分布式锁
3.4 缓存异常
3.4.1 缓存击穿、缓存雪崩
3.5 高可用
3.5.1 主从复制
3.5.2 哨兵模式
3.5.3 集群模式
-
+
游客
注册
登录
主从复制
## 1 什么是主从复制 1. MySQL 主从复制是指数据可以**从一个 MySQL 数据库服务器主节点复制到一个或多个从节点**。 2. **默认采用异步复制方式**,这样**从节点不用一直访问主服务器来更新自己的数据**,**数据的更新可以在远程连接上进行**,**从节点可以复制主数据库中的所有数据库或者特定的数据库**,**或者特定的表**。 ## 2 为什么要主从复制 1. **读写分离**: 1. 在开发工作中,有时候会遇见某个 SQL 语句需要锁表,导致暂时不能使用读的服务,这样就会影响现有业务。 2. 使用主从复制,让**主库负责写**,**从库负责读**,这样,**即使主库出现了锁表的情景**,**通过读从库也可以保证业务的正常运作**。 2. **数据实时备份**: 1. 当系统中**某个节点发生故障**时,可以**方便**的**故障切换**。 3. **高可用 HA**。 4. **架构扩展**: 1. 随着系统中业务访问量的增大,如果是**单机部署数据**库,就会导致**I/O 访问频率过高**。 2. 有了主从复制,**增加多个数据存储节点**,**将负载分布在多个从节点上**,**降低单机磁盘 I/O 访问的频率**,**提高单个机器的 I/O 性能**。 ## 3 常见架构模型 ### 3.1 一主一从/一主多从 1. 一主一从和一主多从是最常见的主从架构模式,一般实现主从配置或者读写分离都可以采用这种架构。 2. 如果是**一主多从模式**,当 `b`**增加到一定数量时**,**`Slave` 对 `Master` 的负载以及网络带宽都会成为一个严重的问题**。![1](/media/202107/2021-07-08_1725220.4615627563605139.png) ### 3.2 多主一从 1. MySQL 5.7 开始支持多主一从的模式,将多个库的数据备份到一个库中存储。![1](/media/202107/2021-07-08_1727100.08125400952718176.png) ### 3.3 双主复制 1. 理论上跟主从一样,但是**两个 MySQL 服务器互做对方的从**,**主从相互授权连接**,**读取对方 Binlog 日志并更新到本地数据库**,**只要对方数据改变**,**自己就跟着改变**。 2. **双主适用于写压力比较大的场景**,或者**DBA 做维护需要主从切换的场景**,通过双主架构**避免了重复搭建从库的麻烦**。 ### 3.4 级联复制 1. 级联模式下因为涉及到的 `Slave` 节点很多,所以如果都连在 `Master` 上对主服务器的压力肯定是不小的,所以部分 `Slave` 节点连接到他上一级的从节点上,这样就缓解了主服务器的压力。 2. 级联复制解决了一主多从场景下**多个从库复制对方从库的压力**,带来的弊端就是**数据同步延迟比较大**。![1](/media/202107/2021-07-09_0959180.38642972342568416.png) ## 4 主从复制原理 主从复制涉及到三个线程: 1. 一个在**主节点的线程**: 1. `Log Dump Thread`,主要用来**给从库 `I/O Thread` 传 Binlog 数据**。 2. 两个在**从库的线程**: 1. 一个 `I/O Thread`,主要用于**请求主库的 Binlog**,并**将得到的 Binlog 写到本地的 Relay Log**(中继日志)**文件中**。 2. 一个 `SQL Thread`,主要用于**读取 Relay Log 文件中的日志**,并**解析成 SQL 语句逐一执行**。 ![4](/media/202107/2021-07-09_1002500.6522393134425326.png) 3. **Log Dump Thread:** 1. 当**从节点连接主节点**时,**主节点会为其创建一个 Log Dump Thread**,**用于发送和读取 Binlog 的内容**。 2. 在**读取 Binlog 的操作中**,**Log Dump Thread 会对主节点上的 Binlog 加锁**,当**读取完成发送给从节点之前**,**锁会被释放**。 3. 主节点会**为自己的每一个从节点创建一个 Log Dump Thread**。 4. **I/O Thread:** 1. 当从节点上执行 `start slave` 命令之后,从节点会**创建一个 `I/O Thread` 用来连接主节点**,**请求主库中更新的 Binlog**。 2. **`I/O Thread` 接收到主节点的 `Log Dump Thread` 进程发来的更新之后**,**保存在 Relay Log 中**。 5. **SQL Thread:** 1. SQL Thread 负责**读取 Relay Log 中的内容**,**解析成具体的操作并执行**,最终**保证主从数据的一致性**。 6. **Relay Log:** 1. MySQL 进行**主主复制**或**主从复制**的时候会在要**复制的服务器下面产生相应的 Relay Log**。 2. **从服务器 `I/O Thread` 将主服务器的 Binlog 日志读取过来**,**解析到各类 Events 之后记录到从服务器本地文件**,**这个文件就被称为 Relay Log**。 3. 然后 `SQL Thread`**会读取 Relay Log 日志的内容并应用到从服务器**,从而**使从服务器和主服务器的数据保持一致**。 4. Relay Log**充当缓冲区**,这样 `Master` 就不必等到 `Slave` 执行完成才发送下一个事件。 5. Relay Log 相关参数: 1. 查询方式: ```shell mysql> show variables like '%relay%'; +---------------------------+--------------------------------------------+ | Variable_name | Value | +---------------------------+--------------------------------------------+ | max_relay_log_size | 0 | | relay_log | | | relay_log_basename | /www/server/data/ecs-q9gui-relay-bin | | relay_log_index | /www/server/data/ecs-q9gui-relay-bin.index | | relay_log_info_file | relay-log.info | | relay_log_info_repository | FILE | | relay_log_purge | ON | | relay_log_recovery | OFF | | relay_log_space_limit | 0 | | sync_relay_log | 10000 | | sync_relay_log_info | 10000 | +---------------------------+--------------------------------------------+ ``` 2. `max_relay_log_size`: 1. **标记 Relay Log 允许的最大值**。 2. 如果该值为 0,则默认值为 `max_binlog_size(1G)`。 3. 如果不为 0,则 `max_relay_log_size` 为最大的 Relay Log 文件大小。 3. `relay_log_purge`: 1. **是否自动清空不再需要的中继日志**,默认为 1(启用)。 4. `relay_log_recovery`: 1. 当**`Slave` 从库宕机后**,**假如 Relay Log 损坏了**,**导致一部分中继日志没有处理**,则**自动放弃所有未执行的 Relay Log**,并且**重新从 `Master` 上获取日志**,这样就**保证了 Relay Log 的完整性**。 2. 默认情况下该功能是关闭的,将 `relay_log_recovery` 的值设置为 1 时,可在 `Slave` 从库上开启该功能,建议开启。 5. `relay_log_space_limit`: 1. **防止中继日志写满磁盘**,这里**设置中继日志最大限额**。 2. 此设置**存在主库崩溃**,**从库中继日志不全的情况**,**不到万不得已**,**不推荐使用**。 6. `sync_relay_log`: 1. 这个参数**和 Binlog 中的 `sync_binlog` 作用相同**。 2. 当**设置为 1 时**,`Slave`**的 `I/O Thread` 每次接收到 `Master` 发送过来的 Binlog 日志都要写入系统缓冲区**,然后**刷入 Relay Log 中继日志里**,这样是**最安全**的,因为在**崩溃的时候**,我们**最多丢失一个事务**,但**会造成磁盘的大量 I/O**。 3. 当**设置为 0 时**,并**不是马上就刷入中继日志里**,而是**由操作系统决定何时来写入**,虽然**安全性降低了**,但**减少了大量的磁盘 I/O 操作**。 4. 这个值**默认是 0**,可动态修改,建议采取默认值。 7. `sync_relay_log_info`: 1. 这个参数**和 Binlog 中的 `sync_binlog` 作用相同**。 2. 当**设置为 1 时**,`Slave`**的 `I/O Thread` 每次接收到 `Master` 发送过来的 Binlog 日志都要写入系统缓冲区**,然后**刷入 `relay-log.info` 里**,这样是**最安全**的,因为在**崩溃的时候**,我们**最多丢失一个事务**,但**会造成磁盘的大量 I/O**。 3. 当**设置为 0 时**,并**不是马上就刷入 `relay-log.info` 里**,而是**由操作系统决定何时来写入**,虽然**安全性降低了**,但**减少了大量的磁盘 I/O 操作**。 4. 这个值**默认是 0**,可动态修改,建议采取默认值。 7. 对于**每一个主从连接**,都**需要这三个进程来完成**,当**主节点有多个从节点时**,**主节点会为每一个当前连接的从节点创建一个 `Log Dump Thread`**,而**每个从节点都有自己的 `I/O Thread`**、**`SQL Thread`**。 8. **从节点用两个线程将从主库拉取更新和执行分成独立的任务**,这样**在执行同步数据任务的时候**,**不会降低读操作的性能**,比如: 1. 如果从节点没有运行,此时 `I/O Thread` 可以很快从主节点获取更新,尽管 `SQL Thread` 还没有执行。 2. 如果在 `SQL Thread` 执行之前从节点服务停止,至少 `I/O Thread` 已经从主节点拉取到了最新的变更并且保存在本地 Relay Log 中,当服务再次起来之后就可以完成数据的同步。 ## 5 复制的基本过程 > 要实施复制,首先**必须打开 `Master` 端的 Binlog 功能**,否则无法实现,因为整个复制过程实际上就是 `Slave` **从 `Master` 端获取该日志**,**然后再在自己身上完全顺序的执行日志中所记录的各种操作**。 ![5](/media/202107/2021-07-09_1101440.00551414399379524.png) 1. 在从节点执行 `start slave` 命令**开启主从复制**开关,**开始进行主从复制**,**从节点上的 `I/O Thread` 连接主节点**,并**请求从指定日志文件的指定位置**(或者从最开始的日志)**之后的日志内容**。 2. **主节点接收到来自从节点的 I/O 请求后**,**通过负责复制的 `Log Dump Thread` 根据请求信息读取指定日志指定位置之后的日志信息**,**返回给从节点**,**返回信息中除了日志所包含的信息之外**,**还包括本次返回的信息的 Binlog File 以及 Binlog Position**(Binlog 下一个数据读取位置)。 3. **从节点的 `I/O Thread` 接收到主节点发送过来的日志内容**、**日志文件及位置点后**,**将接收到的日志内容更新到本机的 Relay Log 文件的最末端**,并**将读取到的 Binlog 文件名和位置保存到 `master-info` 文件中**,**以便在下一次读取的时候能够清楚的告诉 `Master`**“我**需要从哪个 Binlog 的哪个位置开始往后的日志内容**,请发送给我”。 4. **`Slave` 的 `SQL Thread` 检测到 Relay Log 中新增加了内容后**,会**将 Relay Log 的内容解析成能够执行的 SQL 语句**,然后**在本数据库中按照解析出来的顺序执行**,并**在 `relay-log.info` 中记录当前应用中继日志的文件名和位置点**。 ## 6 复制的模式 > MySQL 主从复制**默认是异步的模式**。 ### 6.1 异步模式(Async Mode) ![6](/media/202107/2021-07-09_1115530.729759596392375.png) 1. 这种模式下,**主节点不会主动推送数据到从节点**,主库在**执行完客户端提交的事务后会立即将结果返回给客户端**,并**不关心从库是否已经接收并处理**。 2. 这样就会**有一个问题**,**主节点如果崩溃掉了**,此时**主节点上已经提交的事务可能并没有传到从节点上**,**如果此时强行将从提升为主**,**可能导致新主节点上的数据不完整**。 ### 6.2 半同步模式(Semi Sync Mode) ![7](/media/202107/2021-07-09_1121140.055395934571049965.png) 1. **介于异步复制和全同步复制之间**,**主库在执行完客户端提交的事务后不是立刻返回给客户端**,**而是等待至少一个从库接收到并写到 Relay Log 中才返回成功信息给客户端**(**只能保证主库的 Binlog 至少传输到了一个从节点上**),**否则需要等待直到超时时间然后切换成异步模式再提交**。 2. 相对于异步复制,半同步复制**提高了数据的安全性**,一定程度的**保证了数据能成功备份到从库**。 3. 同时他也**造成了一定程度的延迟**,但是**比全同步模式延迟要低**,这个延迟**至少是一个 TCP/IP 往返的时间**,所以,半同步复制**最好在低延时的网络中使用**。 4. **半同步模式不是 MySQL 内置的**,**从 MySQL 5.5 开始集成**,**需要 `Master` 和 `Slave` 安装插件开启半同步模式**。 ### 6.3 全同步模式 1. 指当**主库执行完一个事务**,然后**所有的从库都复制了该事务并成功执行完才返回成功信息给客户端**。 2. 因为**需要等待所有从库执行完该事务才能返回成功信息**,所以全同步复制的**性能必然会受到严重的影响**。 ## 7 主从复制可能会出现的问题 ### 7.1 Slave 同步延迟 1. 因为 **Slave 端是通过 `I/O Thread` 单线程来实现数据解析入库**,而**Master 端写 Binlog 是顺序写效率很高**,因此**当主库的 TPS 很高的时候**,必然**Master 端的写效率要高过 Slave 端的读效率**,这时候就有**同步延迟**的问题。 2. `I/O Thread` 的同步是基于库的,即同步几个库就会开启几个 `I/O Thread`,可以通过 `show slave status` 命令查看 `Seconds_Behind_Master` 的值来看是否出现同步延迟,这个值代表**主从同步延迟的时间**,值为**0 表示正常情况**,**正值表示已经出现延迟**,**值越大说明延迟越严重**,**从库落后主库也就越多**。 ## 参考文献 1. [什么是主从复制?实现原理是什么?](https://github.com/wolverinn/Waking-Up/blob/master/Database.md#%E4%BB%80%E4%B9%88%E6%98%AF%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86%E6%98%AF%E4%BB%80%E4%B9%88) 2. [深度探索 MySQL 主从复制原理](https://zhuanlan.zhihu.com/p/50597960)。 3. [MySQL 主从复制原理不再难](https://www.cnblogs.com/rickiyang/p/13856388.html)。 4. [深入了解 MySQL 主从复制的原理](https://segmentfault.com/a/1190000038967218)。
ricear
2021年12月19日 15:29
©
BY-NC-ND(4.0)
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
分享
链接
类型
密码
更新密码