小白都能懂的Mysql主從復(fù)制原理(原理+實(shí)操)
Python實(shí)戰(zhàn)社群
Java實(shí)戰(zhàn)社群
長按識別下方二維碼,按需求添加
掃碼關(guān)注添加客服
進(jìn)Python社群▲
掃碼關(guān)注添加客服
進(jìn)Java社群▲
作者丨黎杜
來源丨黎杜編程
主從復(fù)制簡介
在實(shí)際的生產(chǎn)中,為了解決Mysql的單點(diǎn)故障已經(jīng)提高M(jìn)ySQL的整體服務(wù)性能,一般都會采用「主從復(fù)制」。
比如:在復(fù)雜的業(yè)務(wù)系統(tǒng)中,有一句sql執(zhí)行后導(dǎo)致鎖表,并且這條sql的的執(zhí)行時(shí)間有比較長,那么此sql執(zhí)行的期間導(dǎo)致服務(wù)不可用,這樣就會嚴(yán)重影響用戶的體驗(yàn)度。
主從復(fù)制中分為「主服務(wù)器(master)「和」從服務(wù)器(slave)」,「主服務(wù)器負(fù)責(zé)寫,而從服務(wù)器負(fù)責(zé)讀」,Mysql的主從復(fù)制的過程是一個(gè)「異步的過程」。
這樣讀寫分離的過程能夠是整體的服務(wù)性能提高,即使寫操作時(shí)間比較長,也不影響讀操作的進(jìn)行。
主從復(fù)制的原理
首先放一張Mysql主從復(fù)制的原理圖,總的來說Mysql的主從復(fù)制原理還是比較好理解的,原理非常的簡單。

Mysql的主從復(fù)制中主要有三個(gè)線程:master(binlog dump thread)、slave(I/O thread 、SQL thread),Master一條線程和Slave中的兩條線程。
master(binlog dump thread)主要負(fù)責(zé)Master庫中有數(shù)據(jù)更新的時(shí)候,會按照binlog格式,將更新的事件類型寫入到主庫的binlog文件中。
并且,Master會創(chuàng)建log dump線程通知Slave主庫中存在數(shù)據(jù)更新,這就是為什么主庫的binlog日志一定要開啟的原因。
I/O thread線程在Slave中創(chuàng)建,該線程用于請求Master,Master會返回binlog的名稱以及當(dāng)前數(shù)據(jù)更新的位置、binlog文件位置的副本。
然后,將binlog保存在 「relay log(中繼日志)」 中,中繼日志也是記錄數(shù)據(jù)更新的信息。
SQL線程也是在Slave中創(chuàng)建的,當(dāng)Slave檢測到中繼日志有更新,就會將更新的內(nèi)容同步到Slave數(shù)據(jù)庫中,這樣就保證了主從的數(shù)據(jù)的同步。
以上就是主從復(fù)制的過程,當(dāng)然,主從復(fù)制的過程有不同的策略方式進(jìn)行數(shù)據(jù)的同步,主要包含以下幾種:
「同步策略」:Master會等待所有的Slave都回應(yīng)后才會提交,這個(gè)主從的同步的性能會嚴(yán)重的影響。 「半同步策略」:Master至少會等待一個(gè)Slave回應(yīng)后提交。 「異步策略」:Master不用等待Slave回應(yīng)就可以提交。 「延遲策略」:Slave要落后于Master指定的時(shí)間。
對于不同的業(yè)務(wù)需求,有不同的策略方案,但是一般都會采用最終一致性,不會要求強(qiáng)一致性,畢竟強(qiáng)一致性會嚴(yán)重影響性能。
主從搭建
下面我們就來實(shí)操搭建主從,使用的是兩臺centos7并且安裝的是Mysql 8來搭建主從,有一臺centos 7然后直接克隆就行了。
(1)首先檢查centos 7里面的Mysql安裝包和依賴包:
rpm?-qa?|grep?mysql
執(zhí)行后,在我本機(jī)上的顯示如下:

(2)接著可以刪除上面的安裝包和依賴包:
sudo?yum?remove?mysql*
(3)繼續(xù)檢查一下是否存在Mariadb,若是存在直接刪除Mariadb
//?檢查是否存在Mariadb
rpm?-qa?|grep?mariadb
//?刪除Mariadb
sudo?rpm?-e?--nodeps?mariadb-libs-5.5.56-2.el7.x86_64
(4)然后,就是刪除Mysql的配置文件,可以使用下面的命令查找Msqyl配置文件的路徑:
sudo?find?/?-name?mysql
在我本機(jī)上的顯示的Mysql配置文件的路徑如下:

(5)然后,通過下面的命令,將他們逐一刪除:
sudo?rm?-rf?/usr/lib64/mysql
......
(6)接著就開始安裝Mysql 8了,使用wget命令下載Mysql 8的repo源,并且執(zhí)行安裝:
wget?https://repo.mysql.com//mysql80-community-release-el7-3.noarch.rpm
sudo?yum?-y?install?mysql80-community-release-el7-3.noarch.rpm
安裝完后會在/etc/yum.repos.d/目錄下生成下面的兩個(gè)文件,說明安裝成功了:
mysql-community.repo
mysql-community-source.repo

