From 9b1340bf6de2b7a6607414396fb5532e8c1f7e66 Mon Sep 17 00:00:00 2001 From: luoxiang <2806718453@qq.com> Date: Tue, 20 Aug 2019 07:30:58 +0800 Subject: [PATCH] nodify --- notes/MySQL_基础.md | 61 +++++++++++++++++++++------ notes/MySQL_备份.md | 75 +++++++++++++++++++++++++++++++-- notes/MySQL_复制.md | 96 ++++++++++++++++++++++++++++++++++++------- 3 files changed, 200 insertions(+), 32 deletions(-) diff --git a/notes/MySQL_基础.md b/notes/MySQL_基础.md index b9d109f..84c1376 100644 --- a/notes/MySQL_基础.md +++ b/notes/MySQL_基础.md @@ -1,5 +1,32 @@ # MySQL 基础 + + ## 一、常见存储引擎 ### 1.1 InnoDB @@ -17,7 +44,7 @@ InnoDB 是 MySQL 5.5 之后默认的存储引擎,它是一种兼具高可靠 -![innodb-architecture](D:\Full-Stack-Notes\pictures\innodb-architecture.png) +
### 1.2 MyISAM @@ -92,19 +119,19 @@ mysql> SELECT * FROM total; **平衡二叉树数据结构**: -![avl-tree](D:\Full-Stack-Notes\pictures\avl-tree.png) +
**红黑树数据结构**: -![red-black-tree](D:\Full-Stack-Notes\pictures\red-black-tree.png) +
**Btree 数据结构**: -![btree](D:\Full-Stack-Notes\pictures\btree.png) +
**B+ Tree 数据结构** -![B+Trees](D:\Full-Stack-Notes\pictures\B+Trees.png) +
从上面的图示中我们可以看出 B+ Tree 树具有以下优点: @@ -117,11 +144,11 @@ mysql> SELECT * FROM total; 对于 InnoDB ,因为主键索引是聚集索引,所以其叶子节点存储的就是实际的数据。而非主键索引存储则是主键的值 : -![mysql-innodb-索引](D:\Full-Stack-Notes\pictures\mysql-innodb-索引.png) +
对于 MyISAM,因为主键索引是非聚集索引,所以其叶子节点存储的只是指向数据位置的指针: -![mysql-myisam-索引](D:\Full-Stack-Notes\pictures\mysql-myisam-索引.png) +
综上所述,B+ tree 普遍适用于范围查找,优化排序和分组等操作。B+ tree 的查找是基于字典序的,因此其适用的具体查询类型如下: @@ -144,7 +171,7 @@ InnoDB 引擎有一个名为 “自适应哈希索引 (adaptive hash index)” + 索引可以帮助服务器避免排序和临时表; + 索引可以将随机 IO 转换为顺序 IO。 -### 2.5 索引的创建与使用策略 +### 2.5 使用策略 - 在查询时,应该避免在索引列上使用函数或者表达式。 - 对于多列索引,应该按照使用频率由高到低的顺序建立联合索引。 @@ -225,7 +252,7 @@ SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE; ## 四、事务 -### 4.1 ACID +### 4.1 ACID 定义 InnoDB 存储引擎完全支持 ACID 模型: @@ -260,25 +287,25 @@ InnoDB 存储引擎完全支持 ACID 模型: 一个事务的更新操作被另外一个事务的更新操作锁覆盖,从而导致数据不一致: -![mysql-修改丢失](D:\Full-Stack-Notes\pictures\mysql-修改丢失.png) +
**2. 脏读** 在不同的事务下,一个事务读取到其他事务未提交的数据: -![mysql-脏读](D:\Full-Stack-Notes\pictures\mysql-脏读.png) +
**3. 不可重复读** 在同一个事务的两次读取之间,由于其他事务对数据进行了修改,导致对同一条数据两次读到的结果不一致: -![mysql-不可重复读](D:\Full-Stack-Notes\pictures\mysql-不可重复读.png) +
**4.幻读** 在同一个事务的两次读取之间,由于其他事务对数据进行了修改,导致第二次读取到第一次不存在数据,或第一次原本存在的数据,第二次却读取不到,就好像之前的读取是 “幻觉” 一样: -![mysql-幻读](D:\Full-Stack-Notes\pictures\mysql-幻读.png) +
### 4.4 隔离级别 @@ -300,6 +327,14 @@ InnoDB 存储引擎完全支持 ACID 模型: 就数据库层面而言,当前任何隔离级别下都不会发生丢失更新的问题,以 InnoDB 存储引擎为例,如果你想要更改表中某行数据,该行数据上必然会加上 X 锁,而对应的表上则会加上 IX 锁,其他任何事务必须等待获取该锁才能进行修改操作。 + + +## 五、数据库设计范式 + + + + + ## 参考资料 1. 官方文档:[The InnoDB Storage Engine](https://dev.mysql.com/doc/refman/8.0/en/innodb-storage-engine.html),[Optimization and Indexes](https://dev.mysql.com/doc/refman/8.0/en/optimization-indexes.html),[InnoDB Locking and Transaction Model](https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-transaction-model.html) diff --git a/notes/MySQL_备份.md b/notes/MySQL_备份.md index ac1f9c7..de307f7 100644 --- a/notes/MySQL_备份.md +++ b/notes/MySQL_备份.md @@ -1,5 +1,23 @@ # 数据备份与恢复 + + ## 一、备份简介 ### 2.1 备份分类 @@ -9,7 +27,7 @@ **物理备份 与 逻辑备份** + 物理备份:备份的是完整的数据库目录和数据文件。由于其基本都是 IO 复制,并不含任何逻辑转换,因此其备份和恢复速度通常都比较快。 -+ 逻辑备份:通过数据库结构和内容信息来进行备份。因为要执行逻辑转换,因此其速度较慢,并且在以文本格式保存时,其输出文件的大小要远大于物理备份。逻辑备份和还原的粒度可以从服务器级别(所有数据库)精确到具体表,但备份不会包括日志文件、配置文件等与数据库无关的内容。 ++ 逻辑备份:通过数据库结构和内容信息来进行备份。因为要执行逻辑转换,因此其速度较慢,并且在以文本格式保存时,其输出文件的大小大于物理备份。逻辑备份的还原的粒度可以从服务器级别(所有数据库)精确到具体表,但备份不会包括日志文件、配置文件等与数据库无关的内容。 **全量备份 与 增量备份** @@ -106,9 +124,13 @@ options 代表可选操作,常用的可选参数如下: 在开始备份前刷新 MySQL 的日志文件。此选项需要 RELOAD 权限。如果此选项与 --all-databases 配合使用,则会在每个数据库开始备份前都刷新一次日志。如果配合 --lock-all-tables,--master-data 或 --single-transaction 使用,则只会在锁定所有表或者开启事务时刷新一次。 ++ **--master-data[=*value*]** + + 可以通过配置此参数来控制生成的备份文件是否包含 CHANGE MASTER 语句,该语句中包含了当前时间点二进制日志的信息。该选项有两个可选值:1 和 2 ,设置为 1 时 CHANGE MASTER 语句正常生成,设置为 2 时以注释的方式生成。--master-data 选项还会自动关闭 --lock-tables 选项,而且如果你没有指定 --single-transaction 选项,那么它还会启用 --lock-all-tables选项,在这种情况下,会在备份开始时短暂内获取全局读锁。 + ### 2.2 全量备份 -mysqldump 的全量备份与恢复操作比较简单,使用示例如下: +mysqldump 的全量备份与恢复的操作比较简单,示例如下: ```shell # 备份雇员库 @@ -131,9 +153,44 @@ mysql> source /root/mysqldata/titles_bak.sql; ### 2.3 增量备份 +mysqldump 本身并不能直接进行增量备份,需要通过分析二进制日志的方式来完成。具体示例如下: + +#### 1. 基础全备 + +1.先执行一次全备作为基础,这里以单表备份为例,需要用到上文提到的 `--master-data` 参数,语句如下: + +```shell +mysqldump -uroot -p --master-data=2 --flush-logs employees titles > titles_bak.sql +``` + +使用 more 命令查看备份文件,此时可以在文件开头看到 CHANGE MASTER 语句,语句中包含了二进制日志的名称和偏移量信息,具体如下: + +```sql +-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000004', MASTER_LOG_POS=155; +``` + +#### 2. 增量恢复 + +对表内容进行任意修改,然后通过分析二进制日志文件来生成增量备份的脚本文件,示例如下: + +```shell +mysqlbinlog --start-position=155 \ +--database=employees ${MYSQL_HOME}/data/mysql-bin.000004 > titles_inr_bak_01.sql +``` + +需要注意的是,在实际生产环境中,可能在全量备份后与增量备份前的时间间隔里生成了多份二进制文件,此时需要对每一个二进制文件都执行相同的命令: + +```shell +mysqlbinlog --database=employees ${MYSQL_HOME}/data/mysql-bin.000005 > titles_inr_bak_02.sql +mysqlbinlog --database=employees ${MYSQL_HOME}/data/mysql-bin.000006 > titles_inr_bak_03.sql +..... +``` + +之后将全备脚本 ( titles_bak.sql ),以及所有的增备脚本 ( inr_01.sql,inr_02.sql .... ) 通过 source 命令导入即可,这样就完成了全量 + 增量的恢复。 + ## 三、mysqlpump -### 3.1 简介 +### 3.1 功能优势 mysqlpump 在 mysqldump 的基础上进行了扩展增强,其主要的优点如下: @@ -185,7 +242,7 @@ mysqlpump 的使用和 mysqldump 基本一致,这里不再进行赘述。以 ## 四、Xtrabackup -### 4.1 安装 +### 4.1 在线安装 Xtrabackup 可以直接使用 yum 命令进行安装,这里我的 MySQL 为 8.0 ,对应安装的 Xtrabackup 也为 8.0,命令如下: @@ -305,6 +362,16 @@ chown -R mysql:mysql /usr/app/mysql-8.0.17/data ## 五、二进制日志的备份 +想要备份二进制日志文件,可以通过定时执行 cp 或 scp 等命令来实现,也可以通过 mysqlbinlog 自带的功能来实现远程备份,将远程服务器上的二进制日志文件复制到本机,命令如下: + +```shell +mysqlbinlog --read-from-remote-server --raw --stop-never \ +--host=主机名 --port=3306 \ +--user=用户名 --password=密码 初始复制时的日志文件名 +``` + +需要注意的是这里的用户必须具有 replication slave 权限,因为上述命令本质上是模拟主从复制架构下,从节点通过 IO 线程不断去获取主节点的二进制日志,从而达到备份的目的。 + ## 参考资料 diff --git a/notes/MySQL_复制.md b/notes/MySQL_复制.md index 7884c3c..b401257 100644 --- a/notes/MySQL_复制.md +++ b/notes/MySQL_复制.md @@ -1,5 +1,23 @@ # MySQL 复制 + + ## 一、日志格式 ### 1.1 二进制日志格式 @@ -42,7 +60,7 @@ MySQL 的复制原理如下图所示: 如果没有进行任何配置,主库在将变更写入到二进制日志后,就会返回对客户端的响应,因此默认情况下的复制是完全异步进行的,主备之间可能会短暂存在数据不一致的情况。 -![mysql-replication](D:\Full-Stack-Notes\pictures\mysql-replication.jpg) +
@@ -180,7 +198,7 @@ Master_SSL_Verify_Server_Cert: No ## 三、基于 GTID 的复制 -### 2.1 GTID +### 2.1 GTID 简介 MySQL 5.6 版本之后提供了一个新的复制模式:基于 GTID 的复制。GTID 全称为 Global Transaction ID,即全局事务 ID。它由每个服务节点的唯一标识和其上的事务 ID 共同组成,格式为: *server_uuid : transaction_id* 。通过 GTID ,可以保证在主库上的每一个事务都能在备库上得到执行,不会存在任何疏漏。 @@ -240,20 +258,65 @@ GTID 复制的优点在于程序可以自动确认开始复制的 GTID 点。但 ## 四、半同步复制 +在上面我们介绍过,不论是基于二进制日志的复制还是基于 GTID 的复制,其本质上都是异步复制,假设从节点还没有获取到二进制日志信息时主节点就宕机了,那么就会存在数据不一致的问题。想要解决这个问题可以通过配置半同步复制来实现:进行半同步复制时,主节点会等待至少一个从节点获取到二进制日志后才将事务的执行结果返回给客户端。具体配置步骤如下: +#### 1. 安装插件 + +MySQL 从 5.5 之后开始以插件的形式支持半同步复制,所以先需要先进行插件的安装,命令如下: + +```sql +-- 主节点上执行 +mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so'; +-- 从节点上执行 +mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so'; +``` + +如果你的复制是基于高可用架构的,即从节点可能会在主节点宕机后成为新的主节点,而原主节点可能在失败恢复后成为从节点,那么为了保证半同步复制仍然有效,此时可以在主从节点上都安装主从插件。安装后使用以下命令查看是否安装成功: ```shell +mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE '%semi%'; ++----------------------+---------------+ +| PLUGIN_NAME | PLUGIN_STATUS | ++----------------------+---------------+ +| rpl_semi_sync_master | ACTIVE | +| rpl_semi_sync_slave | ACTIVE | ++----------------------+---------------+ +``` + +#### 2. 配置半同步复制 + +半同步复制可以基于日志复制或 GTID 复制开启,只需要在其原有配置上增加以下配置: + +```properties +# 主节点上增加如下配置: +plugin-load=rpl_semi_sync_master=semisync_master.so +rpl_semi_sync_master_enabled=1 + + +# 从节点上增加如下配置: +plugin-load=rpl_semi_sync_slave=semisync_slave.so +rpl_semi_sync_slave_enabled=1 + +# 和上面提到的一样,如果是高可用架构下,则主从节点都可以增加主从配置: +plugin-load = "rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so" +rpl-semi-sync-master-enabled = 1 +rpl-semi-sync-slave-enabled = 1 +``` + +#### 3. 启动复制 + +按照二进制日志或 GTID 的方式正常启动复制即可,此时可以使用如下命令查看半同步日志是否正在执行: + +```shell +# 主节点 mysql> SHOW STATUS LIKE 'Rpl_semi_sync_master_status'; +-----------------------------+-------+ | Variable_name | Value | +-----------------------------+-------+ | Rpl_semi_sync_master_status | ON | +-----------------------------+-------+ -``` - - -```shell +# 从节点 mysql> SHOW STATUS LIKE 'Rpl_semi_sync_slave_status'; +----------------------------+-------+ | Variable_name | Value | @@ -262,7 +325,16 @@ mysql> SHOW STATUS LIKE 'Rpl_semi_sync_slave_status'; +----------------------------+-------+ ``` +值为 ON 代表半同步复制配置成功。 +#### 4. 可选配置 + +半同步日志还有以下两个可选配置:一个是 rpl_semi_sync_master_wait_for_slave_count,它表示主节点需要至少等待几个从节点复制完成,默认值为 1,因为等待过多从节点可能会导致长时间的延迟,所以通常使用默认值即可。另一个常用参数是 rpl_semi_sync_master_wait_point ,它主要是用于控制等待的时间点,它有以下两个可选值: + +- `AFTER_SYNC`(默认值):主服务器将每个事务写入其二进制日志,并将二进制日志同步到磁盘后开始进行等待。在收到从节点的确认后,才将事务提交给存储引擎并将结果返回给客户端。 +- `AFTER_COMMIT`:主服务器将每个事务写入其二进制日志并同步到磁盘,然后将事务提交到存储引擎,提交后再进行等待。在收到从节点的确认后,才将结果返回给客户端。 + +第二种方式是 MySQL 5.7.2 之前默认方式,但这种方式会导致数据的丢失,所以在 5.7.2 版本后就引入了第一种方式作为默认方式,它可以实现无损复制 (lossless replication),数据基本无丢失,因此 rpl_semi_sync_master_wait_point 参数通常也不用进行修改,采用默认值即可。想要查看当前版本该参数的值,可以使用如下命令: ```shell mysql> SHOW VARIABLES LIKE 'rpl_semi_sync_master_wait_point'; @@ -273,15 +345,13 @@ mysql> SHOW VARIABLES LIKE 'rpl_semi_sync_master_wait_point'; +---------------------------------+------------+ ``` - - - +虽然半同步复制能够最大程度的避免数据的丢失,但是因为网络通讯会导致额外的等待时间的开销,所以尽量在低延迟的网络环境下使用,如处于同一机房的主机之间。 ## 五、高可用架构 不论是主主复制结构,还是一主多从复制结构,单存依靠复制只能解决数据可靠性的问题,并不能解决系统高可用的问题,想要保证高可用,系统必须能够自动进行故障转移,即在主库宕机时,主动将其它备库升级为主库。常用的有以下两种解决方案: -### 4.1 MMM +### 5.1 MMM MMM (Master-Master replication manager for MySQL) 是由 Perl 语言开发的一套支持双主故障切换以及双主日常管理的第三方软件。它包含两类角色:`writer` 和 `reader `,分别对应读写节点和只读节点。使用 MMM 管理的双主节点在同一时间上只允许一个进行写入操作,当 `writer` 节点出现宕机(假设是 Master1),程序会自动移除该节点上的读写 VIP,然后切换到 Master2 ,并设置 Master2 的 read_only = 0,即关闭只读限制,同时将所有 Slave 节点重新指向 Master2。 @@ -289,18 +359,14 @@ MMM (Master-Master replication manager for MySQL) 是由 Perl 语言开发的一 - - MMM 架构的缺点在于虽然其能实现自动切换,但却不会主动补齐丢失的数据,所以会存在数据不一致性的风险。另外 MMM 的发布时间比较早,所以其也不支持 MySQL 最新的基于 GTID 的复制,如果你使用的是基于 GTID 的复制,则只能采用 MHA。 -### 4.2 MHA +### 5.2 MHA MHA (Master High Availability) 是由 Perl 实现的一款高可用程序,相对于 MMM ,它能尽量避免数据不一致的问题。它监控的是一主多从的复制架构,架构如下图所示: - - 在 Master 节点宕机后,其处理流程如下: 1. 尝试从宕机 Master 中保存二进制日志;