MySQL主從復制:半同步、異步
前言
本篇我們介紹
MySQL Replication
的相關內容, 我們首先介紹MySQL CLuster
的實現原理和如何一步步構建一個MySQL Replication Cluster
看懂本文需要了解:
MySQL基本操作
,MySQL日志類型及其作用
如何對MySQL進行擴展?
大家之前應該了解; 在單臺服務器性能不足時, 有兩種方式進行擴展
Scale Up ; 垂直擴展
Scale Out ; 水平擴展
垂直擴展: 指的是提升單臺服務器的性能(硬件)來提升服務的性能
水平擴展: 指的是添加服務器通過負載均衡的方式來分擔單臺服務器的負載, 從而提升服務的性能我們可以通過LVS, HAProxy, Nginx等軟件實現一些服務的負載均衡, 但是如果要用到
MySQL
上就會有一些問題, 如下
如何保證多臺
MySQL
服務器數據的一致性如何保證多臺服務器同時提交事務導致數據的完整性
如何保證一臺服務器宕機時, 其的事務能夠正常提交或ROLLBACK
…
我們需要考慮的問題比擴展
WEB
服務多太多了, 畢竟大家都知道,數據無價
, 在很多重要場景中, 數據不能有半點閃失, 但是MySQL
對這方面做得并不是很好, 而Oracle
數據庫在這方面特別的厲害, 所以眾多的銀行都采用Oracle
數據庫存儲客戶的賬戶信息等, 這么說, 難道我們就不用MySQL
了么? 這顯然不可能, 我們首先來介紹一下MySQL Replication Cluster
的幾種同步數據方式
Synchronous Replication 同步復制
Asynchronous Replication 異步復制
Semisynchronous Replication 半同步復制
同步復制: 指的是客戶端連接到
MySQL主服務器
寫入一段數據,MySQL主服務器
同步給MySQL從服務器
需要等待從服務器發出同步完成的響應才返回客戶端OK, 這其中等待同步的過程是阻塞的, 如果有N臺從服務器, 效率極低
異步復制: 指的是客戶端連接到MySQL主服務器
寫入一段數據,MySQL主服務器
將寫入的數據發送給MySQL從服務器
, 然后直接返回客戶端OK, 可能從服務器的數據會和主服務不一致
半同步復制:指的是客戶端連接到MySQL主服務器
寫入一段數據,MySQL主服務器
只將數據同步復制給其中一臺從服務器, 半同步復制給其他的從服務器, 來達到其中一臺從服務器完全同步的效果
MySQL Replication WorkFlow
Master/Slave工作流程
建立主從關系后, 主服務器如果有數據修改之后,
BINLOG
會更新, 從服務通過IO-Thread
讀取主服務器的BINLOG
到本地的Relay Log
, 再通過SQL-Thread
對其進行重放(replay), 從而同步到本地
MySQL主從復制模式
在不同的業務模型中我們可以采用不同的
MySQL
主從復制架構, 一般分為以下兩種
Master/Slave
Master/Master
Master/Slave: 指的是一主多從模式, 這種模式下可以有效的分擔讀請求, 但是寫請求并不能完成負載分擔、從節點可能數據不一致, 并且如果
Master
宕機了客戶端就無法進行寫操作了, 還是有很多問題的
Master/Master: 指的是多主模式, 這種模式中的多臺MySQL
服務器都是Master
, 也就意味著都可以進行讀寫操作, 但是有著更為嚴重的問題, 多個客戶端同時寫入數據時由于復制延遲可能到導致數據沖突等嚴重問題
常用的架構圖
我們可以使用keepalived實現Master高可用, 并且使用半同步模式實現數據的完全同步
上面那種方式太占用Master的帶寬, 我們可以讓一臺Slave扮演為Master, 為其他Slave同步數據
實戰演練
MySQL異步復制實現
實驗拓撲
環境部署
我們需要在各臺服務器上安裝
MySQL
, 這里使用的是rpm包安裝, 版本為5.1
[root@node1 ~]# yum install mysql-server -y
[root@node2 ~]# yum install mysql-server -y
[root@node3 ~]# yum install mysql-server -y
配置文件
node1配置文件(master)
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
innodb_file_per_table = 1
log_bin=master-log #開啟二進制日志
log_bin_index=1
server_id=1 #設置serverid
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
node2配置文件(slave1)
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
relay-log=relay-log #開啟relay日志
innodb_file_per_table = 1
read-only = 1 #設置只讀
server_id = 2 #設置serverid
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
node3配置文件(slave2)
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
relay-log=relay-log
innodb_file_per_table = 1
read-only = 1
server_id = 3
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
##啟動mysql
##注意: serverid一定不能相同
配置Master
Slave節點進行同步需要通過一個特定的用戶進行, 所以我們需要創建一個用戶并賦予
REPLICATION SLAVE, REPLICATION CLIENT
權限
mysql> GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'rpuser'@'%' IDENTIFIED BY 'passwd';
Query OK, 0 rows affected (0.00 sec)
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)
mysql> SHOW MASTER STATUS; 我們要記錄下pos的數值
+-------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-------------------+----------+--------------+------------------+
| master-log.000005 | 523 | | |
+-------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
配置Slave(1)
mysql> CHANGE MASTER TO
-> MASTER_HOST='172.16.1.2',
-> MASTER_USER='rpuser',
-> MASTER_PASSWORD='passwd',
-> MASTER_LOG_FILE='master-log.000005',
-> MASTER_LOG_POS=523;
Query OK, 0 rows affected (0.01 sec
mysql> SHOW SLAVE STATUS\G; #查看相應信息
#########省略##################
Master_Log_File: master-log.000005
Read_Master_Log_Pos: 523
Relay_Log_File: relay-log.000001
Relay_Log_Pos: 4
Relay_Master_Log_File: master-log.000005
Slave_IO_Running: No #IO-thread沒有啟動
Slave_SQL_Running: No #SQL-thread沒有啟動
#########省略##################
mysql> START SLAVE; #啟動sql-thread和io-thred
mysql> SHOW SLAVE STATUS\G; #查看相應信息
Query OK, 0 rows affected (0.00 sec)
#########省略##################
Master_Log_File: master-log.000005
Read_Master_Log_Pos: 523
Relay_Log_File: relay-log.000002
Relay_Log_Pos: 252
Relay_Master_Log_File: master-log.000005
Slave_IO_Running: Yes #IO-thread啟動
Slave_SQL_Running: Yes #SQL-thread啟動
#########省略##################
配置slave(2)
過程和配置slave(1)相同, 不做演示
測試主從復制
##在主服務器上創建數據庫和表
[root@node1 ~]# mysql
mysql> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| test |
+--------------------+
3 rows in set (0.00 sec)
mysql> CREATE DATABASE replication;
Query OK, 1 row affected (0.00 sec)
mysql> USE replication;
Database changed
mysql> CREATE TABLE t1 (id int unsigned auto_increment primary key, name char(30));
Query OK, 0 rows affected (0.01 sec)
mysql> DESC t1;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | char(30) | YES | | NULL | |
+-------+------------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
mysql> SHOW MASTER STATUS;
+-------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-------------------+----------+--------------+------------------+
| master-log.000005 | 765 | | |
+-------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
##在slave服務器測試
[root@node2 ~]# mysql
mysql> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| replication |
| test |
+--------------------+
4 rows in set (0.00 sec)
mysql> use replication;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> DESC t1;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | char(30) | YES | | NULL | |
+-------+------------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
mysql> SHOW SLAVE STATUS\G;
#########省略##################
Master_Log_File: master-log.000005
Read_Master_Log_Pos: 765 #已經同步
Relay_Log_File: relay-log.000002
Relay_Log_Pos: 494
Relay_Master_Log_File: master-log.000005
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
#########省略##################
MySQL半同步復制實現
由于
MySQL
半同步復制在MySQL
5.5以后才以插件的形式進行提供, 所以這里我們的MySQL
要換成5.5版本的MariaDB
由于很多步驟和上面重復,我就不寫出來了,先配置成M/S然后再按照我下面操作
實驗拓撲
配置master
半同步的插件在/usr/lib64/mysql/plugin下, master用的semisync_master.so,slave用的semisync_slave.so,
MariaDB [(none)]> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> SET GLOBAL rpl_semi_sync_master_enabled = 1;
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> SET GLOBAL rpl_semi_sync_master_timeout = 2000; #設置超時時間為2S
Query OK, 0 rows affected (0.00 sec)
配置slave
MariaDB [(none)]> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> SET GLOBAL rpl_semi_sync_slave_enabled=1;
Query OK, 0 rows affected (0.00 sec)
驗證
因為在我的環境中,即使是半同步復制,也是直接就完成,看不出效果,所以我們故意將slave節點關閉
[root@node2 ~]# service mysql stop
##master創建數據庫
MariaDB [(none)]> CREATE DATABASE TEST3;
Query OK, 1 row affected (2.00 sec) #等待2s, 超時不再等待,直接創建
MariaDB [(none)]> CREATE DATABASE TEST4;
Query OK, 1 row affected (0.00 sec)
##完成,這個可能不是特別直觀,但是由于我這邊環境實在做不出效果,望大家理解
實驗中的思考
如果主從服務器數據相差較大, 最好先使用主服務器的二進制日志在從服務器上replay一篇, 然后再進行同步
總結
這篇其實還打算寫SSL復制的,但是因為時間比較緊,就沒有寫了,總體來說不是特別的滿意,有很多地方沒有說明白,還望大家諒解。
作者水平很低, 如果有錯誤及時指出, 如果你覺得本文寫的好請點一波贊~(≧▽≦)/~
作者: AnyISaIln QQ: 1449472454
感謝: MageEdu
原創文章,作者:Net18-AnyISalIn,如若轉載,請注明出處:http://www.www58058.com/15679