MYSQL主從複製與讀寫分離

    在實際的生產環境中,如果對數據庫的讀和寫都在同一個數據庫服務器中操作,無論是在安全性、高可用性還是高併發性等各個方面都不能完全滿足實際需求的。因此,一般都是通過主從複製的方式來同步數據源,再通過讀寫分離來提升數據庫的併發負載能力,通過這樣的方案進行部署與實施的。本篇博客詳細介紹MySQL主從複製和MySQL讀寫分離的原理與配置,希望能夠對您有所幫助。


1. MySQL主從複製的工作原理

    MySQL的主從複製和MySQL的讀寫分離兩者有着緊密的聯繫,首先需要要部署完成主從複製,才能在此基礎上進行數據的讀寫分離

1)MySQL支持的複製類型

(1)基於語句的複製。在服務器上執行sql語句,在從服務器上執行同樣的語句,mysql默認採用基於語句的複製,執行效率高。

(2) 基於行的複製。把改變的內容複製過去,而不是把命令在從服務器上執行一遍。

(3) 混合類型的複製。默認採用基於語句的複製,一旦發現基於語句無法精確複製時,就會採用基於行的複製。

2)複製的工作過程

    MySQL複製的工作過程如下圖所示:

楊書凡13.png                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      

(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緩存中,所以中繼日誌的開銷很小。



 

2.MySQL讀寫分離的工作原理

    讀寫分離就是隻在主服務器上寫,數據會同步到從服務器,從服務器只能讀,實現備份的同時也實現了數據庫性能的優化,提升了服務器安全。

楊書凡14.png

    目前較爲常見的MySQL讀寫分離分爲以下兩種:

1)基於程序代碼內部實現

    在代碼中根據select 、insert進行路由分類,這類方法也是目前生產環境下應用最廣泛的。優點是性能較好,因爲程序在代碼中實現,不需要增加額外的硬件開支,缺點是需要開發人員來實現,運維人員無從下手。

2)基於中間代理層實現

    代理一般介於應用服務器和數據庫服務器之間,代理數據庫服務器接收到應用服務器的請求後根據判斷後轉發到,後端數據庫,有以下代表性的程序。

(1)MySQL_Proxy。MySQL_Proxy是MySQL的一個開源項目,通過其自帶的lua腳本進行SQL判斷。

(2)Atlas。是由 Qihoo 360, Web平臺部基礎架構團隊開發維護的一個基於MySQL協議的數據中間層項目。它是在MySQL_Proxy 0.8.2版本的基礎上,對其進行了優化,增加了一些新的功能特性。360內部使用Atlas運行的MySQL業務,每天承載的讀寫請求數達幾十億條,支持事物以及存儲過程。

(3)Amoeba。由阿里巴巴集團在職員工陳思儒使用序Java語言進行開發,阿里巴巴集團將其用於生產環境下,但是他並不支持事物以及存數過程。

    經過上述簡單的比較,不是所有的應用都能夠在基於程序代碼中實現讀寫分離,像一些大型的Java應用,如果在程序代碼中實現讀寫分離對代碼的改動就較大,所以,像這種應用一般會考慮使用代理層來實現,那麼今天就使用Amoeba爲例,完成主從複製和讀寫分離。




案例概述:

    本案例使用五臺服務器模擬搭建,具體如下所示:

楊書凡15.png

主機
操作系統
IP地址
客戶端Redhat 6.5192.168.1.10/24
AmoebaRedhat 6.5192.168.1.10/24
Master
Redhat 6.5192.168.1.30/24
Slave1
Redhat 6.5192.168.1.40/24
Slave2Redhat 6.5192.168.1.50/24


1. 搭建MySQL主從複製

(1)在Master、Slave1、Slave2上安裝MySQL數據庫

    參考我之前的博文 http://blog.51cto.com/yangshufan/2049291,這裏就不在贅述了

(2)啓動MySQL服務

[root@localhost ~]# service mysqld start
Starting MySQL..                                           [確定]
[root@localhost ~]# chkconfig mysqld on
[root@localhost ~]# mysqladmin -u -root password 123456    //爲root用戶設置密碼

 

(3)配置MySQL主服務器(Master)

[root@localhost ~]# yum -y install ntp        //建立時間同步環境、安裝NTP
[root@localhost ~]# vim /etc/ntp.conf         //配置NTP,添加如下兩行
server 127.127.1.0
fudge 127.127.1.0 stratum 8
[root@localhost ~]# service iptables stop     //關閉防火牆或指定端口開放
[root@localhost ~]# service ntpd restart      //重啓服務
關閉 ntpd:                                                [失敗]
正在啓動 ntpd:                                            [確定] 

[root@localhost ~]# vim /etc/my.cnf     //修改添加配置文件
server-id       = 1                     //mysql數據的唯一標示(不能重複)
log-slave-updates=true                  //允許連級複製  (增加)
log-bin=master-bin                      //二進制文件名(修改)
[root@localhost ~]# service mysqld restart
Shutting down MySQL.                                       [確定]
Starting MySQL..                                           [確定]

[root@localhost ~]# mysql -u root -p123456    //登錄MySQL程序
mysql> grant replication slave on *.* to 'myslave'@'192.168.1.%' identified by '123';                     
Query OK, 0 rows affected (0.00 sec)       //給從服務器授權

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

mysql> show master status;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000009 |      587 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)   //File列顯示日誌名、Position列顯示偏移量,這兩個值在後面配置從服務器的時候需要


