MySQL讀寫分離是在主從複製的基礎上進一步經過在master上執行寫操做,在slave上執行讀操做來實現的。經過主從複製,master上的數據改動可以同步到slave上,從而保持了數據的一致性。實現數據的讀寫分離能帶來的好處有:html
增長物理服務器,提高機器處理能力,也就是拿硬件換性能。前端
主從只負責各自的讀和寫,極大程度緩解X鎖和S鎖爭用。java
slave能夠配置myIasm引擎,提高查詢性能以及節約系統開銷。mysql
master直接寫是併發的,slave經過主庫發送來的binlog恢復數據是異步。linux
slave能夠單獨設置一些參數來提高其讀的性能。git
增長冗餘,提升可用性。github
常見的實現數據庫讀寫分離的方案大體有兩種:應用層,代理層sql
在應用層也就是在代碼中進行操做,經過對數據庫操做類型的不一樣手動指定數據源,能夠經過AOP的方式進行實現,不過對於一個已經搭建起來並正在運行的系統來講,這個方案應該比較複雜。數據庫
另一種實現方式是經過數據庫代理層,代理對應用層呢個是透明的,全部的讀寫分離操做由代理層來完成,好處就是對於開發應用層來講是透明的,不須要管理數據源,缺點在於應用原來直接訪問數據庫如今變成了經過代理訪問數據庫,性能上確定會有影響,不過若是代理層實現的很優秀的話這個影響應該不大。centos
經過代理層實現數據庫讀寫分離又有兩種方案可供選擇,其一是使用MySQL-Proxy,另外一種是使用Amoeba。最開始找到的實現方案是基於MySQL-Proxy的,因爲它沒有配置文件,所要完成的工做須要由Lua腳原本實現,這對於一個Lua門外漢來講壓力不小。後來找到的Amoeba實現起來很簡單,只須要簡單地配置就能實現數據庫的讀寫分離,因此這裏記錄我經過使用Amoeba來實現數據庫讀寫分離的過程。
Amoeba簡介:
Amoeba(變形蟲)致力於MySQL的分佈式數據庫前端代理層,它主要在應用層訪問MySQL的 時候充當SQL路由功能,專一於分佈式數據庫代理層(Database Proxy)開發。座落與 Client、DB Server(s)之間,對客戶端透明。具備負載均衡、高可用性、SQL 過濾、讀寫分離、可路由相關的到目標數據庫、可併發請求多臺數據庫合併結果。 經過Amoeba你可以完成多數據源的高可用、負載均衡、數據切片的功能。
Amoeba使用:
1、準備工做
amoeba服務器 :虛擬機 ip:182.92.172.80 amoeba版本3.0.5-RC mysql版本5. 5.32 Java環境1.7.0_60 操做系統linux
master服務器 :虛擬機 ip:182.92.172.80 mysql版本5. 5.32 操做系統centos6.5 (和amoeba在同一個服務器上,由於我只用了兩個服務器)
slave服務器 :虛擬機 ip:123.57.44.85 mysql版本5.5.39 操做系統centos6.5
2、下載安裝amoeba
下載地址:https://sourceforge.net/projects/amoeba/files/Amoeba%20for%20mysql/3.x/,選擇最新版本進行下載,我下載的版本爲:amoeba-mysql-3.0.5-RC-distribution.zip
安裝:把zip安裝包解壓到本身指定的服務器路徑上就能夠了,我把它放在了/usr/local/amoeba/amoeba-mysql-3.0.5-RC裏面,解壓後的文件結構以下圖:
3、配置amoeba
Amoeba基礎配置介紹:
想象Amoeba做爲數據庫代理層,它必定會和不少數據庫保持通訊,所以它必須知道由它代理的數據庫如何鏈接,好比最基礎的:主機IP、端口、Amoeba使用的用戶名和密碼等等。這些信息存儲在$AMOEBA_HOME/conf/dbServers.xml中。
Amoeba爲了完成數據切分提供了完善的切分規則配置,爲了瞭解如何分片數據、如何將數據庫返回的數據整合,它必須知道切分規則。與切分規則相關的信息存儲在$AMOEBA_HOME/conf/rule.xml中。
當咱們書寫SQL來操做數據庫的時候,經常會用到不少不一樣的數據庫函數,好比:UNIX_TIMESTAMP()、SYSDATE()等等。這些函數如何被Amoeba解析呢?$AMOEBA_HOME/conf/functionMap.xml描述了函數名和函數處理的關係。
對$AMOEBA_HOME/conf/rule.xml進行配置時,會用到一些咱們本身定義的函數,好比咱們須要對用戶ID求HASH值來切分數據,這些函數在$AMOEBA_HOME/conf/ruleFunctionMap.xml中定義。
Amoeba能夠制定一些可訪問以及拒絕訪問的主機IP地址,這部分配置在$AMOEBA_HOME/conf/access_list.conf中
Amoeba容許用戶配置輸出日誌級別以及方式,配置方法使用log4j的文件格式,文件是$AMOEBA_HOME/conf/log4j.xml。
在開始配置amoeba配置文件以前咱們須要先了解爲何要作這些配置工做。
第一,如上第一條所述,Amoeba是經過代理MySQL服務來實現數據庫的讀寫分離的,它必需要知道如何鏈接到須要被代理的數據庫,所以須要被代理的數據庫須要建立一個訪問用戶給amoeba,這樣amoeba才能鏈接到數據庫上。
第二,amobea把對客戶端也就是應用層是透明的,無論amoeba如何實現的讀寫分離,它既然把數據庫全都給代理了,那它就要爲客戶端提供一個相似原來mysql那樣的鏈接,客戶端就把當它是mysql,它實際上是一個虛擬的mysql,對外提供mysql協議,客戶端鏈接amoeba就象鏈接mysql同樣,所以amoeba要爲客戶端提供一個可供鏈接的用戶帳號。
第三,amoeba內部是實現了多數據庫的負載均衡、讀寫分離、可切片的,因此這部分的配置是它功能上的核心配置。
下面就正式開始配置amoeba
mysql>grant all on *.* to 'amoeba'@'182.92.172.80' identified by '123456' #建立用戶並受權 mysql>flush privileges; #刷新權限
爲了方便統一管理就把全部數據庫建立的用戶名和密碼保持一致了
2.配置conf文件
在amoeba安裝目錄的conf文件夾下找到dbServer.xml和amoeba.xml文件,這兩個文件是須要咱們配置的
個人dbServer.xml文件配置以下:
1 <?xml version="1.0" encoding="gbk"?> 2 3 <!DOCTYPE amoeba:dbServers SYSTEM "dbserver.dtd"> 4 <amoeba:dbServers xmlns:amoeba="http://amoeba.meidusa.com/"> 5 6 <!-- 7 Each dbServer needs to be configured into a Pool, 8 If you need to configure multiple dbServer with load balancing that can be simplified by the following configuration: 9 add attribute with name virtual = "true" in dbServer, but the configuration does not allow the element with name factoryConfig 10 such as 'multiPool' dbServer 11 --> 12 13 <dbServer name="abstractServer" abstractive="true"> 14 <factoryConfig class="com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory"> 15 <property name="connectionManager">${defaultManager}</property> 16 <property name="sendBufferSize">64</property> 17 <property name="receiveBufferSize">128</property> 18 19 <!-- mysql port --> 20 <!--<property name="port">3306</property>--> 21 22 <!-- mysql schema --> 23 <property name="schema">yj_platform</property> 24 25 <!-- mysql user --> 26 <property name="user">amoeba</property> 27 28 <property name="password">123456</property> 29 </factoryConfig> 30 31 <poolConfig class="com.meidusa.toolkit.common.poolable.PoolableObjectPool"> 32 <property name="maxActive">500</property> 33 <property name="maxIdle">500</property> 34 <property name="minIdle">1</property> 35 <property name="minEvictableIdleTimeMillis">600000</property> 36 <property name="timeBetweenEvictionRunsMillis">600000</property> 37 <property name="testOnBorrow">true</property> 38 <property name="testOnReturn">true</property> 39 <property name="testWhileIdle">true</property> 40 </poolConfig> 41 </dbServer> 42 43 <dbServer name="master" parent="abstractServer"> 44 <factoryConfig> 45 <!-- mysql ip --> 46 <property name="ipAddress">182.92.172.96</property> 47 <!-- mysql port --> 48 <property name="port">3306</property> 49 </factoryConfig> 50 </dbServer> 51 52 <dbServer name="slave1" parent="abstractServer"> 53 <factoryConfig> 54 <!-- mysql ip --> 55 <property name="ipAddress">123.57.44.78</property> 56 <!-- mysql port --> 57 <property name="port">13306</property> 58 </factoryConfig> 59 </dbServer> 60 61 <!-- <dbServer name="multiPool" virtual="true"> 62 <poolConfig class="com.meidusa.amoeba.server.MultipleServerPool"> 63 #Load balancing strategy: 1=ROUNDROBIN , 2=WEIGHTBASED , 3=HA 64 <property name="loadbalance">1</property> 65 66 #Separated by commas,such as: server1,server2,server1 67 <property name="poolNames">slave1,slave2</property> 68 </poolConfig> 69 </dbServer> 70 --> 71 </amoeba:dbServers>
須要咱們關注的元素用標紅字體顯示出來了,在這裏是指幾個dbServer元素,須要手動修改的部分用黃色背景表示出來。
第一個dbServer元素其abstractive="true"屬性表示這個一個抽象元素能夠被其餘dbServer元素擴展,相似於java裏面的抽象類和類的繼承之間的關係。這個dbServer裏面配置amoeba鏈接它所代理的mysql數據庫的鏈接信息,由於以前已經說過爲了方便管理把每一個數據庫爲amoeba訪問建立的用戶都統一了帳號,在這裏我把端口信息給註釋掉了,由於個人slave數據庫端口用的不是默認的3306,這種和ip,端口不同的信息就沒辦法配置在通用的抽象dbServer裏面了。
第二個dbServer取名爲"maser",其parent="abstractServer"表示拓展了上面的抽象dbServer,在這裏設置的是amoeba鏈接數據庫具體的信息,由於每一個數據庫的ip確定是不一樣的。
一樣第三個dbServer取名爲「slave」,鏈接信息是slave服務器。
在下面被我註釋掉的第四個dbServer其name="multiPool" virtual="true"屬性表示這是一個對多服務器池,這個配置使得amoeba能夠把多個讀數據庫管理成一個讀池,把多個寫數據庫管理成寫池,在每一個池中amoeba就可以實現負載均衡。因爲個人主從同步只設置了一主一從,並不涉及到多個讀數據庫組成池的狀況,因此我就把這個配置註釋掉了。
接下來配置amoeba.xml文件,一樣放上個人配置文件:
1 <?xml version="1.0" encoding="gbk"?> 2 3 <!DOCTYPE amoeba:configuration SYSTEM "amoeba.dtd"> 4 <amoeba:configuration xmlns:amoeba="http://amoeba.meidusa.com/"> 5 6 <proxy> 7 8 <!-- service class must implements com.meidusa.amoeba.service.Service --> 9 <service name="Amoeba for Mysql" class="com.meidusa.amoeba.mysql.server.MySQLService"> 10 <!-- port --> 11 <property name="port">8066</property> 12 13 <!-- bind ipAddress --> 14 15 <!--<property name="ipAddress">127.0.0.1</property>--> 16 17 18 <property name="connectionFactory"> 19 <bean class="com.meidusa.amoeba.mysql.net.MysqlClientConnectionFactory"> 20 <property name="sendBufferSize">128</property> 21 <property name="receiveBufferSize">64</property> 22 </bean> 23 </property> 24 25 <property name="authenticateProvider"> 26 <bean class="com.meidusa.amoeba.mysql.server.MysqlClientAuthenticator"> 27 28 <property name="user">amoeba</property> 29 30 <property name="password">password</property> 31 32 <property name="filter"> 33 <bean class="com.meidusa.toolkit.net.authenticate.server.IPAccessController"> 34 <property name="ipFile">${amoeba.home}/conf/access_list.conf</property> 35 </bean> 36 </property> 37 </bean> 38 </property> 39 40 </service> 41 42 <runtime class="com.meidusa.amoeba.mysql.context.MysqlRuntimeContext"> 43 44 <!-- proxy server client process thread size --> 45 <property name="executeThreadSize">128</property> 46 47 <!-- per connection cache prepared statement size --> 48 <property name="statementCacheSize">500</property> 49 50 <!-- default charset --> 51 <property name="serverCharset">utf8</property> 52 53 <!-- query timeout( default: 60 second , TimeUnit:second) --> 54 <property name="queryTimeout">60</property> 55 </runtime> 56 57 </proxy> 58 59 <!-- 60 Each ConnectionManager will start as thread 61 manager responsible for the Connection IO read , Death Detection 62 --> 63 <connectionManagerList> 64 <connectionManager name="defaultManager" class="com.meidusa.toolkit.net.MultiConnectionManagerWrapper"> 65 <property name="subManagerClassName">com.meidusa.toolkit.net.AuthingableConnectionManager</property> 66 </connectionManager> 67 </connectionManagerList> 68 69 <!-- default using file loader --> 70 <dbServerLoader class="com.meidusa.amoeba.context.DBServerConfigFileLoader"> 71 <property name="configFile">${amoeba.home}/conf/dbServers.xml</property> 72 </dbServerLoader> 73 74 <queryRouter class="com.meidusa.amoeba.mysql.parser.MysqlQueryRouter"> 75 <property name="ruleLoader"> 76 <bean class="com.meidusa.amoeba.route.TableRuleFileLoader"> 77 <property name="ruleFile">${amoeba.home}/conf/rule.xml</property> 78 <property name="functionFile">${amoeba.home}/conf/ruleFunctionMap.xml</property> 79 </bean> 80 </property> 81 <property name="sqlFunctionFile">${amoeba.home}/conf/functionMap.xml</property> 82 <property name="LRUMapSize">1500</property> 83 <property name="defaultPool">slave1</property> 84 <property name="writePool">master</property> 85 <property name="readPool">slave1</property> 86 <property name="needParse">true</property> 87 </queryRouter> 88 </amoeba:configuration>
amoeba.xml文件中須要配置的地方也很少,首先要配置的是service標籤,其中須要配置的地方有三個port,user,password。這裏的端口,用戶名和密碼其實就是爲了虛擬出一個mysql連接作準備的(非真實,amoeba服務器能夠不安裝真實的mysql數據庫),端口默認的事8066,能夠修改可是不要跟現有的端口衝突,用戶名和密碼是客戶端鏈接amoeba虛擬出來的mysql鏈接的用戶名密碼,和以前mysql數據庫建立給amoeba的用戶帳號不一樣。在這裏有一個註釋掉的ipAddress屬性,若是Amoeba所在的服務器在多個網絡環境內你能夠定義該機器的其中一個IP來指定Amoeba所服務的網絡環境,可是若是設置爲127.0.0.1將致使其餘機器沒法訪問Amoeba的服務。
以後配置queryRouter標籤,這是amoeba真正實現讀寫分離所產生做用的地方,以前的配置都是爲了該處作準備。
該處有三個地方須要咱們配置,首先是defaultPool,一些除了SELECT\UPDATE\INSERT\DELETE的語句都會在defaultPool執行。
以後是writePool,這裏是配置寫庫也就是主數據庫,在這裏是前面dbServer.xml中配置的master。
resdPool配置的是讀庫,我這裏是slave1,若是讀庫有多個這裏能夠填讀池,也就是我在dbServer.xml中註釋掉的那個dbServer配置的信息。在這裏就完成了讀寫分離(主寫從讀)的配置。個人配置中是把寫操做限制在了master中,把讀限制在了slave中,若是我把defaultPool改爲master的話那麼讀操做就會在master和slave之間作負載均衡了。
4、配置jvm運行參數
運行在jdk1.7環境中的amoeba要求xss參數必須大於228才能啓動JVM
因此在amoeba安裝目錄下的jvm.properties文件中進行參數設置:
1 # app名字 2 APP_NAME=Amoeba-MySQL 3 4 # app版本號 5 APP_VERSION=3.0.0-beta 6 7 # 日誌輸出路徑,log4j中可引用參數 ${project.output} 8 9 APP_OUTPUT_PATH=$PROJECT_HOME/logs 10 11 # 應用程序的PID文件存放路徑, 默認存放在: ${project.home}/${APP_NAME}.pid 12 13 #APP_PID_PATH=/temp/logs/$APP_NAME 14 15 16 # 控制檯輸出到日誌文件 17 18 APP_CONSOLE_LOG=$APP_OUTPUT_PATH/console.log 19 20 21 # 程序相關的配置參數 22 23 #APP_OPTIONS="-DmyParam=value1 -DmyParam2=value2" 24 25 # 啓動參數 26 27 #APP_ARGS="args0 " 28 29 30 # JVM相關的參數,包括內存配置、垃圾回收策略 31 32 JVM_OPTIONS="-server -Xms512m -Xmx1024m -Xss512k -XX:PermSize=16m -XX:MaxPermSize=96m" 33 34 35 # 應用程序忽略的信號列表,以逗號分割,程序shutdown的信號爲15(可用 kill -15 pid 可以讓程序文明的shutdown,請不要在這兒填15) 36 37 IGNORE_SIGNALS=1,2
如上全部的配置工做就已經完成了,能夠看出amoeba所需的所有配置工做仍是比較少的。
啓動amoeba:
啓動腳本在amoeba安裝目錄的bin目錄下運行lancher:
root@iZ25j1wvn7pZ:/usr/local/amoeba/amoeba-mysql-3.0.5-RC/bin# ./launcher 2016-12-12 21:38:05,748 INFO context.MysqlRuntimeContext - Amoeba for Mysql current versoin=5.1.45-mysql-amoeba-proxy-3.0.4-BETA log4j:WARN ip access config load completed from file:/usr/local/amoeba/amoeba-mysql-3.0.5-RC/conf/access_list.conf 2016-12-12 21:38:06,037 INFO net.ServerableConnectionManager - Server listening on /127.0.0.1:8066. 2016-12-12 22:14:44 [INFO] Project Name=Amoeba-MySQL, PID=2596 , System shutdown .... 2016-12-12 22:14:48 [INFO] Project Name=Amoeba-MySQL, PID=3324 , starting... log4j:WARN log4j config load completed from file:/usr/local/amoeba/amoeba-mysql-3.0.5-RC/conf/log4j.xml 2016-12-12 22:14:49,405 INFO context.MysqlRuntimeContext - Amoeba for Mysql current versoin=5.1.45-mysql-amoeba-proxy-3.0.4-BETA log4j:WARN ip access config load completed from file:/usr/local/amoeba/amoeba-mysql-3.0.5-RC/conf/access_list.conf 2016-12-12 22:14:49,664 INFO net.ServerableConnectionManager - Server listening on 0.0.0.0/0.0.0.0:8066. 2016-12-14 15:02:14 [INFO] Project Name=Amoeba-MySQL, PID=3324 , System shutdown .... 2016-12-14 15:02:20 [INFO] Project Name=Amoeba-MySQL, PID=12246 , starting... log4j:WARN log4j config load completed from file:/usr/local/amoeba/amoeba-mysql-3.0.5-RC/conf/log4j.xml 2016-12-14 15:02:20,955 INFO context.MysqlRuntimeContext - Amoeba for Mysql current versoin=5.1.45-mysql-amoeba-proxy-3.0.4-BETA log4j:WARN ip access config load completed from file:/usr/local/amoeba/amoeba-mysql-3.0.5-RC/conf/access_list.conf 2016-12-14 15:02:21,224 INFO net.ServerableConnectionManager - Server listening on 0.0.0.0/0.0.0.0:8066.
運行結果如上所示表示啓動成功。
以後能夠經過amoeba鏈接到數據庫,鏈接信息以下:
root@iZ25j1wvn7pZ:/usr/local/amoeba/amoeba-mysql-3.0.5-RC/bin# mysql -h182.92.172.80 -P8066 -uamoeba -ppassword Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 2049945506 Server version: 5.1.45-mysql-amoeba-proxy-3.0.4-BETA (Ubuntu) Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
5、amoeba服務測試
從鏈接的server version 能夠看出鏈接數據可的實例是amoeba-proxy實例不是mysql實例,這樣就表示能夠經過amoeba的訪問帳戶鏈接amoeba服務了。以後就能夠進行測試了,首先向數據庫中添加一條記錄,能夠看見數據同時更新到master和slave中,主從同步功能是能夠用的。以後在slave上中止slave服務,再經過amoeba寫入數據,這時amoeba從新讀出的數據就沒有新插入的數據了,由於主從同步功能已經關掉了,寫入的數據在master中,沒有同步到slave中,而amoeba讀數據是從slave中讀取的,所以沒有新加入的數據。以後打開slave的同步服務,再在amoeba中讀取就能夠讀到以前添加的數據了。總體測試下來就保證了amoeba實現了讀寫分離功能。
參考資料: