MySQL 主從複製和讀寫分離實現

環境:

主機IP:172.16.20.120

從機IP:172.16.20.233


1)、修改主機/usr/my.cnf配置:

 log_bin = mysql-bin   // 主機一定要開啓 log-bin 日誌記錄

 server-id = 1  // 設置爲1,該ID值是唯一的

[root@gshen ~]#service mysql restart  或者  /etc/init.d/mysqld restart  // 修改配置文件後一定要重啓MySQL


2)、創建slave端連到master端的用戶,重啓master;

[root@gshen ~]#mysql -uroot -p

mysql> grant replication slave on *.* to 'root'@'172.16.20.233' identified by '123456';  // 登陸數據庫,並添加授權用戶

mysql> flush privileges;

mysql> show master status;



3)、SLAVE從機的配置:

vim /usr/my.cnf 

#log_bin = mysql-bin  // 如果該從服務器還作爲其他從服務器時要開啓 

server_id=10 
將server-id參數修改與MASTER主機不同,建議修改至10以上的數字,

 mysql -uroot -p 

進入mysql後進行如下設置 mysql>change master to 
                        -->master_host='master主機IP地址', 
                        -->master_user='master主機授權時所創建的用戶名',

                        -->master_password='用戶密碼'    

                        -->master_log_file='File值',  

                        -->master_log_pos=Position值;   // 此值不帶引號,是數字

或者也可通過修改/usr/my.cnf來設置:

                      # 從服務器ID  

                      server-id=10 
                      # 主服務器的IP地址或者域名  

                      master-host=172.16.20.120

                      # 主數據庫的端口號  

                      master-port=3306  

                      # 同步數據庫的用戶  

                      master-user=root  

                      # 同步數據庫的密碼  
                      master-password=12345
                      # 如果從服務器發現主服務器斷掉,重新連接的時間差  

                      master-connect-retry=60  

                      # 需要備份的庫 

                      # replicate-do-db=rogerdb   

                      # 忽略的數據庫  

                      replicate-ignore-db=mysql  

                      replicate-ignore-db=test


啓動同步: 
mysql>start slave; 
mysql>show slave status\G; 出現以下顯示即爲成功: 
*************************** 1. row ***************************             

           Slave_IO_State: Waiting for master to send event                  

           Master_Host: 192.168.47.129                   

           Master_User: gangdan0083                   

           Master_Port: 3306                 

           Connect_Retry: 60 
           Master_Log_File: mysql-bin.000005          

           Read_Master_Log_Pos: 106 
           Relay_Log_File: localhost-relay-bin.000002  

           Relay_Log_Pos: 251 
           Relay_Master_Log_File: mysql-bin.000005       

           Slave_IO_Running: Yes            

           Slave_SQL_Running: Yes 

           Last_Errno: 0
注:Slave_IO_Running和Slave_SQL_Running的狀態一定要全爲Yes並且Last_Errno爲0時纔算成功。

4)、驗證mysql主從

1、在主服務器上創建數據庫gang:

