AB複製又稱之爲主從複製,用於實現數據同步,實現Mysql的AB複製時,數據庫的版本儘可能保持一致,若是不能保持一致,最起碼從服務器的版本要高於主服務器,可是就沒法實現雙向複製技術.java
Mysql AB複製的好處
node
1.解決宕機帶來的數據不一致問題,由於Mysql複製能夠實時備份數據.python
2.多臺服務器的性能通常比單臺好,且能夠減輕數據庫服務器的壓力,由於備份等操做能夠在從服務器上進行,可是AB複製不適用於大數據量,若是是一個主服務器有多臺從服務器,那麼主服務器須要同時向多臺服務器中寫入數據,壓力會很大,這個時候就推薦使用集羣.mysql
Mysql複製(replication)是一個異步的複製,從一個Mysql實例(Master)複製到另外一個Mysql實例(Slave),整個主從複製須要由Master服務器上的IO進程,Slave服務器上的Sql線程和IO線程共同完成,首先Master端必須打開binary log(bin-log),由於整個Mysql複製過程實際上就是Slave從Master端獲取相應的二進制日誌,而後在本地徹底順序的執行日誌中所記錄的各類操做.linux
傳統主從複製基本過程:
sql
# 1. Mysql slave端的ID進程鏈接上Master,向Master請求指定日誌文件的指定位置(或者最開始日誌)以後的日誌內容; # 2. Master接收到來自Slave的IO進程的請求後,負責複製的IO進程根據Slave的請求信息,讀取相應日誌內容,返回Slave的IO進程,並將相應日誌內容返回給Slave的IO進程,並將本次請求讀取的bin-log文件名及位置一塊兒返回Slave端. # 3. Slave的IO進程接收到信息後,將接收到的日誌內容依次添加到Slave端的relay-log文件的最末端,並將讀取到的Master端的 bin-log的文件名和位置記錄到master-info文件中,以便在下一次讀取的時候可以清楚的告訴Master「我須要從某個bin-log的哪一個位置開始日後的日誌內容,請發給我」; # 4. Slave的Sql進程檢測到relay-log中新增長了內容後,會立刻解析relay-log的內容成爲在Master端真實執行時候的那些可執行的內容,並在自身執行。
從庫生成兩個線程,一個I/O,一個SQL線程,I/O線程去請求主庫的binlog,並將獲得的binlog日誌寫到relay log(中繼日誌)文件中;
數據庫
主庫會生成一個Log dump線程,用來給從庫I/O線程傳binlog;
安全
從庫的SQL線程會讀取relay log文件的日誌,並解析成具體操做,從而實現主從數據一致
bash
# 兩個進程一個線程 # IO進程: 負責下載日誌,中繼日誌 # SQL進程: SQL負責將中繼日誌應用到數據庫中,完成AB複製數據同步. # logdump線程:
# 1. 同步複製 # master服務器操做完成,當操做做爲時間寫入二進制日誌,傳遞給slave,存放到中繼日誌中,而後再本地執行完成功,即反饋成功. # 2. 半同步複製 # 當有多臺slave服務器時,master向離本身最近的slave服務器同步二進制文件後,即爲反饋成功,不是Mysql官方提供的,是5.5版本時google研發半同步不定後支持,須要semi插件. # 3. 異步複製: # Master服務器操做完成,當操做做爲事件寫入二進制日誌,即反饋成功(默認) # 4. 基於GTID複製技術(5.6版本纔有) # 見下面 # 5. 多源複製(5.7) # 1. 方便備份數據 # 2. 方便對數據進行統一分析
1. 使用GITD技術可讓兩臺服務器自動交換事務ID,通過對比,請求數據,保證服務器之間的數據是同步的;
服務器
2. 提高安全性,多事務並行執行時,也不會形成數據混亂;
3. 多線程複製,從服務器能夠啓動多個SQL Threfad,併發執行多個庫的複製,提高速度
網絡問題
# 要注意mysql主庫和從庫所在服務器間的網絡問題,由於是要作數據庫的主從,主從之間的網絡是要能通的,及從庫可經過網絡訪問到主庫,不然沒法同步數據. # 若是mysql主從使用的是雲服務器,注意去該雲服務器的管理平臺,開放相應數據庫的安全組(如阿里雲,青雲,騰訊雲)
mysql的版本問題
# 主從的數據是要進行同步的,若是數據庫版本或者安裝方式不一樣,會影響數據的同步,產生沒法同步或字符集報錯的狀況 # 主庫和從庫的服務器,安裝mysql數據庫時,要選擇相應的版本,而且安裝方式最好相同
配置文件問題
# mysql或mariadb的關鍵配置文件是my.cnf,默認位置爲etc/my.cnf(因爲安裝方式的不一樣,此配置文件,並不必定在此) # 作主從時,注意要在啓動數據庫前,修改配置文件my.cnf後,再啓動數據庫服務 # 注意主從配置時,必需要在my.cnf中添加server-id,主的server-id的數值要小於從的server-id,每個server-id都必須是惟一的 # 注意主從配置時,必需要在my.cnf中添加log-bin,開啓二進制文件 # 數據庫如配置有調優參數,應使主從的配置文件中參數數值相同,避免因參數不一樣致使的失敗
受權問題
# 數據庫的同步是要經過主庫專門建立的一個用戶來使從庫進行數據的同步的,所以要注意受權的問題 # 注意主庫受權時的ip,用戶,密碼grant replication slave on . to ‘用戶’@‘從庫的IP’ identified by ‘密碼’ # 注意從庫鏈接主庫的各項參數 # change master to master_host = ‘主庫的IP’, master_user = ‘設置主從時設定的主庫的用戶’, master_port=主庫的端口, master_password=’主庫設定的密碼’, master_log_file = ‘主庫狀態的File’, master_log_pos=主庫狀態的Position;
數據庫差異問題
# 咱們在作新的mysql主從的時候,因爲主庫並無產生較多的數據,從庫很容易就進行同步,報錯也幾乎不會產生 # 可是,當咱們的主庫的數據已經有不少了或者是把一個用了好久的數據庫來作主從,這時就須要先將主庫的數據備份導入從庫中,再進行從庫的鏈接到主庫的步驟。不然,就會從庫就會因數據差異較大,產生各類報錯
先在兩臺機器執行下面腳本,分別安裝好數據庫,並改好密碼
#!/usr/bin/env bash # Author: ZhouJian # Mail: 18621048481@163.com # Time: 2019-9-3 # Describe: CentOS 7 Install Mysql.rpm Script clear echo -ne "\\033[0;33m" cat<<EOT _oo0oo_ 088888880 88" . "88 (| -_- |) 0\\ = /0 ___/'---'\\___ .' \\\\\\\\| |// '. / \\\\\\\\||| : |||// \\\\ /_ ||||| -:- |||||- \\\\ | | \\\\\\\\\\\\ - /// | | | \\_| ''\\---/'' |_/ | \\ .-\\__ '-' __/-. / ___'. .' /--.--\\ '. .'___ ."" '< '.___\\_<|>_/___.' >' "". | | : '- \\'.;'\\ _ /';.'/ - ' : | | \\ \\ '_. \\_ __\\ /__ _/ .-' / / ====='-.____'.___ \\_____/___.-'____.-'===== '=---=' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 建議系統 CentOS7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # PS:請儘可能使用純淨的CentOS7系統,咱們會在服務器安裝Mysql5.7, # 將mysql-5.7.23-1.el7.x86_64.rpm-bundle.tar包和腳本放到root目錄下執行便可,密碼爲ZHOUjian.20 EOT echo -ne "\\033[m" init_security() { systemctl stop firewalld systemctl disable firewalld &>/dev/null setenforce 0 sed -i '/^SELINUX=/ s/enforcing/disabled/' /etc/selinux/config sed -i '/^GSSAPIAu/ s/yes/no/' /etc/ssh/sshd_config sed -i '/^#UseDNS/ {s/^#//;s/yes/no/}' /etc/ssh/sshd_config systemctl enable sshd crond &> /dev/null echo -e "\033[32m [安全配置] ==> OK \033[0m" } init_yumsource() { if [ ! -d /etc/yum.repos.d/backup ];then mkdir /etc/yum.repos.d/backup fi mv /etc/yum.repos.d/* /etc/yum.repos.d/backup 2>/dev/null if ! ping -c2 www.baidu.com &>/dev/null then echo "您沒法上外網,不能配置yum源" exit fi curl -o /etc/yum.repos.d/163.repo http://mirrors.163.com/.help/CentOS7-Base-163.repo curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo timedatectl set-timezone Asia/Shanghai echo "nameserver 114.114.114.114" > /etc/resolv.conf echo "nameserver 8.8.8.8" >> /etc/resolv.conf chattr +i /etc/resolv.conf echo -e "\033[32m [YUM Source] ==> OK \033[0m" } init_mysql() { rpm -e mariadb-libs --nodeps rm -rf /var/lib/mysql rm -rf /etc/my.cnf tar xvf /root/mysql-5.7.23-1.el7.x86_64.rpm-bundle.tar -C /usr/local/ cd /usr/local rpm -ivh mysql-community-server-5.7.23-1.el7.x86_64.rpm \ mysql-community-client-5.7.23-1.el7.x86_64.rpm \ mysql-community-common-5.7.23-1.el7.x86_64.rpm \ mysql-community-libs-5.7.23-1.el7.x86_64.rpm | rm -rf mysql-community-* } changepass() { sed -i '/\[mysqld]/ a skip-grant-tables' /etc/my.cnf systemctl restart mysqld mysql <<EOF update mysql.user set authentication_string='' where user='root' and Host='localhost'; flush privileges; EOF sed -i '/skip-grant/d' /etc/my.cnf systemctl restart mysqld yum -y install expect ntpdate expect <<-EOF spawn mysqladmin -uroot -p password "ZHOUjian.20" expect { "password" { send "\r" } } expect eof EOF systemctl restart mysqld } main() { init_hostname init_security init_yumsource init_mysql changepass } main
mysql主庫配置
[root@mysqlhost ~]# cat /etc/my.cnf [mysqld] datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock symbolic-links=0 log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid server-id = 1 log-bin=mysql-bin
mysql從庫配置
[root@mysql-from ~]# cat /etc/my.cnf [mysqld] datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock symbolic-links=0 log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid server-id = 2 log-bin = mysql-bin
主從兩臺服務器分別重啓服務
systemctl restart mysqld
# 建立用於同步的用戶帳號及密碼 grant replication slave on *.* to 'slave'@'192.168.0.%' identified by 'ZHOUjian.200'; # 從新加載權限表,更新權限 flush privileges; # 查看master的狀態 #mysql> show master status; #+------------------+----------+--------------+------------------+-------------------+ #| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | #+------------------+----------+--------------+------------------+-------------------+ #| mysql-bin.000001 | 600 | | | | #+------------------+----------+--------------+------------------+-------------------+ #1 row in set (0.00 sec)
change master to master_host='192.168.0.102', master_user='slave', master_password='ZHOUjian.200', master_auto_position=0; mysql> start slave; # 查看從庫狀態 mysql> show slave status\G; *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.0.117 Master_User: slave Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000001 Read_Master_Log_Pos: 600 Relay_Log_File: mysql-from-relay-bin.000002 Relay_Log_Pos: 813 Relay_Master_Log_File: mysql-bin.000001 Slave_IO_Running: Yes # 此處兩個yes有一個不是就會失敗 Slave_SQL_Running: Yes # Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 600 Relay_Log_Space: 1025 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: 0 Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: Master_Server_Id: 1 Master_UUID: ff0c0da9-8f72-11ea-9d83-000c29245a7e Master_Info_File: /var/lib/mysql/master.info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: Executed_Gtid_Set: Auto_Position: 0 Replicate_Rewrite_DB: Channel_Name: Master_TLS_Version: 1 row in set (0.00 sec)
如下操做是基於上面的GTID複製案例喔,請作完GTID再作這裏,大佬請無視這句話
[root@mysql-from2 ~]# cat /etc/my.cnf [mysqld] datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock symbolic-links=0 log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid server-id = 3 log-bin = mysql-bin
修改配置記得重啓mysqld服務生效配置
systemctl restart mysqld
# 建立用於同步的用戶帳號及密碼 grant replication slave on *.* to 'slave'@'192.168.0.%' identified by 'ZHOUjian.200'; # 從新加載權限表,更新權限 flush privileges;
# 先進入主庫,進行鎖表,此處鎖定爲只讀狀態,防止數據寫入 (可選,因若有數據庫備份,可直接利用備份) flush tables with read lock; mysqldump -uroot -p‘….’ -hlocalhost > mysql.back.sql scp mysql.back.sql 從庫IP:/root/(任意位置) # 從庫導入數據 mysql -uroot -p... -f < mysql.back.sql # 主庫解鎖 unlock tables;
# 從庫開啓slave change master to master_host='192.168.0.102', master_user='slave', master_password='ZHOUjian.200', master_auto_position=0; mysql> start slave; # 查看從庫狀態 mysql> show slave status\G; *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.0.102 Master_User: slave Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000001 Read_Master_Log_Pos: 600 Relay_Log_File: mysql-from-relay-bin.000002 Relay_Log_Pos: 813 Relay_Master_Log_File: mysql-bin.000001 Slave_IO_Running: Yes # 此處兩個yes有一個不是就會失敗 Slave_SQL_Running: Yes # Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 600 Relay_Log_Space: 1025 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: 0 Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 0 Last_SQL_Error: Replicate_Ignore_Server_Ids: Master_Server_Id: 1 Master_UUID: ff0c0da9-8f72-11ea-9d83-000c29245a7e Master_Info_File: /var/lib/mysql/master.info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: Executed_Gtid_Set: Auto_Position: 0 Replicate_Rewrite_DB: Channel_Name: Master_TLS_Version: 1 row in set (0.00 sec)
解決併發問題,不一樣於分表,分表用於解決數據量過大的問題
方式一: 業務層使用不一樣的數據庫
方式二: 使用負載均衡,判斷是什麼語句,分配到不一樣的數據庫
基於應用層和數據層中間件的代理層,主要解決方案以下:
# 1. 開發人員 # 2. 軟件 # mysql-proxy # amoeba JAVA 阿里 # Atlas 360 # TDDL # Sharding-JDBC # cobar (MyCAT前身,java) # 這些中間件,統一爲多個數據庫進行代理,應用只須要鏈接中間件(分佈式數據庫系統),執行SQL,中間件就會根據規則,將SQL分配到不一樣的數據庫中