MYSQL主從複製與讀寫分離

    在實際的生產環境中,若是對數據庫的讀和寫都在同一個數據庫服務器中操做,不管是在安全性、高可用性仍是高併發性等各個方面都不能徹底知足實際需求的。所以,通常都是經過主從複製的方式來同步數據源,再經過讀寫分離來提高數據庫的併發負載能力,經過這樣的方案進行部署與實施的。本篇博客詳細介紹MySQL主從複製和MySQL讀寫分離的原理與配置,但願可以對您有所幫助。java


1. MySQL主從複製的工做原理mysql

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

1)MySQL支持的複製類型sql

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

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

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

2)複製的工做過程緩存

    MySQL複製的工做過程以下圖所示:安全

楊書凡13.png                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      

(1)在每一個事務更新數據完成以前,Master在二進制日誌記錄這些改變。寫入二進制日誌完成後,Master通知存儲引擎提交事務。bash

(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.5 192.168.1.10/24
Amoeba Redhat 6.5 192.168.1.10/24
Master
Redhat 6.5 192.168.1.30/24
Slave1
Redhat 6.5 192.168.1.40/24
Slave2 Redhat 6.5 192.168.1.50/24


1. 搭建MySQL主從複製

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

    參考我以前的博文 https://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)配置從服務器(Slave一、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、slave一、slave2都須要開放3306端口

amoeba開放8066端口

    驗證讀操做:

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

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

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

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


    驗證寫操做:

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

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


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

相關文章
相關標籤/搜索