基于mysql数据库集群的360度水平切割

1.why sharding?

     咱们都知道,信息行业发展日益迅速,积累下来的数据信息愈来愈多,互联网公司门要维护的数据日益庞大。设想一下,假如腾讯公司只用一个数据库的一张表格来存储全部qq注册用户的登陆相关信息,绝不夸张的说,那比如就是一场灾难,腾讯少说都有好几个亿的用户,全部的信息都存储在一个数据库的一张表中,那么咱们的sleect语句那得多么的消耗硬件资源,用户体验度那是至关的差的,基本上不能去运行了,那谁还去用qq,那怎么办呢,数据分割这时候就派上用场了,它根据数据的特性,将一张表单上的内容根据实际需求分割成多张表单,存储在不一样的真实的服务器器上,可以作到指定用户访问指定的服务器,缩小表单,减少单个服务器的压力。其实这样作带来的好处还远不止缩小了表单的大小,来提升用户体验,其实,将数据分割,还能够减少锁表的几率,不会去锁整张表的内容,提升了表的可用率,当单台数据库服务器宕机了,也是是损坏了数据的一小部分,不会致使全部的数据都丢失,数据切割能带来这么多好处,何乐而不为呢?mysql

取模和用户量分布计算
取值说明: user_id % 360 这个取模值均匀的分布到这12台DB,
全部server的库名相同,表结构保持一致,
DB_Server1 0~30度 用户数量为:2583354
DB_Server2 31~60度 用户数量为:2500020
DB_Server3 61~90度 用户数量为:2500020
DB_Server4 91~120度 用户数量为:2500019
DB_Server5 121~150度 用户数量为:2499990
DB_Server6 151~180度 用户数量为:2499990
DB_Server7 181~210度 用户数量为:2499990
DB_Server8 211~240 度 用户数量为:2499990
DB_Server9 241~270 度 用户数量为:2499990
DB_Server10 271~300 度 用户数量为:2499990
DB_Server11 301~330 度 用户数量为:2499990
DB_Server12 331~360 度 用户数量为:2416657

DB架构图
当第一个360度环形库,用户量超过3000万怎么办???开始扩容第二个360度环形库

sql

 

2.数据原型

数据原形:一个数据库,用来存储用户的编号,姓名,以及地址(固然,你能够有多个数据库做为数据原形,能够用到垂直分割进行处理,这里直接用一个数据库做为数据原型进行数据水平切割处理)由于仅仅是去实现水平分割,不作读写分离、也不配置双机热备,因此仅仅须要三台机器,两台独立的mysql服务器,一台amoeba代理服务器便可。
数据库

 

3.环境介绍

 

Mysql_server1--IP:192.168.1.135(服务器1)
Msyql_serrver2---IP:192.168.1.136(从服务器2)
Amoeba_server--IP:192.168.1.137(代理服务器)express

 

 

四、设置Mysql_server1 Mysql_server2 设置Amoeba远程访问受权

(首先受权登陆mysql服务器的用户,两台mysql服务器都要进行受权)
mysql-->grant all privileges on *.* to amoeba@'%' identified by 'amoeba';
mysql-->flush privileges;

数组

五、建立测试表

(1)在Mysql_server1 和mysql_server2 上。注意:两边的表结构以及表名是同样的.
建立test表
create table test (
user_id integer unsigned not null,
user_name varchar(45),
user_address varchar(100),
primary key (user_id)
)engine=innodb;  ·  
Query OK, 0 rows affected (0.01 sec
bash

 

6.amoeba.xml相关配置(安装amoeba略,见前一篇mysql的读写分离)

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

<!DOCTYPE amoeba:configuration SYSTEM "amoeba.dtd">
<amoeba:configuration xmlns:amoeba="">http://amoeba.meidusa.com/">

<!--
amoeba开放接口相关配置
-->
<server>
<!-- proxy server绑定的端口 -->
<property name="port">9006</property>

<!-- proxy server绑定的IP -->
<property name="ipAddress">192.168.1.137</property>

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

<!-- socket Send and receive BufferSize(unit:K) -->
<property name="netBufferSize">128</property>

<!-- Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm). -->
<property name="tcpNoDelay">true</property>

<!-- 对外验证的用户名 -->
<property name="user">amoeba</property>

<!-- 对外验证的密码 -->
<property name="password">aixocm</property>


<!-- query timeout( default: 60 second , TimeUnit:second) -->
<property name="queryTimeout">60</property>
</server>

<!--
每一个ConnectionManager都将做为一个线程启动。
manager负责Connection IO读写/死亡检测
-->
<connectionManagerList>
<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>

<dbServerList>
<!--
一台mysqlServer 须要配置一个pool,
若是多台 平等的mysql须要进行loadBalance,
平台已经提供一个具备负载均衡能力的objectPool:com.meidusa.amoeba.mysql.server.MultipleServerPool
简单的配置是属性加上 virtual="true",该Pool 不容许配置factoryConfig
或者本身写一个ObjectPool。
-->

<!--
mysql服务器受权相关设置
-->
<dbServer name="server1">

<!-- PoolableObjectFactory实现类 -->
<factoryConfig class="com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory">
<property name="manager">defaultManager</property>

<!-- 真实mysql数据库端口 -->
<property name="port">3306</property>

<!-- 真实mysql数据库IP -->
<property name="ipAddress">192.168.1.135</property>

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

<!-- 用于登录mysql的用户名 -->
<property name="user">amoeba</property>

