Mysql主從複製集羣配置與實戰

主從複製實戰的服務器是我在騰訊雲官網上購買的幾臺雲服務器進行操作的,不得不說雲是一個好東西,以前都是在centos上進行模擬,現在在雲服務器上模擬感覺對自己的提升更大。這裏想強調一下,如果是在雲服務器上模擬主從複製,儘量選海外的服務器,因爲在下載mysql的時候國內服務器真的特別慢,海外服務器速度會快很多。現在開始進入正題。
(1)主從複製技術介紹
主從複製是Mysql數據庫的一種容災備份方案,是Mysql自帶的功能,無需藉助第三方工具,Mysql的主從複製並不是數據庫磁盤上的文件直接拷貝,而是通過邏輯的binlog日誌複製到要同步的服務器本地,然後由本地的線程讀取日誌裏面的SQL語句重新應用到Mysql數據庫中。

(2)Mysql主從複製的常用拓撲結構
Mysql數據庫支持單向、雙向、鏈式級聯、環狀等不同業務場景的複製。在複製過程中,一臺服務器充當主服務器(Master),接收來自用戶的內容更新,而一個或多個其他服務器充當從服務器(Slave),接收來自主服務器Binlog文件的日誌內容,解析出SQL重新更新到從服務器,使得主從服務器數據達到一致。
推薦使用單向,雙向和級聯。
在這裏插入圖片描述
(3)Mysql主從複製工作流程
複製一個分爲三大步驟:
1.master將改變記錄到二進制日誌(binary log)中,這些記錄叫做二進制日誌事件(binary log events)
2.slave將master的binary log events拷貝到它的中繼日誌(relay log)中;
3.slave重做中繼日誌中的事件,將日誌操作還原並生成數據。
在這裏插入圖片描述
寫數據訪問的是主服務器,讓會話線程進行增刪改數據改變,當數據改變事務提交後就會以串行的方式寫入二進制日誌文件,此時從庫有一個IO線程會去讀取主庫的二進制日誌文件,在二進制日誌文件中有一個dump線程,這個dump線程會把二進制日誌文件的內容dump下來傳給IO線程,IO進程主要就是從二進制日誌中讀取事件(接受的單位是事件event),如果已經跟上master主機的數據(也就是沒數據發生改變),則IO線程會睡眠等待master產生新的事件。如果有不同,IO線程會把不同寫到中繼日誌中。然後SQL線程去讀中繼日誌(是SQL去讀哈)然後重新執行到從服務器中,所以SQL線程就是把中繼日誌進行回放還原並應用到本地數據庫中。
所以主從複製,主要是從庫主動去主庫去取,最重要的就是IO線程和SQL線程。中繼日誌通常會位於OS的緩存中,所以中繼日誌開銷很小。所以一共四個線程。

(4)Mysql主從複製技術的同步方式
一共有四種。(以下圖片出自網上)
傳統半同步複製:在半同步複製中,master寫數據到binlog且sync,且commit,雖然commit但是並不把結果返回給客戶,而是一直等待ACK。當至少一個slave request bilog後寫入到relay-log並flush disk,就返回ack(不需要回放完日誌)。性能、功能都介於異步和全同步中間,目的是爲了折中上述兩種架構的性能以及優缺點。
在這裏插入圖片描述
無損複製(增強版的半同步複製):在半同步複製中,master寫數據到binlog且sync,然後一直等待ACK. 當至少一個slave request bilog後寫入到relay-log並flush disk,就返回ack,然後主才Commit保證數據一定備份了,然後再把結果返回給客戶。增強版的半同步複製,數據零丟失,性能好。
在這裏插入圖片描述
在這裏插入圖片描述
異步複製:master寫數據到binlog然後comiit,同時sync(讓slave的io線程去dump),slave request binlog後寫入relay-log並flush disk(刷新到磁盤)。MySQL默認的複製即是異步的,主庫在執行完客戶端提交的事務後會立即將結果返給給客戶端,並不關心從庫是否已經接收並處理,這樣就會有一個問題,主如果crash掉了,此時主上已經提交的事務可能並沒有傳到從上,如果此時,強行將從提升爲主,可能導致新主上的數據不完整。搭建簡單,使用廣泛,但是異步所以有丟失數據庫風險,因爲master掛掉後,slave可能會丟失事務。
在這裏插入圖片描述
全同步複製:master寫數據到binlog且sync,然後commit,commit後主進入等待,當所有的從庫slave request binlog後寫入relay-log並flush disk,並且回放完日誌後再返回ack給主,主才把結果返回給客戶。也就是指當主庫執行完一個事務,所有的從庫都執行了該事務才返回給客戶端。因爲需要等待所有從庫執行完該事務才能返回,所以全同步複製的性能必然會收到嚴重的影響。優點保證數據安全,不丟失數據,缺點損失性能。
在這裏插入圖片描述

