代码改变世界

Ubuntu10下MySQL搭建Amoeba_读写分离+分片

2012-12-03 10:35  听风吹雨  阅读(2600)  评论(2编辑  收藏

一、背景知识

之前已经写了一篇关于Amoeba读写分离:Ubuntu10下MySQL搭建Amoeba_读写分离,上篇文章只是简单的测试下搭建读写分离,这里再加上一点的内容,在读写分离的基础上再加入分片。

阅读本篇文章之前建议你先阅读:

Ubuntu10下MySQL搭建Master/Slave

Ubuntu10下搭建MySQL Proxy读写分离

测试内容:把数据分片到Master1与Master2,再由Master1同步到Slave1,Master2同步到Slave2,把对数据的读取分布到Slave1和Slave2。

 

二、搭建过程

(一) 测试环境

Amoeba for MySQL:192.168.1.147

Master1:192.168.1.25

Slave1:192.168.1.30

Master2:192.168.1.35

Slave2:192.168.1.40

数据库为:dba_db,帐号密码统一为:test/123456,GRANT ALL ON *.* TO test@'%' IDENTIFIED BY '123456';

 

(二) 前期准备

1.      验证Amoeba是否安装成功的命令(如下图):/usr/local/amoeba/bin/amoeba


(Figure1:安装成功)

2.      启动amoeba:/usr/local/amoeba/bin/amoeba start


(Figure 2:启动成功)

 

(三) Amoeba读写分离+水平切片配置

1.      修改amoeba.xml,设置登陆amoeba的帐号密码。

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

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

2.      测试使用上面帐号是否正常登陆,如果出现上面的图2界面说明设置的帐号密码成功。

#mysql -u testuser -p -h 192.168.1.147 -P 8066

3.      修改dbServers.xml,设置数据库、登陆MySQL的帐号和密码。

<property name="schema">dba_db</property>

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

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

4.      修改dbServers.xml,设置数据库服务器的IP地址和服务器别名。

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

       <factoryConfig>

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

       </factoryConfig>

    </dbServer>

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

        <factoryConfig>

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

        </factoryConfig>

    </dbServer>

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

         <factoryConfig>

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

         </factoryConfig>

</dbServer>

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

         <factoryConfig>

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

         </factoryConfig>

</dbServer>

修改dbServers.xml,设置ROUNDROBIN(轮询策略);(省略或者注释)

<dbServer name="virtualSlave" virtual="true">

<poolConfig class="com.meidusa.amoeba.server.MultipleServerPool">

<!-- Load balancing strategy: 1=ROUNDROBIN , 2=WEIGHTBASED , 3=HA-->

<property name="loadbalance">1</property>

<property name="poolNames">Slave1,Slave2,Slave2</property>

</poolConfig>

</dbServer>

修改amoeba.xml,设置读写分离,修改queryRouter标签下的;(省略或者注释)

<property name="LRUMapSize">1500</property>

<property name="defaultPool">Master</property>

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

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

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

5.      修改rule.xml,添加对label表的读写分离+水平切片规则;

<tableRule name="label" schema="dba_db" defaultPools="Master1,Slave1,Master2,Slave2" writePools="Master1,Master2" readPools="Slave1,Slave2">

<rule name="rule1" ruleResult="POOLNAME">

<parameters>ID</parameters>

<expression><![CDATA[

var hashid = abs(hash(ID)) % 2;

case hashid when 0 then (isReadStatement?'Slave1':'Master1');

when 1 then (isReadStatement?'Slave2':'Master2');

end case;

]]></expression>

</rule>

</tableRule>

这个规则的意思是:把数据取模切片到Master1与Master2,再由Master1同步到Slave1,Master2同步到Slave2,对数据的读取分布到Slave1和Slave2。isReadStatement?'Slave1':'Master1'判断是否是读,如果是,分到Slave1,如果不是分到Master1。

6.      重新启动amoeba,如果出现上面的图2界面说明设置成功;

 

(四) MySQL的Master/Slave配置

1.      Master1服务器/etc/mysql/my.cnf目录 [mysqld] 区块中加上:

log-bin=mysql-bin

server-id=1

innodb_flush_log_at_trx_commit=1

sync_binlog=1

binlog_do_db=dba_db

binlog_ignore_db=mysql

2.      登陆Master1的MySQL,新建一个用户赋予“REPLICATION SLAVE”的权限。你不需要再赋予其它的权限:(因为是有两个Salve,所以使用了%)

mysql>use mysql;

mysql>create user viajar@'192.168.1.%' identified by '123456';

mysql>grant replication slave on *.* to viajar@'192.168.1.%' identified by '123456';

3.      重启Master的MySQL:

#service mysql restart

4.      获取Master1的binlog信息:(mysql-bin.000136,106)

mysql>SHOW MASTER logs;


Figure 3:Master信息)

5.      Slave1服务器/etc/mysql/my.cnf目录 [mysqld] 区块中加上:

server-id=2

6.      重启Slave1的MySQL:

#service mysql restart

7.      登陆Slave1的MySQL,执行命令:

mysql> change master to master_host='192.168.1.25', master_user='viajar', master_password='123456', master_log_file='mysql-bin.000136', master_log_pos=106;

8.      启动Slave1的Slave:

mysql>START SLAVE;

9.      检查Slave1的Slave是否正常:

mysql>show slave status\G;

10.   以同样的方式配置Master2、Slave2,第5步与第7步会有些差异。

 

(五) 验证读写分离+水平切片

1.      登陆到amoeba(147),插入下面的测试数据

INSERT INTO label(Id,NAME,Description,AddOn)

VALUES (1,'viajar','我的博客',NOW());

INSERT INTO label(Id,NAME,Description,AddOn)

VALUES (2,'viajar','我的博客',NOW());

