MySQL Replication

整体架构

内部架构

arch

链接管理

MySQL服务端采用线程池维护客户端链接mysql

SQL解析

分析查询语句,生成解析树,并将解析结果放入缓存中sql

优化器

优化包括选择合适的索引,数据的读取方式,分析语句执行的开销以及统计信息,优化器能够和存储引擎直接交互,尽管看起来彷佛没必要要。数据库

执行

执行查询语句,返回结果缓存

缓存

缓存SQL解析器解析后的结果bash

存储引擎

  1. 粒度服务器

    • 表级锁(table lock) : 资源消耗最少,但并发度低
    • 行级锁(row lock) : 资源消耗较多,但并发度高
  2. 死锁

死锁的简单例子:两个transaction同时开始执行,它们分别开始执行第一条update的语句时,便锁住了对方的资源,你拿着个人资源不放,我拿着你的资源不放,最后二人都僵持着,当事人事不关己高高挂起,旁观者疾呼:死锁!微信

# transaction 1
START TRANSACTION;
UPDATE USER SET NAME='Bob' WHERE ID=1;
# sleep for some time;
UPDATE USER SET NAME='Jack' WHERE ID=2;
COMMIT;
# transaction 2
START TRANSACTION;
UPDATE USER SET NAME='Bob' WHERE ID=2;
# sleep for some time
UPDATE USER SET NAME='Jack' WHERE ID=1;
COMMIT;
  1. 显示锁定和隐式锁定

隐式锁定就是系统自动加锁而不是人为的添加锁,显示锁定就是人为的添加锁,好比lock tables或者unlock tables。架构

事务

事务的特色由存储引擎决定,是MySQL与其它数据库的不一样。
不支持事务的存储引擎有:并发

  • MYISAM
  • MEMORY
  • ARCHIEVE

MySQL中的表按是否支持事务,分为:事务型表和非事务型表。
非事务型表没有commit或者rollback的概念。dom

SET AUTOCOMMIT=OFF;

或者

SET AUTOCOMMIT=0;

能设置当前链接是不是自动提交的。不过对非事务型表没有做用。

  1. ACID属性

    • 原子性:事务是不可分割的最小工做单元,整个事务要么所有提交要么所有回滚失败。
    • 一致性:数据库老是从一个一致性状态转换到另外一个一致性的状态。
    • 隔离性: 一个事务所作的更改在最终提交以前其它事务是不可见的。
    • 持久性:事务一旦提交所作的修改就会永久保存在数据库中,即便系统崩溃,数据也不会丢失。
  2. 隔离级别

    • 未提交读(READ UNCOMMITTED):未提交读隔离级别也叫读脏,就是事务能够读取其它事务未提交的数据。
    • 提交读(READ COMMITTED):在其它数据库系统好比SQL Server默认的隔离级别就是提交读,已提交读隔离级别就是在事务未提交以前所作的修改其它事务是不可见的。
    • 可重复读(REPEATABLE READ):保证同一个事务中的屡次相同的查询的结果是一致的,好比一个事务一开始查询了一条记录而后过了几秒钟又执行了相同的查询,保证两次查询的结果是相同的,可重复读也是mysql的默认隔离级别。
    • 可串行化(SERIALIZABLE):可串行化就是保证读取的范围内没有新的数据插入,好比事务第一次查询获得某个范围的数据,第二次查询也一样获得了相同范围的数据,中间没有新的数据插入到该范围中。

查询和设置隔离级别:

# 查询系统默认隔离级别,当前会话隔离级别
    select @@global.tx_isolation,@@tx_isolation;
    # 设置系统隔离级别:
    SET global transaction isolation level read committed;
    # 设置会话隔离级别:
    SET SESSION transaction isolation LEVEL read committed;

Replication概念

复制意味着一份数据能够有多个副本,一个数据库中的数据,能够复制至另外一个数据库。
图片描述
复制在咱们的生活中无处不在,同一份数据,有可能在你我的的电脑上有一份,U盘上有一份,云端的网盘上也可能会有一份。甚至在我的电脑里,一样一份数据也会有多个副本。
这里,咱们之因此会将数据复制出多份,目的是显而易见的:备份
当你抱着本身的电脑准备接上投影仪,准备向老板展现你苦战数个通宵后的PPT时,硬盘忽然坏了,或者文件误删,莫名其妙的找不到了,不要紧,你的U盘还有一份。什么!U盘忘了带了?不要紧,你的网盘里还有一个。
复制备份的是两件不一样的事情,能够经过复制来实现备份的目的。可是,复制的却不仅是能提供备份而已。

