MySQL Replication 機制
目前常使用且成熟的關聯式資料庫,一般官方都會提供 Replication 機制,通常官方內建的 Replication 機制已經很成熟,不像幾年前 Open Source RDBMS 都要自己編譯第三方 Replication 功能,當然也有第三方像是 Percona 這樣的套件。透過 Replication 將資料同步複製到其他主機,可以實現運算的擴充與高可用架構。大部分的資料庫應用情境都是 SELECT 居多,最常用到的就是讀寫分離的「主從架構」,如下圖所示:
主要的 MySql Master 節點負責「讀寫」,寫資料會透過 Binlog Relay 機制,以非同步模式複製 Binlog 到每一台 Slave 執行 (正確一點的說法應該是 Slave 透過 REPLICATION 權限連線到 Master 去抓 Binlog 回來執行),運作時就好像讓 Slave 與 Master 進行資料同步。一般來說,Slave 不提供寫入功能,只負責分散 SELECT 運算,這也是最典型的擴充架構。實作時有一個地方很麻煩,就是應用程式必須自行實作「讀寫分離」的機制 (有些 Framework ORM 會內建),自行再程式邏輯將 SELECT Query 分散到 Slave 執行,除非有使用商業的 Proxy Connection Pool 機制,才有提供自動讀寫分離的機制。如果是使用 MariaDB 的話也可以搭配 MaxScale 實現讀寫分離機制,但 MaxScale 我沒玩過,只是打打嘴砲。
此外,建構 Replication 還有一個很重要的好處,就是可以順便備份!一般的情況我們都是用 mysqldump 進行資料備份對吧!?但是如果你的資料已經大到一定的程度,想要 Dump DB 絕對是 GG,搞不好跑個日備份就超過一天了....... 這時候就要借助 Replication 的能力。
建置 MySQL Replication 主從架構環境
廢話說完了,那先來看看如何建置 MySql Master/Slave 這種最典型的架構。以 Ubuntu Server 14.04 為例,首先分別在兩台 Master 與 Slave 機器上,安裝官方提供的 MySQL Server (目前版本是 5.5),如下:
sudo apt-get install mysql-server
設定 MySql Master
我們先設定 Master,修改位於 /etc/mysql/my.cnf 的 MySQL 設定檔,內容如下 (GitHub):
[client] port = 3306 socket = /var/run/mysqld/mysqld.sock [mysqld_safe] socket = /var/run/mysqld/mysqld.sock nice = 0 [mysqld] user = mysql pid-file = /var/run/mysqld/mysqld.pid socket = /var/run/mysqld/mysqld.sock port = 3306 bind-address = 0.0.0.0 basedir = /usr datadir = /var/lib/mysql tmpdir = /tmp lc-messages-dir = /usr/share/mysql skip-external-locking key_buffer = 16M max_allowed_packet = 16M thread_stack = 192K max_connections = 5000 table_cache = 64 thread_concurrency = 8 query_cache_limit = 1M query_cache_size = 16M query_cache_type = 1 log_error = /var/log/mysql/error.log log_slow_queries = /var/log/mysql/mysql-slow.log long_query_time = 2 log-queries-not-using-indexes # 需要才打開 slow log server-id = 1 log_bin = /var/lib/mysql/mysql-bin.log log-slave-updates = 0 expire_logs_days = 10 max_binlog_size = 100M innodb_flush_log_at_trx_commit = 1 sync_binlog = 1 read_only = 0 # innodb tune (optional) innodb_change_buffering = all innodb_adaptive_hash_index = ON innodb_max_dirty_pages_pct = 80 innodb_buffer_pool_size = 256M innodb_buffer_pool_instances = 2 [mysqldump] quick quote-names max_allowed_packet = 16M !includedir /etc/mysql/conf.d/
說明一下設定檔的幾個重點:
- server-id 表示唯一的 Server ID,在 MySql Replication Cluster 架構中,無論 Master 還是 Slave,串連主機中 Server ID 不可重複。
- bind-address = 0.0.0.0 開放可以連線的 Network,當然如果設定 192.168.0.0 這樣的網段也是可以,主要讓 Slave 節點可以與 MySQL Master 進行連線。
- innodb_flush_log_at_trx_commit = 1 設定 Commit 寫進磁碟的策略,1 是預設值,會盡力確保資料被寫入 Disk,雖然比較慢但是在 Replication Cluster 中格外重要,這也是 Replication 架構中官方建議的設定。
- sync_binlog = 1 表示每次的 Transaction 都會被寫進 IO,有效避免 Crash 時造成的資料損壞,也讓最新的 Binlog 可以被即時同步到其他 Slave 上。但這個參數會嚴重影響效能,特別是在大量的 Transaction 發生時,系統使用 SSD 可以大幅改善這個 IO 效能問題,如果是在 Slave 上就不需要開啟,免得同步動作跟不上 Master。
- long_query_time 用來設定 Slow Log,這個跟 Replication 一點關係也沒有。Production 環境中建議 Slow log 不要開啟,避免影響效能,上述的提供的設定檔千萬不要照抄,如果需要詳細的 MySql 效能調整,可以參考我之前寫的另一篇文章作為基礎。
設定好之後重新啟動 MySql Server
sudo service mysql restart
重新啟動後透過 mysql 進入 shell,接著執行以下 SQL 建立用來 Replication 連線的使用者(請自行更換 <password> 為您的連線密碼),如下:
USE mysql; CREATE USER 'replication'@'%' IDENTIFIED BY '<password>'; GRANT REPLICATION SLAVE ON *.* TO 'replication'@'%'; FLUSH PRIVILEGES;
接著透過 SHOW MASTER STATUS\G 命令查看 Master 執行狀態,如果沒有啟動可以執行 MASTER START 來啟動。執行畫面如下:
記下 File 與 Position 這兩個資訊,等等要設定到 Slave 進行同步。
接著我們設定另一台 Slave 節點,my.cfg 內容如下 (GitHub):
[client] port = 3306 socket = /var/run/mysqld/mysqld.sock [mysqld_safe] socket = /var/run/mysqld/mysqld.sock nice = 0 [mysqld] user = mysql pid-file = /var/run/mysqld/mysqld.pid socket = /var/run/mysqld/mysqld.sock port = 3306 bind-address = 0.0.0.0 basedir = /usr datadir = /var/lib/mysql tmpdir = /tmp lc-messages-dir = /usr/share/mysql skip-external-locking key_buffer = 16M max_allowed_packet = 16M thread_stack = 192K max_connections = 5000 table_cache = 64 thread_concurrency = 8 query_cache_limit = 1M query_cache_size = 16M query_cache_type = 1 # 需要才打開 slow log log_error = /var/log/mysql/error.log log_slow_queries = /var/log/mysql/mysql-slow.log long_query_time = 2 log-queries-not-using-indexes server-id = 2 log_bin = /var/lib/mysql/mysql-bin.log log-slave-updates = 0 expire_logs_days = 10 max_binlog_size = 100M innodb_flush_log_at_trx_commit = 1 sync_binlog = 0 read_only = 1 # innodb tune (optional) innodb_change_buffering = all innodb_adaptive_hash_index = ON innodb_max_dirty_pages_pct = 80 innodb_buffer_pool_size = 256M innodb_buffer_pool_instances = 2 [mysqldump] quick quote-names max_allowed_packet = 16M !includedir /etc/mysql/conf.d/
說明一下 Slave 設定檔幾個不同的地方:
- server-id 當然是與 master 不同的 ID 值。
- sync_binlog = 0 剛剛有提到,為了加速同步的速度,可以關閉這個選項。但是如果您的架構是需要主備切換 (兩台都是 Master 也同時是 Slave),那麼就需要開啟這個選項,確保 Transaction 寫入到磁碟中。
- read_only = 1 由於我們的 Slave 只是用來分散 Query,為了怕有笨蛋把資料寫過來,啟動「唯讀」是比較保險的作法。
- log-slave-updates = 0 剛剛沒有提到的參數,如果開啟這個功能表示從其他 Master 讀到的 Binlog 也要寫進自己的 Binlog,這樣自己才能也變成 Master 讓其他 Slave 節點同步,像是有三台 Master/Slave 循環複製實就會需要使用。在我們的案例中不需理會,了解就好。
設定好之後重新啟動 MySql,透過 root 使用者登入後開始設定 Replication 連線,如下:
SLAVE STOP; CHANGE MASTER TO MASTER_HOST='mysql-master', MASTER_USER='replication', MASTER_PASSWORD='<password>', MASTER_LOG_FILE='mysql-bin.00005', MASTER_LOG_POS=529; SLAVE START;
由於我比較習慣用 hosts 管理主機,MASTER_HOST 請填上要連線的 Master 位置,密碼就是剛剛 Master 設定的那一組。還記得 Master 啟動後要記下的資訊嗎 (請看上一張圖)?那個資訊就是要填在 MASTER_LOG_FILE 與 MASTER_LOG_POS 這兩個欄位,Slave 才知道要重哪個點開始同步。完成後 SLAVE START 來啟動同步工作,輸入 SHOW SLAVE STATUS\G 可以看到同步的狀態,畫面如下:
看到這樣的畫面就算完成囉。
測試 MySql Replication
測試一下,首先在 Master 建立資料庫與建立一張 Table 並且 Insert 資料:
接著到 Slave 看看
資料過去了,是不是很無聊?
透過 HAProxy 實現 MySQL 主備自動切換
今天介紹的主從架構只能分散運算,並無法實現 HA 能力,如果採用 Master/Master 的配置方式就可以實現了,但是應用程式要如何判斷其他一台機器出問題呢?我們可以藉由 HAProxy 這個套件來實現。將其中一台機器上線,另一台基器備援 (Replication),當第一台機器發生問題時,自動由 HAProxy 轉接連線至備援機,以實現 HA 模式。HAProxy 的設定方式在 GitHub 上,這裡我們就不按圖施工囉,先介紹到這。掰啦.......