一,什么是mysql分表,分區(qū)
成都創(chuàng)新互聯(lián)是創(chuàng)新、創(chuàng)意、研發(fā)型一體的綜合型網(wǎng)站建設(shè)公司,自成立以來公司不斷探索創(chuàng)新,始終堅(jiān)持為客戶提供滿意周到的服務(wù),在本地打下了良好的口碑,在過去的十多年時(shí)間我們累計(jì)服務(wù)了上千家以及全國政企客戶,如成都石牌坊等企業(yè)單位,完善的項(xiàng)目管理流程,嚴(yán)格把控項(xiàng)目進(jìn)度與質(zhì)量監(jiān)控加上過硬的技術(shù)實(shí)力獲得客戶的一致贊賞。
什么是分表,從表面意思上看呢,就是把一張表分成N多個(gè)小表,具體請(qǐng)看mysql分表的3種方法
什么是分區(qū),分區(qū)呢就是把一張表的數(shù)據(jù)分成N多個(gè)區(qū)塊,這些區(qū)塊可以在同一個(gè)磁盤上,也可以在不同的磁盤上
一,先說一下為什么要分表
當(dāng)一張的數(shù)據(jù)達(dá)到幾百萬時(shí),你查詢一次所花的時(shí)間會(huì)變多,如果有聯(lián)合查詢的話,我想有可能會(huì)死在那兒了。分表的目的就在于此,減小數(shù)據(jù)庫的負(fù)擔(dān),縮短查詢時(shí)間。
根據(jù)個(gè)人經(jīng)驗(yàn),mysql執(zhí)行一個(gè)sql的過程如下:
1,接收到sql;2,把sql放到排隊(duì)隊(duì)列中 ;3,執(zhí)行sql;4,返回執(zhí)行結(jié)果。在這個(gè)執(zhí)行過程中最花時(shí)間在什么地方呢?第一,是排隊(duì)等待的時(shí)間,第二,sql的執(zhí)行時(shí)間。其實(shí)這二個(gè)是一回事,等待的同時(shí),肯定有sql在執(zhí)行。所以我們要縮短sql的執(zhí)行時(shí)間。
mysql中有一種機(jī)制是表鎖定和行鎖定,為什么要出現(xiàn)這種機(jī)制,是為了保證數(shù)據(jù)的完整性,我舉個(gè)例子來說吧,如果有二個(gè)sql都要修改同一張表的同一條數(shù)據(jù),這個(gè)時(shí)候怎么辦呢,是不是二個(gè)sql都可以同時(shí)修改這條數(shù)據(jù)呢?很顯然mysql對(duì)這種情況的處理是,一種是表鎖定(myisam存儲(chǔ)引擎),一個(gè)是行鎖定(innodb存儲(chǔ)引擎)。表鎖定表示你們都不能對(duì)這張表進(jìn)行操作,必須等我對(duì)表操作完才行。行鎖定也一樣,別的sql必須等我對(duì)這條數(shù)據(jù)操作完了,才能對(duì)這條數(shù)據(jù)進(jìn)行操作。如果數(shù)據(jù)太多,一次執(zhí)行的時(shí)間太長(zhǎng),等待的時(shí)間就越長(zhǎng),這也是我們?yōu)槭裁匆直淼脑颉?/p>
二,分表
1,做mysql集群,例如:利用mysql cluster ,mysql proxy,mysql replication,drdb等等
有人會(huì)問mysql集群,根分表有什么關(guān)系嗎?雖然它不是實(shí)際意義上的分表,但是它啟到了分表的作用,做集群的意義是什么呢?為一個(gè)數(shù)據(jù)庫減輕負(fù)擔(dān),說白了就是減少sql排隊(duì)隊(duì)列中的sql的數(shù)量,舉個(gè)例子:有10個(gè)sql請(qǐng)求,如果放在一個(gè)數(shù)據(jù)庫服務(wù)器的排隊(duì)隊(duì)列中,他要等很長(zhǎng)時(shí)間,如果把這10個(gè)sql請(qǐng)求,分配到5個(gè)數(shù)據(jù)庫服務(wù)器的排隊(duì)隊(duì)列中,一個(gè)數(shù)據(jù)庫服務(wù)器的隊(duì)列中只有2個(gè),這樣等待時(shí)間是不是大大的縮短了呢?這已經(jīng)很明顯了。所以我把它列到了分表的范圍以內(nèi),我做過一些mysql的集群:
linux mysql proxy 的安裝,配置,以及讀寫分離
mysql replication 互為主從的安裝及配置,以及數(shù)據(jù)同步
優(yōu)點(diǎn):擴(kuò)展性好,沒有多個(gè)分表后的復(fù)雜操作(php代碼)
缺點(diǎn):?jiǎn)蝹€(gè)表的數(shù)據(jù)量還是沒有變,一次操作所花的時(shí)間還是那么多,硬件開銷大。
2,預(yù)先估計(jì)會(huì)出現(xiàn)大數(shù)據(jù)量并且訪問頻繁的表,將其分為若干個(gè)表
這種預(yù)估大差不差的,論壇里面發(fā)表帖子的表,時(shí)間長(zhǎng)了這張表肯定很大,幾十萬,幾百萬都有可能。 聊天室里面信息表,幾十個(gè)人在一起一聊一個(gè)晚上,時(shí)間長(zhǎng)了,這張表的數(shù)據(jù)肯定很大。像這樣的情況很多。所以這種能預(yù)估出來的大數(shù)據(jù)量表,我們就事先分出個(gè)N個(gè)表,這個(gè)N是多少,根據(jù)實(shí)際情況而定。以聊天信息表為例:
我事先建100個(gè)這樣的表,message_00,message_01,message_02..........message_98,message_99.然后根據(jù)用戶的ID來判斷這個(gè)用戶的聊天信息放到哪張表里面,你可以用hash的方式來獲得,可以用求余的方式來獲得,方法很多,各人想各人的吧。下面用hash的方法來獲得表名:
查看復(fù)制打印?
?php
function get_hash_table($table,$userid) {
$str = crc32($userid);
if($str0){
$hash = "0".substr(abs($str), 0, 1);
}else{
$hash = substr($str, 0, 2);
}
return $table."_".$hash;
}
echo get_hash_table('message','user18991'); //結(jié)果為message_10
echo get_hash_table('message','user34523'); //結(jié)果為message_13
?
說明一下,上面的這個(gè)方法,告訴我們user18991這個(gè)用戶的消息都記錄在message_10這張表里,user34523這個(gè)用戶的消息都記錄在message_13這張表里,讀取的時(shí)候,只要從各自的表中讀取就行了。
優(yōu)點(diǎn):避免一張表出現(xiàn)幾百萬條數(shù)據(jù),縮短了一條sql的執(zhí)行時(shí)間
缺點(diǎn):當(dāng)一種規(guī)則確定時(shí),打破這條規(guī)則會(huì)很麻煩,上面的例子中我用的hash算法是crc32,如果我現(xiàn)在不想用這個(gè)算法了,改用md5后,會(huì)使同一個(gè)用戶的消息被存儲(chǔ)到不同的表中,這樣數(shù)據(jù)亂套了。擴(kuò)展性很差。
3,利用merge存儲(chǔ)引擎來實(shí)現(xiàn)分表
我覺得這種方法比較適合,那些沒有事先考慮,而已經(jīng)出現(xiàn)了得,數(shù)據(jù)查詢慢的情況。這個(gè)時(shí)候如果要把已有的大數(shù)據(jù)量表分開比較痛苦,最痛苦的事就是改代碼,因?yàn)槌绦蚶锩娴膕ql語句已經(jīng)寫好了,現(xiàn)在一張表要分成幾十張表,甚至上百張表,這樣sql語句是不是要重寫呢?舉個(gè)例子,我很喜歡舉子
mysqlshow engines;的時(shí)候你會(huì)發(fā)現(xiàn)mrg_myisam其實(shí)就是merge。
查看復(fù)制打印?
mysql CREATE TABLE IF NOT EXISTS `user1` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `name` varchar(50) DEFAULT NULL,
- `sex` int(1) NOT NULL DEFAULT '0',
- PRIMARY KEY (`id`)
- ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
Query OK, 0 rows affected (0.05 sec)
mysql CREATE TABLE IF NOT EXISTS `user2` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `name` varchar(50) DEFAULT NULL,
- `sex` int(1) NOT NULL DEFAULT '0',
- PRIMARY KEY (`id`)
- ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
Query OK, 0 rows affected (0.01 sec)
mysql INSERT INTO `user1` (`name`, `sex`) VALUES('張映', 0);
Query OK, 1 row affected (0.00 sec)
mysql INSERT INTO `user2` (`name`, `sex`) VALUES('tank', 1);
Query OK, 1 row affected (0.00 sec)
mysql CREATE TABLE IF NOT EXISTS `alluser` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `name` varchar(50) DEFAULT NULL,
- `sex` int(1) NOT NULL DEFAULT '0',
- INDEX(id)
- ) TYPE=MERGE UNION=(user1,user2) INSERT_METHOD=LAST AUTO_INCREMENT=1 ;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql select id,name,sex from alluser;
+----+--------+-----+
| id | name | sex |
+----+--------+-----+
| 1 | 張映 | 0 |
| 1 | tank | 1 |
+----+--------+-----+
2 rows in set (0.00 sec)
mysql INSERT INTO `alluser` (`name`, `sex`) VALUES('tank2', 0);
Query OK, 1 row affected (0.00 sec)
mysql select id,name,sex from user2
- ;
+----+-------+-----+
| id | name | sex |
+----+-------+-----+
| 1 | tank | 1 |
| 2 | tank2 | 0 |
+----+-------+-----+
2 rows in set (0.00 sec)
從上面的操作中,我不知道你有沒有發(fā)現(xiàn)點(diǎn)什么?假如我有一張用戶表user,有50W條數(shù)據(jù),現(xiàn)在要拆成二張表user1和user2,每張表25W條數(shù)據(jù),
INSERT INTO user1(user1.id,user1.name,user1.sex)SELECT (user.id,user.name,user.sex)FROM user where user.id = 250000
INSERT INTO user2(user2.id,user2.name,user2.sex)SELECT (user.id,user.name,user.sex)FROM user where user.id 250000
這樣我就成功的將一張user表,分成了二個(gè)表,這個(gè)時(shí)候有一個(gè)問題,代碼中的sql語句怎么辦,以前是一張表,現(xiàn)在變成二張表了,代碼改動(dòng)很大,這樣給程序員帶來了很大的工作量,有沒有好的辦法解決這一點(diǎn)呢?辦法是把以前的user表備份一下,然后刪除掉,上面的操作中我建立了一個(gè)alluser表,只把這個(gè)alluser表的表名改成user就行了。但是,不是所有的mysql操作都能用的
a,如果你使用 alter table 來把 merge 表變?yōu)槠渌眍愋?,到底層表的映射就被丟失了。取而代之的,來自底層 myisam 表的行被復(fù)制到已更換的表中,該表隨后被指定新類型。
b,網(wǎng)上看到一些說replace不起作用,我試了一下可以起作用的。暈一個(gè)先
mysql UPDATE alluser SET sex=REPLACE(sex, 0, 1) where id=2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql select * from alluser;
+----+--------+-----+
| id | name | sex |
+----+--------+-----+
| 1 | 張映 | 0 |
| 1 | tank | 1 |
| 2 | tank2 | 1 |
+----+--------+-----+
3 rows in set (0.00 sec)
c,一個(gè) merge 表不能在整個(gè)表上維持 unique 約束。當(dāng)你執(zhí)行一個(gè) insert,數(shù)據(jù)進(jìn)入第一個(gè)或者最后一個(gè) myisam 表(取決于 insert_method 選項(xiàng)的值)。mysql 確保唯一鍵值在那個(gè) myisam 表里保持唯一,但不是跨集合里所有的表。
d,當(dāng)你創(chuàng)建一個(gè) merge 表之時(shí),沒有檢查去確保底層表的存在以及有相同的機(jī)構(gòu)。當(dāng) merge 表被使用之時(shí),mysql 檢查每個(gè)被映射的表的記錄長(zhǎng)度是否相等,但這并不十分可靠。如果你從不相似的 myisam 表創(chuàng)建一個(gè) merge 表,你非常有可能撞見奇怪的問題。
優(yōu)點(diǎn):擴(kuò)展性好,并且程序代碼改動(dòng)的不是很大
缺點(diǎn):這種方法的效果比第二種要差一點(diǎn)
三,總結(jié)一下
上面提到的三種方法,我實(shí)際做過二種,第一種和第二種。第三種沒有做過,所以說的細(xì)一點(diǎn)。哈哈。做什么事都有一個(gè)度,超過個(gè)度就過變得很差,不能一味的做數(shù)據(jù)庫服務(wù)器集群,硬件是要花錢買的,也不要一味的分表,分出來1000表,mysql的存儲(chǔ)歸根到底還以文件的形勢(shì)存在硬盤上面,一張表對(duì)應(yīng)三個(gè)文件,1000個(gè)分表就是對(duì)應(yīng)3000個(gè)文件,這樣檢索起來也會(huì)變的很慢。我的建議是
方法1和方法2結(jié)合的方式來進(jìn)行分表
方法1和方法3結(jié)合的方式來進(jìn)行分表
我的二個(gè)建議適合不同的情況,根據(jù)個(gè)人情況而定,我覺得會(huì)有很多人選擇方法1和方法3結(jié)合的方式
二,mysql分表和分區(qū)有什么區(qū)別呢
1,實(shí)現(xiàn)方式上
a),mysql的分表是真正的分表,一張表分成很多表后,每一個(gè)小表都是完正的一張表,都對(duì)應(yīng)三個(gè)文件,一個(gè).MYD數(shù)據(jù)文件,.MYI索引文件,.frm表結(jié)構(gòu)文件。
[root@BlackGhost test]# ls |grep user
alluser.MRG
alluser.frm
user1.MYD
user1.MYI
user1.frm
user2.MYD
user2.MYI
user2.frm
Php代碼
[root@BlackGhost test]# ls |grep user
alluser.MRG
alluser.frm
user1.MYD
user1.MYI
user1.frm
user2.MYD
user2.MYI
user2.frm
簡(jiǎn)單說明一下,上面的分表呢是利用了merge存儲(chǔ)引擎(分表的一種),alluser是總表,下面有二個(gè)分表,user1,user2。他們二個(gè)都是獨(dú)立的表,取數(shù)據(jù)的時(shí)候,我們可以通過總表來取。這里總表是沒有.MYD,.MYI這二個(gè)文件的,也就是說,總表他不是一張表,沒有數(shù)據(jù),數(shù)據(jù)都放在分表里面。我們來看看.MRG到底是什么東西
[root@BlackGhost test]# cat alluser.MRG |more
user1
user2
#INSERT_METHOD=LAST
Php代碼
[root@BlackGhost test]# cat alluser.MRG |more
user1
user2
#INSERT_METHOD=LAST
從上面我們可以看出,alluser.MRG里面就存了一些分表的關(guān)系,以及插入數(shù)據(jù)的方式。可以把總表理解成一個(gè)外殼,或者是聯(lián)接池。
b),分區(qū)不一樣,一張大表進(jìn)行分區(qū)后,他還是一張表,不會(huì)變成二張表,但是他存放數(shù)據(jù)的區(qū)塊變多了。
[root@BlackGhost test]# ls |grep aa
aa#P#p1.MYD
aa#P#p1.MYI
aa#P#p3.MYD
aa#P#p3.MYI
aa.frm
aa.par
Php代碼
[root@BlackGhost test]# ls |grep aa
aa#P#p1.MYD
aa#P#p1.MYI
aa#P#p3.MYD
aa#P#p3.MYI
aa.frm
aa.par
從上面我們可以看出,aa這張表,分為二個(gè)區(qū),p1和p3,本來是三個(gè)區(qū),被我刪了一個(gè)區(qū)。我們都知道一張表對(duì)應(yīng)三個(gè)文件.MYD,.MYI,.frm。分區(qū)呢根據(jù)一定的規(guī)則把數(shù)據(jù)文件和索引文件進(jìn)行了分割,還多出了一個(gè).par文件,打開.par文件后你可以看出他記錄了,這張表的分區(qū)信息,根分表中的.MRG有點(diǎn)像。分區(qū)后,還是一張,而不是多張表。
2,數(shù)據(jù)處理上
a),分表后,數(shù)據(jù)都是存放在分表里,總表只是一個(gè)外殼,存取數(shù)據(jù)發(fā)生在一個(gè)一個(gè)的分表里面??聪旅娴睦樱?/p>
select * from alluser where id=’12′表面上看,是對(duì)表alluser進(jìn)行操作的,其實(shí)不是的。是對(duì)alluser里面的分表進(jìn)行了操作。
b),分區(qū)呢,不存在分表的概念,分區(qū)只不過把存放數(shù)據(jù)的文件分成了許多小塊,分區(qū)后的表呢,還是一張表。數(shù)據(jù)處理還是由自己來完成。
3,提高性能上
a),分表后,單表的并發(fā)能力提高了,磁盤I/O性能也提高了。并發(fā)能力為什么提高了呢,因?yàn)椴閷ひ淮嗡ǖ臅r(shí)間變短了,如果出現(xiàn)高并發(fā)的話,總表可以根據(jù)不同的查詢,將并發(fā)壓力分到不同的小表里面。磁盤I/O性能怎么搞高了呢,本來一個(gè)非常大的.MYD文件現(xiàn)在也分?jǐn)偟礁鱾€(gè)小表的.MYD中去了。
b),mysql提出了分區(qū)的概念,我覺得就想突破磁盤I/O瓶頸,想提高磁盤的讀寫能力,來增加mysql性能。
在這一點(diǎn)上,分區(qū)和分表的測(cè)重點(diǎn)不同,分表重點(diǎn)是存取數(shù)據(jù)時(shí),如何提高mysql并發(fā)能力上;而分區(qū)呢,如何突破磁盤的讀寫能力,從而達(dá)到提高mysql性能的目的。
4),實(shí)現(xiàn)的難易度上
a),分表的方法有很多,用merge來分表,是最簡(jiǎn)單的一種方式。這種方式根分區(qū)難易度差不多,并且對(duì)程序代碼來說可以做到透明的。如果是用其他分表方式就比分區(qū)麻煩了。
b),分區(qū)實(shí)現(xiàn)是比較簡(jiǎn)單的,建立分區(qū)表,根建平常的表沒什么區(qū)別,并且對(duì)開代碼端來說是透明的。
三,mysql分表和分區(qū)有什么聯(lián)系呢
1,都能提高mysql的性高,在高并發(fā)狀態(tài)下都有一個(gè)良好的表面。
2,分表和分區(qū)不矛盾,可以相互配合的,對(duì)于那些大訪問量,并且表數(shù)據(jù)比較多的表,我們可以采取分表和分區(qū)結(jié)合的方式(如果merge這種分表方式,不能和分區(qū)配合的話,可以用其他的分表試),訪問量不大,但是表數(shù)據(jù)很多的表,我們可以采取分區(qū)的方式等。
1、首先我們建立一個(gè)表表的數(shù)據(jù),這個(gè)表里有25條數(shù)據(jù),id從1到25。(下圖是部分截圖)
2、要分頁數(shù)據(jù),首先我們假設(shè)一頁有10條數(shù)據(jù),我們可以用mysql的limit關(guān)鍵字來限定返回多少條數(shù)據(jù)。并且用orderby來排序數(shù)據(jù),這里用id來排序。所以第一頁的sql可以如圖這樣寫。
3、執(zhí)行后得到的數(shù)據(jù)如圖,就是id從1到10的前10條數(shù)據(jù),因?yàn)槲覀兪前磇d升序來排序的。
4、上面第一頁的sql是簡(jiǎn)化的寫法,完整的寫法如圖,得到的結(jié)果和上圖的一模一樣。代碼里limit0,10的意思是從第一條數(shù)據(jù)開始,取10條數(shù)據(jù)。(注意的是第一條數(shù)據(jù)是從0開始的)
5、那么第二頁的數(shù)據(jù),關(guān)鍵是要知道是從哪一條數(shù)據(jù)開始,可以用這個(gè)公式得到:(頁碼-1)?*每頁顯示多少條,即(2-1)*10=10,所以sql語句如圖,limit10,10。
6、執(zhí)行后,結(jié)果正確,得到id從11到20的10條數(shù)據(jù)。
7、同理第三頁數(shù)據(jù)的sql如圖,br/就是limit20,10。
8、查詢的結(jié)果如圖,因?yàn)檫@頁只剩下5條數(shù)據(jù)了,所以只顯示5條數(shù)據(jù)。如果你有更多頁的數(shù)據(jù),后面的數(shù)據(jù)只需要按上面的公式,得到從哪行開始,就可以寫對(duì)應(yīng)的sql語句了。
Mysql分頁采用limt關(guān)鍵字 select * from t_order limit 5,10; #返回第6-15行數(shù)據(jù) select * from t_order limit 5; #返回前5行 select * from t_order limit 0,5; #返回前5行 Mssql 2000分頁采用top關(guān)鍵字(20005以上版本也支持關(guān)鍵字rownum) Select top 10 * from t_order where id not in (select id from t_order where id5 ); //返回第6到15行數(shù)據(jù) 其中10表示取10記錄 5表示從第5條記錄開始取
Oracle分頁
①采用rownum關(guān)鍵字(三層嵌套) SELECT * FROM( SELECT A.*,ROWNUM num FROM (SELECT * FROM t_order)A WHERE ROWNUM=15) WHERE num=5;--返回第5-15行數(shù)據(jù) ②采用row_number解析函數(shù)進(jìn)行分頁(效率更高) SELECT xx.* FROM( SELECT t.*,row_number() over(ORDER BY o_id)AS num FROM t_order t )xx WHERE num BETWEEN 5 AND 15; --返回第5-15行數(shù)據(jù) 解析函數(shù)能用格式 函數(shù)() over(pertion by 字段 order by 字段); Pertion 按照某個(gè)字段分區(qū) Order 按照勒個(gè)字段排序 用分析函數(shù) 一萬條后翻最后一頁會(huì)很慢,使用ROWNUM 一萬條之后每翻一頁都會(huì)慢
希望對(duì)你有所幫助
參考:
圖中是兩組分片,紅色我們稱為shard1,藍(lán)色我們稱為shard2
51 52是服務(wù)器
兩個(gè)3307互為主從(雙主),3309是本地3307的從庫
說明:沒有明確說明是只在某一個(gè)節(jié)點(diǎn)上做的,就是兩個(gè)節(jié)點(diǎn)都做
兩臺(tái)虛擬機(jī) db01 db02
每臺(tái)創(chuàng)建四個(gè)mysql實(shí)例:3307 3308 3309 3310
mysql軟件我們之前已完成二進(jìn)制安裝,直接初始化即可
我們server-id規(guī)劃為:db01上是7/8/9/10,db02上是17/18/19/20
"箭頭指向誰是主庫"
10.0.0.51:3307 ----- 10.0.0.52:3307
10.0.0.51:3309 ------ 10.0.0.51:3307
10.0.0.52:3309 ------ 10.0.0.52:3307
兩個(gè)分片,每個(gè)分片四個(gè)mysql節(jié)點(diǎn)
shard1:
Master:10.0.0.51:3307
slave1:10.0.0.51:3309
Standby Master:10.0.0.52:3307
slave2:10.0.0.52:3309
shard2:
Master:10.0.0.52:3308
slave1:10.0.0.52:3310
Standby Master:10.0.0.51:3308
slave2:10.0.0.51:3310
shard1
10.0.0.51:3307 ----- 10.0.0.52:3307
db02
db01
db02
10.0.0.51:3309 ------ 10.0.0.51:3307
db01
10.0.0.52:3309 ------ 10.0.0.52:3307
db02
shard2
10.0.0.52:3308 ----- 10.0.0.51:3308
db01
db02
db01
10.0.0.52:3310 ----- 10.0.0.52:3308
db02
10.0.0.51:3310 ----- 10.0.0.51:3308
db01
這個(gè)復(fù)制用戶在誰上建都行
注:如果中間出現(xiàn)錯(cuò)誤,在每個(gè)節(jié)點(diǎn)進(jìn)行執(zhí)行以下命令
常見方案:
360 Atlas-Sharding 360
Alibaba cobar 阿里
Mycat 開源
TDDL 淘寶
Heisenberg 百度
Oceanus 58同城
Vitess 谷歌
OneProxy
DRDS 阿里云
我們裝的是openjdk,不是官方的那個(gè)
Mycat-server-xxxxx.linux.tar.gz
配置環(huán)境變量
我們mycat的命令也是在bin目錄下
啟動(dòng)
8066就是對(duì)外提供服務(wù)的端口,9066是管理端口
連接mycat:
默認(rèn)123456
db01:
我們一般先把原schema.xml備份,然后自己新寫一個(gè):
xml和html看起來差不多,xml是從下往上調(diào)用的
前三行我們不用看,直接從第四行schema開始看起:
定義了schema,然后以/schema結(jié)尾
為什么要用邏輯庫?
業(yè)務(wù)透明化
此配置文件就是實(shí)現(xiàn)讀寫分離的配置
重啟mycat
讀寫分離測(cè)試
總結(jié):
以上案例實(shí)現(xiàn)了1主1從的讀寫分離功能,寫操作落到主庫,讀操作落到從庫.如果主庫宕機(jī),從庫不能在繼續(xù)提供服務(wù)了。
我們推薦這種架構(gòu)
一寫三讀,
不設(shè)置雙寫的原因是:性能沒提升多少,反而引起主鍵沖突的情況
配置文件:
之后重啟:mycat restart
真正的 writehost:負(fù)責(zé)寫操作的writehost
standby writeHost :和readhost一樣,只提供讀服務(wù)
我們此處寫了兩個(gè)writehost,默認(rèn)使用第一個(gè)
當(dāng)寫節(jié)點(diǎn)宕機(jī)后,后面跟的readhost也不提供服務(wù),這時(shí)候standby的writehost就提供寫服務(wù),
后面跟的readhost提供讀服務(wù)
測(cè)試:
讀寫分離測(cè)試
對(duì)db01 3307節(jié)點(diǎn)進(jìn)行關(guān)閉和啟動(dòng),測(cè)試讀寫操作
結(jié)果應(yīng)為另一臺(tái)(52)的3307(17)是寫,3309(19)是讀
一旦7號(hào)節(jié)點(diǎn)恢復(fù),此時(shí)因?yàn)?落后了,寫節(jié)點(diǎn)仍是17
balance屬性
負(fù)載均衡類型,目前的取值有3種:
writeType屬性
負(fù)載均衡類型,目前的取值有2種:
switchType屬性
-1 表示不自動(dòng)切換
1 默認(rèn)值,自動(dòng)切換
2 基于MySQL主從同步的狀態(tài)決定是否切換 ,心跳語句為 show slave status
datahost其他配置
dataHost name="localhost1" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1"
maxCon="1000":最大的并發(fā)連接數(shù)
minCon="10" :mycat在啟動(dòng)之后,會(huì)在后端節(jié)點(diǎn)上自動(dòng)開啟的連接線程,長(zhǎng)連接,好處是連接速度快,弊端是占內(nèi)存
tempReadHostAvailable="1"
這個(gè)一主一從時(shí)(1個(gè)writehost,1個(gè)readhost時(shí)),可以開啟這個(gè)參數(shù),如果2個(gè)writehost,2個(gè)readhost時(shí)
heartbeatselect user()/heartbeat 監(jiān)測(cè)心跳
其他參數(shù)sqlMaxLimit自動(dòng)分頁,必須在啟用分表的情況下才生效
創(chuàng)建測(cè)試庫和表:
我們重啟mycat后連接到8066
發(fā)現(xiàn)跟一個(gè)庫一樣,實(shí)際上已經(jīng)分到不同的物理硬件上了
分片:對(duì)一個(gè)"bigtable",比如說t3表
熱點(diǎn)數(shù)據(jù)表 核心表
(1)行數(shù)非常多,800w下坡
(2)訪問非常頻繁
分片的目的:
(1)將大數(shù)據(jù)量進(jìn)行分布存儲(chǔ)
(2)提供均衡的訪問路由
分片策略:
范圍 range 800w 1-400w 400w01-800w 不適用于業(yè)務(wù)訪問不均勻的情況
取模 mod (取余數(shù)) 和節(jié)點(diǎn)的數(shù)量進(jìn)行取模
枚舉 按枚舉的種類分,如移動(dòng)項(xiàng)目按省份分
哈希 hash
時(shí)間 流水
優(yōu)化關(guān)聯(lián)查詢(否則join的表在不同分片上,效率會(huì)比單庫還要低)
全局表
ER分片
案例:移動(dòng)統(tǒng)一:先拆出邊緣業(yè)務(wù),再按地域分片,但對(duì)應(yīng)用來說是統(tǒng)一的
vim rule.xml
tableRule name="auto-sharding-long"
rule
columnsid/columns
algorithmrang-long/algorithm
/rule
function name="rang-long"
class="io.mycat.route.function.AutoPartitionByLong"
property name="mapFile"autopartition-long.txt/property
/function
===================================
vim autopartition-long.txt
0-10=0
11-20=1
創(chuàng)建測(cè)試表:
mysql -S /data/3307/mysql.sock -e "use taobao;create table t3 (id int not null primary key auto_increment,name varchar(20) not null);"
mysql -S /data/3308/mysql.sock -e "use taobao;create table t3 (id int not null primary key auto_increment,name varchar(20) not null);"
測(cè)試:
重啟mycat
mycat restart
mysql -uroot -p123456 -h 127.0.0.1 -P 8066
insert into t3(id,name) values(1,'a');
insert into t3(id,name) values(2,'b');
insert into t3(id,name) values(3,'c');
insert into t3(id,name) values(4,'d');
insert into t3(id,name) values(11,'aa');
insert into t3(id,name) values(12,'bb');
insert into t3(id,name) values(13,'cc');
insert into t3(id,name) values(14,'dd');
取余分片方式:分片鍵(一個(gè)列)與節(jié)點(diǎn)數(shù)量進(jìn)行取余,得到余數(shù),將數(shù)據(jù)寫入對(duì)應(yīng)節(jié)點(diǎn)
vim schema.xml
table name="t4" dataNode="sh1,sh2" rule="mod-long" /
vim rule.xml
property name="count"2/property
準(zhǔn)備測(cè)試環(huán)境
創(chuàng)建測(cè)試表:
mysql -S /data/3307/mysql.sock -e "use taobao;create table t4 (id int not null primary key auto_increment,name varchar(20) not null);"
mysql -S /data/3308/mysql.sock -e "use taobao;create table t4 (id int not null primary key auto_increment,name varchar(20) not null);"
重啟mycat
mycat restart
測(cè)試:
mysql -uroot -p123456 -h10.0.0.52 -P8066
use TESTDB
insert into t4(id,name) values(1,'a');
insert into t4(id,name) values(2,'b');
insert into t4(id,name) values(3,'c');
insert into t4(id,name) values(4,'d');
分別登錄后端節(jié)點(diǎn)查詢數(shù)據(jù)
mysql -S /data/3307/mysql.sock
use taobao
select * from t4;
mysql -S /data/3308/mysql.sock
use taobao
select * from t4;
t5 表
id name telnum
1 bj 1212
2 sh 22222
3 bj 3333
4 sh 44444
5 bj 5555
sharding-by-intfile
vim schema.xml
table name="t5" dataNode="sh1,sh2" rule="sharding-by-intfile" /
vim rule.xml
tableRule name="sharding-by-intfile"
rule columnsname/columns
algorithmhash-int/algorithm
/rule
/tableRule
function name="hash-int" class="org.opencloudb.route.function.PartitionByFileMap"
property name="mapFile"partition-hash-int.txt/property
property name="type"1/property
property name="defaultNode"0/property
/function
partition-hash-int.txt 配置:
bj=0
sh=1
DEFAULT_NODE=1
columns 標(biāo)識(shí)將要分片的表字段,algorithm 分片函數(shù), 其中分片函數(shù)配置中,mapFile標(biāo)識(shí)配置文件名稱
準(zhǔn)備測(cè)試環(huán)境
mysql -S /data/3307/mysql.sock -e "use taobao;create table t5 (id int not null primary key auto_increment,name varchar(20) not null);"
mysql -S /data/3308/mysql.sock -e "use taobao;create table t5 (id int not null primary key auto_increment,name varchar(20) not null);"
重啟mycat
mycat restart
mysql -uroot -p123456 -h10.0.0.51 -P8066
use TESTDB
insert into t5(id,name) values(1,'bj');
insert into t5(id,name) values(2,'sh');
insert into t5(id,name) values(3,'bj');
insert into t5(id,name) values(4,'sh');
insert into t5(id,name) values(5,'tj');
a b c d
join
t
select t1.name ,t.x from t1
join t
select t2.name ,t.x from t2
join t
select t3.name ,t.x from t3
join t
使用場(chǎng)景:
如果你的業(yè)務(wù)中有些數(shù)據(jù)類似于數(shù)據(jù)字典,比如配置文件的配置,
常用業(yè)務(wù)的配置或者數(shù)據(jù)量不大很少變動(dòng)的表,這些表往往不是特別大,
而且大部分的業(yè)務(wù)場(chǎng)景都會(huì)用到,那么這種表適合于Mycat全局表,無須對(duì)數(shù)據(jù)進(jìn)行切分,
要在所有的分片上保存一份數(shù)據(jù)即可,Mycat 在Join操作中,業(yè)務(wù)表與全局表進(jìn)行Join聚合會(huì)優(yōu)先選擇相同分片內(nèi)的全局表join,
避免跨庫Join,在進(jìn)行數(shù)據(jù)插入操作時(shí),mycat將把數(shù)據(jù)分發(fā)到全局表對(duì)應(yīng)的所有分片執(zhí)行,在進(jìn)行數(shù)據(jù)讀取時(shí)候?qū)?huì)隨機(jī)獲取一個(gè)節(jié)點(diǎn)讀取數(shù)據(jù)。
vim schema.xml
table name="t_area" primaryKey="id" type="global" dataNode="sh1,sh2" /
后端數(shù)據(jù)準(zhǔn)備
mysql -S /data/3307/mysql.sock
use taobao
create table t_area (id int not null primary key auto_increment,name varchar(20) not null);
mysql -S /data/3308/mysql.sock
use taobao
create table t_area (id int not null primary key auto_increment,name varchar(20) not null);
重啟mycat
mycat restart
測(cè)試:
mysql -uroot -p123456 -h10.0.0.52 -P8066
use TESTDB
insert into t_area(id,name) values(1,'a');
insert into t_area(id,name) values(2,'b');
insert into t_area(id,name) values(3,'c');
insert into t_area(id,name) values(4,'d');
A
join
B
為了防止跨分片join,可以使用E-R模式
A join B
on a.xx=b.yy
join C
on A.id=C.id
table name="A" dataNode="sh1,sh2" rule="mod-long"
childTable name="B" joinKey="yy" parentKey="xx" /
/table