mysql读写分离之amoeba

一.amoeba介绍

Amoeba(变形虫)项目,该开源框架于2008年 开始发布一款 Amoeba for Mysql软件。这个软件致力于MySQL的分布式数据库前端代理层,它主要在应用层访问MySQL的 时候充当SQL路由功能,专注于分布式数据库代理层(Database Proxy)开发。座落与 Client、DB Server(s)之间,对客户端透明。具有负载均衡、高可用性、SQL 过滤、读写分离、可路由相关的到目标数据库、可并发请求多台数据库合并结果。 通过Amoeba你能够完成多数据源的高可用、负载均衡、数据切片的功能,目前Amoeba已在很多 企业的生产线上面使用。

在MySQL proxy 6.0版本 上面如果想要读写分离并且 读集群、写集群 机器比较多情况下,用mysql proxy 需要相当大的工作量,目前mysql proxy没有现成的 lua脚本。mysql proxy根本没有配置文件, lua脚本就是它的全部,当然lua是相当方便的。那么同样这种东西需要编写大量的脚本才能完成一 个复杂的配置。而Amoeba for Mysql只需要进行相关的配置就可以满足需求。

目前不足:

  1. 目前还不支持事务
    2.暂时不支持存储过程(近期会支持)
    3.不适合从amoeba导数据的场景或者对大数据量查询的query并不合适(比如一次请求返回10w以上甚至更多数据的场合)
    4.暂时不支持分库分表,amoeba目前只做到分数据库实例,每个被切分的节点需要保持库表结构一致。

  2. 原理流程图

技术分享

二 安装amoeba

wget http://sourceforge.net/projects/amoeba/files/Amoeba%20for%20mysql/2.x/amoeba-mysql-binary-2.1.0-RC5.tar.gz 最流行的java后台框架

mkdir -pv /usr/loca/amoeba/

tar -zxvf amoeba-mysql-binary-2.1.0-RC5.tar.gz -C /usr/loca/amoeba/

然后进入bin目录运行amoeba start或者amoeba start &后台的形式运行,不过下面我们先看配置文件;

三 配置amoeba

1.想象Amoeba作为数据库代理层,它一定会和很多数据库保持通信,因此它必须知道由它代理的数据库如何连接,比如最基础的:主机IP、端口、Amoeba使用的用户名和密码等等。这些信息存储在$AMOEBA_HOME/conf/dbServers.xml中。
2.Amoeba为了完成数据切分提供了完善的切分规则配置,为了了解如何分片数据、如何将数据库返回的数据整合,它必须知道切分规则。与切分规则相关的信息存储在$AMOEBA_HOME/conf/rule.xml中。
3.当我们书写SQL来操作数据库的时候,常常会用到很多不同的数据库函数,比如:UNIX_TIMESTAMP()、SYSDATE()等等。这些函数如何被Amoeba解析呢?$AMOEBA_HOME/conf/functionMap.xml描述了函数名和函数处理的关系。
4.对$AMOEBA_HOME/conf/rule.xml进行配置时,会用到一些我们自己定义的函数,比如我们需要对用户ID求HASH值来切分数据,这些函数在$AMOEBA_HOME/conf/ruleFunctionMap.xml中定义。
5.Amoeba可以制定一些可访问以及拒绝访问的主机IP地址,这部分配置在$AMOEBA_HOME/conf/access_list.conf中
6.Amoeba允许用户配置输出日志级别以及方式,配置方法使用log4j的文件格式,文件是$AMOEBA_HOME/conf/log4j.xml。

ok

配置之前我们说说我们的架构,很简单,三台主机

一台 amoeba 192.168.127.140 来转发请求;

一台 master 192.168.127.141 可以进行读写操作;

一台 slave 192.168.127 只能进行读取操作;

本场景是读取数据量比较大,所以master可以读写,slave只能读取,最终的效果读取比例是master:slave=1:3.

7 .配置amoeba节点

7.1红色字体是主配置文件需要注意和修改的地方

