配置MySQL主從/雙主引發的反思 原

記一次mysql配置雙主全過程

[danger] 強烈建議在執行本節所有操作前將所有操作命令操作copy到Sublime Text編輯器替換port爲要配置主從的mysql實例對應的端口,避免誤操作!!!

[danger] 強烈建議在執行本節所有操作前將所有操作命令操作copy到Sublime Text編輯器替換port爲要配置主從的mysql實例對應的端口,避免誤操作!!!

[danger] 強烈建議在執行本節所有操作前將所有操作命令操作copy到Sublime Text編輯器替換port爲要配置主從的mysql實例對應的端口,避免誤操作!!!

備份主庫數據

使用innobackupex工具進行備份(因本次涉及到的數據庫實例較多,所以編寫shell腳本,減少出錯,單實例同樣適用):

#!/bin/bash

#ports='3312 3313 3315'
port=3314  # 單實例時手動指定數據庫port

# for循環和if判斷只在多實例時使用
#for port in $ports;do

#  if [ $port = "3313" ];then
#    passwd='aaaaaaa'
#  else
#    passwd='bbbbbbb'
#  fi
passwd='xxxxxxx'
mkdir /disk1/backup/$port

  innobackupex --socket=/home/mysql/$port/mysql.sock --user=root --password=$passwd  --parallel=1 /disk1/backup/$port/  > /tmp/"$port"_backup.log
  # 將數據rsync由 **monitor1/mysql5** 機器同步到從庫主機(myslq6):
  rsync -avP --bwlimit 50000 /disk1/backup/$port adai@mysql6:/data2/backup/  > /tmp/"$port"_rsync.log
  
  echo "Finish $port"

#done

Note: 執行腳本前保證主庫、從庫磁盤空間充足,並且從庫服務器數據文件存放目錄 (“/data2/backup/”) 存在,還有注意文件權限,否則可能會導致rsync失敗!!!

如果有近期備份好的數據可以直接同步到從庫服務器使用,但是 僅當 備份的binlog文件序號小於主庫保留的最小binlog文件序號時即備份文件的binlog創建日期在主庫保留的binlog文件後面,如mysql-bin.00008(備份文件binlog)、mysql-bin.00005(主庫保留的binlog),備份纔可用,即必須確保從庫搭建好之後,開啓同步時,主庫還保留有同步位置之前的日誌(保證數據連續性、一致性)。

搭建mysql雙主結構

配置文件

數據庫配置示例文件(Attention: 因爲數據庫要配置雙主模式,所以在部署時主庫和從庫的server-id一定不能一樣):

$ cat 3314.cnf 
[mysqld3314]

lower_case_table_names=1
# 爲PXC定製
binlog_format=ROW
default-storage-engine         = InnoDB
innodb_large_prefix=on
innodb_autoinc_lock_mode=2


# 綁定地址之後只能通過內部網絡訪問
# 不能使用: 10.*.*.*
bind-address=10.215.33.23

auto-increment-increment = 2
auto-increment-offset = 2

# 使用 xtrabackup-v2 必須制定datadir, 因爲操作可能直接對 datadir進行
datadir=/home/mysql/3314/data

# http://www.percona.com/doc/percona-xtrabackup/2.2/innobackupex/privileges.html#permissions-and-privileges-needed
# 權限的配置
# xtrapbackup在Donor上執行,因此只需localhost的權限

# 約定:
server-id = 72


# wsrep模式不依賴於GTID
# 開啓GTID
# enforce_gtid_consistency=1
# gtid_mode=on

# 即便臨時作爲Slave,也記錄自己的binlog
log-slave-updates=1

# master_info_repository=TABLE
# relay_log_info_repository=TABLE

# GENERAL #
user                           = mysql
port                           = 3314
socket                         = /home/mysql/3314/mysql.sock
pid-file                       = /home/mysql/3314/mysql.pid

# MyISAM #
key-buffer-size                = 32M
myisam-recover                 = FORCE,BACKUP

ft-min-word-len = 4
event-scheduler = 0

# SAFETY #
max-allowed-packet             = 16M

skip-name-resolve
max_connections = 2000
max_connect_errors = 30

back-log = 500

character-set-client-handshake = 1
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci

#character-set-client-handshake=1
#character-set-client=utf8
#character-set-server=utf8
#collation-server=utf8_general_ci

