天天看點

Mysql叢集:主從同步,負載均與讀寫分離

作者:馬士兵教育CTO
Mysql叢集:主從同步,負載均與讀寫分離

MySQL主從同步(Master-Slave Replication)是一種常用的資料庫備援和擴充政策。在這種架構中,一個MySQL伺服器(稱為主伺服器,Master)将資料更改複制到一個或多個其他伺服器(稱為從伺服器,Slave)。

主從同步基本原理

Mysql叢集:主從同步,負載均與讀寫分離

MySQL主從同步的基本原理如下:

  1. 主伺服器上的資料更改(如插入、更新、删除操作)會記錄在二進制日志(Binary Log)中。每個資料更改都會生成一個日志事件(Log Event),包括事務的送出、復原等。
  2. 從伺服器會啟動一個I/O線程,連接配接到主伺服器并請求二進制日志。I/O線程會從主伺服器讀取日志事件,并将它們寫入從伺服器的中繼日志(Relay Log)。
  3. 從伺服器還會啟動一個SQL線程,從中繼日志中讀取日志事件并在從伺服器上執行這些操作。這樣,從伺服器上的資料更改會與主伺服器保持一緻。

主從同步實踐

在MySQL 5.7中配置一主一從同步,可以按照以下步驟進行:

配置主伺服器(Master)

  1. 修改主伺服器的配置檔案(my.cnf或my.ini,通常位于/etc/mysql/或/etc/mysql/mysql.conf.d/目錄下)。在[mysqld]部分添加以下配置:
  2. bash複制代碼
  3. [mysqld] server-id=1 log-bin=mysql-bin binlog-format=ROW sync_binlog=1 binlog-do-db=your_database_name
  4. 其中:
  5. server-id:為主伺服器配置設定一個唯一的ID,這裡設定為1。
  6. log-bin:啟用二進制日志,并指定日志檔案的字首。
  7. binlog-format:設定二進制日志的格式,這裡使用ROW格式。
  8. sync_binlog:設定為1,表示每次事務送出時都将日志寫入磁盤。這可以提高資料一緻性,但可能會影響性能。
  9. binlog-do-db:指定需要同步的資料庫名稱。
  10. 重新開機MySQL服務使配置生效。在Linux系統中,可以使用以下指令:
  11. bash複制代碼
  12. sudo service mysql restart
  13. 登入到MySQL,建立一個用于複制的使用者并授權:
  14. bash複制代碼
  15. CREATE USER 'repl_user'@'%' IDENTIFIED BY 'your_password'; GRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'%'; FLUSH PRIVILEGES;
  16. 擷取主伺服器的二進制日志檔案名稱和位置資訊。這将在配置從伺服器時用到:
  17. ini複制代碼
  18. SHOW MASTER STATUS;
  19. 記下File和Position列的值,例如:mysql-bin.000001和154.

配置從伺服器(Slave)

  1. 修改從伺服器的配置檔案(my.cnf或my.ini)。在[mysqld]部分添加以下配置:
  2. bash複制代碼
  3. [mysqld] server-id=2 relay-log=mysql-relay-bin log-slave-updates replicate-do-db=your_database_name
  4. 其中:
  5. server-id:為從伺服器配置設定一個唯一的ID,這裡設定為2。
  6. relay-log:指定中繼日志檔案的字首。
  7. log-slave-updates:設定從伺服器記錄二進制日志事件。
  8. replicate-do-db:指定需要同步的資料庫名稱。
  9. 重新開機MySQL服務使配置生效。
  10. 登入到MySQL,配置從伺服器連接配接到主伺服器:
  11. ini複制代碼
  12. CHANGE MASTER TO MASTER_HOST='master_ip_or_hostname', MASTER_USER='repl_user', MASTER_PASSWORD='your_password', MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=154;
  13. 使用步驟1中擷取的File和Position值替換MASTER_LOG_FILE和MASTER_LOG_POS。
  14. 啟動從伺服器的複制程序:
  15. ini複制代碼
  16. START SLAVE;
  17. 檢查從伺服器的複制狀态:
  18. sql複制代碼
  19. SHOW SLAVE STATUS\G
  20. 確定Slave_IO_Running和Slave_SQL_Running的值都為Yes,表示複制正在正常運作。