复制解决了什么问题

在MySQL中,复制能够解决几个问题:

  • 数据分布
  • 读写分离
  • 备份
  • 高可用和故障切换

若是大家公司的数据中心位于全国各地,经过复制,能够实现异地备份,但异地的数据同步会有较大的时间延迟。
同时,若是主数据库的数据都同步复制至从库,那么当须要更新数据时,只须要更新主库便可,新更新的数据将会经过主库同步至从库,在这个基础上,即可以实现读写分离,即DML语句在主库上执行,而查询类SQL语句则在从库上执行,因为主从的同步有时延,所以这里的数据一致性模型并不知足强一致性,是最终一致性模型。
由于有了主从副本,因此当主库不可用(宕机,崩溃等缘由),从库能够临危受命,升级为主库,保证数据库服务的高可用性。

MySQL间如何复制

分为3个步骤

  1. 在主库上把数据更改记录到二进制(binary log)日志中。
  2. 从库把主库上的日志复制到本身的中继日志(relay log)中。
  3. 从库读取中继日志中的事件,将其重放在从库数据中。

图片描述

主库在每次事务准备提交前,按照事务的提交顺序,将更新事件记录到binary log中,并通知存储引擎提交事务。而后,从库会主动启动一个线程与主库创建链接,与此对应,主库会启动一个二进制转储(binlog dump)线程与之合做,将binary log发送给从库,从库接收并产生relay log,而后由从库的一个SQL线程负责将relay log还原为数据。

须要注意的是,从库在relay时,是单线程执行,换言之,串行执行的。

Replication配置

复制的配置步骤

  1. 建立复制帐号
  2. 配置主库和从库
  3. 通知从库开始进行复制

基于二进制日志的主从复制

配置master

经过在my.cnf中添加一个配置项log-bin,来起用master的二进制日志记录功能,若是没有配置log-bin,那么master的二进制记录功能并不会起用,log-bin在这里有两个做用

  • 起用master的日志记录功能
  • 指定日志文件名的前缀

另外,须要在my.cnf中添加一个server-id配置项,用来指定master的惟一ID,范围能够是1到2^32-1。

[mysqld]
# Replication Configurations(by beanlam)
server-id=1
log-bin=bin-log

配置完成后须要重启mysql server。

配置slave

一样,slave也须要配置一个惟一的server-id,不容许跟master的server-id冲突,若是有多个slave,各个slave与master的server-id都应该是不一样的。
slave也能够配置log-bin,配置了之后slave也能够和master同样,记录binary log。slave记录binary log有其用武之地的,好比数据备份和崩溃恢复,若当前的replication环境拓扑结构比较复杂,slave须要做为其它mysql server的master时,那么这个slave也必须启用binary log的功能。

[mysqld]
# Replication Configurations(by beanlam)
server-id=2

建立一个帐号用于复制

slave获取master的binary log时,经过用户名和密码与master创建链接,能够建立一个专用于复制的帐号,并只赋予这个帐号与复制有关的权限。

mysql> CREATE USER 'repl'@'%.mydomain.com' IDENTIFIED BY 'slavepass';
mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%.mydomain.com';

除了REPLICATION SLAVE权限,还能够给用户受权REPLICATION CLIENT权限,这样用户就能够用来监控和管理复制。

获取master二进制文件的坐标

slave必须事先了解从master的二进制文件的哪一个位置开始复制,所以须要先记录master当前二进制日志的坐标,坐标由文件名和偏移量决定。
得到master的二进制日志坐标,须要先保证没有写操做在进行。在master上执行如下语句:

mysql> FLUSH TABLES WITH READ LOCK;

这个语句能为表得到读锁,阻止其它写入操做。须要注意,执行这个语句的会话若是关闭,那么这个锁将会被释放,若是会话没有关闭,那么锁会一直持有。

在另外一个会话里,用如下语句来查看master的二进制日志坐标

mysql> show master status;
+----------------+----------+-------------------------+------------------+-------------------+
| File           | Position | Binlog_Do_DB            | Binlog_Ignore_DB | Executed_Gtid_Set |
+----------------+----------+-------------------------+------------------+-------------------+
| bin-log.000005 |     1264 | beanlam_db1,beanlam_db2 |                  |                   |
+----------------+----------+-------------------------+------------------+-------------------+
1 row in set (0.00 sec)

File和Position即代表了slave应该从何处开始进行复制。