(5)Mysql主從複製技術的GTID特性
GTID:對於一個已提交事務的編號,事務的唯一編號,並且是一個全局唯一編號。GTID和事務會記錄到binlog中,用來標識事務。GTID是用來替代以前傳統複製方法(binlog+position日誌點)。Mysql支持GTID後,一個事務在集羣中就不再孤單,在每一個節點中,如果存在具有相同標識符的情況,可以避免同一個事務在同一個節點中出現多次的情況(也就是說以前是認某個日誌的某個點,現在是認某個日誌裏某個點做的事)。
GTID的出現最直接的效果就是:對每一個事務在集羣中具有了唯一性的意義,相對於行復制來講數據安全性更高,故障切換更簡單。因爲事務定義的越來越明晰,行復制針對的是內容複製。
GTID是由server_uuid:Sequence_Number組成。而server_uuid是一個Mysql實例的全局唯一標識,存放在$datadir/auto.cnf中。而Sequence_Number是Mysql內部的一個事務編號。一個Mysql實例是不會有重複的序列號的(保證服務器內唯一),所以這個也表示在該實例上已經提交事務的數量,並且隨着事務提交而遞增。
根據GTID可以知道事務最初是在哪個實例上提交的,方便故障排查和切換。
Gtid是mysql5.6之後纔出現的,如果現在我一個mysql8.0的從庫去多源複製一羣5.5的主庫,就不能用gtid來實現全局的id,所以這個時候就要做一個需求,做到流式備份。
關於GTID更多的講解,會在之後專門出一篇文章進行闡述。

(6)環境搭建
(主機和從機皆爲騰訊雲購買的服務器,文章中ip不是真實ip,進行了修改)
主機:172.26.0.16 3306端口
從機:172.26.0.12 3306端口
主庫用於生產,從庫用於數據容災和主庫備機。
第一步:
在主機和從機中 vi /etc/hosts加入主機和從機名方便識別。
在這裏插入圖片描述
第二步:兩臺機器都安好Mysql數據庫可以訪問。

(7)Mysql主從複製重要參數
1.基本參數
基本參數:bing-address = 172.26.0.16 綁定地址
服務器id:server_id=163306 主從不相同,規範建議:後IP+端口
跳過主機名/域名解析:skip_name_resolve = off 默認是關閉的
事務隔離級別:transaction-isolation = read-committed 設置爲讀已提交

2.關於binlog二進制日誌參數
log_bin=/mysql/log/3306/binlog/itpuxdb-binlog 二進制路徑放的位置
log_bin_index=/mysql/log/3306/binlog/itpuxdb-binlog.index 二進制索引放的位置
binlog_format=row (必須)二進制日誌文件格式 一定是行
binglog_rows_query_log_events=on 二進制日誌中記錄更詳細的SQL操作
sync_binlog = 1 默認,mysql每次提交事務之前會將二進制同步到磁盤上,保證服務器崩潰時不會丟失事件(同步日誌)
innodb_flush_log_at_trx_commit = 1 默認,每次事務提交時Mysql都會把log buffer(日誌緩存)的數據寫入log file(日誌文件),並且flush(刷到磁盤)中去。保證數據安全。

