環境介紹:
CentOS 7.5
Mysql 5.7.29
Mysql主服務器:192.168.2.128
Mysql從服務器:192.168.2.129
Mysql代理服務器:192.168.2.130
客戶端服務器:192.168.2.132
讀寫分離概述:
1、什麼是讀寫分離?
讀寫分離的基本原理是讓主數據庫處理事務性增、改、刪操作(INSERT、UPDATE、DELETE),而從數據庫處理SELECT查詢操作。數據庫複製被用來把事務性操作導致的變更同步到集羣中的從數據庫。一般來說都是通過 主從複製(Master-Slave)的方式來同步數據,再通過讀寫分離(MySQL-Proxy)來提升數據庫的併發負載能力這樣的方案來進行部署與實施的。
2、爲什麼要讀寫分離?
因爲數據庫的“寫”操作是比較耗時的,但是數據庫的“讀”操作耗時非常短,所以讀寫分離,解決的是數據庫的寫入影響了查詢的效率(即讀操作比寫操作多的場景)。
3、什麼時候讀寫分離?
數據庫不一定要讀寫分離,如果程序使用數據庫較多時,而更新少,查詢多的情況下會考慮使用,利用數據庫主從同步,可以減少數據庫壓力,提高性能。
4、主從複製與讀寫分離:
在實際的生產環境中,對數據庫的讀和寫都在同一個數據庫服務器中,是不能滿足實際需求的。無論是在安全性、高可用性還是高併發等各個方面都是完全不能滿足實際需求的。因此,通過主從複製的方式來同步數據,再通過讀寫分離來提升數據庫的併發負載能力。
5.讀寫分離的好處:
1)分攤服務器壓力, 減輕主服務器的工作壓力,提高機器的系統處理效率。
2)增加冗餘,提高服務可用性,當一臺數據庫服務器宕機後可以調整另外一臺從庫以最快速度恢復服務。
讀寫分離適用於讀遠比寫多的場景,如果有一臺服務器,當select很多時,update和delete會被這些select訪問中的數據堵塞,等待select結束,併發性能並不高,而主從只負責各自的寫和讀,極大程度的緩解X鎖和S鎖爭用。
共享鎖[S鎖] -->讀鎖
排他鎖[X鎖] -->寫鎖
讀鎖是共享的,或者說是相互不阻塞的。
寫鎖是排他的,一個寫鎖會阻塞其他的寫鎖和讀鎖。
6.實現Mysql讀寫分離常見的2種方式:
1)基於程序代碼內部實現
在代碼中根據select 、insert進行路由分類,這類方法也是目前生產環境下應用最廣泛的。優點是性能較好,因爲程序在代碼中實現,不需要增加額外的硬件開支,缺點是需要開發人員來實現,運維人員無從下手。
2) 基於中間件(代理層)實現
代理一般介於應用服務器和數據庫服務器之間,代理數據庫服務器接收到應用服務器的請求後根據判斷後轉發到後端數據庫。如:Mycat、Mysql-proxy、Maxscale...
構建思路:
1.配置Mysql主從同步
這裏就不講述Mysql主從同步的配置了,下面這一篇文章裏面講得很詳細,大家可以去看一下。
傳送門
–> Mysql數據庫實現主從同步,看這一篇就夠了!
2.部署Maxscale服務
1.下載並安裝Maxscale服務
[root@test3 ~]# wget https://downloads.mariadb.com/MaxScale/2.1.2/rhel/7/x86_64/maxscale-2.1.2-1.rhel.7.x86_64.rpm
[root@test3 ~]# ll maxscale-2.1.2-1.rhel.7.x86_64.rpm
-rw-r--r-- 1 root root 17333732 3月 31 2017 maxscale-2.1.2-1.rhel.7.x86_64.rpm
[root@test3 ~]# yum -y install maxscale-2.1.2-1.rhel.7.x86_64.rpm
...
已安裝:
maxscale.x86_64 0:2.1.2-1
作爲依賴被安裝:
gnutls.x86_64 0:3.3.29-9.el7_6 nettle.x86_64 0:2.7.1-8.el7 trousers.x86_64 0:0.3.14-2.el7
完畢!
[root@test3 ~]# max (連續按Tab兩次) //maxscale服務的管理命令
maxadmin maxavrocheck maxbinlogcheck maxkeys maxpasswd
[root@test3 ~]# ll /etc/maxscale.cnf //配置文件
-rw-r--r-- 1 root root 1560 6月 9 16:40 /etc/maxscale.cnf
-----下面是備份maxscale服務的配置文件-----
[root@test3 ~]# mkdir maxscale
[root@test3 ~]# cp /etc/maxscale.cnf /root/maxscale/
[root@test3 ~]# ll /root/maxscale/
總用量 4
-rw-r--r-- 1 root root 1560 6月 9 16:44 maxscale.cnf
2.修改Maxscale配置文件
[root@test3 ~]# vim /etc/maxscale.cnf
[maxscale]
threads=auto //線程數,auto表示自動根據cpu的性能創建多少個線程
...
[server1] //定義數據庫服務器的主機名
type=server
address=192.168.2.128 //master(主庫)主機的ip地址
port=3306
protocol=MySQLBackend
...
[server2] //定義數據庫服務器的主機名
type=server
address=192.168.2.129 //slave(從庫)主機ip地址
port=3306
protocol=MySQLBackend
...
[MySQL Monitor] //定義要監視的服務器及監控的用戶
type=monitor
module=mysqlmon
servers=server1,server2 /主、從數據庫的主機名
user=maxscalemon //監控用戶名
password=123qqq...A //監控用戶密碼
monitor_interval=10000 //監控的時間間隔,單位爲毫秒
...
#[Read-Only-Service] //讀負載均衡模塊,由於讀寫分離模塊也能實現讀負載均衡,因此註釋掉該模塊
#type=service
#router=readconnroute
#servers=server1
#user=myuser
#password=mypwd
#router_options=slave
...
[Read-Write-Service] //定義讀寫分離服務及路由用戶
type=service
router=readwritesplit
servers=server1,server2 //主、從數據庫的主機名
user=maxscalerouter //路由用戶名
password=123qqq...A //路由用戶密碼
max_slave_connections=100% //多少比例的從服務器被使用,默認就是所有從服務器都提供讀服務
...
[MaxAdmin Service] //定義管理服務
type=service
router=cli
#[Read-Only-Listener] //註釋該模塊
#type=listener
#service=Read-Only-Service
#protocol=MariaDBClient
#port=4008
[Read-Write-Listener] //定義讀寫分離服務的端口號
type=listener
service=Read-Write-Service
protocol=MySQLClient
port=4006
[MaxAdmin Listener] //定義管理服務的端口號
type=listener
service=MaxAdmin Service
protocol=maxscaled
socket=default
port=4016
3.在主數據庫上創建授權用戶
[root@localhost ~]# mysql -uroot -p123qqq...A
...
mysql> grant replication slave,replication client on *.* to maxscalemon@"%" identified by "123qqq...A";
//創建監控用戶授權
mysql> grant select on mysql.* to maxscalerouter@"%" identified by "123qqq...A";
//創建路由用戶授權
mysql> select user,host from mysql.user where user like "maxscale%";
+----------------+------+
| user | host |
+----------------+------+
| maxscalemon | % |
| maxscalerouter | % |
+----------------+------+
4.在從數據庫上查看主庫上授權的用戶是否同步
[root@test2 ~]# mysql -uroot -p123qqq...A
...
mysql> select user,host from mysql.user where user like "maxscale%";
+----------------+------+
| user | host |
+----------------+------+
| maxscalemon | % |
| maxscalerouter | % |
+----------------+------+
5.在代理服務器上啓動Maxscale服務
[root@test3 ~]# maxscale -f /etc/maxscale.cnf //啓動maxscale服務
[root@test3 ~]# ss -antulp | grep maxscale
tcp LISTEN 0 128 :::4006 :::* users:(("maxscale",pid=2732,fd=11))
//查詢讀寫分離端口號4006是否啓用
tcp LISTEN 0 128 :::4016 :::* users:(("maxscale",pid=2732,fd=12))
//查詢管理服務端口號4016是否啓用
測試配置:
1.在代理服務器本機訪問Maxscale管理服務
-maxadmin -uadmin -pmariadb -P管理服務端口號
[root@test3 ~]# maxadmin -uadmin -pmariadb -P4016
MaxScale> list servers //顯示監控信息(集羣狀態)
Servers.
-------------------+-----------------+-------+-------------+--------------------
Server | Address | Port | Connections | Status
-------------------+-----------------+-------+-------------+--------------------
server1 | 192.168.2.128 | 3306 | 0 | Master, Running
server2 | 192.168.2.129 | 3306 | 0 | Slave, Running
-------------------+-----------------+-------+-------------+--------------------
//詳細信息server1爲主服務器,server2爲從服務器,running爲開啓狀態,ip以及主機端口
2.在主服務器上新增數據及授權連接用戶
[root@localhost ~]# mysql -uroot -p123qqq...A
mysql> create database gamedb; //創建gamedb庫
mysql> create table gamedb.a(id int); //在gamedb庫創建名爲a的表
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db1 |
| gamedb |
| mysql |
| performance_schema |
| sys |
| test |
| zabbix |
+--------------------+
mysql> use gamedb;
mysql> show tables;
+------------------+
| Tables_in_gamedb |
+------------------+
| a |
+------------------+
mysql> grant select,insert on gamedb.* to tom66@"%" identified by "123qqq...A";
//授權連接用戶tom66,權限爲select、insert
mysql> select user,host from mysql.user where user like "tom66";
+-------+------+
| user | host |
+-------+------+
| tom66 | % |
+-------+------+
3.客戶端132連接代理服務器130訪問數據
-mysql -h服務器地址 -P讀寫分離服務端口號 -u用戶名 -p密碼
[root@VOS3000 ~]# mysql -P4006 -h192.168.2.130 -utom66 -p123qqq...A
...
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| gamedb |
+--------------------+
mysql> use gamedb;
mysql> show tables;
+------------------+
| Tables_in_gamedb |
+------------------+
| a |
+------------------+
驗證代理服務器讀寫分離功能:
-在從數據庫服務器上添加新數據,主數據庫服務器上並不會同步這些數據,客戶端訪問代理服務器訪問數據時能看到從服務新添加的數據,說明讀數據時是讀取的從數據庫服務器上的數據。(驗證讀寫分離中的從“讀”)
-在代理服務器上添加新數據,到主數據庫服務器上查看新數據寫入情況,說明寫數據時是在主服務上寫。(驗證讀寫分離中的主“寫”)
1.在從數據庫服務器上添加新數據
在從服務器上新增數據,並不會同步到主數據庫服務器上。
[root@test2 ~]# mysql -uroot -p123qqq...A
...
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db1 |
| gamedb |
| mysql |
| performance_schema |
| sys |
| test |
| zabbix |
+--------------------+
mysql> use gamedb;
mysql> show tables;
+------------------+
| Tables_in_gamedb |
+------------------+
| a |
+------------------+
mysql> insert into gamedb.a values(55);
mysql> select * from gamedb.a;
+------+
| id |
+------+
| 55 |
+------+
2.在主數據庫服務器上查看數據
[root@localhost ~]# mysql -uroot -p123qqq...A
...
mysql> select * from gamedb.a;
Empty set (0.00 sec) //沒有數據
可以看到主數據庫服務器上並沒有新增數據。
3.客戶端訪問代理服務器查看數據
[root@VOS3000 ~]# mysql -P4006 -h192.168.2.130 -utom66 -p123qqq...A
...
mysql> select * from gamedb.a;
+------+
| id |
+------+
| 55 |
+------+
可以看到客戶端通過代理服務器訪問到了之前在從數據庫服務器上新增的數據,所以說明代理服務器讀數據是讀取的從服務器上的數據。
4.客戶端連接代理服務器新增數據
[root@VOS3000 ~]# mysql -P4006 -h192.168.2.130 -utom66 -p123qqq...A
...
mysql> select * from gamedb.a; //讀取到從服務器上之前新增的數據
+------+
| id |
+------+
| 55 |
+------+
mysql> insert into gamedb.a values(88);
mysql> insert into gamedb.a values(100);
mysql> select * from gamedb.a; //查看新增的數據
+------+
| id |
+------+
| 55 |
| 88 |
| 100 |
+------+
5.主數據庫服務器查看客戶端通過代理服務新增的數據
[root@localhost ~]# mysql -uroot -p123qqq...A
...
mysql> select * from gamedb.a;
+------+
| id |
+------+
| 88 |
| 100 |
+------+
可以看到剛纔通過客戶端連接代理服務器新增的兩條數據全部都寫入到了主數據庫服務器中並同步到從服務器上。
6.從數據庫服務器上查看數據同步情況
[root@test2 ~]# mysql -uroot -p123qqq...A
...
mysql> select * from gamedb.a;
+------+
| id |
+------+
| 55 |
| 88 |
| 100 |
+------+
總結:
上面的實驗說明代理服務器實現了讀寫分離功能。
-寫數據時,代理服務器會在主數據庫服務器上寫。(在主數據庫服務器上寫入的數據會同步到從數據庫服務器上)
-讀數據時,代理服務器會在從數據庫服務器上讀。