一、流程圖
二、要實現讀寫分離必須是主從同步
2.1、環境設定
主機名 | IP |
master | 192.168.182.129 |
slave | 192.168.182.130 |
mysql-proxy | 192.168.182.131 |
2.2、實現主從同步
2.2.1、原理:
1)主從同步過程中主服務器有一個工作線程I/O dump thread,從服務器有兩個工作線程I/O thread和SQL thread。
2)主庫把外界接收的SQL請求記錄到自己的binlog日志中,從庫的I/O thread去請求主庫的binlog日志,並將binlog日志寫到中繼日志中,然后從庫重做中繼日志的SQL語句。主庫通過I/O dump thread給從庫I/O thread傳送binlog日志。
3)異步復制是MySQL默認的復制方式,主庫寫入binlog日志后即可成功返回客戶端,無須等待binlog日志傳遞給從庫的過程,但是一旦主庫宕機,就有可能出現丟失數據的情況。
4)復制原理
4.1 )異步復制
異步復制是MySQL默認的復制方式,主庫寫入binlog日志后即可成功返回客戶端,無須等待binlog日志傳遞給從庫的過程,但是一旦主庫宕機,就有可能出現丟失數據的情況。
4.2) 半同步復制
MySQL默認的復制方式是異步復制,但是當主庫宕機,在高可用架構坐准備切換,就會造成新的主庫丟失數據的現象。
MySQL5.5版本之后引入了半同步復制,但是主從服務器必須同時安裝半同步復制插件。在該功能下,確保從庫接收完成主庫傳遞過來的binlog內容已經寫入到自己的relay log后才會通知主庫上面的等待線程。如果等待超時(超時參數:rpl_semi_sync_master_timeout),則關閉半同步復制,並自動轉換為異步復制模式,直到至少有一台從庫通知主庫已經接收到binlog信息為止。
半同步復制提升了主從之間數據的一致性,讓復制更加安全可靠,在5.7 版本中又增加了rpl_semi_sync_master_wait_point參數,用來控制半同步模式下主庫返回給session事務成功之前的事務提交方式。
該參數有兩個值:
1)AFTER_COMMIT:5.6版本的默認值,主庫將每個事務寫入binlog,並傳遞給從庫,刷新到中繼日志中,同時主庫提交事務。之后主庫開始等待從庫的反饋,只有收到從庫的回復之后,master才將commit OK的結果反饋給客戶端。
2)AFTER_SYNC:5.7版本新增,也是默認的半同步復制方式。主庫將每個事務寫入binlog並傳遞給從庫,刷新到中繼日志中,主庫開始等待從庫的反饋,接收到從庫的回復之后,再提交事務並且返回commit OK結果給客戶端。
注意:可以通過rpl_semi_sync_master_wait_for_slave_count參數來控制主庫接收多少個從庫寫事務成功反饋,才返回成功給客戶端。生產環境中使用半同步復制方式,當從庫出現故障,等待超時的時間又很長,導致主庫無法接收從庫信息而無法正常寫入時,可通過該參數剔除故障從庫。另外rpl_semi_sync_master_timeout單位是毫秒,它表示如果主庫等待從庫回復消息的時間超過該值,就自動切換為異步復制模式,建議調整為很大,禁止向異步復制切換來保證數據復制的安全性。MySQL 5.7默認的半同步復制方式是after_sync模式。
在AFTER_SYNC模式下,即使主庫宕機,所有在主庫上已經提交的事務都能保證已經同步到從庫的中繼日志中,不會丟任何數據。
原理圖:
2.2.2、主從配置:
注意:這里使用的是mysql5.6版本,如果其它版本的話,配置可能會有點不一樣,例如:"log_bin" 對應 "log-bin",只是把"_"換成了"-"了,區別不大,注意一下就行
#=======================master配置(my.cnf)=====================
# 設置優先級,主必須小於從 server-id=1 # bin log文件前綴 log_bin=mysql-bin # 對應要同步的數據庫 binlog_do_db=tuling binlog_do_db=zabbix # 不需要同步的數據庫 binlog_ignore_db=information_schema binlog_ignore_db=mysql binlog_ignore_db=performance_schema binlog_ignore_db=test
#=======================slave配置(my.cnf)=====================
# 實例ID,不能喝集群忠的其它mysql實例相同,唯一性 server-id=2 # 對應要同步的數據庫,如果沒有向其它數據庫同步的要求的話,可以不寫 # log_bin=mysql-bin # 需要同步的數據庫 replicate_do_db=tuling replicate_do_db=zabbix # 設定需要復制的表 # replicate_do_table=tuling.tab1 # 設定需要忽略的復制表 # replicate_ignore_table=tuling.tab2 # 增加通配符的兩個配置 # replicate_wild_do_table=tuling.% 只復制哪個庫的哪個表 # replicate_wild_ignore_table=tuling.% 忽略哪個庫的哪個表 # replicate_do_table 跟 replicate_wild_do_table 一樣,只不過replicate_wild_do_table可以加通配符 # replicate_ignore_table 跟 replicate_wild_ignore_table 一樣,只不過replicate_wild_ignore_table可以加通配符 # 不需要同步的數據庫 replicate_ignore_db=information_schema replicate_ignore_db=mysql replicate_ignore_db=performance_schema replicate_ignore_db=test
# 在master上創建一個同步權限的賬戶 用來同步數據 grant replication slave on *.* to 'master'@'%' identified by '123456'; show master status\G; # 配置從庫 stop slave reset slave; change master to master_host='192.168.182.129',master_user='master',master_password='123456',master_port=3306,master_log_file='mysql-bin.000018',master_log_pos=326; start slave; show slave status\G; # 當Slave_IO_Running和Slave_SQL_Running線程都為yes是主從復制配置成功!
2.3、錯誤及解決辦法
問題: 從數據庫無法同步
Slave_SQL_Running 值為 NO,或 Seconds_Bebind_Master 值為 Null
原因:
1. 程序有可能在 slave 上進行了寫操作
2. 也有可能是 slave 機器重啟后,事務回滾造成的
解決方法一:
msyql> stop slave; msyql> set GLOBAL SQL_SLAVE_SKIP_COUNTER=1; msyql> start slave;
解決方法二:
msyql> stop slave;
#查看主服務器上當前的 bin-log 日志名和偏移量
msyql> show master status;
#獲取到如下內容:
+------------------+----------+--------------+------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +------------------+----------+--------------+------------------+ | mysql-bin.000005 | 286 | | | +------------------+----------+--------------+------------------+
#然后到從服務器上執行手動同步
msyql> change master to ->master_host="192.168.10.1", ->master_user="user", ->master_password="123456", ->master_post=3306, ->master_log_file="mysql-bin.000005", ->master_log_pos=286;
msyql> start slave;
三、通過Atlas實現讀寫分離
Atlas 是由 Qihoo 360公司Web平台部基礎架構團隊開發維護的一個基於MySQL協議的數據中間層項目。它在MySQL官方推出的MySQL-Proxy 0.8.2版本的基礎上,修改了大量bug,添加了很多功能特性。
3.1、Atlas配置
下載Atlas會有兩個版本,其中有個分表的版本,但是這個需要其他的依賴,我這邊不需要分表這種需求,所以安裝普通的版本
Atlas (普通) : Atlas-2.2.1.el6.x86_64.rpm Atlas (分表) : Atlas-sharding_1.0.1-el6.x86_64.rpm
首先進入Linux的Home目錄下,下載非分表的安裝包
[root@localhost ~]# cd /home/ [root@localhost home]# wget https://github.com/Qihoo360/Atlas/releases/download/2.2.1/Atlas-2.2.1.el6.x86_64.rpm
下載好了之后,進行安裝
[root@localhost home]# rpm -ivh Atlas-2.2.1.el6.x86_64.rpm Preparing... ########################################### [100%] 1:Atlas ########################################### [100%]
安裝好了,它會默認在”/usr/local/mysql-proxy”下給你生成4個文件夾,以及需要配置的文件,如下:
[root@localhost home]# ll /usr/local/mysql-proxy/ total 16 drwxr-xr-x. 2 root root 4096 Dec 28 10:47 bin drwxr-xr-x. 2 root root 4096 Dec 28 10:47 conf drwxr-xr-x. 3 root root 4096 Dec 28 10:47 lib drwxr-xr-x. 2 root root 4096 Dec 17 2014 log
bin目錄下放的都是可執行文件 1. “encrypt”是用來生成MySQL密碼加密的,在配置的時候會用到 2. “mysql-proxy”是MySQL自己的讀寫分離代理 3. “mysql-proxyd”是360弄出來的,后面有個“d”,服務的啟動、重啟、停止。都是用他來執行的 conf目錄下放的是配置文件 1. “test.cnf”只有一個文件,用來配置代理的,可以使用vim來編輯 lib目錄下放的是一些包,以及Atlas的依賴 log目錄下放的是日志,如報錯等錯誤信息的記錄
進入bin目錄,使用encrypt來對數據庫的密碼進行加密,我的MySQL數據的用戶名是root,密碼是root,我需要對密碼進行加密
[root@localhost bin]# ./encrypt root DAJnl8cVzy8=
配置Atlas,使用vim進行編輯
[root@localhost conf]# cd /usr/local/mysql-proxy/conf/ [root@localhost conf]# vim test.cnf
進入后,可以在Atlas進行配置,360寫的中文注釋都很詳細,根據注釋來配置信息,其中比較重要,需要說明的配置如下:
這是用來登錄到Atlas的管理員的賬號與密碼,與之對應的是“#Atlas監聽的管理接口IP和端口”,也就是說需要設置管理員登錄的端口,才能進入管理員界面,默認端口是2345,也可以指定IP登錄,指定IP后,其他的IP無法訪問管理員的命令界面。方便測試,我這里沒有指定IP和端口登錄。
#管理接口的用戶名 admin-username = user #管理接口的密碼 admin-password = pwd
這是用來配置主數據的地址與從數據庫的地址,這里配置的主數據庫是135,從數據庫是134
#Atlas后端連接的MySQL主庫的IP和端口,可設置多項,用逗號分隔 proxy-backend-addresses = 192.168.182.129:3306 #Atlas后端連接的MySQL從庫的IP和端口,@后面的數字代表權重,用來作負載均衡,若省略則默認為1,可設置多項,用逗號分隔 proxy-read-only-backend-addresses = 192.168.182.130:3306@1
這個是用來配置MySQL的賬戶與密碼的,我的MySQL的用戶是root,密碼是root,剛剛使用Atlas提供的工具生成了對應的加密密碼
#用戶名與其對應的加密過的MySQL密碼,密碼使用PREFIX/bin目錄下的加密程序encrypt加密,下行的user1和user2為示例,將其替換為你的MySQL的用戶名和加密密碼! pwds = root:DAJnl8cVzy8=
這是設置工作接口與管理接口的,如果ip設置的”0.0.0.0”就是說任意IP都可以訪問這個接口,當然也可以指定IP和端口,方便測試我這邊沒有指定,工作接口的用戶名密碼與MySQL的賬戶對應的,管理員的用戶密碼與上面配置的管理員的用戶密碼對應。
#Atlas監聽的工作接口IP和端口 proxy-address = 0.0.0.0:1234 #Atlas監聽的管理接口IP和端口 admin-address = 0.0.0.0:2345
啟動Atlas
[root@localhost bin]# ./mysql-proxyd test start OK: MySQL-Proxy of test is started
測試一下Atlas服務器的MySQL狀態,要確認它是關閉狀態,並且使用mysql命令,進不去數據庫
[root@localhost bin]# /etc/init.d/mysqld status mysqld is stopped [root@localhost bin]# mysql ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)
確認系統中自帶的MySQL進不去了,使用如下命令,進入Atlas的管理模式“mysql -h127.0.0.1 -P2345 -uuser -ppwd ”,能進去說明Atlas正常運行着呢,因為它會把自己當成一個MySQL數據庫,所以在不需要數據庫環境的情況下,也可以進入到MySQL數據庫模式。
[root@localhost bin]# mysql -h127.0.0.1 -P2345 -uuser -ppwd Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1 Server version: 5.0.99-agent-admin Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
可以訪問“help”表,來看MySQL管理員模式都能做些什么。可以使用SQL語句來訪問
mysql> select * from help; +----------------------------+---------------------------------------------------------+ | command | description | +----------------------------+---------------------------------------------------------+ | SELECT * FROM help | shows this help | | SELECT * FROM backends | lists the backends and their state | | SET OFFLINE $backend_id | offline backend server, $backend_id is backend_ndx's id | | SET ONLINE $backend_id | online backend server, ... | | ADD MASTER $backend | example: "add master 127.0.0.1:3306", ... | | ADD SLAVE $backend | example: "add slave 127.0.0.1:3306", ... | | REMOVE BACKEND $backend_id | example: "remove backend 1", ... | | SELECT * FROM clients | lists the clients | | ADD CLIENT $client | example: "add client 192.168.1.2", ... | | REMOVE CLIENT $client | example: "remove client 192.168.1.2", ... | | SELECT * FROM pwds | lists the pwds | | ADD PWD $pwd | example: "add pwd user:raw_password", ... | | ADD ENPWD $pwd | example: "add enpwd user:encrypted_password", ... | | REMOVE PWD $pwd | example: "remove pwd user", ... | | SAVE CONFIG | save the backends to config file | | SELECT VERSION | display the version of Atlas | +----------------------------+---------------------------------------------------------+ 16 rows in set (0.00 sec) mysql>
也可以使用工作接口來訪問,使用命令“mysql -h127.0.0.1 -P1234 -uroot -proot”
[root@localhost bin]# mysql -h127.0.0.1 -P1234 -uroot -proot Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1 Server version: 5.0.81-log Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
如果工作接口可以進入了,就可以在Windows平台下,使用Navicat來連接數據庫,填寫對應的host,Port,用戶名,密碼就可以
3.2、讀寫分離測試
這里測試讀寫分離需要使用到Jmeter了,它是Java寫第一套開源的壓力測試工具,因為這個比較方便。他有專門測試MySQL的模塊,需要使用MySQL的JDBC驅動jar包,配置很簡單,東西很好很強大很好用。
Jmeter下載地址:http://jmeter.apache.org/download_jmeter.cgi
MySQL的JDBC :http://dev.mysql.com/downloads/connector/j/
下載下來后,分別都解壓開來,打開Jmeter ( 在bin路面下的jmeter.bat ) ,在測試計划中,導致JDBC的jar包
配置JDBC的驅動
分別做查詢與插入語句
配置好了以后,就先運行查詢操作,然后分別監控主數據庫與從數據庫所在機器的流量,來確定是否讀寫,使用在主備Linux命令行輸入“sar -n DEV 1 10000”命令來監控讀寫
先來測試寫,目前數據庫里面一條信息都沒有,開啟配置好了的Jmeter,進行寫入數據測試
sar命令查看網卡流量 sar這個工具RHEL5自帶有,默認也安裝。 一個強大的工具(好像這些工具都蠻強的),參數很多,有時間man一下。 -n參數很有用,他有6個不同的開關:DEV | EDEV | NFS | NFSD | SOCK | ALL 。DEV顯示網絡接口信息,EDEV顯示關於網絡錯誤的統計數據,NFS統計活動的NFS客戶端的信息,NFSD統計NFS服務器的信息,SOCK顯示套 接字信息,ALL顯示所有5個開關。它們可以單獨或者一起使用。我們現在要用的就是-n DEV了。 輸入命令:sar –n DEV 1 4
命令后面 1 4 意思是:每一秒鍾取一次值,取四次。
主數據庫 ( 192.168.182.129 )
從數據庫 ( 192.168.182.130)
批量插入數據語句
delimiter // DROP PROCEDURE IF EXISTS proc_batch_insert; CREATE PROCEDURE proc_batch_insert() BEGIN DECLARE pre_name BIGINT; DECLARE ageVal INT; DECLARE i INT; SET pre_name=187635267; SET ageVal=100; SET i=1; WHILE i <= 1000000 DO INSERT INTO tt(descpro) VALUES(NOW()); SET pre_name=pre_name+100; SET i=i+1; END WHILE; END // delimiter ; call proc_batch_insert();
可以看到測試插入數據的操作時,主(192.168.182.129)數據庫的網卡有些指標流量很大,而從數據庫的流量很小,是應為主數據是主要負責寫入的,而從(192.168.182.130)數據庫主要是負責同步的。
參數說明: IFACE:LAN接口 rxpck/s:每秒鍾接收的數據包 txpck/s:每秒鍾發送的數據包 rxbyt/s:每秒鍾接收的字節數 txbyt/s:每秒鍾發送的字節數 rxcmp/s:每秒鍾接收的壓縮數據包 txcmp/s:每秒鍾發送的壓縮數據包 rxmcst/s:每秒鍾接收的多播數據包 rxerr/s:每秒鍾接收的壞數據包 txerr/s:每秒鍾發送的壞數據包 coll/s:每秒沖突數 rxdrop/s:因為緩沖充滿,每秒鍾丟棄的已接收數據包數 txdrop/s:因為緩沖充滿,每秒鍾丟棄的已發送數據包數 txcarr/s:發送數據包時,每秒載波錯誤數 rxfram/s:每秒接收數據包的幀對齊錯誤數 rxfifo/s:接收的數據包每秒FIFO過速的錯誤數 txfifo/s:發送的數據包每秒FIFO過速的錯誤數
查看數據庫,發現已經插入了100w條數據了
進行讀取數據的測試,只需要執行查詢就好,執行“select *from tt;”來查詢數據表
主數據庫 ( 192.168.182.129 )
從數據庫 ( 192.168.182.130 )
可以看到130數據庫的流量非常大,129沒有什么流量,這下就可以確定了數據是從數據庫讀取的。已經實現了讀寫分離。