天天看點

MySQL主從延時這麼長,要怎麼優化?

MySQL主從複制,讀寫分離是網際網路常見的資料庫架構,該架構最令人诟病的地方就是,在資料量較大并發量較大的場景下,主從延時會比較嚴重。

為什麼主從延時這麼大?

MySQL主從延時這麼長,要怎麼優化?

答:MySQL使用單線程重放RelayLog。

應該怎麼優化,縮短重放時間?

答:多線程并行重放RelayLog可以縮短時間。

多線程并行重放RelayLog有什麼問題?

MySQL主從延時這麼長,要怎麼優化?

答:需要考慮如何分割RelayLog,才能夠讓多個資料庫執行個體,多個線程并行重放RelayLog,不會出現不一緻。

為什麼會出現不一緻?

答:如果RelayLog随機的配置設定給不同的重放線程,假設RelayLog中有這樣三條串行的修改記錄:

update account set money=100 where uid=58;

update account set money=150 where uid=58;

update account set money=200 where uid=58;           

如果單線程串行重放:能保證所有從庫與主庫的執行序列一緻。

畫外音:最後money都将為200。

如果多線程随機配置設定重放:多重放線程并發執行這3個語句,誰最後執行是不确定的,最終從庫資料可能與主庫不同。

畫外音:多個從庫可能money為100,150,200不确定。

如何配置設定,多個從庫多線程重放,也能得到一緻的資料呢?

答:相同庫上的寫操作,用相同的線程來重放RelayLog;不同庫上的寫操作,可以并發用多個線程并發來重放RelayLog。

MySQL主從延時這麼長,要怎麼優化?

如何做到呢?

答:設計一個雜湊演算法,hash(db-name) % thread-num,庫名hash之後再模上線程數,就能很輕易做到,同一個庫上的寫操作,被同一個重放線程串行執行。

畫外音:不同庫上的重放,是并行的,就起到了加速做用。

這個方案有什麼不足?

答:很多公司對MySQL的使用是“單庫多表”,如果是這樣的話,仍然隻有一個庫,還是不能提高RelayLog的重放速度。

啟示:将“單庫多表”的DB架構模式更新為“多庫多表”的DB架構模式。

畫外音:資料量大并發量大的網際網路業務場景,“多庫”模式還具備着其他很多優勢,例如:

(1)非常友善的執行個體擴充:DBA很容易将不同的庫擴充到不同的執行個體上;

(2)按照業務進行庫隔離:業務解耦,進行業務隔離,減少耦合與互相影響;

(3)非常友善微服務拆分:每個服務擁有自己的執行個體就友善了;

“單庫多表”的場景,多線程并行重放RelayLog還能怎麼優化?

答:即使隻有一個庫,事務在主庫上也是并發執行的,既然在主庫上可以并行執行,在從庫上也應該能夠并行執行呀?

新思路:将主庫上同時并行執行的事務,分為一組,編一個号,這些事務在從庫上的回放可以并行執行(事務在主庫上的執行都進入到prepare階段,說明事務之間沒有沖突,否則就不可能送出),沒錯,MySQL正是這麼做的。

解法:基于GTID的并行複制。

從MySQL5.7開始,将組送出的資訊存放在GTID中,使用mysqlbinlog工具,可以看到組送出内部的資訊:

20181014 23:52 server_id 58 XXX GTID last_committed=0 sequence_numer=1

20181014 23:52 server_id 58 XXX GTID last_committed=0 sequence_numer=2

20181014 23:52 server_id 58 XXX GTID last_committed=0 sequence_numer=3

20181014 23:52 server_id 58 XXX GTID last_committed=0 sequence_numer=4           
MySQL主從延時這麼長,要怎麼優化?

和原來的日志相比,多了last_committed和sequence_number。

什麼是last_committed?

答:它是事務送出時,上次事務送出的編号,如果具備相同的last_committed,說明它們在一個組内,可以并發回放執行。

總結

MySQL并行複制,縮短主從同步時延的方法,展現着這樣的一些架構思想:

  • 多線程是一種常見的縮短執行時間的方法;

畫外音:例如,很多crontab可以用多線程,切分資料,并行執行。

  • 多線程并發分派任務時,必須保證幂等性:MySQL提供了“按照庫幂等”,“按照commit_id幂等”兩種方式,很值得借鑒;

畫外音:例如,群消息,可以按照group_id幂等;使用者消息,可以按照user_id幂等。

具體到MySQL主從同步延時:

  • mysql5.5:不支援并行複制,大夥快更新MySQL版本;
  • mysql5.6:按照庫并行複制,建議使用“多庫”架構;
  • mysql5.7:按照GTID并行複制;

思路比結論重要,希望大家有收獲。

MySQL主從延時這麼長,要怎麼優化?

架構師之路-分享可落地的技術文章

繼續閱讀