前言
聽說大家現在都在積極響應國家號召,沒事的時候會推着三輪車去街角、天橋擺個地攤。博主剛剛收攤回來,順手寫了篇MySQL。
MySQL相信大家都很熟悉了,單節點MySQL出現性能瓶頸的時候,大家首先想到的是優化SQL。但是單節點畢竟能力有限,所以在優化之後,還是無法滿足性能要求時,就會想到部署MySQL讀寫分離,也就是主從複製。除了性能瓶頸之外,還有單節點故障、單節點容量等問題,都必須依靠集羣才能解決。本篇主要講解MySQL從單機到集羣的原理和實踐。
環境
- VMware Workstation 15
- CentOS Linux release 7.7.1908
- MySQL 5.7.30
注意事項
- 三個節點
ip
分別爲192.168.1.101
、192.168.1.102
、192.168.1.103
- 確保三個節點都能訪問互聯網,並且三個節點能夠相互通信
- 確保Linux的
yum
、wget
等基礎命令可用 - 建議先關閉防火牆,Centos 7操作如下
firewall-cmd --state ## 查看防火牆狀態 not running表示已經關閉 systemctl stop firewalld.service ## 關閉防火牆 systemctl disable firewalld.service ## 禁止開機啓動防火牆
需要搭建的主從複製集羣如下
單機安裝
安裝
整個過程請保持網絡暢通
wget -i -c http://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpm
yum -y install mysql57-community-release-el7-10.noarch.rpm
yum -y install mysql-community-server
到這一步,MySQL服務的安裝已經完成
啓動
啓動MySQL
systemctl start mysqld.service
查看運行狀態
systemctl status mysqld.service
執行結果
● mysqld.service - MySQL Server
Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)
Active: active (running) since 二 2020-06-02 21:58:25 CST; 11s ago
Docs: man:mysqld(8)
http://dev.mysql.com/doc/refman/en/using-systemd.html
Process: 2160 ExecStart=/usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid $MYSQLD_OPTS (code=exited, status=0/SUCCESS)
Process: 2111 ExecStartPre=/usr/bin/mysqld_pre_systemd (code=exited, status=0/SUCCESS)
Main PID: 2163 (mysqld)
CGroup: /system.slice/mysqld.service
└─2163 /usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid
6月 02 21:58:18 localhost.localdomain systemd[1]: Starting MySQL Server...
6月 02 21:58:25 localhost.localdomain systemd[1]: Started MySQL Server.
根據日誌可以看到MySQL Server已經成功啓動
找到臨時密碼
在MySQL的啓動日誌中,會打印一個臨時密碼用於登錄,用戶名是root
cat /var/log/mysqld.log |grep password
執行結果
2020-06-02T13:58:21.946584Z 1 [Note] A temporary password is generated for root@localhost: cScTwtyMl4;*
可以看到我此處的臨時密碼是cScTwtyMl4;*
用這個密碼登錄,登錄之後需要修改密碼,才能進行其他的操作,且密碼要滿足一定的複雜度。
alter user 'root'@'localhost' identified by 'your password';
因爲安裝了Yum Repository
,以後每次yum
操作都會自動更新,需要把這個卸載掉
yum -y remove mysql57-community-release-el7-10.noarch
至此,此時MySQL的單機安裝已經完成。其餘節點均可按照此方法安裝。
異步複製
原理
不僅是MySQL,幾乎所有的主從複製集羣,都是master\slave
模式,也就是slave
節點從master
節點上同步數據。MySQL主從複製的整個過程如下圖所示
整個過程可以分爲三個步驟
master
節點把對數據的修改記錄到bin log
中,所以master
節點必須開啓bin log
slave
節點會從指定的位置(logfile
和偏移量pos
)開始讀取master
的bin log
,把讀取到的日誌寫入自己的relay log
中slave
節點根據relay log
中的日誌進行重放(replay
),slave
節點可以配置是否需要寫入自己的bin log
瞭解了MySQL主從複製的基本原理,再來進行主從複製的搭建,就會容易理解很多。
異步複製缺點
爲了瞭解異步複製的缺點,先看如下圖
如圖所示,描述了一主兩從的異步複製集羣,相信大家也很容易看出缺點。假設master
節點commit
之後就宕機了,而此時slave
節點可能還沒有讀到master
的全部bin log
,就會導致數據丟失。
異步複製不僅不能保證master
和slave
之間的數據一致性,甚至不能保證slave
與slave
之間的數據一致性。
半同步複製
MySQL5.6對異步複製做了改進,引入半同步複製。
半同步複製過程如下
半同步複製在MySQL5.6中被引入,相比於異步複製,主要的改進就是在master
寫完bin log
之後不會直接commit
,而是收到slave
節點的ACK
之後纔會commit
,期間master
的commit
操作被阻塞。當然,爲了防止部分slave
節點故障導致master
遲遲收到不ACK
。master
的commit
操作可以設置超時時間,超時之後,半同步複製降級爲異步複製。
有經驗的同學應該可以看出來,這其實就是兩階段提交。master
節點commit
的時候,slave
已經讀取了master
的完整bin log
。即使此時master
宕機,slave
節點也能通過重放,實現和master
節點的數據同步。
基於GTID複製
前文說講的主從複製集羣是依靠logfile + pos
的方式實現,除了這種方式外,還有一種就是基於GTID
的主從複製。GTID
(Global Transaction ID
)是全局事務ID。
GTID
的結構如下:source_id:transaction_id
,組成分成兩個部分source_id
和transaction_id
,分別代表執行事務的主機UUID,和事務ID。事務ID是遞增的,保證不重複。
master
節點修改數據時,把GTID
寫入bin log
slave
讀取master
節點的bin log
,寫入到自己的relay log
slave
節點的sql_thread
從relay log
獲取GTID
,查找自己的bin log
中是否有對應的記錄- 如果有,說明該
GTID
的事務已經在slave
上執行,slave
會忽略該事務 - 如果沒有,
slave
就會從relay log
中執行該事務,並記錄到bin log
整個過程與logfile + pos
方式幾乎一致,只是獲取執行偏移的方式不同。並且slave
節點必須開啓bin log
。
基於
GTID
的複製和基於日誌點的複製有什麼區別?
- 基於日誌點的複製是MySQL實現的第一種複製方式,幾乎所有的MySQL分支版本都支持
- 基於日誌點的複製,
slave
請求master
的增量日誌依賴於日誌偏移量 - 基於日誌點的複製配置複製鏈路時,需要指定
master_log_file
和master_log_pos
參數,一旦master
宕機,很難從新的master
中找到正確的偏移量的值
基於日誌點的複製 | 基於GTID 的複製 |
---|---|
兼容性好 | 老版本MySQL 及MariaDB 不兼容 |
支持MMM 和MHA 架構 |
僅支持MHA 架構 |
主從切換後很難找到新的同步點 | 基於事務ID 的複製,可以很方便的找到未完成的同步的事務ID |
可以方便的跳過複製錯誤 | 只能置入空事務的方式跳過複製 |
優先選擇基於GTID
的複製,不能選擇GTID
的複製方式時,再使用基於日誌點的複製。
實踐
異步複製
-
開啓
bin log
,使用如下命令查看bin log
是否開啓show variables like '%log_bin%'; +---------------------------------+-------+ | Variable_name | Value | +---------------------------------+-------+ | log_bin | OFF | | log_bin_basename | | | log_bin_index | | | log_bin_trust_function_creators | OFF | | log_bin_use_v1_row_events | OFF | | sql_log_bin | ON | +---------------------------------+-------+ 6 rows in set (0.00 sec)
log_bin
爲OFF
表示未開啓,可以使用如下方式開啓bin log
vim /etc/my.cnf
配置如下內容
## 開啓bin log log-bin=/var/lib/mysql/mysql-bin ## 服務節點ID,每個節點不一樣 server-id=101 ## 開啓GTID複製模式(如果只想用基於日誌點複製,不需要配置這裏) gtid-mode=on enforce-gtid-consistency=1
重啓MySQL之後,再次查看
bin log
開啓狀態,可以看到bin log
已經開啓show variables like '%log_bin%'; +---------------------------------+--------------------------------+ | Variable_name | Value | +---------------------------------+--------------------------------+ | log_bin | ON | | log_bin_basename | /var/lib/mysql/mysql-bin | | log_bin_index | /var/lib/mysql/mysql-bin.index | | log_bin_trust_function_creators | OFF | | log_bin_use_v1_row_events | OFF | | sql_log_bin | ON | +---------------------------------+--------------------------------+ 6 rows in set (0.00 sec)
slave
節點均按照此方式配置 -
master
創建複製賬號並授權
需要自己指定密碼create user repl@'192.168.1.%' identified by 'your password'; grant replication slave on *.* to repl@'192.168.1.%';
-
備份
master
數據mysqldump --single-transaction -uroot -p --routines --triggers --events --master-data=2 --all-databases > sicimike.sql
可以查看備份的文件中,有
GTID
和logfile:pos
相關的信息
將備份的文件導入到slave
節點的數據庫。 -
在
slave
節點上配置複製鏈路## MASTER_LOG_FILE和MASTER_LOG_POS的值在前一步中可以找到 change master to master_host='192.168.1.101', MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=2615;
執行成功後,可以查看
slave
節點的狀態show slave status\G; *************************** 1. row *************************** Slave_IO_State: Master_Host: 192.168.1.101 Master_User: Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000002 Read_Master_Log_Pos: 2615 Relay_Log_File: localhost-relay-bin.000001 Relay_Log_Pos: 4 Relay_Master_Log_File: mysql-bin.000002 Slave_IO_Running: No Slave_SQL_Running: No ......
-
啓動複製鏈路
## 用戶名和密碼就是在master上配置的用戶名和密碼 start slave user='repl' password= 'your password';
再次查看
slave
節點的狀態show slave status\G; *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.1.101 Master_User: repl Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000002 Read_Master_Log_Pos: 2615 Relay_Log_File: localhost-relay-bin.000002 Relay_Log_Pos: 320 Relay_Master_Log_File: mysql-bin.000002 Slave_IO_Running: Yes Slave_SQL_Running: Yes ......
可以看到
Slave_IO_Running
和Slave_SQL_Running
都變成了Yes
狀態,這兩個線程就是前文主從複製原理圖中io_thread
和sql_thread
其餘的節點也是以同樣的方式配置成
slave
節點。
至此,基於logfile:pos
模式的異步複製已經配置完成。在master
節點上進行數據的修改,馬上就會同步到slave庫
。
可以在master
節點上執行show slave hosts
查看追隨自己的所有slave
節點
show slave hosts;
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID |
+-----------+------+------+-----------+--------------------------------------+
| 103 | | 3306 | 101 | d6532e2a-a592-11ea-99c3-000c297f5b55 |
| 102 | | 3306 | 101 | 1dbd5375-a4d9-11ea-9eef-000c29cf4cca |
+-----------+------+------+-----------+--------------------------------------+
2 rows in set (0.00 sec)
接下來開始配置半同步複製。
半同步複製
- 首先查看
master
是否安裝了半同步複製插件rpl_semi_sync_master
,可以使用如下命令查看
如果沒有安裝的話,使用如下命令安裝show plugins;
install plugin rpl_semi_sync_master soname 'semisync_master.so';
- 配置
master
相關變量
首先查看半同步複製相關的變量show variables like 'rpl%'; +-------------------------------------------+------------+ | 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_for_slave_count | 1 | | rpl_semi_sync_master_wait_no_slave | ON | | rpl_semi_sync_master_wait_point | AFTER_SYNC | | rpl_stop_slave_timeout | 31536000 | +-------------------------------------------+------------+ 7 rows in set (0.01 sec)
rpl_semi_sync_master_enabled
變量需要改成ON
rpl_semi_sync_master_timeout
表示半同步複製的超時時間,可以適當修改
依然是修改/etc/my.cof
文件,配置如下內容
配置完成後重啓MySQL即可rpl_semi_sync_master_enabled=on rpl_semi_sync_master_timeout=500
- 查看
slave
是否安裝了半同步複製插件rpl_semi_sync_slave
可以使用如下命令
如果沒有安裝的話,使用如下命令安裝show plugins;
install plugin rpl_semi_sync_slave soname 'semisync_slave.so';
- 配置
slave
相關變量
首先查看半同步複製相關的變量show variables like 'rpl%'; +---------------------------------+----------+ | Variable_name | Value | +---------------------------------+----------+ | rpl_semi_sync_slave_enabled | OFF | | rpl_semi_sync_slave_trace_level | 32 | | rpl_stop_slave_timeout | 31536000 | +---------------------------------+----------+ 3 rows in set (0.01 sec)
rpl_semi_sync_slave_enabled
變量需要改成ON
,需要修改/etc/my.cof
文件,配置如下內容rpl_semi_sync_slave_enabled=on
slave
完成配置,重啓MySQL後,再次查看slave
的狀態
可以看到,show slave status\G; *************************** 1. row *************************** Slave_IO_State: Master_Host: 192.168.1.101 Master_User: Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000003 Read_Master_Log_Pos: 194 Relay_Log_File: localhost-relay-bin.000005 Relay_Log_Pos: 4 Relay_Master_Log_File: mysql-bin.000003 Slave_IO_Running: No Slave_SQL_Running: Yes .....
Slave_SQL_Running
依然是Yes
,只有Slave_IO_Running
是NO
,所以只需要重啓slave
的IO線程即可
啓動完成後,基於start slave io_thread user='repl' password = 'your password';
logfile:pos
模式的半同步複製也就配置完成。
GTID複製
由於上面的實驗,我們已經啓動了logfile + pos
方式的複製鏈路,所以要改成GTID
方式,先要停止slave
,再重新配置複製鏈路
- 停止
slave
在slave
節點上執行如下命令stop slave;
- 配置複製鏈路
change master to master_host='192.168.1.101', master_user='repl', master_password='your password', master_auto_position=1;
- 啓動複製鏈路
start slave;
查看鏈路狀態
show slave status \G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.1.101
Master_User: repl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000003
Read_Master_Log_Pos: 811
Relay_Log_File: localhost-relay-bin.000002
Relay_Log_Pos: 414
Relay_Master_Log_File: mysql-bin.000003
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
......
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set:
Executed_Gtid_Set: 1dbd5375-a4d9-11ea-9eef-000c29cf4cca:1,
81502f9e-a592-11ea-b912-000c2928707c:1-11
Auto_Position: 1
......
可以看到Auto_Position
變成了1
,說明啓動了基於GTID
方式的複製。
主從複製延遲
主從複製是一種異步複製模型,延遲自然是不可避免。只要延遲在業務能夠接受的範圍之內,都是可以容忍的。但是有時候主從複製的延遲會很大,可以總結爲以下原因
master
上執行了大事務,大事務是指耗時很長的事務。改進辦法是把大事務轉換成多個小事務。master
和slave
之間網絡波動- 單個
master
節點下掛載的slave
節點過多,可能會把master
網卡帶寬打滿。改進辦法就是減少單個master
掛載slave
的數量 master
節點會有多個線程同時寫入,而slave
節點進行replay
的sql_thread
只有一個。改進辦法就是使用MySQL 5.7
的多線程複製的方式、或者使用MGR
複製架構。
總結
本篇主要從理論到實踐,完整的講解了MySQL的幾種主從模型。根據複製點的選取方式,可以分成基於日誌點的方式和基於GTID的方式。根據master
節點事務的提交方式可以分成異步複製和半同步複製。
至於文中提到的MMM
和MHA
架構,留待下一篇再詳細講解。
參考
- https://www.cnblogs.com/bigbrotherer/p/7241845.html
- https://blog.51cto.com/13434336/2178937