今天想聊一下分庫分表,因為對於快速增長的業務來說,這個是無法迴避的一環。之前我在做商城相關的SAAS系統,商品池是一個存儲瓶頸,商品池數量會基於租戶增長和運營變得指數級增長,短短幾個月就能漲到幾千萬的數據,而運營半年後就可能過億。而對於訂單這種數據,也會跟著業務的成長,也會變得愈發巨大。 ...
前言
之前總在聊微服務, 微服務本身也是分散式系統,其實微服務的核心思想是分而治之,把一個複雜的單體系統,按照業務的交付,分成不同的自服務,以降低資深複雜度,同時可以提升系統的擴展性。
今天想聊一下分庫分表,因為對於快速增長的業務來說,這個是無法迴避的一環。之前我在做商城相關的SAAS系統,商品池是一個存儲瓶頸,商品池數量會基於租戶增長和運營變得指數級增長,短短幾個月就能漲到幾千萬的數據,而運營半年後就可能過億。而對於訂單這種數據,也會跟著業務的成長,也會變得愈發巨大。
存儲層來說,提升大數據量下的存儲和查詢性能,就涉及到了另一個層面的問題,但思想還是一樣的,分而治之。
我們面臨什麼樣的問題
關係型資料庫在大於一定數據量的情況下檢索性能會急劇下降。在面對海量數據情況時,所有數據都存於一張表,顯然會輕易超過資料庫表可承受的。
此外單純的分表雖然可以解決數據量過大導致檢索變慢的問題,但無法解決過多併發請求訪問同一個庫,導致資料庫響應變慢的問題。所以需要分庫來解決單資料庫實例性能瓶頸問題。
資料庫架構方案
在講具體解決方案之前,我們需要先瞭解一下資料庫的三種架構涉及方案。
1. Shared Everything
一般指的是單個主機的環境,完全透明共用的CPU/記憶體/硬碟,並行處理能力是最差的,一般不考慮大規模的併發需求,架構比較簡單,一般的應用需求基本都能滿足。
2. Shared Disk
各處理單元使用自己的私有CPU和Memory,共用磁碟系統。典型的代表是Oracle RAC、DB2 PureScale。例如Oracle RAC,他用的是共用存儲,做到了數據共用,可通過增加節點來提高並行處理的能力,擴展能力較好,使用Storage Area Network (SAN),光纖通道連接到多個伺服器的磁碟陣列,降低網路消耗,提高數據讀取的效率,常用於併發量較高的OLTP應用。其類似於SMP(對稱多處理)模式,但是當存儲器介面達到飽和的時候,增加節點並不能獲得更高的性能,同時更多的節點,則增加了運維的成本。
3. Shared Nothing
各處理單元都有自己私有的CPU/記憶體/硬碟等,Nothing,顧名思義,不存在共用資源,類似於MPP(大規模並行處理)模式,各處理單元之間通過協議通信,並行處理和擴展能力更好。典型代表DB2 DPF、帶分庫分表的MySQL Cluster,各節點相互獨立,各自處理自己的數據,處理後的結果可能向上層彙總或在節點間流轉。
我們常說的Sharding其實就是Shared Nothing,他是將某個表從物理存儲上被水平分割,並分配給多台伺服器(或多個實例),每台伺服器可以獨立工作,具備共同的schema,例如MySQL Proxy和Google的各種架構,只需增加伺服器數就可以增加處理能力和容量。
至於MPP,指的是大規模並行分析資料庫(Analytical Massively Parallel Processing (MPP) Databases),他是針對分析工作負載進行了優化的資料庫,一般需要聚合和處理大型數據集。MPP資料庫往往是列式的,因此MPP資料庫通常將每一列存儲為一個對象,而不是將表中的每一行存儲為一個對象。這種體繫結構使複雜的分析查詢可以更快,更有效地處理。例如TeraData、Greenplum,GaussDB100、TBase。
基於以上的這幾種架構方案,我們可以給出大數據量存儲的解決方案:
以上幾種解決方案各有利弊,分區模式最大的問題是準share everything架構,無法水平擴展cpu和記憶體,所以基本可以排除;nosql本身其實是個非常好的備選方案,但是nosql(包括大部分開源newsql)硬體消耗非常大,運維成本較高。而常用的一種方案就是基於Mysql的分庫分表方案。
分庫分表架構方案
對於分庫分表,首先看一下市面上有哪些產品。
業界組件 | 原廠 | 功能特性 | 備註 |
---|---|---|---|
DBLE | 愛可生開源社區 | 專註於mysql的高可擴展性的分散式中間件 | 基於MyCAT開發出來的增強版。 |
Meituan Atlas | 美團 | 讀寫分離、單庫分表 | 目前已經在原廠逐步下架。 |
Cobar | 阿裡(B2B) | Cobar 中間件以 Proxy 的形式位於前臺應用和實際資料庫之間,對前臺的開放的介面是 MySQL 通信協議 | 開源版本中資料庫只支持 MySQL,並且不支持讀寫分離。 |
MyCAT | 阿裡 | 是一個實現了 MySQL 協議的伺服器,前端用戶可以把它看作是一個資料庫代理,用 MySQL 客戶端工具和命令行訪問,而其後端可以用MySQL 原生協議與多個 MySQL 伺服器通信 | MyCAT 基於阿裡開源的 Cobar 產品而研發 |
Atlas | 360 | 讀寫分離、靜態分表 | 2015年後已經不在維護 |
Kingshard | 開源項目 | 由 Go 開發高性能 MySQL Proxy 項目,在滿足基本的讀寫分離的功能上,Kingshard 的性能是直連 MySQL 性能的80%以上。 | |
TDDL | 阿裡淘寶 | 動態數據源、讀寫分離、分庫分表 | TDDL 分為兩個版本, 一個是帶中間件的版本, 一個是直接Java版本 |
Zebra | 美團點評 | 實現動態數據源、讀寫分離、分庫分表、CAT監控 | 功能齊全且有監控,接入複雜、限制多。 |
MTDDL | 美團點評 | 動態數據源、讀寫分離、分散式唯一主鍵生成器、分庫分表、連接池及SQL監控 | |
Vitess | 谷歌、Youtube | 集群基於ZooKeeper管理,通過RPC方式進行數據處理,總體分為,server,command line,gui監控 3部分 | Youtube 大量應用 |
DRDS | 阿裡 | DRDS(Distributed Relational Database Service)專註於解決單機關係型資料庫擴展性問題,具備輕量(無狀態)、靈活、穩定、高效等特性,是阿裡巴巴集團自主研 | |
Sharding-proxy | apache開源項目 | 提供MySQL版本,它可以使用任何相容MySQL協議的訪問客戶端(如:MySQL Command Client, MySQL Workbench等)操作數據,對DBA更加友好。嚮應用程式完全透明,可直接當做MySQL使用。適用於任何相容MySQL協議的客戶端。 | Apache項目,定位為透明化的資料庫代理端,提供封裝了資料庫二進位協議的服務端版本,用於完成對異構語言的支持。 |
Sharding jdbc | apache開源項目 | 完全相容JDBC和各種ORM框架。適用於任何基於Java的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。基於任何第三方的資料庫連接池,如:DBCP,C3P0, BoneCP, Druid, HikariCP等。支持任意實現JDBC規範的資料庫。目前支持MySQL,Oracle,SQLServer和PostgreSQL | Apache項目,定位為輕量級Java框架,在Java的JDBC層提供的額外服務。 它使用客戶端直連資料庫,以jar包形式提供服務,無需額外部署和依賴,可理解為增強版的JDBC驅動 |
對於分庫分表的產品模式,又分為兩種,中間件模式和客戶端模式。
1. 中間件模式其優缺點
中間件模式獨立進程,所以可以支持異構語言,對當前程式沒有侵入性,對業務方來說是透明的mysql服務,但是缺點也非常明顯,硬體消耗大、運維成本高(尤其是在本地化實施情況下),同時因為對關係型資料庫增加了代理,會造成問題難調試。
2. 客戶端模式優缺點
客戶端模式的主要缺點是對代碼有侵入,所以基本只能支持單語言,同時因為每個客戶端都要對schema建立連接,所以如果資料庫實例不多,需要對連接數仔細控制,但是客戶端模式的優點也非常明顯,首先從架構上它是去中心化的,這樣就避免了中間件模式的proxy故障問題,同時因為沒有中間層性能高、靈活可控,而且因為沒有proxy層,不需要考慮proxy的高可用和集群,運維成本也比較低。
sharding-jdbc接入實戰
sharding-jdbc其實是這些產品中最為大家熟知的,也是因為它定位為輕量級 Java 框架,在 Java 的 JDBC 層提供的額外服務。 它使用客戶端直連資料庫,以 jar 包形式提供服務,無需額外部署和依賴,可理解為增強版的 JDBC 驅動,完全相容 JDBC 和各種 ORM 框架。適用於任何基於 JDBC 的 ORM 框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template 或直接使用 JDBC。而且在社區活躍度,代碼質量等方面,也是很不錯的。接下來,我講詳細講一下接入細節。
1. 組件集成
<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId> <version> 5.0.0</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
2. bean配置
配置sharding jdbc數據源並且加入到動態數據源中,用於數據源路由。
修改原配置中心對應服務的mysql數據源配置,對不分庫分表的數據源配置為動態數據源預設路由
3. sharing JDBC配置
spring.shardingsphere.enabled=true #shardingsphere開關
spring.shardingsphere.props.sql.show=true
spring.shardingsphere.mode.type=Standalone #在使用配置中心的情況下,使用standalone模式即可(memery、standalone、cluster三種模式)
spring.shardingsphere.mode.repository.type=File #standalone模式下使用File,即當前配置文件
spring.shardingsphere.mode.overwrite=true # 本地配置是否覆蓋配置中心配置。如果可覆蓋,每次啟動都以本地配置為準。
spring.shardingsphere.datasource.names=ds-0,ds-1 #配置數據源名字,真實數據源
#配置ds-0數據源
spring.shardingsphere.datasource.ds-0.jdbc-url=jdbc:mysql://****
spring.shardingsphere.datasource.ds-0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds-0.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds-0.username=
spring.shardingsphere.datasource.ds-0.password=
#配置ds-1數據源
spring.shardingsphere.datasource.ds-1.jdbc-url=jdbc:mysql://****
spring.shardingsphere.datasource.ds-1.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds-1.driver-class-name=com.mysql.jdbc.Driver
spring.shardingsphere.datasource.ds-1.username=
spring.shardingsphere.datasource.ds-1.password=
#配置模式資料庫分片鍵和相關的表
spring.shardingsphere.rules.sharding.default-database-strategy.standard.sharding-column=user_id
spring.shardingsphere.rules.sharding.default-database-strategy.standard.sharding-algorithm-name=database-inline
spring.shardingsphere.rules.sharding.binding-tables[0]=t_order,t_order_item
spring.shardingsphere.rules.sharding.broadcast-tables=t_address #配置廣播表,即所有庫中都會同步增刪的表
以上是一些基本配置,還有一些業務場景配置,大家可以參考開源社區文檔: https://shardingsphere.apache.org/document/4.1.0/cn/overview/
總結
對於具體業務場景,我們首先是基於DDD的思想劃分業務單元,最開始先做好垂直分庫。接著是針對一些特定的業務增長量巨大的表,進行水平的分庫處理,比如商品子域中的商品池表,訂單子域中的訂單表等等。
而在分表維度,業務初期,就要最好垂直分表的設計。比如商品池設計中,只需要存儲關係信息,而商品詳情的信息單獨存儲在一個底表之中。
作者:京東物流 趙勇萍
來源:京東雲開發者社區