注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Oracle专业打杂

定会重回巅峰……

 
 
 

日志

 
 

Amoeba for Mysql水平扩展与读写分离  

2015-09-09 17:43:45|  分类: MYSQL高级 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

JDK版本:jdk-1_5_0_22-linux-amd64.bin(使用1.6版本会报错,推荐使用1.5版本)

Amoeba版本:amoeba-mysql-binary-2.2.0.tar.gz

Mysql版本:MySQL Database 5.6.25 TAR for Generic Linux (glibc2.5) x86 (64bit).zip

操作系统:RHEL5.5 x86_64

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

本文通过使用Amoeba for Mysql实现了Mysql数据库的水平扩展及读写分离。由于实验环境有限,故所有的操作均在同一台Linux操作系统下完成,Mysql按端口不同,划分成四个Instance,3307与3309是M-S关系,3308与3310是M-S关系;3307、3309实现水平扩展,可进行写操作,而3308、3310进行读操作,前端使用Amoeba做为代理,这样就完成了读写分离。系统架构如下图所示:

Amoeba for Mysql水平扩展与读写分离 - 卢大圣 - 以一技之长得天下……

 

1、JDK的安装

从官网下载JDK5。上传到/usr/local目录下

chmod 755 jdk-1_5_0_22-linux-amd64.bin

./jdk-1_5_0_22-linux-amd64.bin 

设置环境变量,在 /etc/profile中添加如下三行

export JAVA_HOME=/usr/local/jdk1.5.0_22

export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

export PATH=$PATH:$JAVA_HOME/bin

使环境变量生效

source /etc/profile

验证环境变量是否生效

[root@localhost tmp]# java -version

java version "1.6.0"

OpenJDK  Runtime Environment (build 1.6.0-b09)

OpenJDK 64-Bit Server VM (build 1.6.0-b09, mixed mode)

2、Amoeba的安装

Amoeba下载地址:http://sourceforge.net/projects/amoeba/

创建Amoeba的家目录,并将其解压到/usr/local/amoeba目录下

mkdir /usr/local/amoeba;tar -zxvf amoeba-mysql-binary-2.2.0.tar.gz -C /usr/local/amoeba

验证Amoeba是否安装成功

[root@localhost bin]# pwd

/usr/local/amoeba/bin

[root@localhost bin]# ll

total 24

-rwxr-xr-x 1 root root 1651 Aug 29  2012 amoeba

-rwxr-xr-x 1 root root 1296 Aug 29  2012 amoeba.bat

-rwxr-xr-x 1 root root  141 Aug 29  2012 amoeba.classworlds

-rwxr-xr-x 1 root root 1620 Feb 29  2012 benchmark

-rwxr-xr-x 1 root root 1299 Feb 29  2012 benchmark.bat

-rwxr-xr-x 1 root root  151 Feb 29  2012 benchmark.classworlds

[root@localhost bin]# ./amoeba

amoeba start|stop --这样的结果是OK的!

3、MySQL的安装与配置

Mysql四Instance结构如下所示

[root@localhost data]# tree -L 2

