簡介

    在大型項目中,我們會遇到分表分庫的情景。 

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

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

對比

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

    1.自己手動控制,來決定操作那張表,比如要查詢Id為5的用戶信息,則會先5%(表的個數(shù))=N 然后通過字符串拼接user_+"N"的方式得到表名,然后再訪問數(shù)據(jù)庫。

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

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

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

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

    在應對Join查詢上,我們不能再像原來那么操作。

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

    在面對批量插入的時候。 

    等等。 當想要把分表做的更通用,更透明時,都會面對這個問題。

我的解決方案

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

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

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

 

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

萬碼學堂,電腦培訓,計算機培訓,Java培訓,JavaEE開發(fā)培訓,青島軟件培訓,軟件工程師培訓

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