mysql读写分离实现_脱离开发:Mysql读写分离方案之一
案例:Mysql讀寫分離
技能目標:
· 熟悉MySQL主從復制原理
· 熟悉MySQL讀寫分離原理
· 學會配置MySQL主從復制
· 學會配置MySQL讀寫分離
6.1 案例分析
6.1.1 案例概述
在實際的生產環境中,如果對數據庫的讀和寫都在同一個數據庫服務器中操作,無論是在安全性、高可用性還是高并發等各個方面都是完全不能滿足實際需求的,因此,一般來說都是通過主從復制(Master-Slave)的方式來同步數據,再通過讀寫分離來提升數據庫的并發負載能力這樣的方案來進行部署與實施的。
如圖6.1所示,一臺主MySQL帶兩臺從MySQL做了數據復制,前端應用在進行數據庫寫操作時,對主設備進行操作,在進行數據庫讀操作時,對兩臺從設備進行操作,這樣大量減輕了對主設備的壓力。
圖6.1 MySQL主從復制與讀寫分離
6.1.2 案例前置知識點
1.MySQL主從復制原理
MySQL的主從復制和MySQL的讀寫分離兩者有著緊密聯系,首先要部署主從復制,只有主從復制完成了,才能在此基礎上進行數據的讀寫分離。
1)MySQL支持的復制類型
(1)基于語句的復制。在主服務器上執行的SQL語句,在從服務器上執行同樣的語句。MySQL默認采用基于語句的復制,效率比較高。
(2)基于行的復制。把改變的內容復制過去,而不是把命令在從服務器上執行一遍。
(3)混合類型的復制。默認采用基于語句的復制,一旦發現基于語句無法精確復制時,就會采用基于行的復制。
2)復制的工作過程
MySQL復制的工作過程如圖6.2所示。
圖6.2 MySQL復制的工作過程
(1)在每個事務更新數據完成之前,Master在二進制日志記錄這些改變。寫入二進制日志完成后,Master通知存儲引擎提交事務。
(2)Slave將Master的Binary log復制到其中繼日志。首先,Slave開始一個工作線程——I/O線程,I/O線程在Master上打開一個普通的連接,然后開始Binlog dump process。Binlog dump process從Master的二進制日志中讀取事件,如果已經跟上Master,它會睡眠并等待Master產生新的事件。I/O線程將這些事件寫入中繼日志。
(3)SQL slave thread(SQL從線程)處理該過程的最后一步。SQL線程從中繼日志讀取事件,并重放其中的事件而更新Slave的數據,使其與Master中的數據一致。只要該線程與I/O線程保持一致,中繼日志通常會位于OS的緩存中,所以中繼日志的開銷很小。
復制過程有一個很重要的限制,即復制在Slave上是串行化的,也就是說Master上的并行更新操作不能在Slave上并行操作。
2.MySQL讀寫分離原理
簡單來說,讀寫分離(圖6.3)就是只在主服務器上寫,只在從服務器上讀。基本的原理是讓主數據庫處理事務性查詢,而從數據庫處理select查詢。數據庫復制被用來把事務性查詢導致的變更同步到集群中的從數據庫。
圖6.3 MySQL讀寫分離過程
目前較為常見的MySQL讀寫分離分為兩種。
1)基于程序代碼內部實現
在代碼中根據select、insert進行路由分類,這類方法也是目前生產環境應用最廣泛的。優點是性能較好,因為在程序代碼中實現,不需要增加額外的設備作為硬件開支;缺點是需要開發人員來實現,運維人員無從下手。
2)基于中間代理層實現
代理一般位于客戶端和服務器之間,代理服務器接到客戶端請求后通過判斷后轉發到后端數據庫,有兩個代表性程序。
(1)MySQL-Proxy。MySQL-Proxy為MySQL開源項目,通過其自帶的lua腳本進行SQL判斷,雖然是MySQL官方產品,但是MySQL官方并不建議將MySQL-Proxy用到生產環境。
(2)Amoeba。由陳思儒開發,作者曾就職于阿里巴巴。該程序由Java語言進行開發,阿里巴巴將其用于生產環境。它不支持事務和。
經過上述簡單的比較,通過程序代碼實現MySQL讀寫分離自然是一個不錯的選擇,但是并不是所有的應用都適合在程序代碼中實現讀寫分離,像一些大型復雜的Java應用,如果在程序代碼中實現讀寫分離對代碼改動就較大。所以,像這種應用一般會考慮使用代理層來實現。本章后續案例通過Amoeba實現。
6.1.3 案例環境
1. 本案例環境
本案例環境使用五臺服務器模擬搭建,具體的拓撲如圖6.4所示。
圖6.4 集群拓撲
案例環境如表10-1所示。
表10-1 案例環境
2. 案例需求
本案例要求通過Amoeba實現mysql數據庫請求的讀和寫的分離
3. 案例實現思路
1) 安裝MySQL數據庫
2) 配置MySQL主從復制
3) 安裝并配置Amoeba
4) 客戶端測試讀寫分離
6.2 案例實施
6.2.1 搭建MySQL主從復制
(1)建立時間同步環境,在主節點上搭建時間同步服務器。
① 安裝NTP。
[root@localhost ~]# yum -y install ntp
② 配置NTP。
[root@localhost ~]# vim /etc/ntp.conf #添加如下兩行
server 127.127.1.0
fudge 127.127.1.0 stratum 8
③ 重啟服務并設置為開機啟動。
[root@localhost ~]# systemctl restart ntpd
[root@localhost ~]# systemctl enable ntpd
Created symlink from /etc/systemd/system/multi-user.target.wants/ntpd.service to /usr/lib/systemd/system/ntpd.service.
(2)在每臺服務器上關閉firewalld或者指定端口、服務進行開放。
[root@localhost ~]# systemctl stop firewalld
[root@localhost ~]# systemctl disable firewalld
(3)在從節點上進行時間同步。
[root@localhost ~]# yum -y install ntpdate
[root@localhost ~]# ntpdate 192.168.8.134
(4)安裝MySQL數據庫。在Master、Slave1、Slave2上安裝。
① 編譯安裝MySQL。
[root@localhost ~]# yum -y install ncurses-devel
[root@localhost ~]# tar zxvf cmake-2.8.6.tar.gz
[root@localhost ~]# cd cmake-2.8.6
[root@localhost cmake-2.8.6]# ./configure
[root@localhost cmake-2.8.6]# gmake
[root@localhost cmake-2.8.6]# gmake install
[root@localhost cmake-2.8.6]# cd
[root@localhost ~]#
[root@localhost ~]# tar zxvf mysql-5.6.36.tar.gz
[root@localhost ~]# cd mysql-5.6.36
[root@localhost mysql-5.6.36]# cmake -DCMAKE_INSTALL_PREFIX=/usr/local/mysql -DDEFAULT_CHARSET=utf8 -DDEFAULT_COLLATION=utf8_general_ci -DWITH_EXTRA_CHARSETS=all -DSYSCONFDIR=/etc
[root@localhost mysql-5.6.36]# make && make install
② 優化調整。
[root@localhost mysql-5.6.36]# cp support-files/my-default.cnf /etc/my.cnf
[root@localhost mysql-5.6.36]# cp support-files/mysql.server /etc/rc.d/init.d/mysqld
[root@localhost mysql-5.6.36]# chmod +x /etc/rc.d/init.d/mysqld
[root@localhost mysql-5.6.36]# chkconfig --add mysqld
[root@localhost mysql-5.6.36]# echo "PATH=$PATH:/usr/local/mysql/bin" >> /etc/profile
[root@localhost mysql-5.6.36]# . /etc/profile
③ 初始化數據庫。
[root@localhost mysql-5.6.36]# groupadd mysql
[root@localhost mysql-5.6.36]# useradd -M -s /sbin/nologin mysql -g mysql
[root@localhost mysql-5.6.36]# chown -R mysql:mysql /usr/local/mysql
[root@localhost mysql-5.6.36]# /usr/local/mysql/scripts/mysql_install_db --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data --user=mysql
④ 啟動MySQL服務。
[root@localhost ~]# systemctl start mysqld
[root@localhost ~]# systemctl enable mysqld
mysqld.service is not a native service, redirecting to /sbin/chkconfig.
Executing /sbin/chkconfig mysqld on
[root@localhost ~]# mysqladmin -u root password 'pwd123'
//為root用戶設置密碼
(5)配置MySQL Master主服務器。
① 在/etc/my.cnf中修改或者增加下面內容。
[root@localhost ~]# vim /etc/my.cnf
server-id= 11 //增加
log_bin = master-bin //修改
log-slave-updates = true //增加
② 重啟MySQL服務。
[root@localhost ~]# systemctl restart mysqld
③ 登錄MySQL程序,給從服務器以授權。
[root@localhost ~]# mysql -u root -p
mysql> GRANT REPLICATION SLAVE ON *.* TO 'myslave'@'192.168.8.%' IDENTIFIED BY '123456';
mysql> FLUSH PRIVILEGES;
mysql> show master status;
+----------------+--------+-----------+-----------------+-----------------+
| File |Position|Binlog_Do_DB|Binlog_Ignore_DB|Executed_Gtid_Set|
+----------------+--------+------------+----------------+-----------------+
|master-bin.000002| 410 | | | |
+-----------------+-------+------------+----------------+-----------------+
1 row in set (0.00 sec)
其中File列顯示日志名,Position列顯示偏移量,這兩個值在后面配置從服務器的時候需要。Slave應從該點在Master上進行新的更新。
(6)配置從服務器。
① 在/etc/my.cnf中修改或者增加下面內容。
[root@localhost ~]# vim /etc/my.cnf
server-id = 22 //增加
relay-log = relay-log-bin //增加
relay-log-index = slave-relay-bin.index //增加
這里要注意server-id不能相同。
② 重啟MySQL服務。
[root@localhost ~]# systemctl restart mysqld
③ 登錄MySQL,配置同步。
按主服務器結果更改下面命令中master_log_file和master_log_pos參數。
[root@localhost ~]# mysql -u root -p
mysql> change master to master_host='192.168.8.134',master_user='myslave', master_password='123456',master_log_file='master-bin.000002',master_log_pos=410;
Query OK, 0 rows affected, 2 warnings (0.05 sec)
④ 啟動同步。
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
⑤ 查看Slave狀態,確保以下兩個值為YES。
mysql> show slave statusG;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.8.134
Master_User: myslave
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: master-bin.000002
Read_Master_Log_Pos: 410
Relay_Log_File: relay-log-bin.000002
Relay_Log_Pos: 284
Relay_Master_Log_File: master-bin.000002
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
...... //省略部分內容
(7)驗證主從復制效果。
① 在主、從服務器上登錄MySQL。
[root@localhost ~]# mysql –u root –p
mysql> show databases;
兩臺數據庫執行結果應該相同。
② 在主服務器上新建數據庫db_test。
mysql> create database db_test;
③ 在主、從服務器上分別查看數據庫,顯示數據庫相同,則主從復制成功。
mysql> show databases;
+---------------------+
| Database |
+---------------------+
| information_schema |
| db_test |
| mysql |
| performance_schema |
| test |
+---------------------+
5 rows in set (0.00 sec)
6.2.2 搭建MySQL讀寫分離
Amoeba(變形蟲)項目開源框架于2008年發布一款Amoeba for MySQL軟件。這個軟件致力于MySQL的分布式數據庫前端代理層,它主要為應用層訪問MySQL的時候充當SQL路由功能,并具有負載均衡、高可用性、SQL過濾、讀寫分離、可路由相關的到目標數據庫、可并發請求多臺數據庫。通過Amoeba能夠完成多數據源的高可用、負載均衡、數據切片的功能,目前Amoeba已在很多企業的生產線上使用,其版本可在官網進行下載。
(1)在主機Amoeba上安裝Java環境。
因為Amoeba基于是jdk1.5開發的,所以官方推薦使用 jdk1.5或 1.6版本,高版本不建議使用。
[root@localhost ~]# chmod +x jdk-6u14-linux-x64.bin
[root@localhost ~]# ./jdk-6u14-linux-x64.bin //根據提示按Enter鍵完成即可
[root@localhost ~]# mv jdk1.6.0_14/ /usr/local/jdk1.6
[root@localhost ~]# vim /etc/profile
增加以下配置:
export JAVA_HOME=/usr/local/jdk1.6
export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib
export PATH=$JAVA_HOME/lib:$JAVA_HOME/jre/bin:$PATH:$HOME/bin
export AMOEBA_HOME=/usr/local/amoeba/
export PATH=$PATH:$AMOEBA_HOME/bin
[root@localhost ~]# source /etc/profile
[root@localhost ~]# java -version
java version "1.6.0_14"
Java(TM) SE Runtime Environment (build 1.6.0_14-b08)
Java HotSpot(TM) 64-Bit Server VM (build 14.0-b16, mixed mode)
Java環境已配置成功。
(2)安裝并配置Amoeba軟件。
[root@localhost ~]# mkdir /usr/local/amoeba
[root@localhost ~]# tar zxf amoeba-mysql-binary-2.2.0.tar.gz -C /usr/local/amoeba
[root@node5 ~]# chmod -R 755 /usr/local/amoeba/
[root@localhost ~]# /usr/local/amoeba/bin/amoeba
amoeba start|stop //顯示此內容說明Amoeba安裝成功
(3)配置Amoeba讀寫分離,兩個Slave讀負載均衡。
① Master、Slave1、Slave2 中開放權限給 Amoeba 訪問。
grant all on *.* to test@'192.168.8.%' identified by '123.com';
② 編輯amoeba.xml配置文件。
[root@localhost ~]# cd /usr/local/amoeba/
[root@localhost amoeba]# vim conf/amoeba.xml
…… //省略部分內容
以下修改后的內容為帶下劃線的部分。
amoeba
123456
${amoeba.home}/conf/access_ list. conf
…… //省略部分內容
以下修改后的內容為帶下劃線的部分,注意刪除注釋。
${amoeba.home}/conf/rule.xml
${amoeba.home}/conf/ruleFun ctionMap.xml
${amoeba.home}/conf/functionMap.xml
1500
master
master
slaves
true
③ 編輯dbServers.xml配置文件。
[root@localhost amoeba]# vim conf/dbServers.xml
…… //省略部分內容
以下修改后的內容為帶下劃線的部分,注意刪除注釋。
test
123.com
…… //省略部分內容
以下修改后的內容為帶下劃線的部分。
192.168.8.134
192.168.8.136
192.168.8.139
1
slave1,slave2
④ 配置無誤后,可以啟動Amoeba軟件,其默認端口為tcp 8066。
[root@localhost amoeba]# bin/amoeba start&
[root@localhost amoeba]# netstat -anpt | grep java
tcp6 00 127.0.0.1:51388 :::* LISTEN 31083/java
tcp6 00 :::8066 :::* LISTEN 31083/java
tcp6 00 192.168.8.100:58748192.168.8.139:3306ESTABLISHED31083/java
tcp6 00 192.168.8.100:37810192.168.8.136:3306ESTABLISHED 31083/java
tcp6 00 192.168.8.100:56066192.168.8.134:3306ESTABLISHED 31083/java
(4)測試。
① 在Client主機上。
[root@localhost ~]# yum -y install mysql
然后可以通過代理訪問MySQL:
[root@localhost ~]# mysql -u amoeba -p123456 -h 192.168.8.100 -P8066
…… //省略部分內容
MySQL [(none)]>
② 在Master上創建一個表,同步到各從服務器上,然后關掉各從服務器的Slave功能,再插入區別語句。
mysql> use db_test;
Database changed
mysql> create table zang (id int(10),name varchar(10),address varchar(20));
Query OK, 0 rows affected (0.16 sec)
分別在兩臺從服務器上:
mysql> stop slave;
Query OK, 0 rows affected (0.01 sec)
然后在主服務器上:
mysql> insert into zang values('1','zhang','this_is_master');
Query OK,1 row affected (0.06 sec)
③ 從服務器上同步了表,手動插入其他內容。
slave1:
mysql> use db_test;
Database changed
mysql> insert into zang values('2','zhang','this_is_slave1');
Query OK,1 row affected (0.02 sec)
slave2:
mysql> use db_test;
Database changed
mysql> insert into zang values('3','zhang','this_is_slave2');
Query OK,1 row affected (0.02 sec)
④ 測試讀操作。
在Client主機上第一次查詢的結果如下。
MySQL [(none)]> select * from zang;
+------+-------+---------------+
| id | name | address |
+------+-------+----------------+
| 2 | zhang | this_is_slave1 |
+------+-------+---------------+
1 row in set (0.01 sec)
第二次查詢的結果如下。
MySQL [(none)]> select * from zang;
+------+-------+---------------+
| id | name | address |
+------+-------+----------------+
| 3 | zhang | this_is_slave2 |
+------+-------+---------------+
1 row in set (0.01 sec)
第三次查詢的結果如下。
MySQL [(none)]> select * from zang;
+------+-------+---------------+
| id | name | address |
+------+-------+----------------+
| 2 | zhang | this_is_slave1 |
+------+-------+---------------+
1 row in set (0.01 sec)
⑤ 測試寫操作。
在Client主機上插入一條語句:
MySQL [(none)]> insert into zang values('4','zhang','write_test');
Query OK,1 row affected (0.08 sec)
但在Client上查詢不到,最終只有在Master上才能查看到這條語句內容,說明寫操作在Master服務器上。
mysql> select * from zang;
+------+-------+---------------+
| id | name | address |
+------+-------+----------------+
| 1 | zhang | this_is_master |
| 4 | zhang | write_test |
+------+-------+---------------+
2 row in set (0.01 sec)
由此驗證,已經實現了MySQL讀寫分離,目前所有的寫操作都全部在Master主服務器上,用來避免數據的不同步;所有的讀操作都分攤給了Slave從服務器,用來分擔數據庫壓力。
總結
以上是生活随笔為你收集整理的mysql读写分离实现_脱离开发:Mysql读写分离方案之一的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 打卡签到python代码_如何利用Pyt
- 下一篇: php mysql生日提醒_基于AIML