3.其他參數
log_bin_trust_function_creators=1 默認爲0,爲1是同步函數和存儲過程
max_binlog_size = 2048M 最大日誌大小,默認爲1024M
expire_logs_days = 7 binlog保留多少天,看具體安排
binlog_cache_size = 1M 默認32K,binlog緩存的大小,設置時要當心,建議1~4M,根據業務情況。
innodb_support_xa=1 這個參數是在主庫上設置的,默認是自動開啓。看到xa首先想到的是分佈式事務,這個參數確保事務日誌寫入bin-log的順序與事務的time-line是一致的,這樣在系統奔潰的時候,啓用日誌恢復,可以嚴格按照時間線來恢復數據庫。

4.關於relay_log中繼日誌參數
relay_log = /mysql/log/3306/relaylog/itpuxdb-relay.log 中繼日誌的路徑放在哪裏

relay-log-recover = 1 針對的是IO線程安全的,這是打開repication中繼日誌奔潰恢復模式,replication支持中繼日誌的自我修復功能。當slave從庫宕機後,如果replay-log發生損壞,導致一部分中繼日誌沒有處理,就自動放棄未執行的replay-log,重新從master上獲取日誌,繼續完成中繼日誌的恢復。也就是說該參數表示當前接收到的relay-log全部刪除,然後從SQL線程回放到的位置重新拉取。

relay_log_info_repository=table 針對的是SQL線程安全的,默認是file(SQL執行情況存放在文件中),SQL線程的數據回放是寫數據庫操作,而relay-info是寫文件操作,這兩個操作很難保證一致性。所以用table表的形式來記錄SQL線程的執行情況,把執行的中繼日誌消息relay-info將寫入到mysql.slave_relay_log_info這張表中

master_info_repository = table 默認是file(也就是把IO線程執行情況放在文件中),IO線程也是接收一個個的event,所以這個參數的作用是將接收到的event通過設置參數master_info_repository可以將master-info信息寫到什麼位置,設置爲table則把信息寫到表中,性能上比設置爲FILE有很高的的提升,可靠性也得到保證,設置爲table後,master-info將信息保存到mysql.salve_master_info
在這裏插入圖片描述
5.關於同步方式的參數(如果不加這些就默認異步同步)
半同步複製(Mysql5.6的方法):
loose_rpl_semi_sync_master_enabled = 1 開啓主的半同步複製
loose_rpl_semi_sync_slave_enabled = 1 開啓從的半同步複製
loose_rpl_semi_sync_master_timeout = 5000 超時5秒,切回異步

半同步和無損複製開啓(Mysql5.7方法,AFTER_SYNC和AFTER_COMMIT選一個):
rpl_semi_sync_master_wait_for_slave_count=1 至少收到1個slave發回的ack
rpl_semi_sync_master_wait_point=AFTER_SYNC 開啓無損複製
rpl_semi_sync_master_wait_point=AFTER_COMMIT 開啓半同步複製

6.關於GTID的參數
gtid_mode = on 打開gtid的模式
log_slave_updates = 1
enforce_gtid_consistency = 1

gtid_mode:打開gitd的模式有下面幾種
on:產生GTID,slave只接收帶GTID的事務
ON_PERMISSIVE:產生GTID,slave接受不帶GTID事務也接受帶GTID的事務
OFF:不產生GTID,slave只接受不帶參GTID的事務
OFF_PERMISSIVE:不產生GTID,slave接受不帶GTID事務也接受帶GTID的事務。

log_slave_updates:
當從庫log_slave_updates參數沒有開啓時,從庫的binlog不會記錄來源於主庫的操作記錄。只有開啓log_slave_updates,從庫binlog纔會記錄主庫同步的操作日誌。如果是多個從庫,切換後,建議關掉log_slave_updates參數,否則重置成主庫以後,可能會將已經執行過的二進制日誌重複傳送給S2(從庫),導致S2(從庫)同步錯誤。

enforce_gtid_consistency:
on:當發現語句/事務不支持GTID時,返回錯誤信息
WARN:當發現不支持語句/事務,返回警告,並且日誌中記錄警告信息
OFF:不檢查是否有GTID不支持的語句/事務