(7)安裝完Mysql8后,接著來更新一下yum源,并且查看yum倉庫中的Mysql:
//?更新yum源
yum?clean?all
yum?makecache
//?查看yum倉庫中的Mysql
yum?list?|?grep?mysql
(8)可以查看到倉庫中存在mysql-community-server.x86_64,直接安裝就行了:
sudo?yum?-y?install?mysql-community-server
(9)接著啟動Mysql,并檢查Mysql的狀態(tài):
//?啟動Mysql
systemctl?start??mysqld.service
//?檢查Mysql的狀態(tài)
systemctl?status?mysqld
確保查看Mysql的狀態(tài)是active(running),表示正在運(yùn)行,并且配置一下Mysql開機(jī)啟動:
systemctl?enable?mysqld
(10)因?yàn)镸ysql是新安裝的,所以要修改一下初始密碼,先查看一下初始密碼:
grep?"password"?/var/log/mysqld.log
你可能找出來有多個(gè),可能是你之前安裝卸載后的文件沒有刪干凈,這里你就直接看時(shí)間,時(shí)間對應(yīng)你現(xiàn)在的時(shí)間,就是你的初始密碼:

(11)然后使用初始密碼,登陸數(shù)據(jù)庫,并且修改密碼:
mysql?-uroot?-p
ALTER?USER?'root'@'localhost'?IDENTIFIED?BY?'LDCldc@123095;
(12)此時(shí)在創(chuàng)建一個(gè)可以用于給兩一臺centos連接的用戶,默認(rèn)的root用戶只有本機(jī)才能連接:
//?創(chuàng)建連接用戶
create?user?'test'@'%'?identified?by?'LDCldc-2020';
//?并且把防火墻給關(guān)了,或者配置一下3306端口
systemctl stop firewalld.service;
//?設(shè)置防火墻開機(jī)自動關(guān)閉
systemctl?disable?firewalld.service;
(13)測試:到這里就Mysql的安裝教程就就講完了,可以測試一下,兩臺centos是否可以ping通:
ping?192.168.163.156

我這里的兩臺機(jī)是可以互通的,Master:192.168.163.156,Slave:192.168.163.155,并且Slave使用下面的命令可以登陸到Master的Mysql:
mysql?-u[user]?-p[密碼]?-h[遠(yuǎn)程主機(jī)ip]
確保了這兩項(xiàng)測試成功后,就可以進(jìn)行下面的主從搭建了。
(14)我這里使用的使用兩臺centos 7的vmware的ip分別是192.168.163.155(Slave)和192.168.163.156(Master)作為測試,首先在192.168.163.156(Master)中創(chuàng)建一個(gè)測試庫test:
//?創(chuàng)建測試庫
create?database?test?default?character?set?utf8mb4?collate?utf8mb4_general_ci;
//?并且授權(quán)
grant?all?privileges?on?test.*?to?'test'@'%';
(15)然后編輯Master中的my.cnf文件,此文件位于/etc/my.cnf,執(zhí)行下面的sql,并添加下面的信息:
sudo?vi?/etc/my.cnf
==========以下是配置文件中的信息=============
#?配置編碼為utf8
character_set_server=utf8mb4
init_connect='SET?NAMES?utf8mb4'
#?配置要給Slave同步的數(shù)據(jù)庫
binlog-do-db=test
#?不用給Slave同步的數(shù)據(jù)庫,一般是Mysql自帶的數(shù)據(jù)庫就不用給Slave同步了
binlog-ignore-db=mysql
binlog-ignore-db=information_schema
binlog-ignore-db=performance_schema
binlog-ignore-db=sys
#?自動清理30天前的log文件
expire_logs_days=30
#?啟用二進(jìn)制日志
log-bin=mysql-bin
# Master的id,這個(gè)要唯一,唯一是值,在主從中唯一
server-id=3
(16)配置完后重啟Mysql服務(wù),并查看Mysql的log_bin日志是否啟動成功:
systemctl?restart?mysqld
#?查看log_bin日志是否啟動成功
show?variables?like?'%log_bin%';

(17)接著查看Master的狀態(tài):
show?master?status;