主從同步複制政策

MySQL中的主從同步有多種複制政策,主要包括以下三種

  • 異步複制(Asynchronous Replication)
  • 半同步複制(Semi-Synchronous Replication)
  • 全同步複制(Synchronous Replication)

異步複制(Asynchronous Replication)

MySQL預設的複制政策是異步複制(Asynchronous Replication)。在異步複制中,主伺服器在執行事務并将更改記錄到二進制日志(Binary Log)後,不會等待從伺服器的确認。主伺服器會繼續處理其他事務,而從伺服器則負責在背景讀取并應用這些日志事件。

異步複制的優勢和劣勢如下:

  • 優勢:由于主伺服器不需要等待從伺服器的确認,異步複制具有較低的性能開銷,可以提高主伺服器的事務處理速度。
  • 劣勢:異步複制可能導緻主從伺服器之間的資料不一緻,因為在主伺服器和從伺服器之間可能存在一定的延遲。此外,在主伺服器發生故障的情況下,從伺服器可能無法擷取到最近的資料更改,進而導緻資料丢失。

半同步複制(Semi-Synchronous Replication)

半同步複制是介于異步複制和全同步複制之間的一種複制政策。在半同步複制中,當主伺服器執行完一個事務并将更改記錄到二進制日志後,它會等待至少一個從伺服器确認已經接收到這些更改。确認接收後,主伺服器才會送出事務并繼續處理其他事務。這樣,半同步複制可以確定至少有一個從伺服器始終與主伺服器保持資料一緻,進而降低資料丢失的風險。

半同步複制的優勢和劣勢如下:

  • 優勢:相較于異步複制,半同步複制提供了更好的資料一緻性保證,降低了資料丢失的風險。
  • 劣勢:由于主伺服器需要等待從伺服器的确認,半同步複制可能導緻事務送出的延遲,影響性能。

為了啟用半同步複制,需要在主伺服器和從伺服器上安裝半同步插件,并在配置檔案中啟用相應的參數。

全同步複制(Synchronous Replication)

全同步複制是指在主伺服器将資料更改記錄到二進制日志後,等待所有從伺服器确認已接收并應用這些更改。隻有當所有從伺服器都确認後,主伺服器才會送出事務并繼續處理其他事務。全同步複制可以確定主從伺服器之間的資料始終保持一緻,進而提供最進階别的資料一緻性保證。

全同步複制的優勢和劣勢如下:

  • 優勢:全同步複制提供了最進階别的資料一緻性保證,幾乎消除了資料丢失的風險。
  • 劣勢:由于需要等待所有從伺服器的确認,全同步複制可能會導緻較大的性能開銷和事務延遲。

MySQL本身并不直接支援全同步複制。然而,可以通過使用第三方解決方案來實作全同步複制,例如使用Galera Cluster或Percona XtraDB Cluster。

SQL Thread執行政策

