從單機到分布式:拆解高并發數據庫架構的六大生死決策
作者:greencoatman
關系型數據庫(如MySQL)設計側重ACID,分片會破壞事務和Join,需業務層權衡;而Redis/MongoDB等為高擴展設計,犧牲部分特性(如強一致性)內置Sharding支持。
一、數據庫讀寫分離
核心原理
- 主從集群搭建:一主一從/一主多從,主機負責讀寫,從機只讀。
- 數據同步:主機通過復制同步數據到從機,所有節點存儲全量數據。
- 流量分發:業務層將寫操作指向主機,讀操作分發至從機。
適用場景
- 業務量持續增長,且已優化索引、引入緩存后仍性能不足。
常見問題與解法
- 問題:寫后讀數據不一致(如剛寫入主機,從機未同步)。
- 解法:
- 讀寫綁定:寫后讀強制走主機(侵入性強,易留坑)。
- 二次讀取:從機讀失敗后重試主機(增加主機壓力)。
- 業務分級:核心業務讀寫均走主機,非核心業務讀寫分離(需嚴格編碼規范)。
實現方式對比
方式 | 中間件代理 | 客戶端分庫 |
復雜度 | 高(需獨立部署、集群管理) | 低(基于JDBC封裝) |
維護成本 | 高(需高可用設計) | 低(無額外部署) |
語言支持 | 跨語言 | 需各語言單獨實現 |
二、數據庫分庫分表
拆分策略
- 垂直拆分:按列拆分,解決單表字段過多問題(常見于2B場景)。
- 水平拆分:按行拆分,分散數據壓力(常見于2C海量數據場景)。
拆分時機
- B+樹層數超過3層(約2000萬數據)。
- 單表數據占滿Innodb Buffer Pool(如2G數據)。
- 數據持續增長且性能瓶頸明顯。
核心問題與解法
- Join失效:
a.冗余小表(如字典表)。
b.代碼層手動Join。
c.字段冗余(如訂單表直接存商品類型)。
- 事務一致性:
- 引入分布式事務(如2PC、3PC)。
- 路由與聚合:
- 路由算法(如Hash、范圍分片)。
- 分片后Count/Order by需中間件或應用層聚合。
- 擴展限制
- 數據庫連接數瓶頸(如MySQL默認100連接)。
- 中間件聚合操作性能受限,需權衡分片數量。
三、數據庫分布式事務算法
主流方案對比
算法 | 2PC(兩階段提交) | 3PC(三階段提交) |
流程 | 1. 準備階段 | 1. CanCommit |
優點 | 強一致性,實現簡單 | 減少阻塞,降低超時風險 |
缺點 | 協調者單點故障、同步阻塞 | 存在腦裂風險(部分提交、部分回滾) |
XA事務實踐
- 外部XA:跨多數據庫實例,由應用代碼協調(如PHP示例中的多庫事務)。
- 內部XA:單實例多存儲引擎事務,由Binlog協調(如MySQL內部機制)。
隨堂測驗
- **?** 讀寫分離僅提升讀性能,寫仍由主機處理。
- **?** 分庫分表分散寫壓力,提升寫性能。
- **?** 中間件可能成性能瓶頸,需謹慎設計 ? 中間件性能:取決于架構設計(如集群化),不可一概而論 。
- **?** 3PC存在腦裂風險,不優先于2PC ? 3PC與2PC選擇:需權衡「一致性要求」與「系統可用性」,無絕對優先級。
- **?** 協調者可為代碼(外部XA)或獨立系統(如Binlog)。
思考題解析
- 為何傳統數據庫不自帶分庫分表?
關系型數據庫(如MySQL)設計側重ACID,分片會破壞事務和Join,需業務層權衡;而Redis/MongoDB等為高擴展設計,犧牲部分特性(如強一致性)內置Sharding支持。
站在巨人的肩膀上,架構之路更從容!
圖片
責任編輯:武曉燕
來源:
二進制跳動