這兩個(gè)數(shù)據(jù)File和Position要記住,后面配置Slave的時(shí)候要使用到這兩個(gè)數(shù)據(jù)。
(18)最后登陸Master的數(shù)據(jù)庫,并創(chuàng)建一個(gè)用戶用于同步數(shù)據(jù):
create?user?'backup'@'%'?IDENTIFIED?BY?'LDCldc-2020';
grant?file?on?*.*?to?'backup'@'%';
GRANT?REPLICATION?SLAVE,?REPLICATION?CLIENT?ON?*.*?to?'backup'@'%';
到這里Master的配置就配置完了,后面就進(jìn)行Slave的配置。
(19)在Slave中同樣要?jiǎng)?chuàng)建test數(shù)據(jù)庫,并且授權(quán)給test用戶:
#?創(chuàng)建同步數(shù)據(jù)的test數(shù)據(jù)庫
create?database?test?default?character?set?utf8mb4?collate?utf8mb4_general_ci;
#?授權(quán)
grant?all?privileges?on?test.*?to?'test'@'%';
(20)接著編輯Slave中my.cnf文件,同樣是在/etc/my.cnf路徑下,加入如下配置:
#?配置從服務(wù)器的ID,唯一的
server-id=4
#加上以下參數(shù)可以避免更新不及時(shí),SLAVE 重啟后導(dǎo)致的主從復(fù)制出錯(cuò)。
read_only?=?1
master_info_repository=TABLE
relay_log_info_repository=TABLE
(21)并且重啟Slave中的Mysql服務(wù):
systemctl?restart?mysqld
(22)在Slave中添加Master的信息:
#?master_host是Master的ip,master_log_file和master_log_pos就是配置之前查看Master狀態(tài)時(shí)顯示的File和Position信息
change?master?to?master_host='192.168.163.156',master_port=3306,master_user='backup',master_password='LDCldc-2020',master_log_file='mysql-bin.000001',master_log_pos=1513;?
(23)最后查看Slave的狀態(tài):
show?slave?status\G

當(dāng)看到Slave_IO_Running和Slave_SQL_Running都是yes的時(shí)候,這表示主從配置成功。
「Slave_IO_Running也就是Slave中的IO線程用于請求Master,Slave_SQL_Running時(shí)sql線程將中繼日志中更新日志同步到Slave數(shù)據(jù)庫中?!?/strong>
但是,有時(shí)候Slave_IO_Running會為no,而Slave_SQL_Running為yes,這時(shí)候需要檢查一下原因,因?yàn)槲易约撼醮未罱ǖ臅r(shí)候,也是出現(xiàn)這個(gè)問題。
首先看重啟一下Slave的MySQL服務(wù):systemctl restart mysqld,然后執(zhí)行:
stop?slave;
start?slave;
這樣就能夠使Slave_IO_Running和Slave_SQL_Running顯示都是yes了。
(24)最后就是測試了,測試使用的是之前創(chuàng)建的test庫,Master是用來寫的,在Master的test庫中隨機(jī)創(chuàng)建一個(gè)表,你會發(fā)現(xiàn)Slave也會有這個(gè)表,插入數(shù)據(jù)也一樣,都會被同步到Slave中。
主從面試
?Mysql主從有什么優(yōu)點(diǎn)?為什么要選擇主從?
?
高性能方面:主從復(fù)制通過水平擴(kuò)展的方式,解決了原來單點(diǎn)故障的問題,并且原來的并發(fā)都集中到了一臺Mysql服務(wù)器中,現(xiàn)在將單點(diǎn)負(fù)載分散到了多臺機(jī)器上,實(shí)現(xiàn)讀寫分離,不會因?yàn)閷懖僮鬟^長鎖表而導(dǎo)致讀服務(wù)不能進(jìn)行的問題,提高了服務(wù)器的整體性能。 可靠性方面:主從在對外提供服務(wù)的時(shí)候,若是主庫掛了,會有通過主從切換,選擇其中的一臺Slave作為Master;若是Slave掛了,還有其它的Slave提供讀服務(wù),提高了系統(tǒng)的可靠性和穩(wěn)定性。
?若是主從復(fù)制,達(dá)到了寫性能的瓶頸,你是怎么解決的呢?
?
主從模式對于寫少讀多的場景確實(shí)非常大的優(yōu)勢,但是總會寫操作達(dá)到瓶頸的時(shí)候,導(dǎo)致性能提不上去。
這時(shí)候可以在設(shè)計(jì)上進(jìn)行解決采用分庫分表的形式,對于業(yè)務(wù)數(shù)據(jù)比較大的數(shù)據(jù)庫可以采用分表,使得數(shù)據(jù)表的存儲的數(shù)據(jù)量達(dá)到一個(gè)合理的狀態(tài)。
也可以采用分庫,按照業(yè)務(wù)進(jìn)行劃分,這樣對于單點(diǎn)的寫,就會分成多點(diǎn)的寫,性能方面也就會大大提高。
?主從復(fù)制的過程有數(shù)據(jù)延遲怎么辦?導(dǎo)致Slave被讀取到的數(shù)據(jù)并不是最新數(shù)據(jù)。
?
主從復(fù)制有不同的復(fù)制策略,對于不同的場景的適應(yīng)性也不同,對于數(shù)據(jù)的實(shí)時(shí)性要求很高,要求強(qiáng)一致性,可以采用同步復(fù)制策略,但是這樣就會性能就會大打折扣。
若是主從復(fù)制采用異步復(fù)制,要求數(shù)據(jù)最終一致性,性能方面也會好很多。只能說,對于數(shù)據(jù)延遲的解決方案沒有最好的方案,就看你的業(yè)務(wù)場景中哪種方案使比較適合的。


近期精彩內(nèi)容推薦:??
?一個(gè)月薪 12000 的北京程序員的真實(shí)生活 !

