為了保障數(shù)據(jù)的安全與穩(wěn)定性,我們常用數(shù)據(jù)庫的主從復制與主主復制來實現(xiàn)。主從復制為從機實時拷貝一份主機的數(shù)據(jù),當主機有數(shù)據(jù)變化時,從機的數(shù)據(jù)會跟著變,當從機數(shù)據(jù)有變化時,主機數(shù)據(jù)不變;同樣地,主主復制就是,多個主機之間,只要有一個主機的數(shù)據(jù)變化了,其它主機數(shù)據(jù)也會跟著變化。
成都創(chuàng)新互聯(lián)-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設、高性價比林口網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式林口網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設找我們,業(yè)務覆蓋林口地區(qū)。費用合理售后完善,十多年實體公司更值得信賴。
添加以下內(nèi)容
如果你是使用我之前那種方式啟動的MySQL,那么你只需要去你相關聯(lián)的宿主機的配置文件夾里面去建立一個 my.cnf 然后寫入上面的類容就好了。
比如:我的啟動命令如下(不應該換行的,這里為了方便查看,我給它分行了)
那么我只需要在 /docker/mysql_master/conf 這個目錄下創(chuàng)建 my.cnf 文件就好了。
這個命令是需要在容器里面執(zhí)行的
docker重啟mysql會關閉容器,我們需要重啟容器。
確保在主服務器上 skip_networking 選項處于 OFF 關閉狀態(tài), 這是默認值。 如果是啟用的,則從站無法與主站通信,并且復制失敗。
我的命令如下
在從服務器配置連接到主服務器的相關信息 (在容器里面的mysql執(zhí)行)
上面代碼的xxxxx你需要換成你的IP,docker 查看容器 IP 的命令如下:
啟動的那個從服務器的線程
測試的話,你可以在主服務器里面,創(chuàng)建一個數(shù)據(jù)庫,發(fā)現(xiàn)從服務器里面也有了,就成功了。
如果你還想要一個從服務器,那么你只需要按照上面配置從服務器再配置一個就行了,新建的從服務器,會自動保存主服務器之前的數(shù)據(jù)。(測試結果) 如果你上面的主從復制搞定了,那么這個主主復制就很簡單了。我們把上面的從服務器也改成主服務器
1)、修改上面的從服務器的my.cnf文件,和主服務器的一樣(注意這個server-id不能一樣)然后重啟服務器 2)、在從服務器里面創(chuàng)建一個復制用戶創(chuàng)建命令一樣(這里修改一下用戶名可以改為 repl2) 3)、在之前的主服務器里面運行下面這個代碼
上面主要是教你怎么搭建一個MySQL集群,但是這里面還有很多其它的問題。也是我在學習過程中思考的問題,可能有的小伙伴上來看到文章長篇大論的看不下去,只想去實現(xiàn)這樣一直集群功能,所以我就把問題寫在下面了。
1)、MySQL的replication和pxc MySQL的集群方案有replication和pxc兩種,上面是基于replication實現(xiàn)的。
replication: 異步復制,速度快,無法保證數(shù)據(jù)的一致性。 pxc: 同步復制,速度慢,多個集群之間是事務提交的數(shù)據(jù)一致性強。
2)、MySQL的replication數(shù)據(jù)同步的原理 我們在配置的時候開啟了它的二進制日志,每次操作數(shù)據(jù)庫的時候都會更新到這個日志里面去。主從通過同步這個日志來保證數(shù)據(jù)的一致性。
3)、可否不同步全部的數(shù)據(jù) 可以配置,同步哪些數(shù)據(jù)庫,甚至是哪些表。
4)、怎么關閉和開始同步
5)、我就我的理解畫出了,主從、主從從、主主、復制的圖。
往期推薦:
利用Docker僅花1分鐘時間安裝好MySQL服務
Linux下MySQL 5.7的離線與在線安裝(圖文)
Linux下安裝MySQL8.0(收藏?。?/p>
大致流程:主庫將變更寫binlog日志,然后從庫連接到主庫之后,從庫有一個IO線程,將主庫的binlog日志拷貝到自己本地,寫入一個中繼日志 relay日志中。接著從庫中有一個SQL線程會從中繼日志讀取binlog,然后執(zhí)行binlog日志中的內(nèi)容,也就是在自己本地再次執(zhí)行一遍SQL,這樣就可以保證自己跟主庫的數(shù)據(jù)是一樣的。
如果主庫突然宕機,然后恰好數(shù)據(jù)還沒同步到從庫,那么有些數(shù)據(jù)可能在從庫上是沒有的,這時候從庫成為了主庫,那么有些數(shù)據(jù)可能就丟失了。
開啟半同步復制 semi-sync ,用來解決主庫數(shù)據(jù)丟失問題;
這個所謂半同步復制, semi-sync復制 ,指的就是主庫寫入binlog日志之后,就會將強制此時立即將數(shù)據(jù)同步到從庫,從庫將日志 寫入自己本地的relay log之后 ,接著會 返回一個ack 給主庫, 主庫接收到至少一個從庫的ack之后才會認為寫操作完成了。 如果 過程出現(xiàn)失敗 ,那么 我們的客戶端就可以進行重試了 ;
主從延遲對于讀寫分離的涉及影響比較大
這里有一個非常重要的一點,就是 從庫同步主庫數(shù)據(jù)的過程是串行化的 ,也就是說 主庫上并行的操作,在從庫上會串行執(zhí)行 。所以這就是一個非常重要的點了,由于從庫從主庫拷貝日志以及串行執(zhí)行SQL的特點,在 高并發(fā)場景下,主庫大量的寫,那么從庫的數(shù)據(jù)一個個的讀,那么就會導致從庫同步一定會比主庫慢一些,是有延時的 。所以經(jīng)常出現(xiàn),剛寫入主庫的數(shù)據(jù)可能是讀不到的,要過幾十毫秒,甚至幾百毫秒才能讀取到。(主庫并發(fā)寫的量級越高,從庫積壓的同步數(shù)據(jù)越多,延遲越高)
我們可以用 show status 看看 Seconds_Behind_Master 參數(shù),你可以看到從庫復制主庫的數(shù)據(jù)落后了幾ms,但是這個也不是完全準確,可以看 Seconds_Behind_Master的
對于解決主從延遲,解決方案可以從以下方面考慮
MySQL支持單向、異步復制,復制過程中一個服務器充當主服務器,而一個或多個其它服務器充當從服務器。主服務器將更新寫入二進制日志文件,并維 護日志文件的一個索引以跟蹤日志循環(huán)。當一個從服務器連接到主服務器時,它通知主服務器從服務器在日志中讀取的最后一次成功更新的位置。從服務器接收從那 時起發(fā)生的任何更新,然后封鎖并等待主服務器通知下一次更新。
為什么使用主從復制?
1、主服務器/從服務器設置增加了健壯性。主服務器出現(xiàn)問題時,你可以切換到從服務器作為備份。
2、通過在主服務器和從服務器之間切分處理客戶查詢的負荷,可以得到更好的客戶響應時間。但是不要同時在主從服務器上進行更新,這樣可能引起沖突。
3、使用復制的另一個好處是可以使用一個從服務器執(zhí)行備份,而不會干擾主服務器。在備份過程中主服務器可以繼續(xù)處理更新。
MySQL使用3個線程來執(zhí)行復制功能(其中1個在主服務器上,另兩個在從服務器上。當發(fā)出START SLAVE時,從服務器創(chuàng)建一個I/O線程,以連接主服務器并讓主服務器發(fā)送二進制日志。主服務器創(chuàng)建一個線程將二進制日志中的內(nèi)容發(fā)送到從服務器。從服 務器I/O線程讀取主服務器Binlog Dump線程發(fā)送的內(nèi)容并將該數(shù)據(jù)拷貝到從服務器數(shù)據(jù)目錄中的本地文件中,即中繼日志。第3個線程是SQL線程,從服務器使用此線程讀取中繼日志并執(zhí)行日 志中包含的更新。SHOW PROCESSLIST語句可以查詢在主服務器上和從服務器上發(fā)生的關于復制的信息。
默認中繼日志使用host_name-relay-bin.nnnnnn形式的文件名,其中host_name是從服務器主機名,nnnnnn是序 列號。用連續(xù)序列號來創(chuàng)建連續(xù)中繼日志文件,從000001開始。從服務器跟蹤中繼日志索引文件來識別目前正使用的中繼日志。默認中繼日志索引文件名為 host_name-relay-bin.index。在默認情況,這些文件在從服務器的數(shù)據(jù)目錄中被創(chuàng)建。中繼日志與二進制日志的格式相同,并且可以用 mysqlbinlog讀取。當SQL線程執(zhí)行完中繼日志中的所有事件后,中繼日志將會被自動刪除。
從服務器在數(shù)據(jù)目錄中另外創(chuàng)建兩個狀態(tài)文件--master.info和relay-log.info。狀態(tài)文件保存在硬盤上,從服務器關閉時不會丟失。下次從服務器啟動時,讀取這些文件以確定它已經(jīng)從主服務器讀取了多少二進制日志,以及處理自己的中繼日志的程度。
設置主從復制:
1、確保在主服務器和從服務器上安裝的MySQL版本相同,并且最好是MySQL的最新穩(wěn)定版本。
2、在主服務器上為復制設置一個連接賬戶。該賬戶必須授予REPLICATION SLAVE權限。如果賬戶僅用于復制(推薦這樣做),則不需要再授予任何其它權限。
mysql GRANT REPLICATION SLAVE ON *.*
- TO 'replication'@'%.yourdomain.com' IDENTIFIED BY 'slavepass';
3、執(zhí)行FLUSH TABLES WITH READ LOCK語句清空所有表和塊寫入語句:
mysql FLUSH TABLES WITH READ LOCK;
保持mysql客戶端程序不要退出。開啟另一個終端對主服務器數(shù)據(jù)目錄做快照。
shell cd /usr/local/mysql/
shell tar -cvf /tmp/mysql-snapshot.tar ./data
如果從服務器的用戶賬戶與主服務器的不同,你可能不想復制mysql數(shù)據(jù)庫。在這種情況下,應從歸檔中排除該數(shù)據(jù)庫。你也不需要在歸檔中包括任何日志文件或者master.info或relay-log.info文件。
當FLUSH TABLES WITH READ LOCK所置讀鎖定有效時(即mysql客戶端程序不退出),讀取主服務器上當前的二進制日志名和偏移量值:
mysql SHOW MASTER STATUS;
+---------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+---------------+----------+--------------+------------------+
| mysql-bin.003 | 73 | test | manual,mysql |
+---------------+----------+--------------+------------------+
File列顯示日志名,而Position顯示偏移量。在該例子中,二進制日志值為mysql-bin.003,偏移量為73。記錄該值。以后設置從服務器時需要使用這些值。它們表示復制坐標,從服務器應從該點開始從主服務器上進行新的更新。
如果主服務器運行時沒有啟用--logs-bin,SHOW MASTER STATUS顯示的日志名和位置值為空。在這種情況下,當以后指定從服務器的日志文件和位置時需要使用的值為空字符串('')和4.
取得快照并記錄日志名和偏移量后,回到前一中端重新啟用寫活動:
mysql UNLOCK TABLES;
4、確保主服務器主機上my.cnf文件的[mysqld]部分包括一個log-bin選項。該部分還應有一個server-id=Master_id選項,其中master_id必須為1到232–1之間的一個正整數(shù)值。例如:
[mysqld]
log-bin
server-id=1
如果沒有提供那些選項,應添加它們并重啟服務器。
5、停止從服務器上的mysqld服務并在其my.cnf文件中添加下面的行:
[mysqld]
server-id=2
slave_id值同Master_id值一樣,必須為1到232–1之間的一個正整數(shù)值。并且,從服務器的ID必須與主服務器的ID不相同。
6、將數(shù)據(jù)備據(jù)目錄中。確保對這些文件和目錄的權限正確。服務器 MySQL運行的用戶必須能夠讀寫文件,如同在主服務器上一樣。
Shell chown -R mysql:mysql /usr/local/mysql/data
7、啟動從服務器。在從服務器上執(zhí)行下面的語句,用你的系統(tǒng)的實際值替換選項值:
mysql CHANGE MASTER TO
- MASTER_HOST='master_host_name',
- MASTER_USER='replication_user_name',
- MASTER_PASSWORD='replication_password',
- MASTER_LOG_FILE='recorded_log_file_name',
- MASTER_LOG_POS=recorded_log_position;
8、啟動從服務器線程:
mysql START SLAVE;
執(zhí)行這些程序后,從服務器應連接主服務器,并補充自從快照以來發(fā)生的任何更新。
9、如果出現(xiàn)復制錯誤,從服務器的錯誤日志(HOSTNAME.err)中也會出現(xiàn)錯誤消息。
10、從服務器復制時,會在其數(shù)據(jù)目錄中發(fā)現(xiàn)文件master.info和HOSTNAME-relay-log.info。從服務器使用這兩個文 件跟蹤已經(jīng)處理了多少主服務器的二進制日志。不要移除或編輯這些文件,除非你確切知你正在做什么并完全理解其意義。即使這樣,最好是使用CHANGE MASTER TO語句。
MySQL 主從一直是面試常客,里面的知識點雖然基礎,但是能回答全的同學不多。
比如樓哥之前面試小米,就被問到過主從復制的原理,以及主從延遲的解決方案,因為回答的非常不錯,給面試官留下非常好的印象。你之前面試,有遇到過哪些 MySQL 主從的問題呢?
所謂 MySQL 主從,就是建立兩個完全一樣的數(shù)據(jù)庫,一個是主庫,一個是從庫, 主庫對外提供讀寫的操作,從庫對外提供讀的操作 ,下面是一主一從模式:
對于數(shù)據(jù)庫單機部署,在 4 核 8G 的機器上運行 MySQL 5.7 時,大概可以支撐 500 的 TPS 和 10000 的 QPS, 當遇到一些活動時,查詢流量驟然,就需要進行主從分離。
大部分系統(tǒng)的訪問模型是讀多寫少,讀寫請求量的差距可能達到幾個數(shù)量級,所以我們可以通過一主多從的方式, 主庫只負責寫入和部分核心邏輯的查詢,多個從庫只負責查詢,提升查詢性能,降低主庫壓力。
MySQL 主從還能做到服務高可用,當主庫宕機時,從庫可以切成主庫,保證服務的高可用,然后主庫也可以做數(shù)據(jù)的容災備份。
整體場景總結如下:
MySQL 的主從復制是依賴于 binlog 的,也就是記錄 MySQL 上的所有變化并以二進制形式保存在磁盤上二進制日志文件。
主從復制就是將 binlog 中的數(shù)據(jù)從主庫傳輸?shù)綇膸焐?,一般這個過程是異步的,即主庫上的操作不會等待 binlog 同步的完成。
詳細流程如下:
當主庫和從庫數(shù)據(jù)同步時,突然中斷怎么辦?因為主庫與從庫之間維持了一個長鏈接,主庫內(nèi)部有一個線程,專門服務于從庫的這個長鏈接的。
對于下面的情況,假如主庫執(zhí)行如下 SQL,其中 a 和 create_time 都是索引:
我們知道,數(shù)據(jù)選擇了 a 索引和選擇 create_time 索引,最后 limit 1 出來的數(shù)據(jù)一般是不一樣的。
所以就會存在這種情況:在 binlog = statement 格式時,主庫在執(zhí)行這條 SQL 時,使用的是索引 a,而從庫在執(zhí)行這條 SQL 時,使用了索引 create_time,最后主從數(shù)據(jù)不一致了。
那么我們改如何解決呢?
可以把 binlog 格式修改為 row,row 格式的 binlog 日志記錄的不是 SQL 原文,而是兩個 event:Table_map 和 Delete_rows。
Table_map event 說明要操作的表,Delete_rows event用于定義要刪除的行為,記錄刪除的具體行數(shù)。 row 格式的 binlog 記錄的就是要刪除的主鍵 ID 信息,因此不會出現(xiàn)主從不一致的問題。
但是如果 SQL 刪除 10 萬行數(shù)據(jù),使用 row 格式就會很占空間的,10 萬條數(shù)據(jù)都在 binlog 里面,寫 binlog 的時候也很耗 IO。但是 statement 格式的 binlog 可能會導致數(shù)據(jù)不一致。
設計 MySQL 的大叔想了一個折中的方案,mixed 格式的 binlog,其實就是 row 和 statement 格式混合使用, 當 MySQL 判斷可能數(shù)據(jù)不一致時,就用 row 格式,否則使用就用 statement 格式。
有時候我們遇到從數(shù)據(jù)庫中獲取不到信息的詭異問題時,會糾結于代碼中是否有一些邏輯會把之前寫入的內(nèi)容刪除,但是你又會發(fā)現(xiàn),過了一段時間再去查詢時又可以讀到數(shù)據(jù)了,這基本上就是主從延遲在作怪。
主從延遲,其實就是“從庫回放” 完成的時間,與 “主庫寫 binlog” 完成時間的差值, 會導致從庫查詢的數(shù)據(jù),和主庫的不一致 。
談到 MySQL 數(shù)據(jù)庫主從同步延遲原理,得從 MySQL 的主從復制原理說起:
總結一下主從延遲的主要原因 :主從延遲主要是出現(xiàn)在 “relay log 回放” 這一步,當主庫的 TPS 并發(fā)較高,產(chǎn)生的 DDL 數(shù)量超過從庫一個 SQL 線程所能承受的范圍,那么延時就產(chǎn)生了,當然還有就是可能與從庫的大型 query 語句產(chǎn)生了鎖等待。
我們一般會把從庫落后的時間作為一個重點的數(shù)據(jù)庫指標做監(jiān)控和報警,正常的時間是在毫秒級別,一旦落后的時間達到了秒級別就需要告警了。
解決該問題的方法,除了縮短主從延遲的時間,還有一些其它的方法,基本原理都是盡量不查詢從庫。
具體解決方案如下:
在實際應用場景中,對于一些非常核心的場景,比如庫存,支付訂單等,需要直接查詢從庫,其它非核心場景,就不要去查主庫了。
兩臺機器 A 和 B,A 為主庫,負責讀寫,B 為從庫,負責讀數(shù)據(jù)。
如果 A 庫發(fā)生故障,B 庫成為主庫負責讀寫,修復故障后,A 成為從庫,主庫 B 同步數(shù)據(jù)到從庫 A。
一臺主庫多臺從庫,A 為主庫,負責讀寫,B、C、D為從庫,負責讀數(shù)據(jù)。
如果 A 庫發(fā)生故障,B 庫成為主庫負責讀寫,C、D負責讀,修復故障后,A 也成為從庫,主庫 B 同步數(shù)據(jù)到從庫 A。