(8)Mysql主從複製實戰
第一步:準備主從二進制與中繼日誌目錄
mkdir -p /mysql/log/3306/binlog 主庫創建二進制日誌
mkdir -p /mysql/log/3306/relaylog 備庫中繼日誌
chown -R mysql:mysql /mysql/log/3306/binlog 下面修改權限
chown -R mysql:mysql /mysql/log/3306/relaylog
chmod -R 775 /mysql/log/3306/binlog
chmod -R 775 /mysql/log/3306/relaylog

第二步:準備主庫參數 在vi /etc/my.cnf中添加(記住日誌位置)
bind-address= 172.26.0.16 主庫ip
server_id=163306 唯一serverid
skip_name_resolve = ON
expire_logs_days = 7
binlog_cache_size = 1M
max_binlog_size = 2048M
log_bin_trust_function_creators = 1
innodb_flush_log_at_trx_commit =1
sync_binlog = 1

transaction-isolation = READ-COMMITTED
gtid_mode = ON
enforce_gtid_consistency = 1
log-slave-updates = 1
binlog_gtid_simple_recovery=1
//下面的這四行就是開啓二進制日誌格式
log_bin=/mysql/log/3306/binlog/itpuxdb-binlog
log_bin_index=/mysql/log/3306/binlog/itpuxdb-binlog.index
binlog_format=ROW
binlog_rows_query_log_events=on

//配置無損同步配置
plugin_dir= /usr/local/mysql/lib/plugin/
plugin_load =
“rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so”
loose_rpl_semi_sync_master_enabled = 1
loose_rpl_semi_sync_slave_enabled = 1
loose_rpl_semi_sync_master_timeout = 5000
rpl_semi_sync_master_wait_point = AFTER_SYNC
rpl_semi_sync_master_wait_for_slave_count = 1

然後重啓systemctl restart mysqld開是否生效。

第三步:準備從庫
bind-address= 172.26.0.12
server_id=123306
skip_name_resolve = ON
expire_logs_days = 7
binlog_cache_size = 1M
max_binlog_size = 2048M
log_bin_trust_function_creators = 1
innodb_flush_log_at_trx_commit =1
sync_binlog = 1

transaction-isolation = READ-COMMITTED
gtid_mode = ON
enforce_gtid_consistency = 1
log-slave-updates = 1
//二進制日誌
binlog_gtid_simple_recovery=1
log_bin=/mysql/log/3306/binlog/itpuxdb-binlog
log_bin_index=/mysql/log/3306/binlog/itpuxdb-binlog.index
binlog_format=ROW
binlog_rows_query_log_events=on
//中繼日誌
relay_log = /mysql/log/3306/relaylog/itpuxdb-relay.log
read_only=1

//無損同步
plugin_dir=/usr/local/mysql/lib/plugin/
plugin_load =
“rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so”
loose_rpl_semi_sync_master_enabled = 1
loose_rpl_semi_sync_slave_enabled = 1
loose_rpl_semi_sync_master_timeout = 5000
rpl_semi_sync_master_wait_point = AFTER_SYNC
rpl_semi_sync_master_wait_for_slave_count = 1

配置好後,重啓主從數據庫,沒有異常則正確。

第四步:主從庫創建複製用戶並授權
mysql -uroot -prootroot
create user ‘repuser’@’%’ identified with mysql_native_password BY ‘repuser123’;
grant replication client,replication slave on . to ‘repuser’@’%’;
flush privileges;
select user,host from mysql.user;

這個用戶是repuser。首先進入mysql數據庫並創建一個用戶repuser,密碼是repuser123,然後授權replication client和replication slave就是主從數據庫*.*的所有數據庫和對象到repuser這個用戶,然後flush刷新權限。這個步驟主從庫都要去做。

第五步:在從庫上使slave與master建立連接

mysql -uroot -p******
stop slave;
reset master;
reset slave;
change master to
master_host=’ 172.26.0.16’, //從庫連得主機
master_port=3306, //端口
master_user=‘repuser’, //連主庫用戶
master_password=‘repuser123’, //連主庫密碼
master_auto_position=1; //自動開始

上面這個就是開啓gitd這個功能。

第六步:主從同步
start slave; //運行從庫
show slave status \G //查看狀態命令
SHOW PROCESSLIST; //看進程線程
在這裏插入圖片描述
當紅色框的爲yes後,就成功了。

