一、原理及概念:
- 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)
三、半同步的插件功能都已經安裝好了,下面進行測試
測試:在主節點上進行增、刪、改、查等操作,從節點只要有一個同步成功了則提示成功
實驗四:MySQL主從復制加密的實現