若是master以前没有启用过二进制日志的功能,那么show master status查询结果将为空。这时对于slave来讲,File是一个空字符串,Position是4,之因此是4,与二进制日志的文件格式有关。

slave开始复制

根据以上步骤,获得了master二进制文件的坐标后,只须要告诉slave,slave即可以埋头进入复制的状态中。

这里根据master是否有旧数据须要同步,分为两种状况:

  1. 若是master是一个新的数据库服务器,其上没有任何旧的数据须要复制,那么就可使用change master to命令为slave配置master的信息。

    CHANGE MASTER TO
    MASTER_HOST='master_host_name',
    MASTER_USER='replication_user_name',
    MASTER_PASSWORD='replication_password',
    MASTER_LOG_FILE='recorded_log_file_name',
    MASTER_LOG_POS=recorded_log_position;

    配置完后,能够经过start slave命令正式开始进行复制。

  2. 若是master在启用二进制日志功能以前,已经存在有一部分数据,这一部分数据须要在复制开始以前,先同步至slave。

能够经过mysqldump工具对当前master的数据库数据作一个快照,生成一个dump文件,在slave开始复制以前,把这个文件的数据导入slave中。
基本的使用方法:

mysqldump --all-databases --master-data > dbdump.db

-all-databases代表为全部数据库做快照,也能够用--databases来制定须要作快照的数据库。
--ignore-table能够跳过数据库中的全部表
--master-data会自动地在dump文件里加上change master to语句,启动slave复制,若是不加这个选项,则须要先开启一个新的会话,对全部的表加读。
当存储引擎是InnoDB时,推荐使用mysqldump。
另一种方法是直接拷贝数据文件到slave。

Replication原理

基于语句的复制

基于语句的复制也称为(逻辑复制),slave把master上形成数据更改的SQL语句在本身的库上也执行一次。

  • 优势

master的binlog只记录SQL语句,使得日志文件体积更小。

  • 缺点

master除了传输SQL语句给slave,还须要传输一些元数据,好比当前时间戳。
还有一些语句没法被正确复制,好比包含用户自定义函数的语句,这些函数可能有不肯定的行为。如下函数可能致使非正常的复制:

LOAD_FILE(), UUID(), UUID_SHORT(), USER(), FOUND_ROWS(), SYSDATE(), GET_LOCK(), IS_FREE_LOCK(), IS_USED_LOCK, MASTER_POS_WAIT, RAND(), RELEASE_LOCK(), SLEEP(), VERSION()

此外,INSERT......SELECT语句须要获取更多的行级锁,比起基于行的复制来讲。
UPDATE语句可能致使全表扫描(where字句中没有包含索引字段)
若是使用的是InnoDB引擎,带有auto_incrementinsert语句会堵塞其它非冲突的insert语句。
slave上的更新是串行的,所以须要更多的锁。另外,并非全部的存储引擎都支持基于语句的复制。

基于行的复制

MySQL5.1开始支持基于行的复制

  • 优势

更少的锁

  • 缺点

对于某些语句,例如插入或者删除语句,基于行的复制方式会将整行的数据都写进binary log,致使binary log体积很大,也致使须要持有锁的时间变长。
若是包含用户自定义函数,这些函数输出值很是大的文本,那么采起行的复制,会把这么大的文本也写进日志里。
在slave端看不到执行了哪些SQL语句
当使用MyISAM引擎时,insert语句须要得到重量级的锁,这意味着插入操做只能是串行的。

slave也做为master

若是slave配置了log_slave_updates选项,slave也会像master同样记录binary log,从而能够做为一个master存在。
图片描述

拓扑结构

  • 最多见的拓扑结构

图片描述

  • MySQL不支持多主库复制

图片描述

  • 主动-被动模式下的主-主复制

被动服务器时只读的(日志里记录的事件都带有一个server id,发现server id与本身的相同,则忽略这个事件)

图片描述

  • 拥有备库的主-主结构

图片描述

  • 环形结构

很是脆弱,其中一个节点失效会致使由这个节点发起的事件在其它节点之间链式死循环,由于只有它本身能过滤掉与本身server id相同的事件。
图片描述
改进:
图片描述

  • 主库-分发库-备库

主要用在当多个备库执行复制请求时,致使主库负载太高时,能够引进分发库来减小主库的负载。
图片描述

  • 树形或金字塔形

故障处理过程更加复杂
图片描述

Reference

mysql5.6 ref
mysql5.7 ref
《高性能MySQL》 3rd Edition

扫一扫关注个人微信公众号

相关文章
相关标签/搜索