<!-- 用于登录mysql的密码 -->
<property name="password">amoeba</property>


</factoryConfig>

<!-- ObjectPool实现类 -->
<poolConfig class="com.meidusa.amoeba.net.poolable.PoolableObjectPool">
<property name="maxActive">200</property>
<property name="maxIdle">200</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>


<!--
mysql服务器受权相关设置
-->
<dbServer name="server2">

<!-- PoolableObjectFactory实现类 -->
<factoryConfig class="com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory">
<property name="manager">defaultManager</property>

<!-- 真实mysql数据库端口 -->
<property name="port">3306</property>

<!-- 真实mysql数据库IP -->
<property name="ipAddress">192.168.1.136</property>

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

<!-- 用于登录mysql的用户名 -->
<property name="user">amoeba</property>

<!-- 用于登录mysql的密码 -->
<property name="password">amoeba</property>


</factoryConfig>

<!-- ObjectPool实现类 -->
<poolConfig class="com.meidusa.amoeba.net.poolable.PoolableObjectPool">
<property name="maxActive">200</property>
<property name="maxIdle">200</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>

</dbServerList>
<queryRouter class="com.meidusa.amoeba.mysql.parser.MysqlQueryRouter">
<property name="ruleConfig">${amoeba.home}/conf/rule.xml</property>
<property name="functionConfig">${amoeba.home}/conf/functionMap.xml</property>
<property name="ruleFunctionConfig">${amoeba.home}/conf/ruleFunctionMap.xml</property>
<property name="LRUMapSize">1500</property>

<property name="defaultPool">server1</property>
<!--
;默认地址池必定要开启
<property name="writePool">master</property>
<property name="readPool">slave</property>
<property name="needParse">true</property>
-->
</queryRouter>
</amoeba:configuration>
服务器

 

7.rule.xml相关配置

基于user_id的水平分割,360水平分割法,前提user_id是连续的。架构

<?xml version="1.0" encoding="gbk"?>
<!DOCTYPE amoeba:rule SYSTEM "rule.dtd">

<amoeba:rule xmlns:amoeba="">http://amoeba.meidusa.com/">
<tableRule name="test" schema="test" defaultPools="server1,server2">

<rule name="rule1">
<parameters>user_id</parameters>
<expression><![CDATA[
user_id % 360 >=0 and user_id % 360 <=180         ;分红两份,(1-180)+360而且小于5000000存在一个数据库
]]></expression>
<defaultPools>server1</defaultPools>
<readPools>server1</readPools>
<writePools>server1</writePools>
</rule>

<rule name="rule2">
<parameters>user_id</parameters>
<expression><![CDATA[
user_id % 360 >=181 and user_id % 360 <=360     (181-360)+360而且小于5000000存在于一个数据库
]]></expression>
<defaultPools>server2</defaultPools>
<writePools>server2</writePools>
<readPools>server2</readPools>
</rule>
<!--
<rule name="rule4">
<parameters>ID</parameters>
<expression><![CDATA[ ID > 20000000 ]]></expression>
<defaultPools>server3</defaultPools>
</rule>

<rule name="rule3">
<parameters>ID,CREATE_TIME</parameters>
<expression><![CDATA[ID>4 or CREATE_TIME between to_date('2008-11-12 00:00:00.0000') and to_date('2008-12-10 00:00:00.0000') ]]></expression>
<defaultPools>server3</defaultPools>
</rule>
-->
</tableRule>

</amoeba:rule>
app

 

8.启动服务

#:nohup bash -x amoeba & 
这样的启动方法是为了方便查看启动的过程,会生成nohup.out的文件记录启动过程
负载均衡

从新启动服务须要先杀死已经启动的服务再从新启动服务

ps -ef|grep amoeba|awk '{print $2}'|xargs kill -9

 

九、插入测试数据

在Amoeba Server登陆:
# mysql -uamoeba -paixocm -h 192.168.1.137 -P 9006
mysql->use test;
mysql->insert into test(user_id,user_name,user_address) values('1','user1','China');
特别提示,必定要将表的数组名带上,特别是用来做为水平分割的数组名,若是不接上,分割失败,会在两个服务器上所有插入数据。
mysql->insert into test(user_id,user_name,user_address) values('2','user1','China');
mysql->insert into test(user_id,user_name,user_address) values('3','user1','China');
mysql->insert into test(user_id,user_name,user_address) values('181','user1','China');
mysql->insert into test(user_id,user_name,user_address) values('182','user1','China');
mysql->insert into test(user_id,user_name,user_address) values('183','user1','China');

mysql_server1查看,user_id在1-180数据所有写入了server1

mysql_server2查看,user_id在181-360数据所有写入了server2


 

10.总结:

(1)、amoeba 是根据 sql 解析来进行水平切分的, 须要把切分的关键字段(这里是user_id),加入到insert  sql 语句 中。不然 切分规则无效。无效后,会在 server1, server2 均都插入数据。(2)、amoeba插入数据的时候必须先use  dbname(好比要先use test库名,或者查询带上库名和表名,test.t_user) 不然插入数据会默认插到server1上面(3)、在rule.xml 指定的ID范围,在插入数据user_id的时候。不能超过这个范围,不然分片无效,好比定义的ID范围为:1-500000号insert into zyalvin(user_id,user_name,user_address)values('5000001','user1','China'); 若是插入ID超过5000000,变成了5000001的话那么这个数据将同时写到server1和server2 致使分片无效。

相关文章
相关标签/搜索