<?xml version="1.0" encoding="gbk"?>
<!DOCTYPE amoeba:configuration SYSTEM "amoeba.dtd">
<amoeba:configuration xmlns:amoeba="http://amoeba.meidusa.com/">
<proxy>
 
 <!-- service class must implements com.meidusa.amoeba.service.Service -->
 <service name="Amoeba for Mysql" class="com.meidusa.amoeba.net.ServerableConnectionManager">#1.定义这是一个MySQL Proxy Service。相应的也会有MongoDB Proxy Service以及Aladdin Proxy Service。
 <!-- port -->
 <property name="port">8066</property> #2.数据库客户端用来登陆amoeba的端口;
 
 <!-- bind ipAddress -->
 <!-- 
 <property name="ipAddress">192.168.127.140</property> #3.数据库客户端用来登陆amoeba的IP,通常Proxy Service服务的主机地址并不需要定义,如果Amoeba所在的服务器在多个网络环境内你可以定义该机器的其中一个IP来指定Amoeba所服务的网络环境。如果设置为127.0.0.1将导致其他机器无法访问Amoeba的服务。
 -->
 
 <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>
 
 <property name="authenticator">
 <bean class="com.meidusa.amoeba.mysql.server.MysqlClientAuthenticator">
 
 <property name="user">root</property> #6.数据库客户端用来登陆amoeba的用户名;
 
 <property name="password">password</property>#7.数据库客户端用来登陆amoeba的密码;
 
 <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 class="com.meidusa.amoeba.mysql.context.MysqlRuntimeContext">#8.runtime元素定义了一些Proxy相关的运行期配置,如客户端及数据库服务器端的线程数以及SQL超时时间设定等等。
 <!-- 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> #9.connectionManagerList定义了一系列连接管理器,这些连接管理器可以在其他地方被引用,比如clientConnectioneManager在amoeba.xml中被引用作为MySQL Proxy Service的客户端连接管理器;defaultManager在dbServers.xml中被引用作为dbServer的数据库服务器端连接管理器。连接管理器主要配置了用于网络处理的CPU核数,默认其processor属性为Amoeba所在主机的CPU核数。
 <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>
 
 <!-- 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">master</property>#10.表示默认配置读写都会到数据池的master这个角色,在dbServer.xml中定义;
 
 <property name="writePool">master</property>#11.表示只写的数据池指定master这个名称的角色;
 <property name="readPool">virtualSlave</property>#12.表示只读的数据池指定virtualSlave这个名称的角色;
 <property name="needParse">true</property>
 </queryRouter>
</amoeba:configuration>

ok

7.2配置dbServer.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"> #1.这份dbServers配置文件中,我们定义了三个dbServer元素,这是第一个dbServer元素的定义。这个名为abstractServer的dbServer,其abstractive属性为true,这意味着这是一个抽象的dbServer定义,可以由其他dbServer定义拓展。
 <factoryConfig class="com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory">
 <property name="manager">${defaultManager}</property> #2.manager定义了该dbServer选择的连接管理器(ConnectionManager),这里引用了amoeba.xml的配置
 <property name="sendBufferSize">64</property>
 <property name="receiveBufferSize">128</property>
 <!-- mysql port -->
 <property name="port">3306</property>#3.数据库端口
 <!-- mysql schema -->
 <property name="schema">dongdong</property>#4.目标数据库
 <!-- mysql user -->
 <property name="user">haha</property>#5.用于连接后端数据库的用户,注意需要给他赋予操作上面数据库的权限;
 <!-- mysql password -->
 <property name="password">haha123</property>#6.haha用户登陆的密码
 </factoryConfig>
