大家好,我是工藤學編程 🦉 | 一個正在努力學習的小博主,期待你的關注 |
---|---|
實戰代碼系列最新文章😉 | C++實現圖書管理系統(Qt C++ GUI界面版) |
SpringBoot實戰系列🐷 | 【SpringBoot實戰系列】Sharding-Jdbc實現分庫分表到分布式ID生成器Snowflake自定義wrokId實戰 |
環境搭建大集合 | 環境搭建大集合(持續更新) |
前情摘要:
1、數據庫性能優化
本文章目錄
- 一、分庫分表:突破數據庫性能瓶頸的原因
- 一、數據庫連接數瓶頸問題
- 二、單表海量數據查詢性能問題
- 三、單臺數據庫并發訪問壓力問題
- 二、分庫分表帶來的六大核心問題及技術挑戰
- 一、跨節點數據庫Join與多維度查詢難題
- 二、分布式事務一致性挑戰
- 三、SQL排序、翻頁與函數計算的跨庫困境
- 四、全局主鍵沖突與生成策略難題
- 五、容量規劃與二次擴容的復雜性
- 六、分庫分表中間件選型困境
一、分庫分表:突破數據庫性能瓶頸的原因
一、數據庫連接數瓶頸問題
在數據庫與應用程序交互的過程中,每個客戶端請求都需要建立一個數據庫連接。當系統訪問量激增,或者數據庫本身設置的最大連接數過小,就會觸發 “too many connections” 錯誤。一旦連接數達到上限,后續的請求無法建立連接,系統響應速度會大幅下降,嚴重時甚至導致服務崩潰。
以 MySQL 數據庫為例:
- 默認設置:MySQL 默認的最大連接數為 100,這個數值在一般小型項目中或許夠用,但在高并發的互聯網應用場景下,遠遠不能滿足需求。
- 調整限制:雖然 MySQL 理論上允許的最大連接數可達 16384,但實際設置時不能盲目追求高值。因為每個連接都會占用內存等系統資源,過多的連接反而會加重服務器負擔,影響數據庫性能。
通過分庫分表,將數據分散到多個數據庫實例中,每個實例承擔的連接請求相應減少,從而有效緩解連接數瓶頸問題。例如,原本 1000 個請求集中在一個數據庫實例,分庫后可能每個實例只處理 200 個請求,降低了單個實例的連接壓力。
二、單表海量數據查詢性能問題
隨著業務的不斷推進,數據庫中部分核心表的數據量會快速增長。當單表數據量達到百萬甚至千萬級別時,即使是簡單的查詢操作,執行效率也會變得極低。這是因為全表掃描操作會消耗大量磁盤 I/O 和 CPU 資源,使得查詢響應時間顯著變長,影響用戶體驗。
通過分表,數據分散存儲,查詢操作的掃描范圍大幅縮小,查詢性能得到顯著提升。
三、單臺數據庫并發訪問壓力問題
在高并發場景下,單臺數據庫服務器的處理能力是有限的。大量的讀寫請求集中在一臺服務器上,會導致 CPU、內存、磁盤 I/O 等資源被迅速消耗,出現資源利用率過高的情況。最終,數據庫響應延遲增加,甚至可能出現服務不可用的嚴重后果。
數據庫分庫則是將數據分散存儲到多個數據庫實例中,每個實例分擔一部分業務請求。常見的分庫方式是按照業務模塊劃分,比如:
- 將用戶相關的數據存儲在用戶數據庫;
- 訂單數據存儲在訂單數據庫;
- 商品數據存儲在商品數據庫。
通過這種方式,每個數據庫實例的并發訪問量降低,系統整體的并發處理能力得到極大提升,能夠更好地應對高并發請求。
二、分庫分表帶來的六大核心問題及技術挑戰
分庫分表在解決數據庫性能瓶頸的同時,也引入了一系列復雜的技術問題。以下是實踐中常見的六大挑戰及場景解析:
一、跨節點數據庫Join與多維度查詢難題
核心矛盾:數據分片后,關聯查詢與多維度查詢的復雜度呈指數級上升。
- 傳統場景對比:
分庫前:通過單庫SQL Join輕松實現多表關聯(如SELECT * FROM orders JOIN users ON orders.uid=users.id
)。
分庫后:若orders
按user_id
分片,users
按dept_id
分片,則跨庫Join需手動拆分SQL,甚至通過應用層聚合結果。 - 多維度查詢痛點:
- 案例:訂單表以
user_id
為分片鍵,用戶查詢個人訂單時效率高,但商家查詢店鋪訂單(需按shop_id
篩選)時,數據可能分散在多個庫中,需遍歷所有分片節點后聚合結果,性能損耗嚴重。
- 案例:訂單表以
二、分布式事務一致性挑戰
問題本質:跨庫操作打破ACID特性,需引入分布式事務解決方案。
- 典型場景:
電商場景中,用戶下單時需同時扣減庫存(庫存庫)和記錄訂單(訂單庫),若兩庫分片不同,傳統本地事務失效。 - 技術難點:
- 強一致性方案(如2PC)性能開銷大,弱一致性方案(如最終一致性)需處理異常補償邏輯。
三、SQL排序、翻頁與函數計算的跨庫困境
具體問題表現:
- Order By排序:
若排序字段非分片鍵(如按create_time
排序),需從所有分片查詢數據,各節點本地排序后再在應用層合并結果,消耗大量內存與CPU。 - Limit翻頁:
當頁碼較大時(如LIMIT 10000,10
),各分片需返回前10010條數據,應用層合并后再取后10條,產生“深度分頁”性能問題。 - 函數計算:
跨庫聚合函數(如COUNT(*)
、SUM(amount)
)需先在各分片計算局部結果,再匯總全局值,增加網絡傳輸開銷。
四、全局主鍵沖突與生成策略難題
傳統自增ID失效場景:
- 分庫前:單庫自增ID可保證唯一性(如
AUTO_INCREMENT
)。 - 分庫后:若多個庫均使用自增ID,會導致不同庫中出現相同ID(如庫1和庫2的訂單表均生成ID=1001)。
解決方案挑戰: - 雪花算法(Snowflake)需保證時鐘同步,分布式ID生成器(如UUID)存在無序性與存儲冗余問題。
五、容量規劃與二次擴容的復雜性
業務增長帶來的動態挑戰:
- 初次分庫時若分片數量設計不足(如按10萬數據/庫規劃),當數據量突破1000萬時需重新分片(如擴容至100庫)。
- 二次擴容需解決數據遷移問題:
- 全量遷移:停機遷移數據,但影響服務可用性。
- 增量遷移:需處理遷移期間的增量數據同步,避免數據不一致。
六、分庫分表中間件選型困境
主流技術對比與選型難點:
中間件類型 | 代表產品 | 優勢 | 短板 |
---|---|---|---|
客戶端代理 | Sharding-JDBC | 無額外組件,與應用同進程部署 | 需修改應用代碼,運維成本高 |
服務端代理 | MyCAT | 應用無感知,支持多數據庫協議 | 單點性能瓶頸,版本迭代緩慢 |
云原生方案 | OceanBase | 自動分片與擴容,高可用性 | 學習成本高,適用于大型企業 |
后續將針對每個問題展開具體解決方案,歡迎關注技術連載!