第一節:mysql 高可用方案
1.1 一主一從架構
mysql 配置為主從模式,從庫是主庫的 backup,同一時間設置其中一台為主服務器,提供讀寫,另一台服務器作為熱備,不提供讀寫,通過復制與主服務器數據保持一致,二者均開啟 binlog。
(1)主從復制實現
在主庫把數據更改記錄到 binlog 中;
備庫將主庫的日志復制到自己的 relaylog 中;
備庫讀取 relaylog 中的事件,將其重放到備庫上。
(2)主從復制關鍵技術
異步復制、半同步復制
1.2 雙主(主從)架構
在一主一從架構的基礎上配置雙向復制和 Keepalived 自動切換功能,通過周期性調用監測腳本,監測進程,實現故障時 VIP 的無縫切換,當活躍點出現故障時,通過 VIP+Keepalived 腳本執行實現向另一台數據庫的切換,以此實現 mysql 架構的高可用。
(1)Keepalived 切換實現
雙向復制運行;
VIP 所在的庫作為主庫;
主庫出現問題時,VIP 切換至另一個主庫。
(2)Keepalived 切換關鍵技術
VRRP 原理、Keepalived 監測機制
1.3 MHA + 一主兩從架構
MHA(Master High Availability)在 mysql 高可用方面是一個相對成熟的解決方案。在 mysql 故障切換的過程中,MHA 能做到在 0-30 秒之內自動完成數據庫的故障切換工作,並且在進行故障切換的過程中,MHA 能在最大程度上保證數據的一致性,已達到真正意義上的高可用,但 GTID 出現后 MHA 功能弱化。
(1)MHA切換實現
主庫;備主;備庫;
MHA 配合 VIP 漂移;
補齊數據。
(2)MHA切換關鍵技術
MHA manager、GTID(全局事務標志)出現,MHA弱化
一個事務對應一個唯一ID,一個GTID在一個服務器上只會執行一次(一個事務在從庫上只能出現一次)
1.4 mysql 集群架構
集群架構原理(PXC):節點接收 sql 請求后,對於 ddl 操作,在 commit 之前,由 wsrep API 調用 galera 庫進行集群內廣播,所有其他節點驗證成功后事務在集群所有節點進行提交,反之 roll back。PXC 保證整個集群所有數據的強一致性,滿足:Consistency和Availability。
(1)mysql 集群實現
上層中間調度如 HAproxy;
調度到的 Node上進行讀寫;
同步至其他兩個節點。
(2)mysql 集群關鍵技術
同步復制、wsrep 插件技術
2、mysql 主從復制
2.1 mysql 主從復制概念
mysql 主從復制是指數據可以從一個 mysql 數據庫服務器主節點復制到一個或多個從節點。mysql 默認采用異步復制方式,這樣從節點不用一直訪問主服務器來更新自己的數據,數據的更新可以在遠程連接上進行,從節點可以復制主數據庫中的所有數據庫或者特定的數據庫,或者特定的表。
2.2 mysql 主從復制的主要用途
(1)讀寫分離
(2)數據實時備份,當系統某節點發生故障時,可以進行故障切換
(3)高可用性(HA)
隨着系統中業務訪問量的增大,如果是單機部署數據庫,就會導致 I/O 訪問頻率過高。有了主從復制,增加多個數據存儲節點,將負載分布在多個從節點上,降低單機磁盤 I/O 訪問的頻率,提高單個機器的 I/O 性能。
2.3 mysql 主從復制原理
過程:主庫開啟 binlog 功能並授權從庫連接主庫,主庫 IO 線程根據從庫的請求,從 master.info 開始記錄的位置點向下開始取信息,同時把取到的位置點和最新的位置與 binlog 信息一同發給從庫 IO 線程,從庫將相關的 sql 語句存放在 relay-log 里面,最終從庫的 sql 線程將 relay-log 里的 sql 語句應用到從庫上,至此整個同步過程完成,之后將是無限重復上述過程。
binlog 輸出線程:每當有從庫連接到主庫的時候,主庫都會創建一個線程然后發送 binlog 內容到從庫。對於每一個即將發送給從庫的 sql 事件,binlog 輸出線程會將其鎖住。一旦該事件被線程讀取完之后,該鎖會被釋放,即使在該事件完全發送到從庫的時候,該鎖也會被釋放。在從庫里,當復制開始的時候,從庫就會創建兩個線程進行處理:
從庫 I/O 線程:當 START SLAVE 語句在從庫開始執行之后,從庫創建一個 I/O 線程,該線程連接到主庫並請求主庫發送 binlog 里面的更新記錄到從庫上。從庫 I/O 線程讀取主庫的 binlog 輸出線程發送的更新並拷貝這些更新到本地文件,其中包括 relay log 文件。
從庫的 SQL 線程:從庫創建一個 SQL 線程,這個線程讀取從庫 I/O 線程寫到 relay log 的更新事件並執行。
可以知道,對於每一個主從復制的連接,都有三個線程。擁有多個從庫的主庫為每一個連接到主庫的從庫創建一個 binlog 輸出線程,每一個從庫都有它自己的 I/O 線程和 SQL 線程。
從庫通過創建兩個獨立的線程,使得在進行復制時,從庫的讀和寫進行了分離。因此,即使負責執行的線程運行較慢,負責讀取更新語句的線程並不會因此變得緩慢。比如說,如果從庫有一段時間沒運行了,當它在此啟動的時候,盡管它的 SQL 線程執行比較慢,它的 I/O 線程可以快速地從主庫里讀取所有的 binlog 內容。這樣一來,即使從庫在 SQL 線程執行完所有讀取到的語句前停止運行了,I/O 線程也至少完全讀取了所有的內容,並將其安全地備份在從庫本地的 relay log,隨時准備在從庫下一次啟動的時候執行語句。
2.4 主從復制的實現
(1)環境構建:基於 centos7 操作系統,mariadb 數據庫(同 mysql 數據庫)
master節點:192.168.129.128 slave1節點:192.168.129.129
(2)分別在 master 節點和 slave1 節點上關閉防火牆,關閉 selinux
#master節點: [root@Master ~]#systemctl stop firewalld [root@Master ~]#systemctl disable firewalld Removed symlink /etc/systemd/system/multi-user.target.wants/firewalld.service. Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service. [root@Master ~]# sed -ri '/^SELINUX=/s/(SELINUX=).*/\1disabled/' /etc/selinux/config#slave1節點: [root@Slave1 ~]# systemctl stop firewalld [root@Slave1 ~]# systemctl disable firewalld Removed symlink /etc/systemd/system/multi-user.target.wants/firewalld.service. Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service. [root@Slave1 ~]# sed -ri '/^SELINUX=/s/(SELINUX=).*/\1disabled/' /etc/selinux/config
(3)master 節點和 slave1 節點上分別安裝 mariadb:
#兩個節點分別執行: yum install mariadb-server -y
(4)在主服務器(master)上:
啟用二進制日志
選擇一個唯一的server-id
創建具有復制權限的用戶
[root@Master ~]#vim /etc/my.cnf [mysqld] log-bin=master-bin # 行模式 binlog_format = row # 刷新binlog到磁盤 sync_binlog = 1 # 禁止域名解析 skip_name_resolv = 1 # 同步設置的重要參數 log_slave_updates = 1 # 設置唯一id server_id = 128 datadir=/var/lib/mysql [root@Master ~]#systemctl restart mariadb [root@Master ~]#mysql MariaDB [(none)]> reset master; #刪除所有的binglog日志文件,並將日志索引文件清空,重新開始所有新的日志文件。用於第一次進行搭建主從庫時,進行主庫binlog初始化工作; Query OK, 0 rows affected (0.02 sec) MariaDB [(none)]> grant replication slave,replication client on *.* -> to rep@'192.168.129.%' identified by 'localhost'; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> flush privileges; Query OK, 0 rows affected (0.00 sec)
(5)在從服務器(slave1)上
啟用中繼日志(二進制日志可開啟,也可不開啟)
選擇一個唯一的 server-id
連接至主服務器,並開始復制
首先測試是否能遠程登錄 master 節點上的數據庫:
[root@Slave1 ~]# mysql -h 192.168.129.128 -urep -plocalhost Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 3 Server version: 5.5.56-MariaDB MariaDB Server Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MariaDB [(none)]> quit #測試成功,退出
配置從服務器:
[root@Slave1 ~]# vim /etc/my.cnf [mysqld] log-bin=slave1-bin binlog_format = row sync_binlog = 1 skip_name_resolv = 1 log_slave_updates = 1 server_id = 129 datadir=/var/lib/mysql [root@Slave1 ~]# systemctl start mariadb [root@Slave1 ~]# mysql MariaDB [(none)]> reset master; Query OK, 0 rows affected (0.02 sec) MariaDB [(none)]> change master to -> master_host='192.168.129.128', -> master_user='rep', -> master_password='localhost', -> master_log_file='master-bin.000001', -> master_log_pos=0; Query OK, 0 rows affected (0.04 sec) MariaDB [(none)]> show slave status\G *************************** 1. row *************************** Slave_IO_State: Master_Host: 192.168.129.128 Master_User: rep Master_Port: 3306 Connect_Retry: 60 Master_Log_File: master-bin.000001 Read_Master_Log_Pos: 4 Relay_Log_File: mariadb-relay-bin.000001 Relay_Log_Pos: 4 Relay_Master_Log_File: master-bin.000001 Slave_IO_Running: No Slave_SQL_Running: No MariaDB [(none)]> start slave; Query OK, 0 rows affected (0.01 sec) MariaDB [(none)]> show slave status\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.129.128 Master_User: rep Master_Port: 3306 Connect_Retry: 60 Master_Log_File: master-bin.000001 Read_Master_Log_Pos: 493 Relay_Log_File: mariadb-relay-bin.000002 Relay_Log_Pos: 778 Relay_Master_Log_File: master-bin.000001 Slave_IO_Running: Yes Slave_SQL_Running: Yes
(6)測試:master 創建數據庫數據,slave 節點查看是同步了 master 節點的數據庫信息
master節點:
MariaDB [(none)]> show processlist\G *************************** 2. row *************************** Id: 5 User: rep Host: 192.168.129.129:47964 db: NULL Command: Binlog Dump Time: 40 State: Master has sent all binlog to slave; waiting for binlog to be updated Info: NULL Progress: 0.000 2 rows in set (0.00 sec) MariaDB [(none)]> create database bbs; Query OK, 1 row affected (0.00 sec) MariaDB [(none)]> create table bbs.t1(id int); Query OK, 0 rows affected (0.02 sec) MariaDB [(none)]> insert into bbs.t1 values(1); Query OK, 1 row affected (0.01 sec) MariaDB [(none)]> select * from bbs.t1; +------+ | id | +------+ | 1 | +------+ 1 row in set (0.00 sec)
slave1節點:
MariaDB [(none)]> show processlist\G *************************** 1. row *************************** Id: 2 User: root Host: localhost db: NULL Command: Query Time: 0 State: NULL Info: show processlist Progress: 0.000 *************************** 2. row *************************** Id: 3 User: system user Host: db: NULL Command: Connect Time: 203 State: Waiting for master to send event Info: NULL Progress: 0.000 *************************** 3. row *************************** Id: 4 User: system user Host: db: NULL Command: Connect Time: 42 State: Slave has read all relay log; waiting for the slave I/O thread to update it Info: NULL Progress: 0.000 3 rows in set (0.00 sec) MariaDB [(none)]> select * from bbs.t1; #查看數據主從配置成功 +------+ | id | +------+ | 1 | +------+ 1 row in set (0.01 sec)
2.5 mysql 主從狀況監測主要參數
Slave_IO_Running:線程是否打開 YES/No/NULL
Slave_SQL_Running:線程是否打開 YES/No/NULL
Seconds_Behind_Master:和主庫比同步的延遲的秒數
2.6 可能導致主從延時的因素
主從時鍾是否一致
網絡通信是否存在延遲
是否和日志類型,數據過大有關
從庫性能,有沒開啟 binlog
從庫查詢是否優化
3、mysql 雙主架構
3.1 實現
(1)兩台 mysql 都可讀寫,互為主備,默認只使用一台(masterA)負責數據的寫入,另一台(masterB)備用;
(2)masterA 是 masterB 的主庫,masterB 又是 masterA 的主庫,它們互為主從;
(3)兩台主庫之間做高可用,可以采用 keepalived 等方案(使用 VIP 對外提供服務);
(4)所有提供服務的從服務器與 masterB 進行主從同步(雙主多從);
(5)建議采用高可用策略的時候,masterA 或 masterB 均不因宕機恢復后而搶占 VIP(非搶占模式);
這樣做可以在一定程度上保證主庫的高可用,在一台主庫 down 掉之后,可以在極短的時間內切換到另一台主庫上(盡可能減少主庫宕機對業務造成的影響),減少了主從同步給線上主庫帶來的壓力;
masterB 可能會一直處於空閑狀態(可以用它當從庫,負責部分查詢);
主庫后面提供服務的從庫要等 masterB 先同步完了數據后才能去 masterB 上去同步數據,這樣可能會造成一定程度的同步延時;
3.2 mysql 主主同步配置
主主環境構建:同樣基於centos7-mariadb
mysql1:192.168.129.128
mysql2:192.168.129.129
(1)關閉防火牆、selinux(同上:主從)
(2)mysql1 節點:
[root@mysql1 ~]#vim /etc/my.cnf log-bin=mysql-bin server-id = 4 [root@mysql1 ~]#systemctl start mariadb [root@mysql1 ~]#mysql MariaDB [(none)]> reset master; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> grant replication slave,replication client on *.* -> to rep@'192.168.129.%' identified by 'localhost'; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> flush privileges; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> change master to -> master_host='192.168.129.129', -> master_user='rep', -> master_password='localhost', -> master_log_file='mysql-bin.000001', -> master_log_pos=0; Query OK, 0 rows affected (0.02 sec) MariaDB [(none)]> show slave status\G *************************** 1. row *************************** Slave_IO_State: Master_Host: 192.168.129.129 Master_User: rep Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000001 Read_Master_Log_Pos: 4 Relay_Log_File: mariadb-relay-bin.000001 Relay_Log_Pos: 4 Relay_Master_Log_File: mysql-bin.000001 Slave_IO_Running: No Slave_SQL_Running: No MariaDB [(none)]> slave start; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> show slave status\G *************************** 1. row *************************** Slave_IO_State: Connecting to master Master_Host: 192.168.129.129 Master_User: rep Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000001 Read_Master_Log_Pos: 4 Relay_Log_File: mariadb-relay-bin.000001 Relay_Log_Pos: 4 Relay_Master_Log_File: mysql-bin.000001 Slave_IO_Running: Connecting Slave_SQL_Running: Yes
(3)mysql2 節點:
[root@mysql2 ~]# vim /etc/my.cnf log-bin=mysql-bin server-id = 251 [root@mysql2 ~]# systemctl start mariadb [root@mysql2 ~]# mysql MariaDB [(none)]> reset master; Query OK, 0 rows affected (0.01 sec) MariaDB [(none)]> grant replication slave,replication client on *.* -> to rep@'192.168.129.%' identified by 'localhost'; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> flush privileges; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> change master to -> master_host='192.168.129.128', -> master_user='rep', -> master_password='localhost', -> master_log_file='mysql-bin.000001', -> master_log_pos=0; ERROR 1198 (HY000): This operation cannot be performed with a running slave; run STOP SLAVE first #此處報錯需要停止SLAVE MariaDB [(none)]> stop slave #停止SLAVE -> ; Query OK, 0 rows affected (0.01 sec) MariaDB [(none)]> change master to master_host='192.168.129.128', master_user='rep', master_password='localhost', master_log_file='mysql-bin.000001', master_log_pos=0; Query OK, 0 rows affected (0.02 sec) MariaDB [(none)]> show slave status\G *************************** 1. row *************************** Slave_IO_State: Master_Host: 192.168.129.128 Master_User: rep Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000001 Read_Master_Log_Pos: 4 Relay_Log_File: mariadb-relay-bin.000001 Relay_Log_Pos: 4 Relay_Master_Log_File: mysql-bin.000001 Slave_IO_Running: No Slave_SQL_Running: No MariaDB [(none)]> slave start; Query OK, 0 rows affected (0.00 sec) MariaDB [(none)]> show slave status\G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.129.128 Master_User: rep Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000001 Read_Master_Log_Pos: 493 Relay_Log_File: mariadb-relay-bin.000002 Relay_Log_Pos: 777 Relay_Master_Log_File: mysql-bin.000001 Slave_IO_Running: Yes Slave_SQL_Running: Yes
(4)測試:
在 mysql1 節點創建數據庫,在 mysql2 節點查看:
mysql1 節點:
MariaDB [(none)]> create database data1; Query OK, 1 row affected (0.01 sec) MariaDB [(none)]> create table data1.t1; ERROR 1113 (42000): A table must have at least 1 column MariaDB [(none)]> create table data1.t1(name int); Query OK, 0 rows affected (0.02 sec) MariaDB [(none)]> insert into data1.t1 values(1); Query OK, 1 row affected (0.00 sec) MariaDB [(none)]> select * from data1.t1; +------+ | name | +------+ | 1 | +------+
mysql2 節點查看:
MariaDB [(none)]> select * from data1.t1; +------+ | name | +------+ | 1 | +------+
同理 mysql2 節點創建數據庫,mysql1 節點查看;至此實現 mysql 主主復制。
4、生產環境其他常用設置
4.1 配置忽略權限庫同步參數
binlog-ignore-db='information_schema mysql test'
4.2 從庫備份開啟 binlog
log-slave-updates log_bin = mysql-bin expire_logs_days = 7
應用場景:級聯復制或從庫做數據備份。
4.3 從庫只讀 read-only 來實現
innodb_read_only = ON
結論:當用戶權限中沒有SUPER權限(ALL權限是包括SUPER的)時,從庫的read-only生效!