一、Amoeba 是什么
Amoeba(变形虫)项目,专注 分布式数据库 proxy 开发。座落与Client、DB Server(s)之间。对客户端透明。具有负载均衡、高可用性、sql过滤、读写分离、可路由相关的query到目标数据库、可并发请求多台数据库合并结果。
主要解决:
降低 数据切分带来的复杂多数据库结构
提供切分规则并降低 数据切分规则 给应用带来的影响
降低db 与客户端的连接数
读写分离
二、为什么要用Amoeba
目前要实现mysql的主从读写分离,主要有以下几种方案:
1、 通过程序实现,网上很多现成的代码,比较复杂,如果添加从服务器要更改多台服务器的代码。
2、 通过mysql-proxy来实现,由于mysql-proxy的主从读写分离是通过lua脚本来实现,目前lua的脚本的开发跟不上节奏,而写没有完美的现成的脚本,因此导致用于生产环境的话风险比较大,据网上很多人说mysql-proxy的性能不高。
3、 自己开发接口实现,这种方案门槛高,开发成本高,不是一般的小公司能承担得起。
4、 利用阿里巴巴的开源项目Amoeba来实现,具有负载均衡、高可用性、sql过滤、读写分离、可路由相关的query到目标数据库,并且安装配置非常简单,但是目前还不支持事务。国产的开源软件,应该支持,目前正在使用,不发表太多结论,一切等测试完再发表结论吧,哈哈!
三、快速架设amoeba,实现mysql主从读写分离
假设amoeba的前提条件:
n Java SE 1.5 或以上 Amoeba 框架是基于JDK1.5开发的,采用了JDK1.5的特性。
n 支持Mysql 协议版本10(mysql 4.1以后的版本)。
n 您的网络环境至少运行有一个mysql 4.1以上的服务
1、首先介绍下我的实验环境。
System: CentOS release 5.5
Master mysql:188.188.1.144
Slave mysql:188.188.1.175
Amoeba server: 188.188.1.188
架构如如下所示:
1.配置主从,(略)
Master:188.188.1.144
slave:188.188.1.175
1.1 在Master和slave上建立访问用户
grant all privileges on *.* to ‘root‘@‘188.188.1.%‘ identified by ‘123456‘;
1.2 配置java环境:(略)
[[email protected]_172 conf]# java -version
java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03)
Java HotSpot(TM) Client VM (build 20.1-b02, mixed mode, sharing)
2.配置amoeba(188.188.1.188)
2.1 建立目录,解压文件:
[[email protected]_172 soft]# mkdir /usr/local/amoeba/
[[email protected]_172 soft]# tar -zxvf amoeba-mysql-binary-2.1.0-RC5.tar.gz -C /usr/local/amoeba/
2.3 进入目录,查看文件:
[[email protected]_172 soft]# cd /usr/local/amoeba/
[[email protected]_172 amoeba]# ll
total 64
drwxr-xr-x 2 root root 4096 Mar 28 15:35 benchmark
drwxr-xr-x 2 root root 4096 Feb 28 2011 bin
-rw-r--r-- 1 root root 3983 May 18 2011 changelogs.txt
drwxr-xr-x 2 root root 4096 Mar 28 16:22 conf
drwxr-xr-x 3 root root 4096 Mar 28 15:35 lib
-rw-r--r-- 1 root root 34520 May 18 2011 LICENSE.txt
drwxr-xr-x 2 root root 4096 Mar 28 16:39 logs
-rw-r--r-- 1 root root 2031 May 18 2011 README.html
2.4 进入配置文件目录
[[email protected]_172 amoeba]# cd conf/
[[email protected]_172 conf]# ls
access_list.conf amoeba.xml dbServers.xml functionMap.xml log4j.xml ruleFunctionMap.xml
amoeba.dtd dbserver.dtd function.dtd log4j.dtd rule.dtd rule.xml
amoeba.xml 需要修改 主配置文件,配置所有数据源及Amoeba自身的参数
dbServer.xml 需要修改
access_list.conf 需要修改
rule.xml 数据切分时使用
log4j.xml 无需修改
functionMap.xml 无需修改 配置用于解析Query中的函数所对应的Java实现类nullFunctionMap.xml 无需修改 配置路由规则中需要使用到的特定函数的实现类
2.5 修改主配置文件:
[[email protected]_172 conf]# vi 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 must implements com.meidusa.amoeba.service.Service -->
<service name="Amoeba for Mysql" class="com.meidusa.amoeba.net.ServerableConnectionManager">
<!-- port -->
<property name="port">8066</property>
<!-- bind ipAddress -->
<!-- 修改主机地址 -->
<property name="ipAddress">188.188.1.188</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>
<property name="authenticator">
<bean class="com.meidusa.amoeba.mysql.server.MysqlClientAuthenticator">
<!-- 修改用户名为自己数据库用户 -->
<property name="user">root</property>
<!-- 密码为自己密码 -->
<property name="password">123456</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 class="com.meidusa.amoeba.mysql.context.MysqlRuntimeContext">
<!-- proxy server net IO Read thread size -->
<property name="readThreadPoolSize">200</property>
<!-- proxy server client process thread size -->
<property name="clientSideThreadPoolSize">300</property>
<!-- mysql server data packet process thread size -->
<property name="serverSideThreadPoolSize">300</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>
<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">server1</property>
<!-- 修改写为server1,读为server2 -->
<property name="writePool">server1</property>
<property name="readPool">server2</property>
<property name="needParse">true</property>
</queryRouter>
</amoeba:configuration>
2.6 配置dbServers.xml 文件,增加server2
[[email protected]_172 conf]# vi 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">
<factoryConfig class="com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory">
<property name="manager">${defaultManager}</property>
<property name="sendBufferSize">64</property>
<property name="receiveBufferSize">128</property>
<!-- mysql port -->
<property name="port">3306</property>
<!-- mysql schema -->
<property name="schema">test</property>
<!-- mysql user -->
<!-- 自己用户名 -->
<property name="user">root</property>
<!-- 自己密码-->
<property name="password">123456</property>
</factoryConfig>
<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="testWhileIdle">true</property>
</poolConfig>
</dbServer>
<dbServer name="server1" parent="abstractServer">
<factoryConfig>
<!-- mysql ip -->
<!--自己主机地址-->
<property name="ipAddress">188.188.1.144</property>
</factoryConfig>
</dbServer>
<dbServer name="multiPool" 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">server1</property>
</poolConfig>
</dbServer>
<!-- 这后面是server2的配置 ,复制上面的内容,server1的 -->
<dbServer name="abstractServer" abstractive="true">
<factoryConfig class="com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory">
<property name="manager">${defaultManager}</property>
<property name="sendBufferSize">64</property>
<property name="receiveBufferSize">128</property>
<!-- mysql port -->
<property name="port">3306</property>
<!-- mysql schema -->
<property name="schema">test</property>
<!-- mysql user -->
<!-- 自己用户名 -->
<property name="user">root</property>
<!-- 自己密码-->
<property name="password">123456</property>
</factoryConfig>
<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="testWhileIdle">true</property>
</poolConfig>
</dbServer>
<dbServer name="server2" parent="abstractServer">
<factoryConfig>
<!-- mysql ip -->
<property name="ipAddress">188.188.1.175</property>
</factoryConfig>
</dbServer>
<dbServer name="multiPool" 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">server2</property>
</poolConfig>
</dbServer>
2.7 启动服务:
[[email protected]_172 logs]# /usr/local/amoeba/bin/amoeba start &
查看服务状态:
[[email protected]_172 logs]# netstat -ntpl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:813 0.0.0.0:* LISTEN 2751/rpc.statd
tcp 0 0 0.0.0.0:110 0.0.0.0:* LISTEN 3070/couriertcpd
tcp 0 0 0.0.0.0:143 0.0.0.0:* LISTEN 3064/couriertcpd
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN 2721/portmap
tcp 0 0 0.0.0.0:16851 0.0.0.0:* LISTEN 3321/modclusterd
tcp 0 0 ::ffff:188.188.1.188:8066 :::* LISTEN 20280/java
tcp 0 0 :::22 :::* LISTEN 3031/sshd
tcp 0 0 ::ffff:127.0.0.1:38269 :::* LISTEN 20280/java
[[email protected]_172 logs]# ps -ef | grep amoe
root 20280 3411 0 16:22 pts/0 00:00:02 /usr/local/jdk/bin/java -server -Xms256m -Xmx256m -Xss128k -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 20655 3411 0 17:43 pts/0 00:00:00 grep amoe
3.测试:
为了测试成功,停掉主从服务
3.1登陆到代理主机上测试:
[[email protected]_172 logs]# mysql -uroot -p123456 -h188.188.1.188 -P8066
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 17738170
Server version: 5.1.45-mysql-amoeba-proxy-2.1.0-RC5 Source distribution
Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
This software comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to modify and redistribute it under the GPL v2 license
Type ‘help;‘ or ‘\h‘ for help. Type ‘\c‘ to clear the current input statement.
mysql> use ckl
Database changed
mysql> select * from qinglv;
+-----------+------+
| name | age |
+-----------+------+
| ckl | 26 |
| xiong | 24 |
| ckl | 26 |
| xiong | 24 |
| kangle | 0 |
| kangkang | 26 |
| xiaoxiong | 24 |
| haha | 33 |
| ceshi | 34 |
+-----------+------+
9 rows in set (0.01 sec)
mysql> insert into qinglv values(‘wukaka‘,30);
Query OK, 1 row affected (0.00 sec)
3.2 登陆到主服务器上查看:
[[email protected] tmp]# mysql -uroot -p123456 -h188.188.1.144
Logging to file ‘/tmp/mysql-op.log‘
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 38
Server version: 5.1.35-log Source distribution
Type ‘help;‘ or ‘\h‘ for help. Type ‘\c‘ to clear the current input statement.
mysql> use ckl
Database changed
mysql> select * from qinglv;
+-----------+------+
| name | age |
+-----------+------+
| ckl | 26 |
| xiong | 24 |
| ckl | 26 |
| xiong | 24 |
| kangle | 0 |
| kangkang | 26 |
| xiaoxiong | 24 |
| haha | 33 |
| ceshi | 34 |
| wukaka | 30 |
+-----------+------+
10 rows in set (0.00 sec)
已经有了新插入的数据
3.3 登陆到从上查看:
[[email protected] tmp]# mysql -uroot -p123456 -h188.188.1.175
Logging to file ‘/tmp/mysql-op.log‘
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1270
Server version: 5.1.35-log Source distribution
Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
This software comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to modify and redistribute it under the GPL v2 license
Type ‘help;‘ or ‘\h‘ for help. Type ‘\c‘ to clear the current input statement.
mysql> use ckl
Database changed
mysql> select * from qinglv;
+-----------+------+
| name | age |
+-----------+------+
| ckl | 26 |
| xiong | 24 |
| ckl | 26 |
| xiong | 24 |
| kangle | 0 |
| kangkang | 26 |
| xiaoxiong | 24 |
| haha | 33 |
| ceshi | 34 |
+-----------+------+
9 rows in set (0.00 sec)
没有新插入的数据
3.4 启动从服务器:
[[email protected] tmp]# mysql -uroot -p123456 -h188.188.1.175
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
3.5 在amoeba上插入数据:
[[email protected]_172 logs]# mysql -uroot -p123456 -h188.188.1.188 -P8066
mysql> insert into qinglv values(‘heixiu‘,28);
Query OK, 1 row affected (0.00 sec)
3.6 在从服务器上查看:
[[email protected] tmp]# mysql -uroot -p123456 -h188.188.1.175
mysql> select * from qinglv;
+-----------+------+
| name | age |
+-----------+------+
| ckl | 26 |
| xiong | 24 |
| ckl | 26 |
| xiong | 24 |
| kangle | 0 |
| kangkang | 26 |
| xiaoxiong | 24 |
| haha | 33 |
| ceshi | 34 |
| wukaka | 30 |
| heixiu | 28 |
+-----------+------+
11 rows in set (0.00 sec)
已经看到数据。