背景
分庫分表這個詞相信很多人都不陌生,在互聯(lián)網(wǎng)公司數(shù)據(jù)到達一定規(guī)模的時候,多數(shù)都會對數(shù)據(jù)進行分庫分表,或者也有人叫分片,英文翻譯為Sharding;更加準(zhǔn)確來說我們常常關(guān)心的是水平分片,即單個業(yè)務(wù)的某些表到達一定規(guī)模后,即使建立索引也無法從根本上帶來很大的性能提升,這時我們會考慮把單表拆分,以MySQL為例,B+樹索引的深度會隨著記錄的增多而逐漸加深,根據(jù)索引查詢的開銷也會越來越大,而單表拆分成多個表之后,B+樹深度降低,每個單表獨立查詢的速度也會加快,如果同時還分庫的話,并且在不同的實例上,大量的查詢壓力也會分擔(dān)到不同的機器上,這對單個數(shù)據(jù)庫機器減壓也帶來好處。
分庫分表的技術(shù)方案總體上來講分為兩大類:應(yīng)用層依賴類中間件、中間層代理類中間件。
應(yīng)用層依賴類中間件
這類分庫分表中間件的特點就是和應(yīng)用強耦合,需要應(yīng)用顯示依賴相應(yīng)的jar包(以Java為例),比如知名的TDDL、當(dāng)當(dāng)開源的sharding-jdbc、蘑菇街的TSharding、攜程開源的Ctrip-DAL、支付寶開源但比較低調(diào)的zdal等。
此類中間件的基本思路就是重新實現(xiàn)JDBC的API,通過重新實現(xiàn)DataSource、PrepareStatement等操作數(shù)據(jù)庫的接口,讓應(yīng)用層在基本(注意:這里用了基本)不改變業(yè)務(wù)代碼的情況下透明地實現(xiàn)分庫分表的能力。中間件給上層應(yīng)用提供熟悉的JDBC API,內(nèi)部通過sql解析、sql重寫、sql路由等一系列的準(zhǔn)備工作獲取真正可執(zhí)行的sql,然后底層再按照傳統(tǒng)的方法(比如數(shù)據(jù)庫連接池)獲取物理連接來執(zhí)行sql,最后把數(shù)據(jù)結(jié)果合并處理成ResultSet返回給應(yīng)用層。
此類中間件的優(yōu)點很明顯,就是無需額外部署,只要和應(yīng)用綁定一起發(fā)布即可,但是缺點也很明顯,就是不能跨語言,比如Java寫的sharding-jdbc顯然不能用在C#項目中,所以攜程的dal也要重新寫一套C#的客戶端。
中間層代理類中間件
這類分庫分表中間件的核心原理是在應(yīng)用和數(shù)據(jù)庫的連接之間搭起一個代理層,上層應(yīng)用以標(biāo)準(zhǔn)的MySQL協(xié)議來連接代理層,然后代理層負責(zé)轉(zhuǎn)發(fā)請求到底層的MySQL物理實例,這種方式對應(yīng)用只有一個要求,就是只要用MySQL協(xié)議來通信即可,所以用MySQL Workbench這種純的客戶端都可以直接連接你的分布式數(shù)據(jù)庫,自然也天然支持所有的編程語言。比較有代表性的產(chǎn)品有開創(chuàng)性質(zhì)的Amoeba、阿里開源的Cobar、社區(qū)發(fā)展比較好的Mycat 等。
在技術(shù)實現(xiàn)上除了和應(yīng)用層依賴類中間件基本相似外,代理類的分庫分表產(chǎn)品必須實現(xiàn)標(biāo)準(zhǔn)的MySQL協(xié)議,某種意義上講數(shù)據(jù)庫代理層轉(zhuǎn)發(fā)的就是MySQL協(xié)議請求,就像Nginx轉(zhuǎn)發(fā)的是Http協(xié)議請求。
上述無論哪種類型的產(chǎn)品,除了實現(xiàn)分庫分表這一主要功能外,都會額外實現(xiàn)一些其他很有實用價值的功能,比如讀寫分離、負載均衡等。