#key-buffer-size = 256M
table-open-cache = 2048
max-allowed-packet = 2048M
slave-skip-errors = all                       #Skip duplicated key
sort-buffer-size = 4M
join-buffer-size = 8M
thread-cache-size = 50
concurrent-insert = 2

thread-stack = 192K
net-buffer-length = 8K
read-buffer-size = 256K
read-rnd-buffer-size = 16M
bulk-insert-buffer-size = 64M

# 採用thread pool來處理連接
thread-handling=pool-of-threads
# 新線程創建等待時間,, 單位爲10ms,50即爲500ms
thread-pool-stall-limit = 50


sql-mode                       = STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_AUTO_VALUE_ON_ZERO,NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY
sysdate-is-now                 = 1
innodb                         = FORCE
innodb-strict-mode             = 1


# BINARY LOGGING #
log-bin                        = /home/mysql/3314/data/mysql-bin
expire-logs-days               = 5
# LOGGING #
# log-output=file 默認就是FILE
log-error                      = /home/mysql/3314/data/mysql-error.log
long-query-time = 0.3
# log-queries-not-using-indexes  = 1
slow-query-log                 = 1
slow-query-log-file            = /home/mysql/3314/data/mysql-slow.log

# 默認爲0(MySQL不控制binlog的輸出)
# sync-binlog                    = 1

# CACHES AND LIMITS #

tmp-table-size                 = 32M
max-heap-table-size            = 32M

# 頻繁修改的表不適合做query-cache, 否則反而影響效率
query-cache-type               = 0
query-cache-size               = 0
# query-cache-limit = 2M
# query-cache-min-res-unit = 512

thread-cache-size              = 100
open-files-limit               = 65535
table-definition-cache         = 1024
table-open-cache               = 4096

# INNODB #
innodb-flush-method            = O_DIRECT
innodb-log-files-in-group      = 2

# innodb-file-per-table = 1設置之後, 下面的配置基本失效
innodb_data_file_path = ibdata1:10M:autoextend
innodb-thread-concurrency = 32
innodb-log-file-size           = 256M
innodb-flush-log-at-trx-commit = 2
innodb-file-per-table          = 1
innodb-large-prefix            = on
# 內存: 全部內存*0.7
innodb-buffer-pool-size = 2G

performance-schema = 0
net-read-timeout = 60

# innodb-open-files 在MySQL5.6 auto-sized
# 來自May2
innodb-rollback-on-timeout
innodb-status-file = 1


# http://dev.mysql.com/doc/refman/5.6/en/innodb-performance-multiple_io_threads.html
# http://zhan.renren.com/formysql?tagId=3942&checked=true
# 從MySQL 5.5
# innodb_file_io_threads = 4
innodb-read-io-threads = 16
innodb-write-io-threads = 8

innodb-io-capacity = 2000
# innodb-stats-update-need-lock = 0 # MySQL 5.6中無效
# innodb-stats-auto-update = 0
innodb-old-blocks-pct = 75
# innodb-adaptive-flushing-method = "estimate"
# innodb-adaptive-flushing = 1

# https://www.facebook.com/notes/mysql-at-facebook/repeatable-read-versus-read-committed-for-innodb/244956410932
# READ-COMMITTED 每次QUERY都要求調用: read_view_open_now, 而REPEATABLE-READ每次Transaction中只要求一次
# REPEATABLE-READ 會導致讀寫不同步
transaction-isolation = READ-COMMITTED

innodb-sync-spin-loops = 100
innodb-spin-wait-delay = 30

innodb-file-format = "Barracuda"
innodb-file-format-max = "Barracuda"

恢復數據到從庫

如上mysql配置,在使用innobackupex恢復數據,會有報錯

Error: datadir must be specified.

解決上述報錯(在配置文件中添加如下配置):

$ vim /etc/mysql/3314.cnf
[mysqld]
# 使用 xtrabackup-v2 必須制定datadir, 因爲操作可能直接對 datadir進行
datadir=/home/mysql/3314/data

恢復數據到從庫:

$ cd /data2/backup/3314/