|-- 3307
| |-- data
| |-- my.cnf
| `-- mysql.sock
|-- 3308
| |-- data
| |-- my.cnf
| `-- mysql.sock
|-- 3309
| |-- data
| |-- my.cnf
| `-- mysql.sock
`-- 3310
|-- data
|-- my.cnf
`-- mysql.sock

以3309与3310为例进行主从的配置

--3309

mysql> show master status;

+------------------+----------+--------------+------------------+-------------------+

| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |

+------------------+----------+--------------+------------------+-------------------+

| mysql-bin.000001 |      430 |              |                  |                   |

+------------------+----------+--------------+------------------+-------------------+

1 row in set (0.00 sec)

mysql> grant replication client,replication slave on *.* to "rep"@"127.0.0.1" identified by '123';

--3310

mysql> change master to master_host='127.0.0.1',master_port=3309,master_user='rep',master_password='123',master_log_file='mysql-bin.000001',master_log_pos=430;

--忽略主从验证的过程

4、Amoeda配置

由于配置文件篇幅太长,在这里只简单的列举几个关键点。

  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。

[root@node bin]# cat ../conf/dbServers.xml 

<?xml version="1.0" encoding="gbk"?>


<!DOCTYPE amoeba:dbServers SYSTEM "dbserver.dtd">

<amoeba:dbServers xmlns:amoeba="http://amoeba.meidusa.com/">

        <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>

                        <property name="schema">test</property><!--数据库名-->

                        <property name="user">root</property><!--数据库用户名-->

                        <property name="password">123</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="testOnReturn">true</property>

                        <property name="testWhileIdle">true</property>

                </poolConfig>

        </dbServer>

<!--定义了四个节点,两个主节点和两个从节点,由于端口号不一样,所以将其单独列出来, 如果密码和用户不一样同样可以添加到下面的配置项中,abstractServer是定义的一个抽象的节 点,下面的master1、master2、slave1、slave2等节点通过重用其信息,同时也可以对个别信息 进行个性化配置-->

        <dbServer name="master1"  parent="abstractServer">

                <factoryConfig>

                        <property name="ipAddress">127.0.0.1</property>

                        <property name="port">3307</property>

                </factoryConfig>

        </dbServer>


        <dbServer name="slave1"  parent="abstractServer">

                <factoryConfig>

                        <property name="ipAddress">127.0.0.1</property>

                        <property name="port">3308</property>

                </factoryConfig>

        </dbServer>


        <dbServer name="master2"  parent="abstractServer">

                <factoryConfig>

                        <property name="ipAddress">127.0.0.1</property>

                        <property name="port">3309</property>

                </factoryConfig>

        </dbServer>


        <dbServer name="slave2"  parent="abstractServer">

                <factoryConfig>

                        <property name="ipAddress">127.0.0.1</property>

                        <property name="port">3310</property>

                </factoryConfig>

        </dbServer>


</amoeba:dbServers>

[root@node bin]# cat ../conf/amoeba.xml 

<?xml version="1.0" encoding="gbk"?>

<!DOCTYPE amoeba:configuration SYSTEM "amoeba.dtd">

<amoeba:configuration xmlns:amoeba="http://amoeba.meidusa.com/">

        <proxy>

                <service name="Amoeba for Mysql" class="com.meidusa.amoeba.net.ServerableConnectionManager">

                        <property name="port">8066</property><!--Amoeba连接Mysql端口号-->

                        ……

                        <property name="authenticator">

                                <bean class="com.meidusa.amoeba.mysql.server.MysqlClientAuthenticator">

                                        <property name="user">root</property>

                                        <property name="password">1234</property>

<!--以上两行分别是连接msyql的用户名和密码,可以和各 实例的用户名和密码不一样-->

                                        ……

                                </bean>

                        </property>


                </service>

                <service name="Amoeba Monitor Server" class="com.meidusa.amoeba.monitor.MonitorServer">

                        ……

                </service>


                <runtime class="com.meidusa.amoeba.mysql.context.MysqlRuntimeContext">

                        ……

                </runtime>


        </proxy>


        <connectionManagerList>

                ……

        </connectionManagerList>


                <!-- default using file loader -->

        <dbServerLoader class="com.meidusa.amoeba.context.DBServerConfigFileLoader">

                <property name="configFile">${amoeba.home}/conf/dbServers.xml</property>

        </dbServerLoader>

<!--查询路由信息,其中defaultpool、readpool、writepool都只能填写一个-->

        <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">master1</property>

                <property name="writePool">master1</property>

                <property name="readPool">slave1</property>

                <property name="needParse">true</property>

        </queryRouter>

</amoeba:configuration>

[root@node bin]# vim ../conf/rule.xml 

<?xml version="1.0" encoding="gbk"?>

<!DOCTYPE amoeba:rule SYSTEM "rule.dtd">


<amoeba:rule xmlns:amoeba="http://amoeba.meidusa.com/">

<!--规则只与test库中的student表有关,默认池为slave1、slave2-->

        <tableRule name="student" schema="test" defaultPools="slave1,slave2">

<!--根据ID分配插入数据所在的位置-->

                <rule name="rule1">

                        <parameters>ID</parameters>

                        <expression><![CDATA[ ID <= 1000]]></expression>

                        <defaultPools>master1</defaultPools>

                        <writePools>master1</writePools>

                        <readPools>slave1</readPools>

                </rule>


                <rule name="rule2">

                        <parameters>ID</parameters>

                        <expression><![CDATA[ ID > 1000 ]]></expression>

                        <defaultPools>master2</defaultPools>

                        <writePools>master2</writePools>

                        <readPools>slave2</readPools>

                </rule>


        </tableRule>

</amoeba:rule>       


5、验证

在实例3307、3309上分别在test库中创建student表结构,语句如下:

create table student(ID int primary key auto_increment,name varchar(20),age int);

其中3307与3308、3309与3310主从正常工作,启动Amoeba进程,命令如下:

[root@node bin]# pwd

/usr/local/amoeda/bin

[root@node bin]# ./amoeba start &  

利用Amoeba登陆msyql,命令如下:

/usr/local/mysql/bin/mysql -h127.0.0.1 -P8066 -uroot -p1234

在表student中插入数据,在正常情况下,ID小于等于1000的数据将存储到3307/3308上,否则存储到3309/3310上,先进行如下操作:

mysql> insert into student (ID,name,age) values(1,'a',1);

Query OK, 1 row affected (0.07 sec)


mysql> insert into student (ID,name,age) values(1001,'b',1001);

Query OK, 1 row affected (0.00 sec)

停止实例3308的从服务器同步服务

stop slave;

继续利用Amoeba登陆数据库插入数据:

mysql> insert into student (ID,name,age) values(2,'c',2);

Query OK, 1 row affected (0.01 sec)


mysql> insert into student (ID,name,age) values(1002,'d',1002);

Query OK, 1 row affected (0.00 sec)


mysql> select * from student;

+------+------+------+

| ID   | name | age  |

+------+------+------+

|    1 | a    |    1 |

| 1001 | b    | 1001 |

| 1002 | d    | 1002 |

+------+------+------+

3 rows in set (0.01 sec)


注意:我们一共插入了四条语句,但是此时我们只查到了三条语句,这个从侧面证明了数据读的是从库。

打开3308从服务器同步服务

start slave;

利用Amoeba查询student表中的数据

mysql> select * from student;

+------+------+------+

| ID   | name | age  |

+------+------+------+

|    1 | a    |    1 |

|    2 | c    |    2 |

| 1001 | b    | 1001 |

| 1002 | d    | 1002 |

+------+------+------+

4 rows in set (0.00 sec)

分别查看3308、3310从服务器中的数据

--3308中的数据

mysql> select * from student;

+----+------+------+

| ID | name | age  |

+----+------+------+

|  1 | a    |    1 |

|  2 | c    |    2 |

+----+------+------+

2 rows in set (0.00 sec)

--3310中的数据

mysql> select * from student;

+------+------+------+

| ID   | name | age  |

+------+------+------+

| 1001 | b    | 1001 |

| 1002 | d    | 1002 |

+------+------+------+

2 rows in set (0.00 sec)

从上面的小例子我们可以看到数据水平的切分到了两个数据库中,并且读数据是从从库读取的!

6、注意事项

下面从利用Amoeba使用insert 语句的操作做一简要说明:

1.不支持insert into student(3,'c',3);必须写成insert into student(ID,name,age) values(3,'c',3);如果前面不指定路由字段,便会将SQL语句分发到各个写库中,所以同一条SQL语句会同时写两份,结果很可怕。

2.不支持insert into student(ID,name,age) values(3,'c',3),(4,'d',4);一次性插入多条语句

3.不支持truncate操作,由于上面配置的主服务器是master1,所以truncate操作只会truncate掉master1及slave1节点的数据信息,而master2与slave2信息则会保留

4.不支持order by 语句,只是将各个分库进行了order by,但是整体结果并不排序。

~~~~~~~~~~~~~~~~~~~

本文主要参考资料:http://docs.hexnova.com/amoeba/index.html

  评论这张
 
阅读(54)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017