MariaDB数据库读写分离实现(二):amoeba的使用

本文接上一篇博客: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。


本文出自 “飞雪连天射白鹿” 博客,请务必保留此出处http://sohudrgon.blog.51cto.com/3088108/1609007

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。