在MySQL複制過程中,從伺服器會啟動一個SQL線程(SQL Thread)來應用從主伺服器接收到的日志事件。這個線程會從中繼日志(Relay Log)中讀取日志事件,并在從伺服器上執行這些操作。SQL線程的一些政策和特性如下:

  1. 單線程執行:預設情況下,MySQL複制中的SQL線程是單線程的。這意味着,盡管主伺服器上的事務可能是并行執行的,但在從伺服器上應用這些事務時,它們會按照順序一個接一個地執行。這可能導緻從伺服器在高并發場景下出現性能瓶頸。
  2. 多線程複制:為解決單線程執行的性能問題,MySQL 5.6及更高版本引入了多線程複制(Parallel Replication)。在多線程複制中,從伺服器可以啟動多個工作線程并行地應用日志事件。多線程複制可以在一定程度上提高從伺服器的性能,但它需要考慮資料一緻性和線程之間的同步。要啟用多線程複制,需要配置slave_parallel_type和slave_parallel_workers參數。
  3. 自動恢複:當從伺服器重新開機或者複制過程中出現問題時,SQL線程會嘗試自動恢複。這意味着,如果問題是暫時性的,例如網絡波動,SQL線程會自動重新連接配接到主伺服器并繼續應用日志事件。然而,在某些情況下,例如資料不一緻,SQL線程可能無法自動恢複,此時需要手動幹預。
  4. 延遲複制:從MySQL 5.6開始,可以配置從伺服器延遲複制指定的時間。這可以通過設定slave_delay參數來實作。延遲複制可以用于實作時間點恢複或者保護主伺服器免受誤操作的影響。需要注意的是,延遲複制可能會導緻從伺服器與主伺服器之間的資料差異增大。
  5. 過濾器:在從伺服器上,可以使用過濾器來指定需要應用哪些資料庫和表的更改。這可以通過在配置檔案中設定replicate-do-db、replicate-ignore-db、replicate-do-table和replicate-ignore-table參數來實作。過濾器可以用于減少從伺服器上不需要的資料,并降低網絡和存儲資源的消耗。

主從同步常見問題:主備延遲

MySQL主從同步中,主備延遲(Master-Slave Lag)是指從伺服器在複制主伺服器上的資料更改時可能出現的延遲。

假設有如下過程

  1. 主庫 A 執行完成一個事務,寫入 binlog,我們把這個時刻記為 T1;
  2. 之後傳給備庫 B,我們把備庫 B 接收完這個 binlog 的時刻記為 T2;
  3. 備庫 B 執行完成這個事務,我們把這個時刻記為 T3。

網絡正常的時候,日志從主庫傳給備庫所需的時間是很短的,即 T2-T1 的值是非常小的。也就是說,網絡正常情況下,主備延遲的主要來源是備庫接收完 binlog 和執行完這個事務之間的時間差

我們可以使用Seconds_Behind_Master作為衡量主備延遲(Master-Slave Lag)的一個名額。

Seconds_Behind_Master是MySQL從伺服器上的一個狀态變量,用于表示從伺服器在複制主伺服器上的資料更改時的延遲。它以秒為機關表示從伺服器在處理二進制日志(Binary Log)時落後主伺服器的時間。

要檢視Seconds_Behind_Master的目前值,可以在從伺服器上執行以下指令:

bash複制代碼SHOW SLAVE STATUS\G
           

以下是一些可能導緻主備延遲的原因:

  1. 網絡延遲:主伺服器和從伺服器之間的網絡連接配接可能會出現延遲,尤其是在跨地域或雲環境中。當網絡延遲較高時,從伺服器接收主伺服器發送的二進制日志資料會變慢,進而導緻主備延遲。
  2. 主伺服器負載:當主伺服器上的負載很高時,它可能會花費更多的時間來生成和發送二進制日志。這可能導緻從伺服器在接收到日志資料時出現延遲。
  3. 從伺服器負載:從伺服器上的負載也可能導緻主備延遲。如果從伺服器在執行其他任務(例如查詢、備份等)時資源不足,它可能會花費更多的時間來應用主伺服器上的資料更改。
  4. 單線程SQL線程:預設情況下,MySQL複制使用單線程SQL線程在從伺服器上應用主伺服器的資料更改。在高并發場景下,單線程SQL線程可能成為性能瓶頸,導緻主備延遲。可以通過啟用多線程複制來緩解這一問題。
  5. 大事務或者慢查詢:在主伺服器上執行的大事務或者慢查詢可能會導緻從伺服器在應用這些更改時出現延遲。優化查詢性能和分割大事務可以幫助減少主備延遲。
  6. 延遲複制:MySQL允許配置從伺服器延遲複制指定的時間。這是通過設定slave_delay參數實作的。延遲複制可以用于實作時間點恢複或保護主伺服器免受誤操作的影響,但會導緻從伺服器與主伺服器之間的資料差異增大。

Mysql中間件: 負載均衡與讀寫分離(MyCat)

Mysql叢集:主從同步,負載均與讀寫分離