mysql> create database gang;
Query OK, 1 row affected (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

2、在從服務器上看是否存在剛:



如果主從機都關機重啓後,發現slave報錯:
ERROR 1201 (HY000): Could not initialize master info structure; more error messages can be found in the MySQL error log 

mysql> stop slave;

mysql>start slave; 
mysql>show slave status\G; // 查看slave狀態

如果一開始主數據庫中就有數據做法:

mysql> grant replication slave on *.* to 'root'@'172.16.20.233' identified by '123456'; 

mysql> flush tables with read lock; // 進入MySQL進行表鎖定操作,不讓數據再進行寫入動作

mysql> show master status; // 記錄下File和Position的值

+------------------+ | File                                  | Position |

+------------------+ |mysql-bin.000001            | 369845 |

[root@gshen ~]# mysqldump -u root -p 123456 > backup.sql //將需要複製到slave的數據庫backup.sql複製出來

mysql> unlock tables; // 取消主數據庫鎖定

[root@gshen ~]# scp backup.sql [email protected]:/home/backup

然後進入從數據庫通過 mysqladmin 行 backup.sql;

下面的步驟一樣。

MySQL主從複製原理:

主服務器上面的任何修改會保存在二進制日誌文件Binary log(mysql-bin.000001)裏,slave服務器上啓動一個I/O thread進程與master服務器的I/O聯繫,並請求從指定日誌文件的位置之後的內容。當主服務器接收到Slave服務器I/O線程請求後,通過I/O線程根據請求信息讀取指定日誌指定位置之後的日誌信息,返回給Slave服務器的I/O線程。在返回的信息中除了日誌所包含的信息之外,還有master端的binary log文件的名稱和binary log中的位置。然後把讀取到的二進制日誌內容寫到本地的一個Realy log裏面,將讀取到的master端的bin-log文件名和位置記錄到master-info文件中。slave服務器上面開啓一個SQL thread定時檢查Realy log,如果發現有更改立即把更改的內容在本機上面執行一遍。這樣就實現了在主服務器上操作,從服務器上實時也跟着操作。

File的文件是不變的,而Position是跟着master的數據庫變化而變化的。
========================================================================================================

MySQL讀寫分離實現

主服務器:172.16.20.120

從服務器:172.16.20.233

MySQL-Proxy 調度服務器:172.16.20.120(在同一臺機器上,強烈不建議這麼做,最好分離 )

MySQL-Proxy的讀寫分離主要是通過rw-splitting.lua腳本實現的,因此需要安裝lua:

1、安裝libreadline 庫: sudo yum install readline-devel.i686

2、下載源碼:wget http://www.lua.org/ftp/lua-5.1.4.tar.gz

3、解壓編譯:

tar -xzvf lua-5.1.4.tar.gz

cd lua-5.1.4

make linux                                  

sudo cp src/lua /usr/local/bin/

sudo cp src/luac /usr/local/bin/

4、測試lua是否安裝成功,直接運行lua看能否進入編譯模式

安裝配置MySQL-Proxy

MySQL-Proxy可通過以下網址獲得:
http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/

推薦採用已經編譯好的二進制版本,因爲採用源碼包進行編譯時,最新版的MySQL-Proxy對automake,glib以及libevent的版本都有很高的要求,而這些軟件包都是系統的基礎套件,不建議強行進行更新。
並且這些已經編譯好的二進制版本在解壓後都在統一的目錄內,因此建議選擇以下版本:
32位RHEL5平臺:
http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/mysql-proxy-0.8.3-linux-rhel5-x86-32bit.tar.gz
64位RHEL5平臺:
http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/mysql-proxy-0.8.3-linux-rhel5-x86-64bit.tar.gz


tar xzvf mysql-proxy-0.8.1-linux-rhel5-x86-32bit.tar.gz
mv mysql-proxy-0.8.1-linux-rhel5-x86-32bit /opt/mysql-proxy

#創建mysql-proxy服務管理腳本
mkdir /opt/mysql-proxy/init.d/

cd /opt/mysql-proxy/init.d/

touch mysql-proxy

vim mysql-proxy

#!/bin/sh
# mysql-proxy This script starts and stops the mysql-proxy daemon
# chkconfig: - 78 30
# processname: mysql-proxy
# description: mysql-proxy is a proxy daemon to mysql


# Source function library.  源函數庫
. /etc/rc.d/init.d/functions

#PROXY_PATH 定義mysql-proxy服務二進制文件路徑
PROXY_PATH=/opt/mysql-proxy/bin 

prog="mysql-proxy"

# Source networking configuration. 源網絡配置
. /etc/sysconfig/network

# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 0

# Set default mysql-proxy configuration.
# PROXY_OPTIONS="--daemon"
# --admin-username                        定義內部管理服務器賬號
# --admin-password                        定義內部管理服務器密碼
# --proxy-read-only-backend-addresses     定義只讀從服務器地址
# --proxy-backend-addresses               定義主服務器地址
# --admin-lua-script                      定義lua管理腳本路徑
# --proxy-lua-script                      定義lua讀寫分離腳本路徑
# 

PROXY_OPTIONS="--admin-username=root --admin-password=password --proxy-read-only-backend-addresses=172.16.20.233:3306 --proxy-backend-addresses=172.16.20.120:3306  --admin-lua-script=/opt/mysql-proxy/lib/mysql-proxy/lua/admin.lua --proxy-lua-script=/opt/mysql-proxy/scripts/rw-splitting.lua"

# 定義mysql-proxy PID文件路徑
PROXY_PID=/opt/mysql-proxy/run/mysql-proxy.pid  

# Source mysql-proxy configuration.
if [ -f /etc/sysconfig/mysql-proxy ]; then
	 . /etc/sysconfig/mysql-proxy	 
fi

PATH=$PATH:/usr/bin:/usr/local/bin:$PROXY_PATH

# By default it's all good
RETVAL=0

# See how we were called.
case "$1" in
	start)
 # Start daemon.
	 echo -n $"Starting $prog: "
		# --daemon       		 定義以守護進程模式啓動
		# --keepalive  			 使進程在異常關閉後能夠自動恢復
		# --pid-file=$PROXY_PID  定義mysql-proxy PID文件路徑
		# --user=mysql  		 以mysql用戶身份啓動服務
		# --log-level  			 定義log日誌級別,由高到低分別有(error|warning|info|message|debug)
		# --log-file 			 定義log日誌文件路徑
	 
	 $NICELEVEL $PROXY_PATH/mysql-proxy $PROXY_OPTIONS --daemon --pid-file=$PROXY_PID --user=mysql --log-level=warning --log-file=/opt/mysql-proxy/log/mysql-proxy.log
		 RETVAL=$?
		 echo
		if [ $RETVAL = 0 ]; then	
			touch /var/lock/subsys/mysql-proxy
		fi
		;;
	 stop)
		# Stop daemons.
		 echo -n $"Stopping $prog: "
			killproc $prog
			RETVAL=$?
			echo
		 if [ $RETVAL = 0 ]; then
			 rm -f /var/lock/subsys/mysql-proxy
			 rm -f $PROXY_PID
		 fi
		 ;;
	 restart)
	  $0 stop
	  sleep 3
	   $0 start
	    ;;
	 condrestart)
		 [ -e /var/lock/subsys/mysql-proxy ] && $0 restart
		  ;;
	 status)
		 status mysql-proxy
		 RETVAL=$?
		 ;;
	 *)	 
		echo "Usage: $0 {start|stop|restart|status|condrestart}"
		 RETVAL=1
		 ;; 
