1.普通文件的數據同步與數據庫同步
1.1)普通文件的數據同步方案
NFS網絡文件共享可以同步存儲數據(掛載到新服務器);
samba共享數據 (http://taokey.blog.51cto.com/4633273/1203553);
定時任務或守護進程結合rsync,scp;
inotify(sersync)+rsync觸發式實時數據同步;
ftp 數據同步;
ssh key+scp/rsync;
1.2)數據庫同步方案
自身同步機制——mysql replication,mysql主從復制(邏輯的SQL從寫);oracle dataguard(物理的磁盤塊,邏輯的SQL語句從寫)
第三方drbd,參考http://oldboy.blog.51cto.com/2561410/1240412
兩個服務器同時寫數據,也是一種復制機制
2.mysql主從復制架構
2.1)架構模式 # mysql主從同步都是異步同步的方式
主從同步:一主一從,一主兩從......
主主同步
線性級聯單項雙主同步(主-主-從)
環狀級聯單向多主同步
環狀級聯單向多主多從同步(主主構成環狀,每個主再附加從)
2.2)對於主從存在不一致可采取的方法
找一台從庫只做備份用,主庫能起來,把主庫的binlog拉到從庫,把宕機一瞬間主庫上的寫恢復到從庫
雙寫可以相對保證數據一致
通過應用程序寫一個短時間的日志,只記錄宕機一瞬間發生的事放在內存里
把異步同步換成實時同步,mysql有個Google開發的半同步的插件,要求如果在主上寫,主成功,且某一個半同步的從成功,才算真正的成功
3.主從同步的作用
主從服務器互為備份,從而達到實時備份的目的
主從服務器讀寫分離分擔網站壓力(主庫寫,從庫讀,對於讀多寫少的,再把從庫橫向擴展,推薦用程序實現讀寫分離,小公司會用proxy、Amoeba實現,門戶網站會開發dbproxy實現)
分布式dbproxy(讀寫分離,hash負載均衡,健康檢查) ——有難度!
根據服務器拆分業務,獨立分擔壓力
4.mysql主從同步的原理
主庫由一個線程完成主從同步——IO線程;
從庫由兩個線程完成主從同步——SQL線程和IO線程;
要實現主從同步,主庫必須開啟binlog;
當用戶執行增刪改的請求時,數據會寫到數據文件中,把更新的結果寫到binlog中;
主從同步是從庫找主庫,在change master的點之前,需把主庫的數據都給到從庫,從庫中change master去配置連到主庫:包括master_host,master_user,master_password,master_port,master_log_file,master_log_pos等(# change master to master_log_file='mysql-bin.000020',master_log_pos=1191;);
配置完成后,需創建同步的賬號,需在從庫上打開start slave的開關,開啟同步;
【同步原理】開啟同步后,從庫向主庫的mysql主進程發出請求,主庫通過驗證用戶名、IP地址、端口、密碼等判斷是否允許連接,然后交給主庫的IO處理,主庫IO收到從哪個位置點同步,給從庫發binlog,從庫收到log日志后將其寫入relay-log,稱為中繼日志,並把最后得到的日志及位置點記錄master info,這樣再次向主庫提取log時,接着上次的位置點向主庫索要,以便告訴master服務器從哪個文件開始讀。IO把binlog放入中繼日志之后就不管了,由從庫的SQL實時的讀中繼日志,然后及時的把log文件中的內容解析成在master端曾經執行的SQL語句的內容,並在自身slave服務器上按語句的順序執行應用這些SQL語句,存放在數據文件中,應用完畢后清理應用過的日志,因此這個主從同步是異步的。
官方版圖:
5.實戰
【實戰環境】
選擇一台服務器上3306和3307兩個mysql實例來模擬主從同步過程
主庫 master 3306
從庫 slave 3307
5.1)確保主庫的log-bin,server-id開啟,log-bin可指定路徑,如:/data/3306/mysql-bin
#上述兩個參數要放在my.cnf的【mysqld】模塊下,否則會出錯
從庫的log-bin可開可不開,server-id主從要不一樣!
(補充:從庫需要開啟binlog的情況:
1.當前從庫作為其他從庫的主庫,即級聯同步;
2.把從庫作為數據庫備份服務器時;
在從庫的my.cnf中做以下步驟:
1.打開log-bin
2.添加參數:log-slave-updates
3.expire_logs_days=7 #binlog保留時間設置)
確認log-bin開啟,一是可以ll /data/3306/看是否有mysql-bin文件,二是可以進庫查看log_bin參數的ON/OFF設置情況
5.2)在主庫上建立用於從庫復制的賬號rep
use oldboy
grant replication slave on *.* to 'rep'@'192.168.6.%' identified by '123456'; #這里要改成mysql使用的虛擬機IP
show grants for rep@'192.168.6.%'; #查看是否授權成功該用戶
5.3)在主庫上做備份
mysql> flush table with read lock; #鎖表,窗口不能退出,退出無效
mysql> show master status; #拿到備份的位置點(這里為602),臨界點,將來恢復就從0010開始
mysqldump -uroot -poldboy123 -S /data/3306/mysql.sock -A -B --events|gzip >/opt/rep.sql.gz #重新開一個窗口備份數據
或mysqldump -uroot -poldboy123 -S /data/3306/mysql.sock -A -B --events --master-data=2 >/opt/rep.sql.gz #也能拿到備份的起始位置點
再回到原來窗口,看看bin-log有沒有變,確保主庫是鎖住了的
mysql> show master logs;
mysql> show master status;
mysql> unlock tables;
將主庫備份同步到從庫:
mysql -uroot -poldboy123 -S /data/3307/mysql.sock </opt/rep.sql.gz
5.4)建立主從復制:
登錄到從庫:
mysql -uroot -p456 -S /data/3307/mysql.sock
mysql> CHANGE MASTER TO
MASTER_HOST='192.168.6.128',
MASTER_PORT=3306,
MASTER_USER='rep',
MASTER_PASSWORD='123456',
MASTER_LOG_FILE='mysqlbin_coco.000001',
MASTER_LOG_POS=107;
#如果master-data指定=1,則上述最后兩步可省略,自動找到位置,相當於利用mysqldump在半夜做一次全備數據並恢復到從庫
#會在3307下產生master.info文件
mysql> start slave; #啟動從庫
mysql> show slave status\G #看IO,SQL兩個線程是否都正常工作,兩個yes表示主從搭建成功
5.5)驗證主從同步
在主庫上建立一個新的database:
mysql> show databases;
mysql> create database oldboy;
mysql> show databases;
換從庫:
mysql> show databases; #同樣生成了oldgril庫表示成功
【此過程會產生一系列文件】
在relay-bin.XXXXXX中查看是否有‘create database oldboy’,應該是有的
relay-bin.index記錄了relay-bin log更新到哪了
relay-log.info記錄了SQL讀到relay-bin log的位置和IO取log即master.info中截止的位置
至此,模擬一次主從同步完成了。
6.mysql主從復制常見問題
1)show master status時沒有位置點
查看bin-log有沒有打開;
2)Last_IO_Error:Got fatal errror 1236 from master when reading data from binary log:'Counld not find first log file name in binary log index file'
查看change master 配置時,MASTER_LOG_FILE指定的文件是否多了空格;
3)flush tables with read lock無法鎖表
mysql5.1的鎖表是tables,mysql5.5是table,根據不同版本寫法不同;
另外,鎖表命令的時間會受到兩個參數的控制,如果超過設置時間不操作會自動解鎖:interactive_timeout = 60、wait_timeout = 60;
show variables like '%timeout%';
4)服務無法正常啟動故障
mysql意外關閉,殺了mysql進程后,啟動mysql仍然顯示mysql is running
ps -ef|grep mysqld
killall mysqld
chkconfig mysqld off
ps -ef|grep mysqld
/data/3306/mysql start >>>>顯示mysql is running...
這是由於啟動腳本中的相應配置導致,此時需將之前啟動產生的文件刪除:rm -f /data/3306/mysql.sock /data/3306/*.pid
/data/3306/mysql start >>>>顯示Starting mysql...
5)由於切換binlog導致show master status位置變化無影響
6)從庫IO顯示connecting,SQL同步為yes,需檢查:
mysql配置文件my.cnf中log-bin是否打開;
主從server-id是否為不同的設置;
主從的網絡是否暢通
7)從庫IO同步正常,但SQL同步異常顯示為NO
比如在從庫先創建個數據庫butongbu,然后再在主庫上創建個butongbu,這時看從庫會發現報錯
解決方法1:stop slave; set global sql_slave_skip_counter=1; start slave;即讓slave跳過一步
解決方法2:根據錯誤號跳過指定的錯誤,每個錯誤號都有不同的含義。在配置文件中添加slave-skip-errors=1032,1062,1007;一般由於入庫重復的失敗就可以忽略
7.查看復制線程狀態
show processlists可以分別在主庫、從庫上查看主從復制線程狀態,從而判斷數據庫同步是否完成。
7.1)主服務器的常見狀態
sending binlog event to slave
finished reading one binlog, switching to next binlog
has sent all binlog to slave, waiting for binlog to be updated
waiting to finalize termination #線程停止時發生的一個很簡單的狀態
7.2)從服務器的常見狀態
從I/O狀態:
connecting to master
checking master version
registering slave on master
repquesting binlog dump
waiting to reconnect after a failed binlog dump request
reconnecting after a failed binlog dump request
waiting for master to send event
queneing master event to the relay log
waiting to reconnect after a failed master event read
從SQL線程狀態:
reading event from the relay log
has read all relay log ,waiting for the salve I/O thread to update it
waiting for slave mutex on exit #線程停止時發生的一個很簡單的狀態
8.可實現生產場景主從讀寫分離的方法
實現從庫只能讀的方式:
1)生產權限方案1-主庫不能再更改了
主庫:web oldboy123 10.0.0.1 3306 (select insert delete update)
從庫:主庫的web用戶同步到從庫,然后回收insert delete update 權限。
開發只需知道10.0.0.1是主,10.0.0.2 是從。運維則需要回收從的權限
不收回從庫權限的話,在從庫設置read-only參數防止從庫寫的操作
# read-only設置方式-在從庫的my.cnf中的【mysqld】下添加一行read-only,並重啟mysql,但是對於具有super或all privilege權限的用戶不生效,可以嘗試創建一個只有增刪改查詢權限的用戶。
2) 生產權限方案2
主庫:web_w oldboy123 10.0.0.1 3306 (select insert delete update)
從庫:web_r oldboy456 10.0.0.2 3306 (select)
風險:web_w連接從庫!可能把主庫同步到從庫了,因此也可設read-only保證從庫只讀
開發多套用戶密碼相對不專業
3) 生產權限方案3
mysql庫不同步(在配置文件等隨便修改一點點參數):主從庫分別進行如下授權
主庫:web oldboy123 10.0.0.1 3306 (select insert delete update)
從庫:web oldboy123 10.0.0.2 3306 (select)
缺陷:當從庫切換主庫時,連接用戶權限問題。因此可借鑒百度的做法,保留一個從庫專門接替主(或者只做簡單的備份)。
9.忽略授權表,限制哪些同步,哪些不同步
主庫執行:
vi /data/3306/my.cnf
配置-
replicate-ignore-db = mysql
binlog-ignore-db = mysql
binlog-ignore-db = performance_schema
binlog-ignore-db = information_schema
(補充:
master端:
binlog-do-db 二進制記錄的數據庫,多個數據庫用逗號分隔
binlog-ignore-db 二進制忽略的數據庫,多個數據庫用逗號分隔
slave端:
replication-do-db 設定需要復制的數據庫,多個數據庫用逗號分隔
replication-ignore-db 設定忽略復制的數據庫,多個數據庫用逗號分隔
replication-do-table 設定需要復制的表,多個表用逗號分隔
replication-ignore-table 設定忽略復制的表,多個表用逗號分隔
replication-wild-do-table 設定要復制的表,但是可以加通配符
replication-wild-ignore-table 設定忽略復制的表,但可以加通配符)
/data/3306/mysql stop
/data/3306/mysql start
mysql> select user.host from mysql.user;
mysql> flush privileges;
mysql> create user oldgirl@localhost identified by 'oldboy123';
從庫查看是否有相同的用戶創建出來:
mysql> show slave status\G #從庫依舊兩個yes,同步
mysql> select user.host from mysql.user; #從庫沒有相應的用戶,即忽略了授權表
10.主從復制原理總結
異步方式同步;
邏輯同步模式,多種模式,默認是通過SQL語句執行(主從不能保證完全一致);
主庫通過記錄binlog實現對從庫的同步,binlog記錄數據庫的更新語句;
主庫1個IO線程,從庫由1個IO線程和1個SQL線程完成的;
從庫關鍵文件master info,relay-log,relay-info等有各自的功能;
如果從庫還想級聯從庫,需要打開從庫的log-bin和log-slave-updates參數。
11.主從同步下宕機問題&調整為雙主同步的解決方式
11.1)主庫master宕機(數據庫/服務器)-假設一主多從
登錄從庫:
show processlist\G #查看復制狀態
cat /data/3307/data/master.info #分別查看從庫的master.info,其中mysql-bin對應序號及下面位置號更大的從庫,代表其同步性越高,丟失的數據相對少,將此從庫作為新的主庫
#如果主庫還可以拉起來,則可以把主庫的binlog拉取到從庫中,再拉起從庫為主庫
#或者利用半同步功能,直接選擇了實時同步的這個從庫(半同步待了解)
>>>確保所有relay log全部更新完畢
在每個從庫上執行stop slave io_thread; show processlist; #直到查看到has read all relay log表示從庫更新都執行完畢
>>>登錄新的主庫-如果該從庫配置過授權表,read-only等,都需要注銷掉
如:mysql -uroot -p456 -S /data/3307/mysql.sock
stop slave;
retset master;
quit;
>>>進到數據庫數據目錄,刪除master.info和relay-log.info
cd /data/3307/data
rm -f master.info relay-log.info
>>>3307 提升該從庫為主庫
vi /data/3307/my,cnf
開啟log-bin = /data/3307/mysql-bin
重啟數據庫:/data/3307/mysql restart
>>>其他從庫操作
已檢查(同步user rep均存在)
登錄新的從庫:
stop slave;
change master to master_host = '192.168.1.32'; #如果之前在master上設定過VIP,則此步驟可以省略,VIP可以自動漂浮;如果不同步,可以指定位置點進行同步
start slave;
show slave status\G
>>>修改程序配置文件從主庫指向從庫(新的主庫)-開發層面對
>>>修理損壞的主庫,作為從庫使用
【補充】
如果不是宕機,而是有計划的切換主從
>>>主庫鎖表
>>>登錄所有的庫查看同步狀態是否完成
>>>
在之前的從庫上執行以下:
#在執行reset master時有風險,從庫原來的mysqlbin log都會不在了
在之前的主庫上執行以下:
11.2)從庫slave宕機(數據庫/服務器)-假設一主多從
若從庫宕機,則需要重新做從庫:
stop slave;
gzip -d oldboy_data_5.sql.gz
mysql -uroot -p456 -S /data/3307/mysql.sock < oldboy_data_5.sql & //直接灌入數據
change master to master_host='192.168.1.35' , master_user='repl' , master_password='slavepass' , master_log_file='mysql-bin.000004', master_log_pos=333;
start slave;
show slave status\G
11.3)雙主模式主從同步-假設原來3306是主,3307是從
>>>解決表的主鍵自增長變量沖突【mysqld】:
Master1:
auto_increment_increment = 2 #自增ID的間隔,如 1 3 5間隔為2
auto_increment_offset = 1 #ID的初始位置
Master2:
auto_increment_increment = 2 #自增ID的間隔,如 2 4 6間隔為2
auto_increment_offset = 2 #ID的初始位置
生成序列為: 1 3 5 6 8 10 11 13 這種,ID可能會不連續
//或者通過程序控制主鍵自增形式
>>>設置互為主從參數
log-slave-updates #開啟從庫即3307的binlog日志
log-bin=/data/3307/mysqlcoco_bin
>>>原主從數據不同步的解決
如果不同步,則需要通過MySQLdump -master-data=1 -x 雙向做一下同步
>>>配置3306為從庫,其主庫為3307
mysql> CHANGE MASTER TO
MASTER_HOST='3307的IP',
MASTER_PORT=3307,
MASTER_USER='rep',
MASTER_PASSWORD='123456'; #因為做了一次master-data=1,已自動記錄了文件讀取位置,無需再添加標識位置的參數行
然后查看3306作為3307的從庫的狀態正常即可 show slave status; #需重啟slave
至此完成了雙主模式的主從同步模擬~
2018年11月1日
祝好!