1. 程式人生 > >記錄一次經歷的數據庫從單庫到分庫分表的過程

記錄一次經歷的數據庫從單庫到分庫分表的過程

人力 per 靠譜 img center 沒有 tdd 推出 數據

前言

目前所在的的項目組,由於項目正在處於一個業務爆發期,每天數據的增長量已經給我們數據庫乃至系統造成了很多不確定的因數,前期依靠優化業務和SQL等方式暫時還能夠支撐住。但是最近發現某些表數據達到500W+以後查詢統計性能嚴重下降,高峰時段出現了很多SQL阻塞的情況例如:

技術分享

這種阻塞帶來的災難是滾雪球的,由於越堆越多基本上把數據庫已經拖死,所以我們就面臨數據庫切分的問題。

技術選型

既然要分庫分表那數據庫集群是少不了的,那我們的項目怎樣和這些集群打交道呢?我調研了大概分為以下幾種來完成這個功能(僅僅針對java項目)

中間件

例如淘寶開源的cobar,以及後來開源社區根據cobar做二次開發的Mycat(個人建議如果使用中間件的話可以考慮Mycat)

Jar形式的開源工具

例如淘寶的TDDL,以及當當開源出來的,Sharding-JDBC等

動態數據源

根據自己的業務來指定數據源來完成不同庫和表的操作

給予上面三個我最後選擇了估計看起來最LOW的第三種方式:我說一下我自己選擇的依據:

上述開元產品中淘寶系的cobar沒有維護,TDDL開源出來的和內部版本也不一樣有不少BUG我們這邊人力緊缺,估計沒時間來爬坑。Sharding-JDBC呢,剛推出來沒有項目實戰經驗。Mycat其實是我發現目前比較好的一個解決方案,但是mycat是給予代理模式的需要人維護,如果維護不得力,性能也不會太高,基於我們組人員的能力和我還是最終放棄了。

之所以選擇動態數據源:主要是因為技術相對簡單,對於業務代碼修改也比較少,可控性較高,減少了加入中間件或者第三方工具所帶來的風險。(申明一下我們項目完全沒有使用JPA事物的,對於事物是采用的補償機制這裏就不贅述)

主鍵生成策略

既然要分庫分表那麽全局唯一主鍵也是我們需要考慮的問題,我所知道的和有使用經驗的有如下幾種技術:

問題

可行性

基於redis

單點問題,redis重啟問題等

較高,公司有項目使用

給予DB(每次生成多個使用時去取出來)

單點問題,並發量問題

低並發,數據量較小的可以使用

UUID

暫用存儲空間比較大,非可排序的,體現不出增長的趨勢

較高

twitter snowflake

Xx年以後可能存在重復問題,需要配置生產參數

高,分布式的沒單點故障問題,時間上是遞增的。推薦

基於DB步長的方式

不是所有數據庫都支持

我選擇的是snowflake。

實現細節

因為分庫分表所以查詢和添加都需要帶上分配策略主鍵。

添加流程

技術分享

查詢邏輯

技術分享

分庫分表後能解決我們的性能問題,但是也帶來了很多其他的問題:我總結了一下分庫分表後的坑

1.分完之後只能直接按分片鍵查詢,為了避免掃所有分片,如果按非分片鍵查詢,在OLTP環境中得走搜索引擎。數據庫和搜索引擎同步數據靠binlog 2.按不同維度查詢,比如買家維度和賣家維度查訂單。除了走搜索引擎之外,還可以在不同的系統中各寫一條訂單數據。 3.ID得通過ID生成器。 4.有熱點數據問題,比如一個超級買家,買了好多種商品,然而還有不怎麽熱的買家,沒什麽訂單。解決方法兩種,熱點數據拿出來放到單獨的系統。或者按數據塊分片,比如十種商品算一個塊,但這種方法具體細節我忘了,只是聽人分享過。 5.跨庫事務問題,NPC一般不用,補償是一種方法,TCC是一種方法,TCC的變種,比如SAGA比如XTS,努力送達是一種方法 6.數據擴展問題,可以看看阿裏的愚公。我個人覺得還半夜停機維護比較靠譜。 7.分頁的坑,前期可以用中間件Limit,中期得走搜索引擎,後期OLAP 8.可用性問題,依賴數據庫高可用方案。據說會出現 sharding 算法 會因為網絡抖動 造成部分分區錯誤 導致片出問題 9.配置中心問題。盡量使用配置中心,不要用zookeeper 10.非代理模式,就是JDBC路由模式 每個client都會對 db開啟pool ,數據庫可能會死在數據庫連接上,一種方法是定制 Mysql,設置高低水位,讓超過數據庫處理能力的數據庫連接排隊。第二種方法是在JDBC路由模式之上做Mysql的Proxy

我把我現在的項目抽出來了一個簡單的模型放出來:源碼我將放在git上面

https://github.com/bingzhilanmo-bowen/spring-multi-datasource

記錄一次經歷的數據庫從單庫到分庫分表的過程