業務量增長到一定程度後,簡單的主從架構已經不能滿足業務需要,主庫的讀寫壓力增大,逐漸達到瓶頸,這時引入主從讀寫分離是一個不錯的選擇。本文介紹了實現讀寫分離的一款工具---Amoeba。 ...
一、Amoeba簡介
Amoeba(變形蟲),專註於分散式資料庫代理層(Database Proxy)開發,介於應用層與DB Server(s)之間,對客戶端透明,主要在應用層訪問DB Server(s)的時候充當SQL路由功能。它具有負載均衡、高可用性、sql過濾、讀寫分離、可路由相關的query到目標資料庫、可併發請求多台資料庫合併結果。在Amoeba上面你能夠完成多數據源的高可用、負載均衡、數據切片的功能。
二、Amoeba的特點
主要解決:
• 降低數據切分帶來的複雜多資料庫結構
• 提供切分規則並降低數據切分規則給應用帶來的影響
• 降低db與客戶端的連接數
• 讀寫分離
不能解決:
• 目前還不支持事務
• 暫時不支持存儲過程
• 不適合從amoeba導數據的場景,對大數據量查詢的query也不合適(比如一次請求返回10w以上甚至更多數據的場合)
• 暫時不支持分庫分表,amoeba目前只做到分資料庫實例,每個被切分的節點需要保持庫表結構一致
三、基於Amoeba實現mysql資料庫讀寫分離
本文主要是為了使用Amoeba實現mysql資料庫主從讀寫分離,故需要提前配置好mysql主從複製環境,這裡不再演示。
1、實驗環境,Amoeba的要求,簡要原理圖
1)實驗環境
System:CentOS release 6.8
Amoeba:172.16.1.201
Master:172.16.1.202
Slave:172.16.1.203
2)Amoeba的要求
Amoeba 是基於jdk1.5 開發的,所以如果要運行 Amoeba,必須先安裝 jdk1.5或以上環境。
3)簡要原理圖
2、安裝Java環境
先去官網下載:http://download.oracle.com/otn-pub/java/jdk/8u161-b12/2f38c3b165be4555a1fa6e98c45e0808/jdk-8u161-linux-x64.rpm
上傳到Amoeba伺服器然後安裝:
[root@amoeba ~]# rpm -ivh jdk-8u161-linux-x64.rpm #設置java環境變數 [root@amoeba ~]# vim /etc/profile #在最後一行添加 #set java environment JAVA_HOME=/usr/java/jdk1.8.0_161 JRE_HOME=/usr/java/jdk1.8.0_161/jre CLASS_PATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin export JAVA_HOME JRE_HOME CLASS_PATH PATH #使profile文件生效 [root@amoeba ~]# source /etc/profile #測試java是否安裝成功 [root@amoeba ~]# java -version java version "1.8.0_161" Java(TM) SE Runtime Environment (build 1.8.0_161-b12) Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)
3、安裝Amoeba
下載地址:https://sourceforge.net/projects/amoeba/
我這裡下載的是amoeba-mysql-3.0.5-RC-distribution.zip,安裝非常簡單,直接將Amoeba解壓到/usr/local/amoeba目錄下即可。
[root@amoeba ~]# unzip amoeba-mysql-3.0.5-RC-distribution.zip -d /usr/local/ [root@amoeba local]# mv amoeba-mysql-3.0.5-RC/ amoeba [root@amoeba amoeba]# ll total 28 -rw-r--r-- 1 root root 4 Apr 11 23:32 Amoeba-MySQL.pid drwxrwxrwx 2 root root 4096 Jul 5 2013 benchmark drwxrwxrwx 2 root root 4096 Apr 11 23:23 bin drwxrwxrwx 2 root root 4096 Apr 11 10:52 conf -rwxrwxrwx 1 root root 780 Apr 11 23:28 jvm.properties drwxrwxrwx 2 root root 4096 Jul 5 2013 lib drwxr-xr-x 2 root root 4096 Apr 13 00:00 logs
4、配置Amoeba
1)Amoeba的配置文件位於/usr/local/amoeba/conf目錄下。總共有7個配置文件,分別如下:
• 主配置文件($AMOEBA_HOME/conf/amoeba.xml),用來配置Amoeba服務的基本參數,如Amoeba主機地址、埠、認證方式、用於連接的用戶名、密碼、線程數、超時時間、其他配置文件的位置等。
• 資料庫伺服器配置文件($AMOEBA_HOME/conf/dbServers.xml),用來存儲和配置Amoeba所代理的資料庫伺服器的信息,如:主機IP、埠、用戶名、密碼等。
• 切分規則配置文件($AMOEBA_HOME/conf/rule.xml),用來配置切分規則。
• 資料庫函數配置文件($AMOEBA_HOME/conf/functionMap.xml),用來配置資料庫函數的處理方法,Amoeba將使用該配置文件中的方法解析資料庫函數。
• 切分規則函數配置文件($AMOEBA_HOME/conf/ruleFunctionMap.xml),用來配置切分規則中使用的用戶自定義函數的處理方法。
• 訪問規則配置文件($AMOEBA_HOME/conf/access_list.conf),用來授權或禁止某些伺服器IP訪問Amoeba。
• 日誌規格配置文件($AMOEBA_HOME/conf/log4j.xml),用來配置Amoeba輸出日誌的級別和方式。
2)配置文件比較多,但是使用讀寫分離功能,只需配置兩個文件即可,分別是dbServers.xml和amoeba.xml。下麵首先介紹dbServers.xml:
1 [root@amoeba conf]# vim dbServers.xml 2 .........................(省略) 3 <dbServer name="abstractServer" abstractive="true"> 4 <factoryConfig class="com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory"> 5 <property name="connectionManager">${defaultManager}</property> 6 <property name="sendBufferSize">64</property> 7 <property name="receiveBufferSize">128</property> 8 9 <!-- mysql port --> #設置 mysql 資料庫的埠 10 <property name="port">3306</property> 11 #設置預設的資料庫,當連接amoeba時,操作表必須顯式的指定資料庫名,即採用dbname.tablename的方式,不支持 use dbname指定預設庫,因為操作會調度到各個後端dbserver 12 <!-- mysql schema --> 13 <property name="schema">testdb</property> 14 #設置amoeba連接後端資料庫伺服器的賬號和密碼,需在後端資料庫器上創建該用戶,並授權amoeba連接 15 <!-- mysql user --> 16 <property name="user">amoeba</property> 17 18 <property name="password">amoeba123</property> 19 </factoryConfig> 20 21 <poolConfig class="com.meidusa.toolkit.common.poolable.PoolableObjectPool"> 22 <property name="maxActive">500</property> #最大連接數[預設] 23 <property name="maxIdle">500</property> #最大空閑連接數[預設] 24 <property name="minIdle">1</property> 25 <property name="minEvictableIdleTimeMillis">600000</property> 26 <property name="timeBetweenEvictionRunsMillis">600000</property> 27 <property name="testOnBorrow">true</property> 28 <property name="testOnReturn">true</property> 29 <property name="testWhileIdle">true</property> 30 </poolConfig> 31 </dbServer> 32 33 #設置一個後端的dbServer,名為master,這個可以隨便取,但是為了明確其含義,最好給予特殊含義的單詞,這裡是主庫 34 <dbServer name="master" parent="abstractServer"> 35 <factoryConfig> 36 <!-- mysql ip --> #設置這台dbServer的ip地址 37 <property name="ipAddress">172.16.1.202</property> 38 </factoryConfig> 39 </dbServer> 40 41 #再設置一個後端的dbServer,這裡叫slave,名字需要唯一[這裡可以創建N個後端資料庫,只要複製下麵<dbServer>...</dbServer>] 42 <dbServer name="slave" parent="abstractServer"> 43 <factoryConfig> 44 <!-- mysql ip --> #設置這台dbServer的ip地址 45 <property name="ipAddress">172.16.1.203</property> 46 </factoryConfig> 47 </dbServer> 48 49 #指定一個虛擬的dbServer,將上面定義的dbserver加入這個虛擬的dbserver,相當於組成一個組[這裡我們將讀的資料庫組成一個組] 50 #這裡需要將name="mul..."改成自己想要取的名字,如Myslave,這個名字也需要有含義,後面會用到 51 <dbServer name="Myslave" virtual="true"> 52 <poolConfig class="com.meidusa.amoeba.server.MultipleServerPool"> 53 <!-- Load balancing strategy: 1=ROUNDROBIN , 2=WEIGHTBASED , 3=HA--> 54 #選擇調度演算法,1是輪詢,2是權重,3是HA,這裡選擇1輪詢 55 <property name="loadbalance">1</property> 56 57 <!-- Separated by commas,such as: server1,server2,server1 --> 58 #負載均衡,slave1,slave2當成2個伺服器進行調度,這模擬量加權的調度演算法。 59 #註意這裡使用的dbserver必須是已經定義了的,可以寫多個,如slave1,slave2 60 <property name="poolNames">slave</property> #Myslave組成員 61 </poolConfig> 62 </dbServer> 63 </amoeba:dbServers>
3)下麵配置amoeba.xml:
1 [root@amoeba conf]# vim amoeba.xml 2 .........................(省略) 3 <proxy> 4 <!-- service class must implements com.meidusa.amoeba.service.Service --> 5 <service name="Amoeba for Mysql" class="com.meidusa.amoeba.mysql.server.MySQLService"> 6 <!-- port --> 7 #設置amoeba監聽的埠(這裡如果預設,後面測試需要指定埠,就是這裡的埠) 8 <property name="port">8066</property> #也可以設置為3306,模擬MySQL埠 9 <!-- bind ipAddress --> 10 <!-- 11 #設置監聽的IP,如果不設置,則監聽所有的IP[選擇預設] 12 <property name="ipAddress">127.0.0.1</property> 13 --> 14 .........................(省略) 15 <property name="authenticator"> 16 <bean class="com.meidusa.amoeba.mysql.server.MysqlClientAuthenticator"> 17 #客戶端連接amoeba時需要使用這裡設定的賬號(這裡的賬號密碼和amoeba連接後端資料庫伺服器的密碼無關) 18 <property name="user">root</property> 19 #客戶端連接amoeba時需要使用這裡設定的密碼 20 <property name="password">amoeba123</property> 21 22 <property name="filter"> 23 <bean class="com.meidusa.toolkit.net.authenticate.server.IPAccessController"> 24 <property name="ipFile">${amoeba.home}/conf/access_list.conf</property> 25 </bean> 26 </property> 27 </bean> 28 </property> 29 </service> 30 .........................(省略) 31 <queryRouter class="com.meidusa.amoeba.mysql.parser.MysqlQueryRouter"> 32 <property name="ruleLoader"> 33 <bean class="com.meidusa.amoeba.route.TableRuleFileLoader"> 34 <property name="ruleFile">${amoeba.home}/conf/rule.xml</property> 35 <property name="functionFile">${amoeba.home}/conf/ruleFunctionMap.xml</property> 36 </bean> 37 </property> 38 <property name="sqlFunctionFile">${amoeba.home}/conf/functionMap.xml</property> 39 <property name="LRUMapSize">1500</property> 40 <property name="defaultPool">master</property> #設置預設連接的組為master 41 <!-- --> 42 #把註釋去掉並將writePool設置為master,將readPool設置為myslave(這個名字,我們前面在dbServer.xml里設置一個讀資料庫組,這裡是作為只讀池) 43 <property name="writePool">master</property> 44 <property name="readPool">myslave</property> 45 <property name="needParse">true</property> 46 </queryRouter>
4)在master上創建資料庫testdb
mysql> create database testdb; Query OK, 1 row affected (0.08 sec) mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | testdb | +--------------------+ 4 rows in set (0.00 sec) #查看slave是否複製成功 mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | testdb | +--------------------+ 4 rows in set (0.00 sec)
5)分別在master和slave上為amoeba授權
mysql> GRANT ALL ON testdb.* TO 'amoeba'@'172.16.1.201' IDENTIFIED BY 'amoeba123'; Query OK, 0 rows affected (0.05 sec) mysql> flush privileges; Query OK, 0 rows affected (0.02 sec)
6)啟動amoeba
[root@amoeba amoeba]# /usr/local/amoeba/bin/launcher #可以為amoeba配置環境變數,不使用全路徑啟動 Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=16m; support was removed in 8.0 Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=96m; support was removed in 8.0 The stack size specified is too small, Specify at least 228k Error: Could not create the Java Virtual Machine. Error: A fatal exception has occurred. Program will exit.
出現報錯,從錯誤文字上看,應該是由於stack size太小,導致JVM啟動失敗,要如何修改呢?
其實Amoeba已經考慮到這個問題,並將JVM參數配置寫在屬性文件里。現在,讓我們通過該屬性文件修改JVM參數。
修改jvm.properties文件JVM_OPTIONS參數:
[root@amoeba amoeba]# vim jvm.properties 改成:JVM_OPTIONS="-server -Xms1024m -Xmx1024m -Xss256k" #看上面提示,後面兩個參數在8.0被移除了 原為:JVM_OPTIONS="-server -Xms256m -Xmx1024m -Xss196k -XX:PermSize=16m -XX:MaxPermSize=96m"
再次啟動
[root@amoeba amoeba]# /usr/local/amoeba/bin/launcher at org.codehaus.plexus.classworlds.launcher.Launcher.launchStandard(Launcher.java:329) at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:239) at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:409) at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:127) at org.codehaus.classworlds.Launcher.main(Launcher.java:110) Caused by: com.meidusa.toolkit.common.bean.util.InitialisationException: cannot found Pool=myslave #出現一個錯誤,是myslave單詞寫錯了,改正後啟動成功 at com.meidusa.amoeba.route.AbstractQueryRouter.init(AbstractQueryRouter.java:469) at com.meidusa.amoeba.context.ProxyRuntimeContext.initAllInitialisableBeans(ProxyRuntimeContext.java:337) ... 11 more 2018-04-11 10:36:12 [INFO] Project Name=Amoeba-MySQL, PID=5060 , System shutdown .... Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=16m; support was removed in 8.0 Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=96m; support was removed in 8.0 2018-04-11 10:41:35 [INFO] Project Name=Amoeba-MySQL, PID=5096 , starting... log4j:WARN log4j config load completed from file:/usr/local/amoeba/conf/log4j.xml 2018-04-11 10:41:36,873 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/conf/access_list.conf 2018-04-11 10:41:53,394 INFO net.ServerableConnectionManager - Server listening on 0.0.0.0/0.0.0.0:8066. #查看埠 [root@bogon ~]# netstat -unlpt | grep java tcp 0 0 :::8066 :::* LISTEN 5096/java
7)測試
選擇一臺安裝mysql客戶端的伺服器,通過amoeba配置文件中指定的用戶名、密碼、埠以及amoeba伺服器ip地址遠程連接mysql資料庫
[root@db02 ~]# mysql -uroot -pamoeba123 -h172.16.1.201 -P8066
Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1286393262 Server version: 5.1.45-mysql-amoeba-proxy-3.0.4-BETA Source distribution Copyright (c) 2000, 2016, 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>
在testdb中創建表test並插入數據
mysql> use testdb; Database changed mysql> create table test_table(id int(4) not null); Query OK, 0 rows affected (0.33 sec) mysql> show tables; +------------------+ | Tables_in_testdb | +------------------+ | test_table | +------------------+ 1 row in set (0.01 sec) mysql> insert into test_table values(1); Query OK, 1 row affected (0.11 sec) mysql> select * from test_table; +----+ | id | +----+ | 1 | +----+ 1 row in set (0.00 sec)
分別登陸master和slave查看數據
master: mysql> use testdb Database changed mysql> show tables; +------------------+ | Tables_in_testdb | +------------------+ | test_table | +------------------+ 1 row in set (0.00 sec) mysql> select * from test_table; +----+ | id | +----+ | 1 | +----+ 1 row in set (0.00 sec)
slave: mysql> use testdb Database changed mysql> show tables; +------------------+ | Tables_in_testdb | +------------------+ | test_table | +------------------+ 1 row in set (0.00 sec) mysql> select * from test_table; +----+ | id | +----+ | 1 | +----+ 1 row in set (0.00 sec)
停掉master,然後在客戶端分別執行插入和查詢功能
master: [root@master ~]# /etc/init.d/mysqld stop Shutting down MySQL..... SUCCESS! 客戶端: mysql> insert into test_table values(2); ERROR 1044 (42000): Amoeba could not connect to MySQL server[172.16.1.202:3306],Connection refused mysql> select * from test_table; +----+ | id | +----+ | 1 | +----+ 1 row in set (0.07 sec)
可以看到,關掉master之後寫入報錯,讀正常
開啟master上的msyql 關閉slave上的mysql
master: [root@master ~]# /etc/init.d/mysqld start Starting MySQL... SUCCESS! slave: [root@slave ~]# /etc/init.d/mysqld stop Shutting down MySQL...... SUCCESS!
客戶端再次嘗試
mysql> insert into test_table values(2); Query OK, 1 row affected (0.08 sec) mysql> select * from test_table; ERROR 1044 (42000): poolName=myslave, no valid pools
可以看到插入成功,讀取失敗
開啟slave上的mysql,查看數據是否自動同步
slave: [root@slave ~]# /etc/init.d/mysqld start Starting MySQL..... SUCCESS! 客戶端: mysql> select * from test_table; +----+ | id | +----+ | 1 | | 2 | +----+ 2 rows in set (0.01 sec) mysql> insert into test_table values(3); Query OK, 1 row affected (0.20 sec) mysql> select * from test_table; +----+ | id | +----+ | 1 | | 2 | | 3 | +----+ 3 rows in set (0.00 sec)
OK 一切正常,到此全部結束