第七步:數據驗證,看是否同步了。
主庫:
create database itpuxdb1;
create user ‘itpux0’@’%’ identified with mysql_native_password by ‘itpux01’;
grant all privileges on itpuxdb1.* to ‘itpux0’@’%’;
flush privileges;

use itpuxdb1;
create table itpuxbak11 (id int,name varchar(40));
insert into itpuxbak values
(1,‘itpux111’),(2,‘itpux112’),(3,‘itpux113’),(4,‘itpux114’),(5,‘itpux115’);
commit;
select * from itpuxbak11;

備庫檢查:
mysql -uitpux0 -pitpux01
select * from itpuxdb1.itpuxbak11;
insert into itpuxdb1.itpuxbak11 values (6,‘itpux116’);
mysql -uroot -prootroot
show slave status \G
show processlist;

因爲從庫設置了read_only=1,所以只能讀。但是如果你是用超級管理員root登錄的,那麼從機也可以插入。之後要使用只需要操作從機就可以了,start slave。

第八步:如果想設置互爲主從,則首先雙方停掉stop slave
先在b機器show master status;查看file和position字段的值;然後在a機器中設置:
change master to
master_host=‘172.26.0.16’,
master_port=3306,
master_user=‘repuser’,
master_password=‘repuser123’,
master_auto_position=0,
master_log_file=’ itpuxdb-binlog.000001’, //b機器的file
master_log_pos=155; //b機器的pos

change master to
master_host=‘172.26.0.12’,
master_port=3306,
master_user=‘repuser’,
master_password=‘repuser123’,
master_auto_position=0,
master_log_file=‘itpuxdb-binlog.000002’,
master_log_pos=55989;

然後start slave。
然後再a機器中show master status;查看file和position字段的值;然後在b機器中設置:
change master to
master_host=‘172.26.0.12’,
master_port=3306,
master_user=‘repuser’,
master_password=‘repuser123’,
master_auto_position=0,
master_log_file=‘itpuxdb-binlog.000001’,
master_log_pos=155;

然後再slave sstart就可以了。

(9)主從同步延遲
之所以會造成主從同步延遲,主要原因是從庫是以單線程的形式去讀取主庫寫操作的binlog,當主庫的TPS(每秒事務量)併發較高時,產生的DDL數量了超過slave一個sql線程所能承受的範圍:
①主庫針對寫操作,順序寫binlog,主庫對所有的DDL和DML在binlog中都是順序寫,效率高,只有當主庫事務commit後從庫纔去讀取binlog進行同步,如果主庫一個事務執行了一分鐘,那麼延遲就出來了。

②其次,從庫的Slave_SQL_Running線程讀取binlog在本地原樣執行是隨機寫,這樣成本高很多,就可能在slave的其他查詢上產生lock爭用,而且Slave_SQL_Running是單線程的,當一個DDL卡住了要執行10分鐘,那麼所有之後的DDL也會等待這個DDL執行完二次可以繼續執行,就導致了延遲。而對於這個卡住的DDL在主庫上其實也會卡,但因爲主庫可以併發執行,而從庫單線程不可以,所以slave會延遲。

DDL:創建數據庫中的各種對象-----表、視圖、索引
DML:insert、update、delete

對於主從同步延遲的解決:
對於ddl而言,可以採用一個online DDL的方式,也就是在線ddl:也就是新建一個表,這個表有兩個操作,一個是拷存量(就是把原始表的數據通過replace的方式插入新表),第二個是添增量(就是模擬自己是一個從庫,然後添加原始表更改添加的數據),最後鎖表1秒鐘用來進行表重命名。這些步驟在執行的過程中從表也在跟着執行,所以從表也會有一張這種表,從而解決DDL的延遲問題。
對於DML而言,就是主庫多個事務併發執行的情況,在Mysql5.6之後可以設置slave_parallel_workers參數來實現並行複製,也就是在從庫中創建slave_parallel_workers設置的參數那麼多個worker空間,從庫會把讀取到主庫的binlog裏的數據放到這些worker空間中並行執行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章