原文出處:https://github.com/doocs/advanced-java/blob/master/docs/high-concurrency/database-shard.md
歡迎 star 關注 GitHub 項目最新動態(tài)匪燕!
面試題
為什么要分庫分表(設計高并發(fā)系統(tǒng)的時候蕾羊,數(shù)據(jù)庫層面該如何設計)?用過哪些分庫分表中間件帽驯?不同的分庫分表中間件都有什么優(yōu)點和缺點龟再?你們具體是如何對數(shù)據(jù)庫如何進行垂直拆分或水平拆分的?
面試官心理分析
其實這塊肯定是扯到高并發(fā)了尼变,因為分庫分表一定是為了支撐高并發(fā)利凑、數(shù)據(jù)量大兩個問題的。而且現(xiàn)在說實話嫌术,尤其是互聯(lián)網類的公司面試哀澈,基本上都會來這么一下,分庫分表如此普遍的技術問題度气,不問實在是不行割按,而如果你不知道那也實在是說不過去!
面試題剖析
為什么要分庫分表磷籍?(設計高并發(fā)系統(tǒng)的時候适荣,數(shù)據(jù)庫層面該如何設計?)
說白了院领,分庫分表是兩回事兒弛矛,大家可別搞混了,可能是光分庫不分表栅盲,也可能是光分表不分庫汪诉,都有可能。
我先給大家拋出來一個場景谈秫。
假如我們現(xiàn)在是一個小創(chuàng)業(yè)公司(或者是一個 BAT 公司剛興起的一個新部門)扒寄,現(xiàn)在注冊用戶就 20 萬,每天活躍用戶就 1 萬拟烫,每天單表數(shù)據(jù)量就 1000该编,然后高峰期每秒鐘并發(fā)請求最多就 10。天硕淑,就這種系統(tǒng)课竣,隨便找一個有幾年工作經驗的嘉赎,然后帶幾個剛培訓出來的,隨便干干都可以于樟。
結果沒想到我們運氣居然這么好公条,碰上個 CEO 帶著我們走上了康莊大道,業(yè)務發(fā)展迅猛迂曲,過了幾個月靶橱,注冊用戶數(shù)達到了 2000 萬!每天活躍用戶數(shù) 100 萬路捧!每天單表數(shù)據(jù)量 10 萬條关霸!高峰期每秒最大請求達到 1000!同時公司還順帶著融資了兩輪杰扫,進賬了幾個億人民幣岸涌堋!公司估值達到了驚人的幾億美金章姓!這是小獨角獸的節(jié)奏佳遣!
好吧,沒事啤覆,現(xiàn)在大家感覺壓力已經有點大了苍日,為啥呢?因為每天多 10 萬條數(shù)據(jù)窗声,一個月就多 300 萬條數(shù)據(jù)相恃,現(xiàn)在咱們單表已經幾百萬數(shù)據(jù)了,馬上就破千萬了笨觅。但是勉強還能撐著拦耐。高峰期請求現(xiàn)在是 1000,咱們線上部署了幾臺機器见剩,負載均衡搞了一下杀糯,數(shù)據(jù)庫撐 1000QPS 也還湊合。但是大家現(xiàn)在開始感覺有點擔心了苍苞,接下來咋整呢......
再接下來幾個月固翰,我的天,CEO 太牛逼了羹呵,公司用戶數(shù)已經達到 1 億骂际,公司繼續(xù)融資幾十億人民幣啊冈欢!公司估值達到了驚人的幾十億美金歉铝,成為了國內今年最牛逼的明星創(chuàng)業(yè)公司!天凑耻,我們太幸運了太示。
但是我們同時也是不幸的柠贤,因為此時每天活躍用戶數(shù)上千萬,每天單表新增數(shù)據(jù)多達 50 萬类缤,目前一個表總數(shù)據(jù)量都已經達到了兩三千萬了臼勉!扛不住啊呀非!數(shù)據(jù)庫磁盤容量不斷消耗掉坚俗!高峰期并發(fā)達到驚人的 5000~8000
!別開玩笑了岸裙,哥。我跟你保證速缆,你的系統(tǒng)支撐不到現(xiàn)在降允,已經掛掉了!
好吧艺糜,所以你看到這里差不多就理解分庫分表是怎么回事兒了剧董,實際上這是跟著你的公司業(yè)務發(fā)展走的,你公司業(yè)務發(fā)展越好破停,用戶就越多翅楼,數(shù)據(jù)量越大,請求量越大真慢,那你單個數(shù)據(jù)庫一定扛不住毅臊。
分表
比如你單表都幾千萬數(shù)據(jù)了,你確定你能扛住么黑界?絕對不行管嬉,單表數(shù)據(jù)量太大,會極大影響你的 sql 執(zhí)行的性能朗鸠,到了后面你的 sql 可能就跑的很慢了蚯撩。一般來說,就以我的經驗來看烛占,單表到幾百萬的時候胎挎,性能就會相對差一些了,你就得分表了忆家。
分表是啥意思犹菇?就是把一個表的數(shù)據(jù)放到多個表中,然后查詢的時候你就查一個表弦赖。比如按照用戶 id 來分表项栏,將一個用戶的數(shù)據(jù)就放在一個表中。然后操作的時候你對一個用戶就操作那個表就好了蹬竖。這樣可以控制每個表的數(shù)據(jù)量在可控的范圍內沼沈,比如每個表就固定在 200 萬以內流酬。
分庫
分庫是啥意思?就是你一個庫一般我們經驗而言列另,最多支撐到并發(fā) 2000芽腾,一定要擴容了,而且一個健康的單庫并發(fā)值你最好保持在每秒 1000 左右页衙,不要太大摊滔。那么你可以將一個庫的數(shù)據(jù)拆分到多個庫中,訪問的時候就訪問一個庫好了店乐。
這就是所謂的分庫分表艰躺,為啥要分庫分表?你明白了吧眨八。
# | 分庫分表前 | 分庫分表后 |
---|---|---|
并發(fā)支撐情況 | MySQL 單機部署腺兴,扛不住高并發(fā) | MySQL從單機到多機,能承受的并發(fā)增加了多倍 |
磁盤使用情況 | MySQL 單機磁盤容量幾乎撐滿 | 拆分為多個庫廉侧,數(shù)據(jù)庫服務器磁盤使用率大大降低 |
SQL 執(zhí)行性能 | 單表數(shù)據(jù)量太大页响,SQL 越跑越慢 | 單表數(shù)據(jù)量減少,SQL 執(zhí)行效率明顯提升 |
用過哪些分庫分表中間件段誊?不同的分庫分表中間件都有什么優(yōu)點和缺點闰蚕?
這個其實就是看看你了解哪些分庫分表的中間件,各個中間件的優(yōu)缺點是啥连舍?然后你用過哪些分庫分表的中間件没陡。
比較常見的包括:
- Cobar
- TDDL
- Atlas
- Sharding-jdbc
- Mycat
Cobar
阿里 b2b 團隊開發(fā)和開源的,屬于 proxy 層方案烟瞧,就是介于應用服務器和數(shù)據(jù)庫服務器之間诗鸭。應用程序通過 JDBC 驅動訪問 Cobar 集群,Cobar 根據(jù) SQL 和分庫規(guī)則對 SQL 做分解参滴,然后分發(fā)到 MySQL 集群不同的數(shù)據(jù)庫實例上執(zhí)行强岸。早些年還可以用,但是最近幾年都沒更新了砾赔,基本沒啥人用蝌箍,差不多算是被拋棄的狀態(tài)吧。而且不支持讀寫分離暴心、存儲過程妓盲、跨庫 join 和分頁等操作。
TDDL
淘寶團隊開發(fā)的专普,屬于 client 層方案悯衬。支持基本的 crud 語法和讀寫分離,但不支持 join檀夹、多表查詢等語法筋粗。目前使用的也不多策橘,因為還依賴淘寶的 diamond 配置管理系統(tǒng)。
Atlas
360 開源的娜亿,屬于 proxy 層方案丽已,以前是有一些公司在用的,但是確實有一個很大的問題就是社區(qū)最新的維護都在 5 年前了买决。所以沛婴,現(xiàn)在用的公司基本也很少了。
Sharding-jdbc
當當開源的督赤,屬于 client 層方案嘁灯,目前已經更名為 ShardingSphere
(后文所提到的 Sharding-jdbc
,等同于 ShardingSphere
)躲舌。確實之前用的還比較多一些旁仿,因為 SQL 語法支持也比較多,沒有太多限制孽糖,而且截至 2019.4,已經推出到了 4.0.0-RC1
版本毅贮,支持分庫分表办悟、讀寫分離、分布式 id 生成滩褥、柔性事務(最大努力送達型事務病蛉、TCC 事務)。而且確實之前使用的公司會比較多一些(這個在官網有登記使用的公司瑰煎,可以看到從 2017 年一直到現(xiàn)在铺然,是有不少公司在用的)零抬,目前社區(qū)也還一直在開發(fā)和維護倍谜,還算是比較活躍狡忙,個人認為算是一個現(xiàn)在也可以選擇的方案昆庇。
Mycat
基于 Cobar 改造的吃溅,屬于 proxy 層方案迁杨,支持的功能非常完善啦租,而且目前應該是非持晾剩火的而且不斷流行的數(shù)據(jù)庫中間件农尖,社區(qū)很活躍析恋,也有一些公司開始在用了。但是確實相比于 Sharding jdbc 來說盛卡,年輕一些助隧,經歷的錘煉少一些。
總結
綜上滑沧,現(xiàn)在其實建議考量的并村,就是 Sharding-jdbc 和 Mycat巍实,這兩個都可以去考慮使用。
Sharding-jdbc 這種 client 層方案的優(yōu)點在于不用部署橘霎,運維成本低蔫浆,不需要代理層的二次轉發(fā)請求,性能很高姐叁,但是如果遇到升級啥的需要各個系統(tǒng)都重新升級版本再發(fā)布瓦盛,各個系統(tǒng)都需要耦合 Sharding-jdbc 的依賴;
Mycat 這種 proxy 層方案的缺點在于需要部署外潜,自己運維一套中間件原环,運維成本高,但是好處在于對于各個項目是透明的处窥,如果遇到升級之類的都是自己中間件那里搞就行了嘱吗。
通常來說,這兩個方案其實都可以選用滔驾,但是我個人建議中小型公司選用 Sharding-jdbc谒麦,client 層方案輕便,而且維護成本低哆致,不需要額外增派人手绕德,而且中小型公司系統(tǒng)復雜度會低一些,項目也沒那么多摊阀;但是中大型公司最好還是選用 Mycat 這類 proxy 層方案耻蛇,因為可能大公司系統(tǒng)和項目非常多,團隊很大胞此,人員充足臣咖,那么最好是專門弄個人來研究和維護 Mycat,然后大量項目直接透明使用即可漱牵。
你們具體是如何對數(shù)據(jù)庫如何進行垂直拆分或水平拆分的夺蛇?
水平拆分的意思,就是把一個表的數(shù)據(jù)給弄到多個庫的多個表里去布疙,但是每個庫的表結構都一樣蚊惯,只不過每個庫表放的數(shù)據(jù)是不同的,所有庫表的數(shù)據(jù)加起來就是全部數(shù)據(jù)灵临。水平拆分的意義截型,就是將數(shù)據(jù)均勻放更多的庫里,然后用多個庫來扛更高的并發(fā)儒溉,還有就是用多個庫的存儲容量來進行擴容宦焦。
垂直拆分的意思,就是把一個有很多字段的表給拆分成多個表,或者是多個庫上去波闹。每個庫表的結構都不一樣酝豪,每個庫表都包含部分字段。一般來說精堕,會將較少的訪問頻率很高的字段放到一個表里去孵淘,然后將較多的訪問頻率很低的字段放到另外一個表里去。因為數(shù)據(jù)庫是有緩存的歹篓,你訪問頻率高的行字段越少瘫证,就可以在緩存里緩存更多的行,性能就越好庄撮。這個一般在表層面做的較多一些背捌。
這個其實挺常見的,不一定我說洞斯,大家很多同學可能自己都做過毡庆,把一個大表拆開,訂單表烙如、訂單支付表么抗、訂單商品表。
還有表層面的拆分亚铁,就是分表乖坠,將一個表變成 N 個表,就是讓每個表的數(shù)據(jù)量控制在一定范圍內刀闷,保證 SQL 的性能。否則單表數(shù)據(jù)量越大仰迁,SQL 性能就越差甸昏。一般是 200 萬行左右,不要太多徐许,但是也得看具體你怎么操作施蜜,也可能是 500 萬,或者是 100 萬雌隅。你的SQL越復雜翻默,就最好讓單表行數(shù)越少。
好了恰起,無論分庫還是分表修械,上面說的那些數(shù)據(jù)庫中間件都是可以支持的。就是基本上那些中間件可以做到你分庫分表之后检盼,中間件可以根據(jù)你指定的某個字段值肯污,比如說 userid,自動路由到對應的庫上去,然后再自動路由到對應的表里去蹦渣。
你就得考慮一下哄芜,你的項目里該如何分庫分表?一般來說柬唯,垂直拆分认臊,你可以在表層面來做,對一些字段特別多的表做一下拆分锄奢;水平拆分失晴,你可以說是并發(fā)承載不了,或者是數(shù)據(jù)量太大斟薇,容量承載不了师坎,你給拆了,按什么字段來拆堪滨,你自己想好胯陋;分表,你考慮一下袱箱,你如果哪怕是拆到每個庫里去遏乔,并發(fā)和容量都 ok 了,但是每個庫的表還是太大了发笔,那么你就分表盟萨,將這個表分開,保證每個表的數(shù)據(jù)量并不是很大了讨。
而且這兒還有兩種分庫分表的方式:
- 一種是按照 range 來分捻激,就是每個庫一段連續(xù)的數(shù)據(jù),這個一般是按比如時間范圍來的前计,但是這種一般較少用胞谭,因為很容易產生熱點問題,大量的流量都打在最新的數(shù)據(jù)上了男杈。
- 或者是按照某個字段 hash 一下均勻分散丈屹,這個較為常用。
range 來分伶棒,好處在于說旺垒,擴容的時候很簡單,因為你只要預備好肤无,給每個月都準備一個庫就可以了先蒋,到了一個新的月份的時候,自然而然宛渐,就會寫新的庫了鞭达;缺點司忱,但是大部分的請求,都是訪問最新的數(shù)據(jù)畴蹭。實際生產用 range坦仍,要看場景。
hash 分發(fā)叨襟,好處在于說繁扎,可以平均分配每個庫的數(shù)據(jù)量和請求壓力;壞處在于說擴容起來比較麻煩糊闽,會有一個數(shù)據(jù)遷移的過程梳玫,之前的數(shù)據(jù)需要重新計算 hash 值重新分配到不同的庫或表。