MySQL中間件是位于應用程式和MySQL資料庫之間的軟體層,用于處理應用程式與資料庫之間的通信。以下是一些常見的MySQL中間件,它們提供了連接配接管理、查詢路由、負載均衡、讀寫分離等功能:

  1. ProxySQL:ProxySQL是一個高性能、高可用的MySQL代理和負載均衡器。它提供了查詢路由、連接配接池、多路複用、查詢緩存等進階功能,适用于對資料庫服務進行優化和管理的場景。
  2. MyCAT:MyCAT是一個基于Java的MySQL中間件,主要用于實作資料庫的分片、讀寫分離和負載均衡。它提供了靈活的配置和插件機制,可以根據具體需求進行定制。

下面的例子将展示如何使用MyCAT進行負載均衡和讀寫分離

部署MySQL主從伺服器

準備一個MySQL主從伺服器環境,至少包括一個主伺服器(Master)和一個或多個從伺服器(Slave)。主伺服器負責處理寫操作(INSERT、UPDATE、DELETE),從伺服器負責處理讀操作(SELECT)。

安裝并配置MyCAT

下載下傳MyCAT

通路MyCAT的GitHub倉庫(github.com/MyCATApache…),在“Releases”頁面下載下傳最新版本的MyCAT。也可以直接使用wget指令下載下傳:

bash複制代碼wget <https://github.com/MyCATApache/Mycat-Server/releases/download/><latest-version>/mycat-<latest-version>-bin.tar.gz

           

請将<latest-version>替換為實際的版本号。

解壓MyCAT

解壓下載下傳的MyCAT壓縮包:

bash複制代碼tar -zxvf mycat-<latest-version>-bin.tar.gz

           

配置MyCAT

進入MyCAT解壓後的目錄,編輯conf/schema.xml檔案以配置資料庫資訊。在<dataHost>标簽中,配置主從伺服器的資訊:

xml複制代碼<dataHost name="dataHost1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
    <heartbeat>select user()</heartbeat>
    <writeHost host="master" url="192.168.0.2:3306" user="root" password="123456">
        <readHost host="slave1" url="192.168.0.3:3306" user="root" password="123456"/>
        <readHost host="slave2" url="192.168.0.4:3306" user="root" password="123456"/>
    </writeHost>
</dataHost>

           

請将url、user和password替換為實際MySQL主從伺服器資訊。

然後,在<schema>标簽中配置資料庫模式和表資訊:

xml複制代碼<schema name="mydb" checkSQLschema="false" sqlMaxLimit="100">
    <table name="user" primaryKey="id" dataNode="dataNode1" rule="rule1"/>
</schema>

           

這裡的name屬性應實際資料庫名稱相比對,table标簽中的name屬性應與實際資料表名稱相比對。

配置MyCAT監聽端口

編輯conf/server.xml檔案,配置MyCAT的監聽端口。預設情況下,MyCAT監聽在8066端口。可以根據需要修改該端口。

啟動MyCAT

在MyCAT的目錄中,運作以下指令啟動MyCAT:

bash複制代碼./bin/mycat start
           

将應用程式連接配接到MyCAT

将應用程式連接配接到MyCAT而不是直接連接配接到MySQL伺服器。修改應用程式的資料庫連接配接配置,将其指向MyCAT伺服器的IP位址和監聽端口。例如,在Java應用程式中,可以修改application.properties檔案:

xml複制代碼spring.datasource.url=jdbc:mysql://<mycat-server-ip>:<mycat-server-port>/<your-database-name>?useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf8
spring.datasource.username=<mycat-username>
spring.datasource.password=<mycat-password>
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
           

将<mycat-server-ip>、<mycat-server-port>、<your-database-name>、<mycat-username>和<mycat-password>替換為實際MyCAT和資料庫資訊。

現在,應用程式将通過MyCAT與MySQL資料庫通信。MyCAT會自動将寫操作路由到主伺服器(Master),将讀操作路由到從伺服器(Slaves)。這樣,在應用程式層面,無需關心資料庫的負載均衡和讀寫分離,可以專注于業務邏輯的實作。

繼續閱讀