簡(jiǎn)介

    在大型項(xiàng)目中,我們會(huì)遇到分表分庫(kù)的情景。 

    分庫(kù),將不同模塊對(duì)應(yīng)的表拆分到對(duì)應(yīng)的數(shù)據(jù)庫(kù)下,其實(shí)伴隨著公司內(nèi)分布式系統(tǒng)的出現(xiàn),這個(gè)過(guò)程也是自然而然就發(fā)生了,對(duì)應(yīng)商品模塊和用戶(hù)模塊,我們會(huì)建立商品服務(wù)和用戶(hù)服務(wù),各個(gè)服務(wù)訪問(wèn)各自的數(shù)據(jù)庫(kù),系統(tǒng)間的交互,通過(guò)遠(yuǎn)程調(diào)用實(shí)現(xiàn),而不是直接訪問(wèn)其數(shù)據(jù)庫(kù)。

    但是隨著業(yè)務(wù)的進(jìn)一步發(fā)展,數(shù)據(jù)表也會(huì)出現(xiàn)瓶頸,比如數(shù)據(jù)表的記錄已經(jīng)超過(guò)了千萬(wàn)級(jí),到了這個(gè)量級(jí),速度也會(huì)慢下來(lái)。所以接下來(lái)就是分表?!”热缬脩?hù)表,我們會(huì)分user_1,user_2,user_3,....,我們會(huì)按照用戶(hù)的Id取模的方式來(lái)定位表,假如用戶(hù)表有3個(gè),則Id是5的用戶(hù)信息會(huì)落在第二張表。 分表的方式多種多樣,比如商品表就適合按照日期來(lái)分表,一個(gè)月一張。 (分表還有一種是將不同的字段,分配到不同的表中)

對(duì)比

目前我所知道的分表的方式,大概有以下幾種

    1.自己手動(dòng)控制,來(lái)決定操作那張表,比如要查詢(xún)Id為5的用戶(hù)信息,則會(huì)先5%(表的個(gè)數(shù))=N 然后通過(guò)字符串拼接user_+"N"的方式得到表名,然后再訪問(wèn)數(shù)據(jù)庫(kù)。

    2. sql解析替換,比如要查詢(xún)Id為5的用戶(hù)信息,sql為select * from user,這里user表其實(shí)在數(shù)據(jù)庫(kù)中不存在,是一個(gè)邏輯表,在調(diào)用的更底層,會(huì)解析這個(gè)sql語(yǔ)句,找出表名,然后根據(jù)分表規(guī)則,替換成具體的表名。 這種方式比上面的侵入性要底。

    3. 代理方式,其實(shí)和上面的類(lèi)似,只是具體替換工作是代理服務(wù)器做的,在連接數(shù)據(jù)庫(kù)服務(wù)器的時(shí)候,我們連接的是代理,代理再連接數(shù)據(jù)庫(kù),我們執(zhí)行一個(gè)sql語(yǔ)句,會(huì)先發(fā)送到代理服務(wù)器,代理服務(wù)器根據(jù)預(yù)先指定的分庫(kù)分表規(guī)則,路由到具體的數(shù)據(jù)庫(kù)。 對(duì)于我們系統(tǒng)來(lái)說(shuō),就是零侵入。 

    4. 數(shù)據(jù)庫(kù)服務(wù)器本身的支持,比如sql server本本身就支持分表。

數(shù)據(jù)分表看似簡(jiǎn)單, 其實(shí)也非常困難,比如: 

    在應(yīng)對(duì)Join查詢(xún)上,我們不能再像原來(lái)那么操作。

    在未使用分表規(guī)則時(shí)的查詢(xún),比如,用戶(hù)表是按照Id取模分表的,但是如果有一個(gè)查詢(xún)是select * from user where loginid='XX' , 那就相當(dāng)于要并行查詢(xún)多張表。 

    在面對(duì)批量插入的時(shí)候。 

    等等。 當(dāng)想要把分表做的更通用,更透明時(shí),都會(huì)面對(duì)這個(gè)問(wèn)題。

我的解決方案

我的想法和上面第一種比較類(lèi)似,我想做的更通用一些,但是表名是始終繞不過(guò)去的,后來(lái)索性換了一種思路,既然這樣做如此麻煩,那表名就不替換了,替換庫(kù),這就是我標(biāo)題里說(shuō)的,用分庫(kù)的思想來(lái)分表,同時(shí)還得到另外的一個(gè)好處,就是當(dāng)數(shù)據(jù)庫(kù)服務(wù)器IO遇到瓶頸的時(shí)候,可以將這些數(shù)據(jù)庫(kù)中一部分遷移到其他機(jī)器上。

    比如 用戶(hù)表(user)需要分成3個(gè),那我就新建3個(gè)數(shù)據(jù)庫(kù),每個(gè)數(shù)據(jù)庫(kù)中各有一張表(user),當(dāng)我執(zhí)行select * from user  where id=5 的時(shí)候,我會(huì)根據(jù)規(guī)則,切換數(shù)據(jù)庫(kù)連接,這個(gè)sql里面的user表,在對(duì)應(yīng)數(shù)據(jù)庫(kù)里是真實(shí)存在的。 這些數(shù)據(jù)庫(kù)可以在同一臺(tái)機(jī)器上,當(dāng)服務(wù)器遇到壓力時(shí),可以將這3個(gè)數(shù)據(jù)庫(kù)分布到3臺(tái)機(jī)器上去,比起遷表,遷庫(kù)更容易。 

    有了這個(gè)思路,接下來(lái)就是如何盡可能的低浸入,這里我使用.net的Attribute(當(dāng)然,也可以搞成配置文件方式),通過(guò)給方法打標(biāo)簽來(lái)提供一些信息,最后就是如何解析這些標(biāo)簽,我這里使用AOP, 當(dāng)然完全的零侵入是不可能的,但是也只是需要你在訪問(wèn)數(shù)據(jù)庫(kù)的方法中,多一行代碼,就是獲取數(shù)據(jù)庫(kù)連接的。 

 

 我們先看數(shù)據(jù)訪問(wèn)層

萬(wàn)碼學(xué)堂,電腦培訓(xùn),計(jì)算機(jī)培訓(xùn),Java培訓(xùn),JavaEE開(kāi)發(fā)培訓(xùn),青島軟件培訓(xùn),軟件工程師培訓(xùn)

這里數(shù)據(jù)訪問(wèn)我用的是dapper,對(duì)于需要分