<poolConfig class="com.meidusa.amoeba.net.poolable.PoolableObjectPool">#7.dbServer下有poolConfig的元素,这个元素的属性主要配置了与数据库的连接池,与此相关的具体配置会在后面详细介绍。
 <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="testWhileIdle">true</property>
 </poolConfig>
 </dbServer><dbServer name="master" parent="abstractServer">#8.这个master是abstractServer的拓展,parent属性配置了拓展的抽象dbServer,它拓展了abstractServer的ipAddress属性来指名数据库的IP地址,而在端口、用户名密码、连接池配置等属性沿用了abstractServer的配置。
 <factoryConfig>
 <!-- mysql ip -->
 <property name="ipAddress">192.168.127.141</property>#9.master的地址;
 </factoryConfig>
 </dbServer>
 <dbServer name="slave" parent="abstractServer">
 <factoryConfig>
 <!-- mysql ip -->
 <property name="ipAddress">192.168.127.142</property>#9.slave的地址;
 </factoryConfig>
 </dbServer>
 <dbServer name="virtualSlave" virtual="true">#10. 这一段其实并不需要配置,并不会影响到基本使用。以下大致介绍下此配置的含义:multiPool是一个虚拟的数据库节点,可以将这个节点配置成好几台数据库组成的数据库池。比如上面这个配置中仅配置了一台server1,负载均衡策略为ROUNDROBIN(轮询)。与虚拟数据库节点相关的详细教程会在后面的章节中介绍。
 <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">master,slave,slave,slave</property>#11.此处master和slave配置出现的此处就是给它们分配请求的比例,此处是1:3
 </poolConfig>
 </dbServer>
</amoeba:dbServers>

补充 定义abstractServer的原因:当我们有一个数据库集群需要管理,这个数据库集群中节点的大部分信息可能是相同的,比如:端口号、用户名、密码等等。因此通过归纳这些共性定义出的abstractServer极大地简化了dbServers配置文件。

四.运行amoeba以及测试

1./usr/loca/amoeba/bin/amoeba start &

日志显示

open socket channel to server[192.168.127.141:3306] success!
open socket channel to server[192.168.127.142:3306] success!

如果没有显示就证明没有连接到后端数据库,笔者之前有一个连接不到,结果原因是配置文件里面的注释未去掉,o(�□�)o

2.因为实际环境需要master与slave同步,不是本文重点,可看其他文章;

这里前提是关闭slave的同步,在slave上  stop slave,但是如果大量测试数据,那么你可以让slave把master的数据库同步过来在关闭也ok;

分别在master和slave上创建数据库

grant all privileges on hehe.* to hehe@‘%‘ indefied by ‘hehe123‘;
 flush privileges;
create database hehe;
 use hehe;
create tables heheta(id int(10),name varchar(20));
insert into heheta (id,name,address)value(‘9,‘master‘,‘100‘); 给master插入数据
insert into heheta (id,name,address)value(‘10‘,‘slave‘,‘101‘);给slave插入数据
然后在amoeba主机上进行登陆以及测试
mysql -uroot -ppassword -h192.168.127.140 -P8066
use heheta;
mysql> select * from heheta;
+------+-------+---------+
| id | name | address |
+------+-------+---------+
| 10 | slave | 101 |
+------+-------+---------+
1 row in set (0.01 sec)
mysql> select * from heheta;
+------+-------+---------+
| id | name | address |
+------+-------+---------+
| 10 | slave | 101 |
+------+-------+---------+
1 row in set (0.00 sec)
mysql> select * from heheta;
+------+-------+---------+
| id | name | address |
+------+-------+---------+
| 10 | slave | 101 |
+------+-------+---------+
1 row in set (0.01 sec)
mysql> select * from heheta;
+------+--------+---------+
| id | name | address |
+------+--------+---------+
| 9 | master | 100 |
+------+--------+---------+
1 row in set (0.01 sec)

读取比例master:slave=1:3

插入数据测试
insert into heheta(id,name,address)value(‘11‘,‘adddata‘,‘102‘);
查询只能在负责写入数据的master上才会有数据
mysql> select * from heheta;
+------+-------+---------+
| id | name | address |
+------+-------+---------+
| 10 | slave | 101 |
+------+-------+---------+
1 row in set (0.01 sec)
mysql> select * from heheta;
+------+---------+---------+
| id | name | address |
+------+---------+---------+
| 9 | master | 100 |
| 11 | adddata | 102 |
+------+---------+---------+
2 rows in set (0.02 se
相关文章
相关标签/搜索