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

以上這種設計模式,把SQL組合、數據庫路由、執行結果合並等功能全部存放在一個代理服務中,而與分庫分表相關的處理邏輯全部存放在另外的服務中,這種設計模式的優點是對業務代碼無侵入,業務只需要關注自身的業務邏輯即可。
(2)Client模式:還是借用shardingSphere官方文檔的圖來說明,如下圖所示:

以上這種設計模式,把分庫分表相關邏輯存放在客戶端,一版客戶端的應用會引用一個jar,然后再jar中處理SQL組合、數據庫路由、執行結果合並等相關功能。
市面上,關於這兩種模式的中間件有如下選擇:

看到這里,我們已經知道市面上開源中間件的設計模式,那么我們到底該選擇哪種模式呢?簡單對比下這2個模式的優缺點,你就知道答案了。

因為看重代碼靈活可控這個優勢,所以我們選擇了Client模式里的Sharding-JDBC來實現分庫分表。當然,關於拆分存儲選擇哪種技術,在實際工作中我們需要根據各自的實際情況來定。