INSERT INTO label(Id,NAME,Description,AddOn)

VALUES (3,'viajar','我的博客',NOW());

INSERT INTO label(Id,NAME,Description,AddOn)

VALUES (4,'viajar','我的博客',NOW());

2.      登陆Master1(25)、Slave1(30)分别验证数据的分布,看到数据都如下图所示:

mysql> SELECT * FROM label;


(Figure 4:Master1、Slave1)

3.      登陆Master2(35)、Slave2(40)分别验证数据的分布,看到数据都如下图所示:

mysql> SELECT * FROM label;


(Figure 5:Master2、Slave2)

       图4与图5已经证明了数据进行了水平切片。

       为了更明显的测试读写分离,我们修改几台服务器上的值:

master1mysql>UPDATE label SET NAME = 'master1';

slave1mysql>UPDATE label SET NAME = 'slave1';

master2mysql>UPDATE label SET NAME = 'master2';

slave2mysql>UPDATE label SET NAME = 'slave2';

4.      登陆Amoeba(147)验证数据的分布,看到数据都如下图所示:

mysql> SELECT * FROM label;

(Figure 6:Amoeba)

5.      登陆Amoeba(147)验证数据的分布,看到数据都如下图所示:

mysql> SELECT * FROM label WHERE id =1;

(Figure 7:Amoeba)

图4的意思是搭建从Master1到Slave1的replication成功了;

图5的意思是搭建从Master2到Slave2的replication成功了;

图6可以看到查询的都是从服务器上的数据;

图7的意思是在一定程度上达到了读写分离的效果了,Master2与Slave2同样有ID=1的记录,但是只返回了一条记录。

我们再进一步验证Amoeba读取到的这条记录是Master2还是Slave2的数据:

6.      停止Slave2上的Slave,删除id为1的记录,剩余图8中显示的数据:

mysql>stop slave

mysql>DELETE FROM label WHERE id =1;

(Figure 8:Slave2)

7.      到Amoeba上执行下面查询,查询返回的结果集:

mysql>SELECT * FROM label WHERE id =1;

(Figure 9:结果集为空)

到此Amoeba的读写分离+水平切片已经测试完毕。

 

三、注意事项

1.      在做Master/Slave的时候,我们有两台Salve,而且是内网的机器,所以使用了“192.168.1.%”这样的方式来创建用户,在一定的程度上保障帐号的安全性,又方便管理,使用“*”是错误的;

2.      对于多Slave的帐号问题,还可以有其它方式来创建帐号的,就是在Master为每个Slave创建独立的帐号和密码;

3.      修改log4j.xml 取消日志文件生成(太大了,磁盘很容易满),<param name="file" value="${amoeba.home}/logs/project.log"/>改成:<param name="file" value="<![CDATA[${amoeba.home}/logs/project.log>/dev/null]]>"/>

4.      性能优化,打开bin/amoeba,DEFAULT_OPTS="-server -Xms256m -Xmx256m -Xss128k"改成:DEFAULT_OPTS="-server -Xms512m -Xmx512m -Xmn100m -Xss1204k"Amoeba新版本MYSQL读写分离配置

5.      当tableRule中没有任何规则能命中该表,将操作tableRule配置的writePools(若没有配置则使用defaultPools)属性中的数据库节点;Amoeba切分规则配置详解

6.      当某个表在任何tableRules都没有被路由到,将操作queryRouter配置的writePools(若没有配置则使用defaultPools)属性中的数据库节点。

7.      rule的属性group表示规则的组名,若多个rule元素有相同的组名,则一旦命中不再验证后面的规则。

8.      rule的属性ruleResult有两个选项:POOLNAME和BOOLEAN。配置为POOLNAME则expression返回数据库节点名;配置为BOOLEAN则当expreesion返回true是操作writePools(若没有配置writePools则操作defaultPools)

9.      defaultPools、readPools、writePools均是一个或多个数据库节点名以逗号为分隔符连接的字符串。数据库节点名必须在dbServers.xml定义。需要切分的表名可以使用正则表达式,但是不允许用“.”号,因为目前“.”号作为schema与table的分割符号。 比如如果需要通配以“blog”开头的任意表名,需要写成:“blog[A-Za-z0-9]*”。

10.   所有的切片规则都一样,首先要知道切分规则并且要命中,所以要首先生成ID值,在插入的时候指明ID值;

 

四、疑问解答

1.      在Amoeba中执行mysql> SELECT * FROM label; 有可能会返回下图的结果集,造成这样的原因是在rule.xml的匹配过程中没有符合规则的(查询中没有带ID),所以它到每个数据库都执行了一次全表查询,再把数据记录合并起来;

应该如何防止这些情况的出现呢?如何在rule.xml的匹配规则中防止全表的查询?还有没类似全表查询这样类似的情况呢?

(Figure 10:结果集)

在rule.xml的tableRule标签中没有设置writePools="Master1,Master2" readPools="Slave1,Slave2"

2.      rule.xml中使用的函数能自定义嘛?ruleFunctionMap.xml是如何使用的?类似于我能不能把对UUID做hash,再对key值取模等这些规则放到配置中去呢?自定义的函数。amoeba-mysql-binary-2.1.0-RC5.tar.gz暂时还没有相关的文档:Amoeba:分布式数据库Proxy解决方案

 

五、参考文献

在Master/Slave结构下的读写分离基础

Amoeba切分规则配置详解规则比较有含量

Amoeba新版本MYSQL读写分离配置log4j.xml设置

Amoeba for mysql读写分离比较多的测试

Amoeba搞定mysql主从读写分离比较多的测试

MYSQL之--amoeba 实现读写分离,负载均衡百度文库

Amoeba使用指南

Mysql 基于 Amoeba 读写分离

Amoeba for Mysql 试用小结