# 準備備份文件”--apply-log“
$ innobackupex --use-memory=1G --apply-log /data2/backup/3314/xxxx-xx-xx-xx
## --apply-log:根據Innodb日誌文件中的更改來讀取備份文件,並將更改應用到表空間,保證備份數據的一致性,應該在恢復備份之前執行。
## 參考:http://www.cnblogs.com/zhoujinyi/p/5893333.html
$ rm -rf /home/mysql/3314/data/*   # 清除從庫中的髒數據

# 恢復數據到從庫
$ innobackupex --defaults-file=/etc/mysql/3314.cnf --copy-back /data2/backup/3314/xxxx-xx-xx-xx

$ chown -R mysql:mysql /home/mysql/3314

# 啓動mysql
$ systemctl start mysqld@3314

# 數據庫登錄腳本(使用ansible部署時會創建):
# cat /home/mysql/3314/mysql_client.sh 
#!/bin/sh
# Do NOT modify this file by hand!
# Generate by ansible
mysql -u root -pxxxxxx -S /home/mysql/3314/mysql.sock $@

配置主從

主從複製原理

20181018153984408074880.png

  • master服務器將數據的改變記錄二進制binlog日誌,當master上的數據發生改變時,則將其改變寫入二進制日誌中;
  • slave將master的binary log拷貝到它自己的中繼日誌。
    • 首先,slave開始一個工作線程——I/O線程。I/O線程在master上打開一個普通的連接,然後開始binlog dump process。Binlog dump process從master的二進制日誌中讀取事件,如果已經跟上master,它會睡眠並等待master產生新的事件。I/O線程將這些事件寫入中繼日誌。
    • SQL slave thread(SQL從線程)處理該過程的最後一步。SQL線程從中繼日誌讀取事件,並重放其中的事件而更新slave的數據,使其與master中的數據一致。只要該線程與I/O線程保持一致,中繼日誌通常會位於OS的緩存中,所以中繼日誌的開銷很小。

注意幾點:

  1. --master將操作語句記錄到binlog日誌中,然後授予slave遠程連接的權限(master一定要開啓binlog二進制日誌功能;通常爲了數據安全考慮,slave也開啓binlog功能)。
  2. --slave開啓兩個線程:IO線程和SQL線程。其中:IO線程負責讀取master的binlog內容到中繼日誌relay log裏;SQL線程負責從relay log日誌裏讀出binlog內容,並更新到slave的數據庫裏,這樣就能保證slave數據和 master數據保持一致了。
  3. --Mysql複製至少需要兩個Mysql的服務,當然Mysql服務可以分佈在不同的服務器上,也可以在一臺服務器上啓動多個服務。
  4. --Mysql複製最好確保master和slave服務器上的Mysql版本相同(如果不能滿足版本一致,那麼要保證master主節點的版本低於slave從節點的版本)
  5. --master和slave兩節點間時間需同步
  • mysql複製的模式:

    • 主從複製: 主庫授權從庫遠程連接,讀取binlog日誌並更新到本地數據庫的過程;主庫寫數據後,從庫會自動同步過來(從庫跟着主庫變);
    • 主主複製: 主從相互授權連接,讀取對方binlog日誌並更新到本地數據庫的過程;只要對方數據改變,自己就跟着改變;
  • mysql主從複製模式

    • 基於SQL語句的複製(statement-based replication, SBR)
    • 基於行的複製(row-based replication, RBR)
    • 混合模式複製(mixed-based replication, MBR)
  • 參考: https://www.cnblogs.com/wade-lt/p/9008058.html

binlog

binlog日誌作用是用來記錄mysql內部增刪改查等對mysql數據庫有更新的內容的記錄(對數據庫的改動),對數據庫的查詢select或show等不會被binlog日誌記錄;主要用於數據庫的主從複製(實時備份)以及增量恢復。

  • 開啓mysql的binlog:

    log-bin = /home/mysql/3314/mysql-bin
    
  • 查看是否啓用了日誌:

    mysql> show variables like 'log_bin';
    
  • binlog的三種模式:

    • Row level :日誌中會記錄每一行數據被修改的情況,然後在slave端對相同的數據進行修改。
      • 優點:能清楚的記錄每一行數據修改的細節
      • 缺點:數據量太大
    • Statement level(默認):每一條被修改數據的sql都會記錄到master的bin-log中,slave在複製的時候sql進程會解析成和原來master端執行過的相同的sql再次執行
      • 優點:解決了 Row level下的缺點,不需要記錄每一行的數據變化,減少bin-log日誌量,節約磁盤IO,提高新能
      • 缺點:容易出現主從複製不一致
    • Mixed(混合模式):結合了Row level和Statement level的優點
  • 參考:

開始配置

  • 主庫授權:

    # 在主庫創建主從同步要用到的用戶,並授權(嚴格針對ip授權):
    mysql> GRANT REPLICATION SLAVE ON *.* TO 'sstuser'@'10.xxx.xx.xx' IDENTIFIED BY 'sstuser_xxxxxxx';
    mysql> flush privileges;
    
  • 配置從庫:

    $ systemctl start mysqld@3314
    $ systemctl status mysqld@3314
    
    # 獲取備份文件binlog文件名、偏移量(搭建主從時用)
    $ cat /home/mysql/3314/data/xtrabackup_binlog_pos_innodb
    ## eg:mysql-bin.000028     145809329
    
    # 登錄並配置從庫
    $ sh mysql_client.sh
    
  • 授權:

    ## 指定主庫
    mysql> CHANGE MASTER TO MASTER_HOST='10.xxx.xx.xx', MASTER_PORT=3314,MASTER_USER='sstuser', MASTER_PASSWORD='sstuser_xxxxxx', MASTER_LOG_FILE='mysql-bin.000028', MASTER_LOG_POS=145809329;
    
    ## 開啓主從同步
    mysql> start slave;
    
    ## 檢查主從同步狀態
    mysql> show slave status\G   
    
    # 驗證:
    ## 在主庫插入數據,在從庫查看(簡單操作:create database test_slave;)
    ## 如果配置了haproxy,也可以檢測haproxy狀態:http://vip:7901/status
    
  • 主從重要狀態信息:

    • Slave_IO_Running: I/O線程是否被啓動併成功地連接到主服務器上,Yes表示連接成功!
    • **Slave_SQL_Running: ** SQL線程是否被啓動,Yes表示啓動成功!
    • **Exec_Master_Log_Pos: ** 來自主服務器的二進制日誌的由SQL線程執行的上一個時間的位置(Relay_Master_Log_File)。
    • **Relay_Log_Space: ** 所有原有的中繼日誌結合起來的總大小
    • Slave_SQL_Running_State: 從庫SQL線程運行狀態,正常應該處於等待接收主庫數據同步狀態( “ Slave has read all relay log; waiting for the slave I/O thread to update it“)

配置雙主

Note:如果需要新從庫和主庫構建雙主集羣,從庫必須不能接受任何寫請求!!!

  • 在從庫服務器對主庫服務器授權:

    mysql> GRANT REPLICATION SLAVE ON *.* TO 'sstuser'@'10.xxx.xx.xx2' IDENTIFIED BY 'sstuser_xxxxxx';
    
    # 查看數據庫binlog文件名、偏移量
    mysql> show master status;
    +------------------+----------+--------------+------------------+-------------------+
    | File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
    +------------------+----------+--------------+------------------+-------------------+
    | mysql-bin.000001 |  2954215 |              |                  |                   |
    +------------------+----------+--------------+------------------+-------------------+
    1 row in set (0.01 sec)
    
    
  • 配置主庫:

    # 停止原有的slave
    mysql> stop slave;
    
    mysql> CHANGE MASTER TO MASTER_HOST='10.xxx.xx.xx2', MASTER_PORT=3314,MASTER_USER='sstuser', MASTER_PASSWORD='sstuser_xxxxxx', MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=2954215;
    
    mysql> start slave;
    
    mysql> show slave status\G
    
    ## 搭建完成後用同樣的方式(插入數據)檢測雙主狀態!!!
    

問題處理

  • 如果搭建過程中發現slave狀態錯誤,應立刻停止slave(stop slave),檢測操作步驟,排查錯誤,重建主從!

  • 如果是恢復雙主中的一個節點,必須先停止2個節點主從同步。不能讓健康的節點一直同步錯誤的節點。

  • 因mysql版本問題導致的問題:

    ERROR 1558 (HY000): Column count of mysql.user is wrong. Expected 43, found 42. Created with MySQL 50552, now running 50637. Please use mysql_upgrade to fix this error	
    
    • 原因: 新部署的數據庫和原有數據庫版本不一致(檢測發現小版本有升級),錯誤是由於你曾經升級過數據庫,升級完後沒有使用 mysql_upgrade升級數據結構造成的。

    • 解決辦法: 升級數據結構

      $ mysql_upgrade -u root -pxxxxxx -S /home/mysql/3314/mysql.sock 
      
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章