esac	
 
exit $RETVAL	 


chmod +x /opt/mysql-proxy/init.d/mysql-proxy

mkdir /opt/mysql-proxy/run
mkdir /opt/mysql-proxy/log

mkdir /opt/mysql-proxy/scripts


配置並使用rw-splitting.lua讀寫分離腳本
最新的腳本我們可以從最新的mysql-proxy源碼包中獲取,位於share/doc/mysql-proxy/rw-splitting.lua,或者通過find ./ -name rw-splitting.lua查找
將該腳本複製到scripts下:

cp share/doc/mysql-proxy/rw-splitting.lua /opt/mysql-proxy/scripts

修改讀寫分離腳本rw-splitting.lua
修改默認連接,進行快速測試,不修改的話要達到連接數爲4時才啓用讀寫分離
vim /opt/mysql-proxy/scripts/rw-splitting.lua
==============================================
-- connection pool
if not proxy.global.config.rwsplit then
proxy.global.config.rwsplit = {
min_idle_connections = 1,  //默認爲4
max_idle_connections = 1, //默認爲8
is_debug = false
}
end

=========================================

修改完成後,啓動mysql-proxy


/opt/mysql-proxy/init.d/mysql-proxy start


測試讀寫分離效果

創建用於讀寫分離的數據庫連接用戶
登陸主數據庫服務器172.16.20.120,通過命令行登錄管理MySQL服務器


