官术网_书友最值得收藏!

2.2 性能提升

MySQL一直致力于提升半同步復(fù)制的性能,從以下三個方面便可見:

(1)支持發(fā)送二進制日志事件和接收ACK的異步化。

(2)控制主庫接收確認(rèn)從庫的反饋數(shù)量。

(3)二進制日志互斥鎖的改進。

2.2.1 ACK異步化

舊版本的半同步復(fù)制受限于Binlog Dump線程,原因是該線程承擔(dān)了兩個不同且又十分頻繁的任務(wù):傳送二進制日志事件給從庫;接收從庫的ACK反饋信息。這兩個任務(wù)是串行的,Binlog Dump線程必須等待從庫返回之后才會傳送下一個事件。Binlog Dump線程已然成為整個半同步復(fù)制性能的瓶頸。在高并發(fā)業(yè)務(wù)場景下,這樣的機制會影響數(shù)據(jù)庫整體的吞吐量。單個Binlog Dump線程發(fā)送和接收的工作流程如圖2-1所示。

圖2-1 單個Binlog Dump線程發(fā)送和接收的工作流程

為了解決上述問題,在MySQL 5.7.4版本的半同步復(fù)制框架中,獨立出一個Ack Receiver線程,專門用于接收從庫返回的ACK請求,這將之前Binlog Dump線程的發(fā)送和接收工作分為了兩個線程來處理。這樣主庫上有兩個線程獨立工作,可以同時發(fā)送二進制日志事件到從庫,和接收從庫的ACK信息。因此半同步復(fù)制得到了極大的性能提升。Binlog Dump線程與Ack Receiver線程的工作流程如圖2-2所示。

圖2-2 Binlog Dump線程與Ack Receiver線程的工作流程

Ack Receiver線程在主庫啟用半同步復(fù)制時創(chuàng)建,并在主庫禁用半同步復(fù)制時銷毀,它是自動創(chuàng)建和銷毀的,因此不受用戶控制。它的狀態(tài)信息可以從performance_schema中查詢到:

Ack receiver線程有以下三個狀態(tài):

  • Waiting for semi-sync slave connection
  • Waiting for semi-sync ACK from slave
  • Reading semi-sync ACK from slave

在MySQL 5.7.17之前,這個Ack Receiver線程采用了select機制來監(jiān)聽從庫返回的結(jié)果,然而select機制監(jiān)控的文件句柄只能是0~1024,當(dāng)超過1024時,用戶在MySQL的錯誤日志中會收到類似如下的報錯,更有甚者會導(dǎo)致MySQL發(fā)生宕機。

     semi-sync master failed on net_flush() before waiting for slave reply.

從MySQL 5.7.17版本開始,官方修復(fù)了這個bug,開始使用poll機制來替換原來的select機制,從而可以避免上面的問題。其實poll調(diào)用本質(zhì)上和select沒有區(qū)別,只是I/O句柄數(shù)理論上沒有了上限,因為它是基于鏈表來存儲的。

2.2.2 控制從庫反饋的數(shù)量

MySQL 5.7新增了rpl_semi_sync_master_wait_for_slave_count系統(tǒng)變量,可以用來控制主庫接收多少個從庫寫事務(wù)成功后的反饋,給高可用架構(gòu)切換提供了靈活性。如圖2-3所示,當(dāng)該變量值為2時,主庫需等待兩個從庫的ACK。

圖2-3 “一主兩從”的半同步復(fù)制

使用這個功能,可以在不同機房部署主服務(wù)器和兩個從服務(wù)器,并配置半同步復(fù)制以將事務(wù)復(fù)制到至少兩個從庫,以便在多個服務(wù)器一次性崩潰的情況下減少數(shù)據(jù)丟失的可能,從庫越多,數(shù)據(jù)越安全。

2.2.3 二進制日志互斥鎖的改進

舊版本半同步復(fù)制在主庫提交二進制日志的寫會話和Binlog Dump線程讀取二進制日志的操作時,都會對二進制日志添加binlog lock互斥鎖,用于保護二進制日志的讀寫安全。使用此互斥鎖,二進制日志讀寫操作是安全的,但會導(dǎo)致二進制日志文件的讀寫串行化。不僅Binlog Dump線程和用戶會話不能同時讀寫二進制日志,就連多個Binlog Dump線程本身也無法同時讀寫。每當(dāng)一個會話正在讀取或?qū)懭攵M制日志文件時,所有其他會話都必須等待。如此順序讀寫是一個瓶頸,尤其是當(dāng)讀寫操作很慢時。串行化讀寫二進制日志如圖2-4所示。

圖2-4 串行化讀寫二進制日志

MySQL 5.7.2對binlog lock進行了以下兩方面的優(yōu)化:

  • 從Binlog Dump線程中移除binlog lock。
  • 加入了安全邊際以保證二進制日志的讀安全。

二進制日志文件是一個僅用于追加二進制事件的日志文件,可以安全地從中讀取沒有鎖定的二進制事件,因此可以從Binlog Dump線程中刪除binlog鎖。不使用binlog鎖,而是為活動binlog維護安全讀取邊界(最大位置)。Binlog Dump線程永遠不會讀取超過安全讀取的邊界。當(dāng)?shù)竭_邊界時,它將等待邊界更新。用戶會話負責(zé)在追加了二進制事件后更新安全讀取邊界。改進后的二進制日志讀寫如圖2-5所示。

圖2-5 改進后的二進制日志讀寫

從圖2-5中一目了然:

  • 讀取二進制日志事件時,Binlog Dump線程不會相互阻塞。
  • 正在寫二進制日志事件的用戶會話不會阻止Binlog Dump線程。
  • 讀取二進制日志事件的Binlog Dump不會阻塞用戶會話。

因此,Binlog Dump線程和用戶會話都可以獲得更好的吞吐量,尤其是在有很多從庫時,這種改進非常顯著。

主站蜘蛛池模板: 遂川县| 金湖县| 怀柔区| 德江县| 普兰县| 民和| 平果县| 黔西| 兴安盟| 抚远县| 当涂县| 临夏县| 青铜峡市| 榆中县| 禄丰县| 桂林市| 高要市| 山东省| 长春市| 乌拉特后旗| 长宁区| 策勒县| 台州市| 浑源县| 太白县| 绿春县| 红安县| 三都| 五原县| 时尚| 铁力市| 青岛市| 兰坪| 华容县| 高阳县| 天峻县| 柯坪县| 和硕县| 永登县| 大连市| 云南省|