咱們都知道,信息行業發展日益迅速,積累下來的數據信息愈來愈多,互聯網公司門要維護的數據日益龐大。設想一下,假如騰訊公司只用一個數據庫的一張表格來存儲全部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
數據原形:一個數據庫,用來存儲用戶的編號,姓名,以及地址(固然,你能夠有多個數據庫做爲數據原形,能夠用到垂直分割進行處理,這裏直接用一個數據庫做爲數據原型進行數據水平切割處理)由於僅僅是去實現水平分割,不作讀寫分離、也不配置雙機熱備,因此僅僅須要三臺機器,兩臺獨立的mysql服務器,一臺amoeba代理服務器便可。
數據庫
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服務器的用戶,兩臺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 secbash
<?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> 服務器
基於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
#: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
(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 致使分片無效。