(4)配置從服務器(Slave1、Slave1

[root@localhost ~]# yum -y install ntpdate          //安裝ntpdate 
[root@localhost ~]# /usr/sbin/ntpdate 192.168.1.30  //在從服務器進行時間同步
[root@localhost ~]# service iptables stop     //關閉防火牆或指定端口開放

[root@localhost ~]# vim /etc/my.cnf  
server-id  = 2         //不能與主服務器相同,但其他從服務器要相同
relay-log=relay-log-bin     //複製過來的二進制文件名,增加
relay-log-index=slave-relay-bin.index   //中繼日誌存放的文件名稱,增加
[root@localhost ~]# service mysqld restart
Shutting down MySQL.                                       [確定]
Starting MySQL..                                           [確定]

[root@localhost ~]# mysql -u root -p123456       //登錄MySQL,配置同步
mysql> change master to master_host='192.168.1.30',master_user='myslave',
    -> master_password='123',master_log_file='master-bin.000009',   
    -> master_log_pos=587;                  
Query OK, 0 rows affected (0.02 sec)

mysql> start slave;         //啓動同步
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> show slave status\G;    //確保以下兩個值爲Yes
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes


(5)驗證主從複製效果

1)在主服務器上新建數據庫“yangshufan”

[root@localhost ~]# mysql -u root -p123456
mysql> create database yangshufan;
Query OK, 1 row affected (0.00 sec)

2)在主、從服務器上查看數據庫,顯示數據庫相同,說明主從複製成功

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test               |
| yangshufan         |
+--------------------+
5 rows in set (0.06 sec)




2. 搭建MySQL讀寫分離

(1)在主機Amoeba上安裝java環境(amoeba軟件基於java平臺運行)

[root@localhost ~]# chmod +x jdk-6u14-linux-x64.bin 
[root@localhost ~]# ./jdk-6u14-linux-x64.bin      //選擇yes安裝
[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 ~]# soure /etc/profile     //執行文件
[root@localhost ~]# java -version       //Java環境配置成功
java version "1.7.0_45"
OpenJDK Runtime Environment (rhel-2.4.3.3.el6-x86_64 u45-b15)
OpenJDK 64-Bit Server VM (build 24.45-b08, mixed mode)


(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@localhost ~]# chmod -R 755 /usr/local/amoeba/
[root@localhost ~]# /usr/local/amoeba/bin/amoeba   //顯示此消息說明Amoeba安裝成功
amoeba start|stop


(3)配置amoeba讀寫分離,兩個slave讀負載均衡

1)在主、從服務器上開放權限給amoeba訪問

mysql> grant all on *.* to ysf@'192.168.1.%' identified by '123abc';
Query OK, 0 rows affected (0.01 sec)


2)編輯amoeba.xml文件

[root@localhost ~]# vim /usr/local/amoeba/conf/amoeba.xml    //修改以下文件
    <property name="authenticator">
           <bean class="com.meidusa.amoeba.mysql.server.MysqlClientAuthenticator">
           <property name="user">amoeba</property>         //這裏用戶名、密碼後面連接Amoeba使用
           <property name="password">123456</property>
//……省略部分內容             
  </property>
           <property name="sqlFunctionFile">${amoeba.home}/conf/functionMap.xml</property>
           <property name="LRUMapSize">1500</property>
           <property name="defaultPool">master</property>   //定義默認的池,注意去掉註釋
              
           <property name="writePool">master</property>  //定義寫池
           <property name="readPool">slaves</property>   //定義讀池
               
           <property name="needParse">true</property>
    </queryRouter>


3)編輯dbServers.xml文件

[root@localhost ~]# vim /usr/local/amoeba/conf/dbServers.xml  
  <!-- mysql user -->
  <property name="user">ysf</property>  //修改爲第3步的用戶名、密碼
  <property name="password">123abc</property>  //去掉註釋
//……省略部分內容   
  <dbServer name="master"  parent="abstractServer">   //定義master
     <factoryConfig>
        <!-- mysql ip -->
        <property name="ipAddress">192.168.1.30</property>
    </factoryConfig>
  </dbServer>

   <dbServer name="slave1"  parent="abstractServer">  //定義slave1
      <factoryConfig>
         <!-- mysql ip -->
         <property name="ipAddress">192.168.1.40</property>
      </factoryConfig>
        </dbServer>  
   <dbServer name="slave2"  parent="abstractServer">  //定義slave2
      <factoryConfig>
         <!-- mysql ip -->
         <property name="ipAddress">192.168.1.50</property>
      </factoryConfig>
        </dbServer>   
  
   <dbServer name="slaves" virtual="true">           //定義slave池
      <poolConfig class="com.meidusa.amoeba.server.MultipleServerPool">
         <!-- Load balancing strategy: 1=ROUNDROBIN , 2=WEIGHTBASED , 3=HA-->
         <property name="loadbalance">1</property>
                        
         <!-- Separated by commas,such as: server1,server2,server1 -->
         <property name="poolNames">slave1,slave2</property>  //用逗號分隔slave名
      </poolConfig>
   </dbServer>

[root@localhost ~]# /usr/local/amoeba/bin/amoeba start&  //啓動amoeba默認端口8066



4)在客戶端測試讀寫分離

[root@localhost ~]# yum -y install mysql
[root@localhost ~]# mysql -u amoeba -p123456 -h 192.168.1.20 -P8066

master、slave1、slave2都需要開放3306端口

amoeba開放8066端口

    驗證讀操作:

(1)在Master創建一個ysf表,同步到各從服務器上

(2)分別在兩臺從服務器上關閉Slave功能(stop slave;)

(3)分別在主、從服務器ysf表上插入不同的語句

(4)在client上查詢ysf表,發現只能查看兩臺從服務器的數據


    驗證寫操作:

(1)在client上插入一條語句

(2)分別到主、從服務器上查詢語句,發現只有主服務器才能查看這條語句


    由此驗證,寫操作都在主服務器上,實現數據的統一更新;從服務器只負責讀取,分擔了數據庫壓力




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章