mysql> GRANT ALL ON *.* TO 'proxy1'@'192.168.10.132' IDENTIFIED BY 'password';


由於我們配置了主從複製功能,因此從數據庫服務器172.16.20.233上已經同步了此操作。

爲了清晰的看到讀寫分離的效果,需要暫時關閉MySQL主從複製功能
登陸從數據庫服務器172.16.20.233,通過命令行登錄管理MySQL服務器

關閉Slave同步進程
mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)

連接MySQL-Proxy調度服務器
mysql -uproxy1 -p'password' -P4040 -h172.16.20.120

登陸成功後,在first_db數據的first_tb表中插入兩條記錄
mysql> use first_db;
Database changed
mysql> insert into first_tb values (007,’first’);
Query Ok, 1 row affected (0.00 sec)
mysql> insert into first_tb values (110,’second’);
Query Ok, 1 row affected (0.00 sec)

查詢記錄
mysql> select * from first_tb;
=============================
+------+------+
| id | name |
+------+------+
| 1 | myself |
+------+------+
1 rows in set (0.00 sec)
=============================
通過讀操作並沒有看到新記錄

mysql> quit
退出MySQL-Proxy

下面,分別登陸到主從數據庫服務器,對比記錄信息
首先,檢查主數據庫服務器
mysql> select * from first_tb;
=============================
+------+------+
| id | name |
+------+------+
| 1 | myself |
+------+------+
| 007 | first |
+------+------+
| 110 | second |
+------+------+
3 rows in set (0.00 sec)
=============================
兩條新記錄都已經存在

然後,檢查從數據庫服務器
mysql> select * from first_tb;
=============================
+------+------+
| id | name |
+------+------+
| 1 | myself |
+------+------+
1 rows in set (0.00 sec)
=============================
沒有新記錄存在

由此驗證,我們已經實現了MySQL讀寫分離,目前所有的寫操作都全部在Master主服務器上,用來避免數據的不同步;
另外,所有的讀操作都分攤給了其它各個Slave從服務器上,用來分擔數據庫壓力。

經驗分享:
1.當MySQL主從複製在 show slave status\G 時出現Slave_IO_Running或Slave_SQL_Running 的值不爲YES時,需要首先通過 stop slave 來停止從服務器,然後再執行一次。MySQL主從複製的原理其實就是從服務器讀取主服務器的binlog,然後根據binlog的記錄來更新數據庫。

2.MySQL-Proxy的rw-splitting.lua腳本在網上有很多版本,但是最準確無誤的版本仍然是源碼包中所附帶的lib/rw-splitting.lua腳本,如果有lua腳本編程基礎的話,可以在這個腳本的基礎上再進行優化;

3.MySQL-Proxy實際上非常不穩定,在高併發或有錯誤連接的情況下,進程很容易自動關閉,因此打開--keepalive參數讓進程自動恢復是個比較好的辦法,但還是不能從根本上解決問題,因此通常最穩妥的做法是在每個從服務器上安裝一個MySQL-Proxy供自身使用,雖然比較低效但卻能保證穩定性;

4.一主多從的架構並不是最好的架構,通常比較優的做法是通過程序代碼和中間件等方面,來規劃,比如設置對錶數據的自增id值差異增長等方式來實現兩個或多個主服務器,但一定要注意保證好這些主服務器數據的完整性,否則效果會比多個一主多從的架構還要差;

5.MySQL-Cluster 的穩定性也不是太好;

6.Amoeba for MySQL 是一款優秀的中間件軟件,同樣可以實現讀寫分離,負載均衡等功能,並且穩定性要大大超過MySQL-Proxy,建議大家用來替代MySQL-Proxy,甚至MySQL-Cluster。


使用Amoeba(變形蟲)實現MySQL讀寫分離


參考阿里開源的Amoeba官方文章: http://docs.hexnova.com/amoeba/





發佈了39 篇原創文章 · 獲贊 7 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章