學習也好,分析問題也好,都要有系統思維。
當別人還停留在只有一個Mysql實例的認知時,你要知道,其實生產環境的Mysql,最起碼也應該長這樣:
為什么要主從
幾乎每個上了生產環境的系統,都不可能是單機的,通常都采用了主從架構。
而為什么要采用主從,只需記住這幾個關鍵字:SPOF,讀寫分離,Backup,Scale-Out。
歸納一下,其實就兩點。
1、
防止SPOF:SPOF,single point of failure,如果你只有一個Mysql實例,那么它的死亡,就意味著你數據庫服務的終止,也就意味著你整個系統的奔潰。但是如果你掛了一個Mysql,還有千千萬萬個Mysql頂上去,那就稍微牛B些了。
2、
讀寫分離:通常我們的業務,都是讀多于寫,這時候就可以把寫交給Master,把讀交給其他的Slave。
比如你想要備份(backup)數據,如果直接在Master上執行mysqldump,很明顯,會影響到線上的寫操作,這時候就可以找一臺slave,安安靜靜的執行;
比如你發現讀請求越來越多了,這時候只需要加多幾臺Slave,來分擔下讀請求,這就是Scale-Out,拓展性;
又比如,你想對數據進行分析,統計一下最近幾天各種類型的訂單數量,這時候,在一臺Slave上默默操作,或者從一臺Slave上,把數據導出到hadoop,交給hadoop去分析,都可以。
兩個動作
每個支持主從架構的系統,都要考慮要如何實現兩個動作:主從復制和主從切換。
平時數據要從Master復制到各個Slave;而在Master宕機時,則要進行主從切換,將Master切換到其中一臺Slave上。
下面就來聊聊Mysql是如何實現這兩個動作的。
主從復制
Master寫入數據后,需要把數據同步給Slave,這就是主從復制。
那么Master把這些數據,以什么樣的協議、格式發給Slave呢?由于不同系統的功能不同,他們用于存儲數據的數據結構也不同,所以,他們之間的復制方式也各有差異。
比如redis,發的就是rdb或者aof文件,而Mysql,則發的是bin log。
bin log有三種格式,statement/row/mixed ,具體可以參考 Replication Formats 。
那么bin log又是如何從Master發給Slave,又是如何被Slave執行的呢?
Mysql用了三個線程,來實現這個過程,一個在Master,兩個在Slave:
- Binlog dump thread:負責把bin log發給slave
- Slave I/O thread:負責接收master發過來的bin log,并把它暫時存放在一個叫relay log的日志文件
- Slave SQL thread:讀取relay log,執行里面的內容
至于為什么mysql要這么設計,其實仔細觀察,就會發現這整個過程,有點像消息中間件處理消息的過程,所以問題就變成我之前寫的另一篇文章:為什么要使用消息中間件
你看,知識是互通的。
主從延遲
在講主從切換之前,我們來聊下主從延遲。
有主從的系統,都會有延遲,那種在Master寫入后,Slave馬上同步發生變化的事情,想想就知道,是不存在的。
那么導致主從延遲的原因有哪些呢?
可能是Slave機器性能太差,在Master執行1s的語句,在Slave要執行5s,通常在經濟拮據的公司就會這么干,搞一臺很一般的機器,來做Slave;
咱們不差錢,那就讓Slave的機器和Master一樣優秀。
可是這樣還是主從延遲很大,為啥?
噢,原來咱們把太多的查詢分析業務放slave了,各個業務端,在分析數據時,為了不影響Master,都選擇走Slave,Slave壓力太大,自然延遲了。
于是我們有了一主多從,Slave你不是忙不過來嗎,那我給你找多幾個幫手。
這下應該延遲會小了吧?
并沒有,我們發現系統偶爾還是會有很大延遲,查了很久,發現是Slave在執行一個耗時10s的事務,等執行完commit時,Slave已經延遲了10s。
這下知道為什么盡量不要寫大事務了吧。
主從切換
現在可以來講「主從切換」了。
正因為有上面的「主從延遲」,才有了當Master宕機時,我們在一致性和可用性之間尋求優先級的糾結。
其實也就是CAP理論里經常遇到的選擇,在P(分區容忍性)必須滿足的情況下,到底是選擇C(強一致性)還是A(可用性)。
如果要保證強一致性,那么切換時就有這幾個步驟:
- 把原來的Master,設置為read-only = true,這個時刻記為time1;
- 等待Slave執行完Master發給它的bin log,直到Slave和Master一致,這個時刻記為time2;
- 現在一致了,可以把slave設置為read-only = false,即可寫入
在這個過程中,從time1到time2的時間,系統是無法被寫入的,即不可用。
這個不可用的時間,取決于切換的時候,slave和master的延遲時間,延遲的越長,同步完成需要的時間就越長,不可用的時間也就越長。
保證強一致性,就會犧牲可用性,如果你不想系統有不可用的時間呢?那就得犧牲強一致性,因為你必須在Slave和Master還沒完全同步時,就把Slave切換為Master。
主從數據不一致,會有什么問題呢?思考題。
總結
這篇文章只是在講Mysql的主從嗎?
我們總會說,技術那么多,還日新月異的,好像每天都有新的很厲害的技術出來,學不動。
但其實,如果學一項技術,就只是在學一項技術,而不去舉一反三,發現知識背后通用的規則,那你之前學的知識,就只是在占用你大腦的內存,對你之后學的東西,沒任何幫助。
但是如果你可以把所學的知識,串起來,形成一個體系,用系統的角度去看他們,那就不一樣了。
比如今天我學了Mysql主從,那么當我們下次在學習其他系統的主從架構時,比如說redis,就可以照著今天這個思路去學習:
- redis的主從架構長什么樣子?
- redis主從之間如何進行復制,數據格式是怎么樣的?
- redis主從延遲的原因有哪些?
- master宕機時,redis如何進行主從切換?
- ...
知識都是通的。
留個問題
現在我們學會用「主從」的角度來看待mysql,而不再是一個獨立的機器。
有什么用呢?留個問題好了。
我們在業務中經常會用到外鍵,比如有兩張表,一張是「方案表 plan」,另一種是「方案適用員工表 plan_staff」,plan_staff里有一個字段,plan_id,指向了plan表的主鍵,這樣做,有問題嗎?
參考
- Mysql Replication
- Mysql實戰45講 丁奇