一、原理及概念:
- MySQL 主从复制概念
MySQL 主从复制是指数据可以从一个MySQL数据库服务器主节点复制到一个或多个从节点。MySQL 默认采用异步复制方式,这样从节点不用一直访问主服务器来更新自己的数据,数据的更新可以在远程连接上进行,从节点可以复制主数据库中的所有数据库或者特定的数据库,或者特定的表。
- MySQL 主从复制主要用途
l 读写分离
在开发工作中,有时候会遇见某个sql 语句需要锁表,导致暂时不能使用读的服务,这样就会影响现有业务,使用主从复制,让主库负责写,从库负责读,这样,即使主库出现了锁表的情景,通过读从库也可以保证业务的正常运作。
l 数据实时备份,当系统中某个节点发生故障时,可以方便的故障切换
l 高可用HA
l 架构扩展
随着系统中业务访问量的增大,如果是单机部署数据库,就会导致I/O访问频率过高。有了主从复制,增加多个数据存储节点,将负载分布在多个从节点上,降低单机磁盘I/O访问的频率,提高单个机器的I/O性能。
- MySQL 主从形式
一主一从
一主多从,提高系统的读性能
一主一从和一主多从是最常见的主从架构,实施起来简单并且有效,不仅可以实现HA,而且还能读写分离,进而提升集群的并发能力。
多主一从 (从5.7开始支持)
多主一从可以将多个mysql数据库备份到一台存储性能比较好的服务器上。
双主复制
双主复制,也就是互做主从复制,每个master既是master,又是另外一台服务器的slave。这样任何一方所做的变更,都会通过复制应用到另外一方的数据库中。
级联复制
级联复制模式下,部分slave的数据同步不连接主节点,而是连接从节点。因为如果主节点有太多的从节点,就会损耗一部分性能用于replication,那么我们可以让3~5个从节点连接主节点,其它从节点作为二级或者三级与从节点连接,这样不仅可以缓解主节点的压力,并且对数据一致性没有负面影响。
- MySQL 主从复制原理
MySQL主从复制涉及到三个线程,一个运行在主节点(log dump thread),其余两个(I/O thread, SQL thread)运行在从节点,如下图所示:
l 主节点 binary log dump 线程
当从节点连接主节点时,主节点会创建一个log dump 线程,用于发送bin-log的内容。在读取bin-log中的操作时,此线程会对主节点上的bin-log加锁,当读取完成,甚至在发动给从节点之前,锁会被释放。
l 从节点I/O线程
当从节点上执行`start slave`命令之后,从节点会创建一个I/O线程用来连接主节点,请求主库中更新的bin-log。I/O线程接收到主节点binlog dump 进程发来的更新之后,保存在本地relay-log中。
l 从节点SQL线程
SQL线程负责读取relay log中的内容,解析成具体的操作并执行,最终保证主从数据的一致性。
对于每一个主从连接,都需要三个进程来完成。当主节点有多个从节点时,主节点会为每一个当前连接的从节点建一个binary log dump 进程,而每个从节点都有自己的I/O进程,SQL进程。从节点用两个线程将从主库拉取更新和执行分成独立的任务,这样在执行同步数据任务的时候,不会降低读操作的性能。比如,如果从节点没有运行,此时I/O进程可以很快从主节点获取更新,尽管SQL进程还没有执行。如果在SQL进程执行之前从节点服务停止,至少I/O进程已经从主节点拉取到了最新的变更并且保存在本地relay日志中,当服务再次起来之后,就可以完成数据的同步。
要实施复制,首先必须打开Master 端的binary log(bin-log)功能,否则无法实现。
因为整个复制过程实际上就是Slave 从Master 端获取该日志然后再在自己身上完全顺序的执行日志中所记录的各种操作。如下图所示:
复制的基本过程如下:
- 从节点上的I/O 进程连接主节点,并请求从指定日志文件的指定位置(或者从最开始的日志)之后的日志内容;
- 主节点接收到来自从节点的I/O请求后,通过负责复制的I/O进程根据请求信息读取指定日志指定位置之后的日志信息,返回给从节点。返回信息中除了日志所包含的信息之外,还包括本次返回的信息的bin-log file 的以及bin-log position;从节点的I/O进程接收到内容后,将接收到的日志内容更新到本机的relay log中,并将读取到的binary log文件名和位置保存到master-info 文件中,以便在下一次读取的时候能够清楚的告诉Master“我需要从某个bin-log 的哪个位置开始往后的日志内容,请发给我”;
- Slave 的 SQL线程检测到relay-log 中新增加了内容后,会将relay-log的内容解析成在祝节点上实际执行过的操作,并在本数据库中执行。
- MySQL 主从复制模式
MySQL 主从复制默认是异步的模式。MySQL增删改操作会全部记录在binary log中,当slave节点连接master时,会主动从master处获取最新的bin log文件。并把bin log中的sql relay。
l 异步模式(mysql async-mode)
异步模式如下图所示,这种模式下,主节点不会主动push bin log到从节点,这样有可能导致failover的情况下,也许从节点没有即时地将最新的bin log同步到本地。
l 半同步模式(mysql semi-sync)
这种模式下主节点只需要接收到其中一台从节点的返回信息,就会commit;否则需要等待直到超时时间然后切换成异步模式再提交;这样做的目的可以使主从数据库的数据延迟缩小,可以提高数据安全性,确保了事务提交后,binlog至少传输到了一个从节点上,不能保证从节点将此事务更新到db中。性能上会有一定的降低,响应时间会变长。如下图所示:
半同步模式不是mysql内置的,从mysql 5.5开始集成,需要master 和slave 安装插件开启半同步模式。
二、实验步骤如下:
同一环境:CentOS7.6,MariaDB版本:5.5.60 (yum安装)
实验一:MySQL的主从架构的实现
主节点的IP: 192.168.99.110
从节点的IP : 192.168.99.120
主服务器的配置:
1、修改配置文件
① 为当前节点设置一个全局惟一的ID号:server_id
2、先查看一下节点的位置,然后在数据库中创建一个用于授权同步的账号 :
+--------------------+-----------+
| Log_name | File_size |
+--------------------+-----------+
| mariadb-bin.000001 | 245 |
+--------------------+-----------+
1 row in set (0.00 sec)
MariaDB [(none)]> grant replication slave on *.* to ‘tongbu‘@‘192.168.99.%‘ identified by ‘xu‘; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> select user,host,password from mysql.user; +--------+--------------+-------------------------------------------+ | user | host | password | +--------+--------------+-------------------------------------------+ | root | localhost | | | root | centos7 | | | root | 127.0.0.1 | | | root | ::1 | | | | localhost | | | | centos7 | | | tongbu | 192.168.99.% | *DA1E6BE7062B84E5F3F815D4372304A374D9039F | +--------+--------------+-------------------------------------------+ 7 rows in set (0.00 sec)
3、配置从服务器
① 修改配置文件:添加server_id唯一的编号,
②设置数据库只读 read_only=ON #此项目前也可以不加,后面使用proxy代理时必须加此项,用于识别当前节点的用途
③ 重启服务
④ 进入数据库中进行同步配置:使用刚刚创建的同步账号进行同步数据库
CHANGE MASTER TO MASTER_HOST=‘192.168.99.110‘, MASTER_USER=‘tongbu‘, MASTER_PASSWORD=‘xu‘, MASTER_LOG_FILE=‘mariadb-bin.000001‘, MASTER_LOG_POS=245; START SLAVE;
⑤启动后查看一下同步的状态:
mysql> show slave status\G
此时两个节点就已经实现了主从复制的功能,在主节点上增删改查操作都会被同步到从服务器上,从而达到了类似数据库备份的作用,当主节点宕机后通过修改配置让从节点继续工作
复制架构中应该注意的问题:
?1、限制从服务器为只读
?在从服务器上设置read_only=ON
注意:此限制对拥有SUPER权限的用户均无效
?阻止所有用户, 包括主服务器复制的更新
mysql> FLUSH TABLES WITH READ LOCK;
?2、RESET SLAVE:从服务器清除master.info ,relay-log.info, relay log ,开始新的relay log
RESET SLAVE ALL:清除所有从服务器上设置的主服务器同步信息,如PORT, HOST, USER和 PASSWORD 等
注意:以上都需要先STOP SLAVE
?3、sql_slave_skip_counter = N 从服务器忽略几个主服务器的复制事件,
global变量
? 在master节点启用参数:
sync_binlog=1 每次写后立即同步二进制日志到磁盘,性能差
如果用到的为InnoDB存储引擎:
innodb_flush_log_at_trx_commit=1 每次事务提交立即同步日志写磁盘
innodb_support_xa=ON 默认值,分布式事务MariaDB10.3.0废除
sync_master_info=# 第#次事件后master.info同步到磁盘
? 在slave节点启用服务器选项:
skip-slave-start=ON 不自动启动slave
? 在slave节点启用参数:
sync_relay_log=# #次写后同步relay log到磁盘
sync_relay_log_info=# #次事务后同步relay-log.info到磁盘
实验二:MySQL主主架构的实现:
主主复制:互为主从
?容易产生的问题:数据不一致;因此慎用
?考虑要点:自动增长id
主要配置:
配置一个节点使用奇数id
auto_increment_offset=1 开始点
auto_increment_increment=2 增长幅度
另一个节点使用偶数id
auto_increment_offset=2
auto_increment_increment=2
? 主主复制的配置步骤:
1、修改配置文件的内容:
① 各节点使用一个惟一server_id
② 都启动binary log和relay log
③ 定义自动增长id字段的数值范围,因为从节点上也需要配置为了避免冲突可以配置为奇偶数,起始点为1增长幅度是2,也就是 1 3 5 7....,另一个节点为2 4 6 8...
A节点配置:
B节点配置:
2、 在A节点中创建拥有复制权限的用户账号,这里就使用上面创建的账号 ‘ tongbu ‘
3、在两个节点上各自查看当前pos点的位置,并把对方指定为主节点(互为主从关系,也就是主主),并启动复制线程
在99.110上查看pos点,同步关系指向99.120节点
MariaDB [(none)]> show master logs; +--------------------+-----------+ | Log_name | File_size | +--------------------+-----------+ | mariadb-bin.000001 | 415 | | mariadb-bin.000002 | 245 | +--------------------+-----------+ 2 rows in set (0.00 sec) MariaDB [(none)]> CHANGE MASTER TO MASTER_HOST=‘192.168.99.120‘, -> MASTER_USER=‘tongbu‘, -> MASTER_PASSWORD=‘xu‘, -> MASTER_LOG_FILE=‘mariadb-bin.000001‘, -> MASTER_LOG_POS=245; Query OK, 0 rows affected (0.01 sec) MariaDB [(none)]> slave start; Query OK, 0 rows affected (0.00 sec)
互相指定后查看同步状态:
在99.110上查看
4、此时两个节点已经是主主关系,但是当同时在两个节点上创建表且有主键设置时就会产生冲突
两个节点同时插入表时,同步就会出错误
查看同步状态
因为一个表中只能存在一个主键,,此时已经影响同步功能了,所以只好跳过这个错误以恢复同步状态继续同步
实验三:MySQL半同步的实现
三台机器: 主节点:IP:99.110
从节点A 的 IP:99.120
从节点B 的IP:99.130
① 修改配置文件内容
# 三台机器的配置中都需要加入server-id,主节点启用log-bin功能
[root@centos7 ~]#vim /etc/my.cnf [mysqld] server-id=110 log-bin
② 在主节点上创建同步的账号
MariaDB [(none)]> grant replication slave on *.* to tongbu@‘192.168.99.%‘ identified by ‘xu‘; Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> show master logs;
+--------------------+-----------+
| Log_name | File_size |
+--------------------+-----------+
| mariadb-bin.000001 | 415 |
| mariadb-bin.000002 | 8627 |
| mariadb-bin.000003 | 245 |
+--------------------+-----------+
3 rows in set (0.00 sec)
③在从节点进行同步
MariaDB [(none)]> CHANGE MASTER TO MASTER_HOST=‘192.168.99.110‘, MASTER_USER=‘tongbu‘, MASTER_PASSWORD=‘xu‘, MASTER_PORT=3306, MASTER_LOG_FILE=‘mariadb-bin.000003‘, MASTER_LOG_POS=245;
Query OK, 0 rows affected (0.02 sec)
slave start;
Query OK, 0 rows affected (0.00 sec)
二、半同步的实现: 半同步的实现需要借助一个插件功能实现
1、在节点中安装相应的插件功能(插件分为 server 和 slave 端)
① #先查看一下当前服务器中的插件
②在主节点中安装半同步的插件功能:在主节点中需要安装server端的
MariaDB [(none)]> install plugin rpl_semi_sync_master SONAME ‘semisync_master.so‘; Query OK, 0 rows affected (0.01 sec) MariaDB [(none)]> show plugins; +--------------------------------+----------+--------------------+--------------------+---------+ | Name | Status | Type | Library | License | +--------------------------------+----------+--------------------+--------------------+---------+ | binlog | ACTIVE | STORAGE ENGINE | NULL | GPL | | mysql_native_password | ACTIVE | AUTHENTICATION | NULL | GPL | | mysql_old_password | ACTIVE | AUTHENTICATION | NULL | GPL | ........ ........ | FEEDBACK | DISABLED | INFORMATION SCHEMA | NULL | GPL | | partition | ACTIVE | STORAGE ENGINE | NULL | GPL | | rpl_semi_sync_master | ACTIVE | REPLICATION | semisync_master.so | GPL | #server端的插件已经安装上了 +--------------------------------+----------+--------------------+--------------------+---------+ 43 rows in set (0.01 sec)
③在主节点中查看插件相关的信息
#查看插件的相关信息 MariaDB [(none)]> show global variables like ‘%semi%‘; +------------------------------------+-------+ | Variable_name | Value | +------------------------------------+-------+ | rpl_semi_sync_master_enabled | OFF | #服务端的启用状态 | rpl_semi_sync_master_timeout | 10000 | #超时时间 | rpl_semi_sync_master_trace_level | 32 | | rpl_semi_sync_master_wait_no_slave | ON | +------------------------------------+-------+ 4 rows in set (0.00 sec) #启用半同步的插件功能 MariaDB [(none)]> set global rpl_semi_sync_master_enabled=on; Query OK, 0 rows affected (0.00 sec) #查看半同步的相关信息 MariaDB [(none)]> show global status like ‘%semi%‘; +--------------------------------------------+-------+ | Variable_name | Value | +--------------------------------------------+-------+ | Rpl_semi_sync_master_clients | 0 | #半同步的客户端数量,当前没有配置启用slave端所以为0 | Rpl_semi_sync_master_net_avg_wait_time | 0 | | Rpl_semi_sync_master_no_tx | 0 | | Rpl_semi_sync_master_status | ON | #半同步master端的状态,刚刚已经启用了 | Rpl_semi_sync_master_timefunc_failures | 0 | ... | Rpl_semi_sync_master_yes_tx | 0 | +--------------------------------------------+-------+ 14 rows in set (0.00 sec)
2、 在两个从节点中也安装slave端的半同步的插件功能
#安装slave端的插件 MariaDB [(none)]> install plugin rpl_semi_sync_slave SONAME ‘semisync_slave.so‘; Query OK, 0 rows affected (0.00 sec) #查看插件的变量 MariaDB [(none)]> show global variables like ‘%semi%‘; +---------------------------------+-------+ | Variable_name | Value | +---------------------------------+-------+ | rpl_semi_sync_slave_enabled | OFF | #插件的启用状态 | rpl_semi_sync_slave_trace_level | 32 | +---------------------------------+-------+ 2 rows in set (0.00 sec) #启用插件功能 MariaDB [(none)]> set global rpl_semi_sync_slave_enabled=on; Query OK, 0 rows affected (0.00 sec) #查看semi插件的状态,如果没有启用则需要重新启用slave线程 MariaDB [(none)]> show global status like ‘%semi%‘; +----------------------------+-------+ | Variable_name | Value | +----------------------------+-------+ | Rpl_semi_sync_slave_status | OFF | +----------------------------+-------+
3、在主节点中再次查看半同步插件相关变量
#查看全局变量 MariaDB [(none)]> show global status like ‘%semi%‘; +--------------------------------------------+-------+ | Variable_name | Value | +--------------------------------------------+-------+ | Rpl_semi_sync_master_clients | 2 | #目前已经有2个节点开启了slave端的同步功能 | Rpl_semi_sync_master_no_tx | 0 | | Rpl_semi_sync_master_status | ON | ... | Rpl_semi_sync_master_yes_tx | 0 | +--------------------------------------------+-------+ 14 rows in set (0.00 sec)
三、半同步的插件功能都已经安装好了,下面进行测试
测试:在主节点上进行增、删、改、查等操作,从节点只要有一个同步成功了则提示成功