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

时间:2022-09-20 15:34:12

本文接上一篇博客: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/latestexport PATH=$JAVA_HOME/bin:$PATH

加载环境变量:

[root@node5 ~]# source /etc/profile.d/java.sh


查看java的版本:

[root@node5 ~]# java -versionjava 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]# lsbenchmark  bin  changelogs.txt  conf  lib  LICENSE.txt  README.html


下面要做的就是配置。

[root@node5 ~]# cd /usr/local/amoeba/conf     [root@node5 conf]# lsaccess_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]# ./amoebaThe stack size specified is too small, Specify at least 228kError: Could not create the Java Virtual Machine.Error: A fatal exception has occurred. Program will exit.

报错了,我们的amoeb脚本中的定义的堆栈空间太小了,我们将其定义为512k吧,默认是128,需要增大

[root@node5 bin]# vim amoebaDEFAULT_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\""


如图:

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


再次测试amoeba指令:

[root@node5 bin]# ./amoeba  amoeba start|stop


我们可以启动amoeba了:

[root@node5 bin]# ./amoeba startlog4j:WARN log4j config load completed from file:/usr/local/amoeba/conf/log4j.xml2015-01-25 10:45:11,689 INFO  context.MysqlRuntimeContext - Amoeba for Mysql current versoin=5.1.45-mysql-amoeba-proxy-2.2.0log4j:WARN ip access config load completed from file:/usr/local/amoeba/conf/access_list.conf2015-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 amoebaroot      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 startroot      2362  0.0  0.0 103252   820 pts/1    S+   10:46   0:00 grep amoeba


[root@node5 ~]# netstat -tnlp |grep javatcp        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.22Welcome to the MySQL monitor.  Commands end with ; or \g.Your MySQL connection id is 1495684478Server 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 itsaffiliates. Other names may be trademarks of their respectiveowners.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   root@node5.stu31.com as anonymous on hellodb150125 12:08:50    50 Connect   root@node5.stu31.com as anonymous on hellodb150125 12:10:13    50 Query     set names latin1                   50 Query     show databases150125 12:10:36    50 Query     create database amoeba



我们去slave节点node4查看mysql的日志,查询操作需要临时开启查询日志:

[root@node4 ~]# tail /mydata/data/node4.log150125 12:11:01    43 Query     select @@version_comment limit 1                   43 Query     select * from hellodb.students150125 12:11:07    43 Query     select @@version_comment limit 1                   43 Query     select * from hellodb.teachers150125 12:15:46    43 Query     select @@version_comment limit 1                   43 Query     select * from hellodb.teachers150125 12:15:47    43 Query     select @@version_comment limit 1                   43 Query     select * from hellodb.teachers150125 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