本文接上一篇博客:MariaDB数据库读写分离实现(一):mysql-proxy的使用
http://sohudrgon.blog.51cto.com/3088108/1608605
我们将mysql-proxy停止,在节点node5上安装amoeba,测试实现数据库的读写分离。
一.amoeba的简介
Amoeba for MySQL致力于MySQL的分布式数据库前端代理层,它主要在应用层访问MySQL的时候充当query 路由功能,专注分布式数据库 proxy 开发。座落于Client、DB Server(s)之间。对客户端透明。具有负载均衡、高可用性、Query过滤、读写分离、可路由相关的query到目标数据库、可并发请求多台数据库合并结果。 在Amoeba上面你能够完成多数据源的高可用、负载均衡、数据切片的功能。目前在很多企业的生产线上面使用。
我们就当它是mysql吧,它是一个虚拟的mysql,对外提供mysql协议。客户端连接amoeba就象连接mysql一样。在amoeba内部需要配置相关的认证属性。
二.Amoeba for Mysql 与MySQL Proxy比较
在MySQL proxy 6.0版本 上面如果想要读写分离并且读集群、写集群机器比较多情况下,用mysql proxy 需要相当大的工作量,目前mysql proxy没有现成的 lua脚本。mysql proxy根本没有配置文件, lua脚本就是它的全部,当然lua是相当方便的。那么同样这种东西需要编写大量的脚本才能完成一 个复杂的配置。而Amoeba for Mysql只需要进行相关的配置就可以满足需求。
Amoeba不能做什么?
目前还不支持事务
暂时不支持存储过程
不适合从amoeba导数据的场景或者对大数据量查询的query并不合适(比如一次请求返回10w以上甚至更多数据的场合)
暂时不支持分库分表,amoeba目前只做到分数据库实例,每个被切分的节点需要保持库表结构一致
三.配置安装和使用amoeba
1.Amoeba框架是基于Java SE1.5开发的,建议使用Java SE 1.5版本。
目前Amoeba经验证在JavaTM SE 1.5和Java SE 1.6能正常运行,(可能包括其他未经验证的版本)。
我这里就使用一下Java(TM) SE 1.7
jdk-7u67-linux-x64.rpm
安装jdk:
[root@node5 ~]# rpm -ivh jdk-7u67-linux-x64.rpm
设置环境变量:
[root@node5 ~]# vim /etc/profile.d/java.sh export JAVA_HOME=/usr/java/latest export PATH=$JAVA_HOME/bin:$PATH
加载环境变量:
[root@node5 ~]# source /etc/profile.d/java.sh
查看java的版本:
[root@node5 ~]# java -version java version "1.7.0_67" Java(TM) SE Runtime Environment (build 1.7.0_67-b01) Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode)
2.安装amoeba
你可以在Amoeba在SourceForge的主页下载Amoeba,http://sourceforge.net/projects/amoeba/files/。
当你下载的时候,请确保选择Amoeba的最新版本。Amoeba目前有三个开源产品,分别是适用于拥有JDBC Driver的数据库的Amoeba for Aladdin、适用于MySQL数据库的Amoeba for MySQL以及适用于mongoDB数据库的Amoeba for mongoDB。Amoeba for MySQL的最新版本是amoeba-mysql-binary-2.2.0.tar.gz。
我这里就使用最新版本了:
amoeba-mysql-binary-2.2.0.tar.gz
我这里提供下载:
http://down.51cto.com/data/1978353
下载后存放并解压到安装的位置。文件解压到/usr/local/amoeba,解压到其他路径也是一样的。进入Ameoba运行目录:
[root@node5 ~]# mkdir /usr/local/amoeba [root@node5 ~]# tar xf amoeba-mysql-binary-2.2.0.tar.gz -C /usr/local/amoeba [root@node5 ~]# cd /usr/local/amoeba [root@node5 amoeba]# ls benchmark bin changelogs.txt conf lib LICENSE.txt README.html
下面要做的就是配置。
[root@node5 ~]# cd /usr/local/amoeba/conf [root@node5 conf]# ls access_list.conf amoeba.dtd amoeba.xml dbserver.dtd dbServers.xml function.dtd functionMap.xml log4j.dtd log4j.xml rule.dtd ruleFunctionMap.xml rule.xml
#主要是配置下面两个文件
dbServer.xml #定义连接数据库的信息
amoeba.xml #定义读写分离的节点管理信息
3.配置amoeba
先配置定义连接数据库的信息:
[root@node5 conf]# cat dbServers.xml <?xml version="1.0" encoding="gbk"?> <!DOCTYPE amoeba:dbServers SYSTEM "dbserver.dtd"> <amoeba:dbServers xmlns:amoeba="http://amoeba.meidusa.com/"> <!-- Each dbServer needs to be configured into a Pool, If you need to configure multiple dbServer with load balancing that can be simplified by the following configuration: add attribute with name virtual = "true" in dbServer, but the configuration does not allow the element with name factoryConfig such as 'multiPool' dbServer --> <dbServer name="abstractServer" abstractive="true"> <!--这份dbServers配置文件中,我们定义了三个dbServer元素,这是第一个dbServer元素的定义。这个名为abstractServer的dbServer,其abstractive属性为true,这意味着这是一个抽象的dbServer定义,可以由其他dbServer定义拓展。 --> <factoryConfig class="com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory"> <!--manager定义了该dbServer选择的连接管理器(ConnectionManager),这里引用了amoeba.xml的配置,稍后介绍。--> <property name="manager">${defaultManager}</property> <property name="sendBufferSize">64</property> <property name="receiveBufferSize">128</property> <!-- mysql port 在第一个dbServer元素分别定义MySQL的端口号。--> <property name="port">3306</property> <!-- mysql schema 定义数据库名--> <property name="schema">hellodb</property> <!-- mysql user 定义用户名 --> <property name="user">root</property> <!-- mysql password 定义数据库密码--> <property name="password">oracle</property> </factoryConfig> <!--dbServer下有poolConfig的元素,这个元素的属性主要配置了与数据库的连接池,与此相关的具体配置会在后面的章节中详细介绍。--> <poolConfig class="com.meidusa.amoeba.net.poolable.PoolableObjectPool"> <property name="maxActive">500</property> <property name="maxIdle">500</property> <property name="minIdle">10</property> <property name="minEvictableIdleTimeMillis">600000</property> <property name="timeBetweenEvictionRunsMillis">600000</property> <property name="testOnBorrow">true</property> <property name="testOnReturn">true</property> <property name="testWhileIdle">true</property> </poolConfig> </dbServer> <!--命名为server1的dbServer元素,正如你设想的那样,这个master是abstractServer的拓展,parent属性配置了拓展的抽象dbServer,它拓展了abstractServer的ipAddress属性来指名数据库的IP地址,而在端口、用户名密码、连接池配置等属性沿用了abstractServer的配置。--> <dbServer name="master" parent="abstractServer"> <factoryConfig> <!-- mysql ip --> <property name="ipAddress">172.16.31.20</property> <property name="user">root</property> <property name="password">oracle</property> </factoryConfig> </dbServer> <dbServer name="slave" parent="abstractServer"> <factoryConfig> <!-- mysql ip --> <property name="ipAddress">172.16.31.21</property> <property name="user">root</property> <property name="password">oracle</property> </factoryConfig> </dbServer> <!--定义了池,server1是一个虚拟的数据库节点,可以将这个节点配置成好几台数据库组成的数据库池。比如上面这个配置中仅配置了一台master,负载均衡策略为ROUNDROBIN(轮询)。--> <dbServer name="server1" virtual="true"> <poolConfig class="com.meidusa.amoeba.server.MultipleServerPool"> <!--负载均衡参数1=ROUNDROBIN 轮询, 2=WEIGHTBASED 加权轮询, 3=HA高可用--> <!-- 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">master</property> </poolConfig> </dbServer> <!--定义了从节点的池,如上的主节点池,介绍略--> <dbServer name="server2" virtual="true"> <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">slave</property> </poolConfig> </dbServer> </amoeba:dbServers>
定义读写分离的节点管理信息:
[root@node5 conf]# cat amoeba.xml <?xml version="1.0" encoding="gbk"?> <!DOCTYPE amoeba:configuration SYSTEM "amoeba.dtd"> <amoeba:configuration xmlns:amoeba="http://amoeba.meidusa.com/"> <proxy> <!--Service节点定义了需要启动的服务,在本配置中其class属性为“com.meidusa.amoeba.net.ServerableConnectionManager”,这意味着这是一个Proxy Service(就目前而言)。在这个元素下的connectionFactory元素中定义其class属性为“com.meidusa.amoeba.mysql.net.MysqlClientConnectionFactory”,这意味着这是一个MySQL Proxy Service。相应的也会有MongoDB Proxy Service以及Aladdin Proxy Service。--> <!-- service class must implements com.meidusa.amoeba.service.Service --> <service name="Amoeba for Mysql" class="com.meidusa.amoeba.net.ServerableConnectionManager"> <!-- port 这里定义了之前我们所定义的MySQL Proxy Service的服务端口和主机地址。--> <property name="port">3306</property> <!-- bind ipAddress 通常Proxy Service服务的主机地址并不需要定义,如果Amoeba所在的服务器在多个网络环境内你可以定义该机器的其中一个IP来指定Amoeba所服务的网络环境。如果设置为127.0.0.1将导致其他机器无法访问Amoeba的服务。--> <!-- <property name="ipAddress">127.0.0.1</property> --> <property name="manager">${clientConnectioneManager}</property> <property name="connectionFactory"> <bean class="com.meidusa.amoeba.mysql.net.MysqlClientConnectionFactory"> <property name="sendBufferSize">128</property> <property name="receiveBufferSize">64</property> </bean> </property> <!--这里配置了MySQL Proxy Service的认证器,user和passwd属性分别定义Amoeba对外服务的用户名和密码。你的程序或者数据库客户端需要使用该用户名和密码来通过Amoeba连接之前定义的dbServer。--> <property name="authenticator"> <bean class="com.meidusa.amoeba.mysql.server.MysqlClientAuthenticator"> <property name="user">root</property> <property name="password">oracle</property> <property name="filter"> <bean class="com.meidusa.amoeba.server.IPAccessController"> <property name="ipFile">${amoeba.home}/conf/access_list.conf</property> </bean> </property> </bean> </property> </service> <!-- server class must implements com.meidusa.amoeba.service.Service --> <service name="Amoeba Monitor Server" class="com.meidusa.amoeba.monitor.MonitorServer"> <!-- port --> <!-- default value: random number <property name="port">9066</property> --> <!-- bind ipAddress --> <property name="ipAddress">127.0.0.1</property> <property name="daemon">true</property> <property name="manager">${clientConnectioneManager}</property> <property name="connectionFactory"> <bean class="com.meidusa.amoeba.monitor.net.MonitorClientConnectionFactory"></bean> </property> </service> <!--runtime元素定义了一些Proxy相关的运行期配置,如客户端及数据库服务器端的线程数以及SQL超时时间设定等等。--> <runtime class="com.meidusa.amoeba.mysql.context.MysqlRuntimeContext"> <!-- proxy server net IO Read thread size --> <property name="readThreadPoolSize">20</property> <!-- proxy server client process thread size --> <property name="clientSideThreadPoolSize">30</property> <!-- mysql server data packet process thread size --> <property name="serverSideThreadPoolSize">30</property> <!-- per connection cache prepared statement size --> <property name="statementCacheSize">500</property> <!-- query timeout( default: 60 second , TimeUnit:second) --> <property name="queryTimeout">60</property> </runtime> </proxy> <!-- Each ConnectionManager will start as thread manager responsible for the Connection IO read , Death Detection --> <!-- connectionManagerList定义了一系列连接管理器,这些连接管理器可以在其他地方被引用,比如clientConnectioneManager在amoeba.xml中被引用作为MySQL Proxy Service的客户端连接管理器;defaultManager在dbServers.xml中被引用作为dbServer的数据库服务器端连接管理器。连接管理器主要配置了用于网络处理的CPU核数,默认其processor属性为Amoeba所在主机的CPU核数。 --> <connectionManagerList> <connectionManager name="clientConnectioneManager" class="com.meidusa.amoeba.net.MultiConnectionManagerWrapper"> <property name="subManagerClassName">com.meidusa.amoeba.net.ConnectionManager</property> <!-- default value is avaliable Processors <property name="processors">5</property> --> </connectionManager> <connectionManager name="defaultManager" class="com.meidusa.amoeba.net.MultiConnectionManagerWrapper"> <property name="subManagerClassName">com.meidusa.amoeba.net.AuthingableConnectionManager</property> <!-- default value is avaliable Processors <property name="processors">5</property> --> </connectionManager> </connectionManagerList> <!--最后一部分dbServerLoader定义了dbServers.xml的位置。queryRouter定义了规则配置及函数配置等相关文件的位置。--> <!-- default using file loader --> <dbServerLoader class="com.meidusa.amoeba.context.DBServerConfigFileLoader"> <property name="configFile">${amoeba.home}/conf/dbServers.xml</property> </dbServerLoader> <queryRouter class="com.meidusa.amoeba.mysql.parser.MysqlQueryRouter"> <property name="ruleLoader"> <bean class="com.meidusa.amoeba.route.TableRuleFileLoader"> <property name="ruleFile">${amoeba.home}/conf/rule.xml</property> <property name="functionFile">${amoeba.home}/conf/ruleFunctionMap.xml</property> </bean> </property> <property name="sqlFunctionFile">${amoeba.home}/conf/functionMap.xml</property> <property name="LRUMapSize">1500</property> <!-- <property name="defaultPool">server1</property> --> <!--定义读写分离,我们将读操作定位到server2这个池,将写操作定位到server1这个池。--> <property name="writePool">server1</property> <property name="readPool">server2</property> <property name="needParse">true</property> </queryRouter> </amoeba:configuration>
4.配置完成后启动amoeb:
[root@node5 bin]# pwd /usr/local/amoeba/bin [root@node5 bin]# ./amoeba 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.
报错了,我们的amoeb脚本中的定义的堆栈空间太小了,我们将其定义为512k吧,默认是128,需要增大
[root@node5 bin]# vim amoeba DEFAULT_OPTS="-server -Xms256m -Xmx256m -Xss512k" # DEFAULT_OPTS="$DEFAULT_OPTS -XX:+HeapDumpOnOutOfMemoryError -XX:+AggressiveOpts -XX:+UseParallelGC -XX:+UseBiasedLocking -XX:NewSize=64m" DEFAULT_OPTS="$DEFAULT_OPTS -Damoeba.home=\"$AMOEBA_HOME\"" DEFAULT_OPTS="$DEFAULT_OPTS -Dclassworlds.conf=\"$AMOEBA_HOME/bin/amoeba.classworlds\""
如图:
再次测试amoeba指令:
[root@node5 bin]# ./amoeba amoeba start|stop
我们可以启动amoeba了:
[root@node5 bin]# ./amoeba start log4j:WARN log4j config load completed from file:/usr/local/amoeba/conf/log4j.xml 2015-01-25 10:45:11,689 INFO context.MysqlRuntimeContext - Amoeba for Mysql current versoin=5.1.45-mysql-amoeba-proxy-2.2.0 log4j:WARN ip access config load completed from file:/usr/local/amoeba/conf/access_list.conf 2015-01-25 10:45:12,439 INFO net.ServerableConnectionManager - Amoeba for Mysql listening on 0.0.0.0/0.0.0.0:3306. 2015-01-25 10:45:12,464 INFO net.ServerableConnectionManager - Amoeba Monitor Server listening on /127.0.0.1:5477.
从上面的信息中可以看到3306端口打开了。可查看进程:
[root@node5 ~]# ps aux |grep amoeba root 2313 3.6 6.1 1076656 63060 pts/0 Sl+ 10:45 0:02 /usr/java/latest/bin/java -server -Xms256m -Xmx256m -Xss512k -Damoeba.home=/usr/local/amoeba -Dclassworlds.conf=/usr/local/amoeba/bin/amoeba.classworlds -classpath /usr/local/amoeba/lib/classworlds-1.0.jar org.codehaus.classworlds.Launcher start root 2362 0.0 0.0 103252 820 pts/1 S+ 10:46 0:00 grep amoeba
[root@node5 ~]# netstat -tnlp |grep java tcp 0 0 ::ffff:127.0.0.1:5477 :::* LISTEN 2313/java tcp 0 0 :::3306 :::* LISTEN 2313/java
从上面的一些信息可以看到amoeba已经启动,下面就可以测试一下了。
5.读写分离测试:
为了更好的看到测试结果,要做以下这些步骤:
测试要先保证amoeba-server有访问两个主从服务器hellodb库的权限,在主节点node3服务器上上执行:
MariaDB [(none)]> grant all on *.* to 'root'@'172.16.%.%' identified by 'oracle'; Query OK, 0 rows affected (0.01 sec) MariaDB [(none)]> flush privileges; Query OK, 0 rows affected (0.00 sec)
用户创建授权完成后我们在amoeba代理节点上登录数据库:
[root@node5 ~]# mysql -uroot -poracle -h 172.16.31.22 Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 1495684478 Server version: 5.1.45-mysql-amoeba-proxy-2.2.0 Source distribution #通过Server version可以得知连接的是Amoeba实例而不是MySQL实例。 Copyright (c) 2000, 2013, 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>
临时开启查询日志,建议操作完成后关闭:
事例:开启节点node3的查询日志;
MariaDB [(none)]> set global general_log=1; Query OK, 0 rows affected (0.06 sec) MariaDB [(none)]> show global variables like '%general_log%'; +------------------+-----------+ | Variable_name | Value | +------------------+-----------+ | general_log | ON | | general_log_file | node3.log | +------------------+-----------+ 2 rows in set (0.03 sec)
执行一些查看指令:
[root@node5 ~]# mysql -uroot -poracle -h 172.16.31.22 -e 'show databases' +--------------------+ | Database | +--------------------+ | binlog | | hellodb | | information_schema | | mysql | | performance_schema | | relaylog | | test | +--------------------+
登录测试成功,amoeba代理成功了;
我们再执行一条创建数据库amoeba语句:
[root@node5 conf]# mysql -uroot -poracle -h 172.16.31.22 -e 'create database amoeba' 再执行一些查询语句: [root@node5 ~]# mysql -uroot -poracle -h 172.16.31.22 -e 'select * from hellodb.students' [root@node5 ~]# mysql -uroot -poracle -h 172.16.31.22 -e 'select * from hellodb.teachers' 多执行几次;
我们去master节点node3查看mysql的日志,需要临时将查询日志打开,上面已经开启了,和slave节点进行对比:
[root@node3 ~]# tail /mydata/data/node3.log 150125 12:07:48 49 Connect [email protected] as anonymous on hellodb 150125 12:08:50 50 Connect [email protected] as anonymous on hellodb 150125 12:10:13 50 Query set names latin1 50 Query show databases 150125 12:10:36 50 Query create database amoeba
我们去slave节点node4查看mysql的日志,查询操作需要临时开启查询日志:
[root@node4 ~]# tail /mydata/data/node4.log 150125 12:11:01 43 Query select @@version_comment limit 1 43 Query select * from hellodb.students 150125 12:11:07 43 Query select @@version_comment limit 1 43 Query select * from hellodb.teachers 150125 12:15:46 43 Query select @@version_comment limit 1 43 Query select * from hellodb.teachers 150125 12:15:47 43 Query select @@version_comment limit 1 43 Query select * from hellodb.teachers 150125 12:15:48 43 Query select @@version_comment limit 1 43 Query select * from hellodb.teachers
通过实验基本确定实现了读写分离。
以上是通过Amoeba对一个数据库实例进行操作的整个过程。可以由此得知:Amoeba是一款优秀且透明的数据库中间层,如果你不习惯用命令行的方式操作数据库,你甚至可以尝试一些GUI数据库管理工具,经过使用大多数GUI工具兼容Amoeba。