分庫分表最全詳解 -圖文全面總結-

大家好,我是 mikechen。

分庫分表是大型架構的必備技能,也是大廠重點考察的對象,下面我就全面來詳解分庫分表 @mikechen

分庫分表

分庫分表是數據庫設計、和管理中的一種策略,主要解決隨着數據量、和併發訪問量的增加而帶來的性能、和擴展性問題。

分庫分表,主要就是兩種常用手段:“分庫”、和 “分表”。

如下圖所示:

分庫(Database Sharding): 將數據按照某種規則,分散到多個獨立的數據庫中,每個數據庫稱爲一個 “分庫”。

分表(Table Sharding): 將一個大表的數據按照某種規則,分散到多個小表中,每個小表稱爲一個 “分片”、或 “分表”。

爲什麼要分庫分表

在系統不斷髮展、數據量急劇增加的情況下,傳統的數據庫架構往往難以應對性能和擴展性的問題。

特別是當單表的數據量達到千萬、甚至億級別時,即使使用了索引,查詢性能也會受到影響。

爲了解決這一問題,分庫分表是一種有效的策略。

分庫分表通過將數據,按照某種策略分配到多個數據庫節點、或表中,提高了查詢和寫入性能,從而,增強系統的可擴展性和容錯能力。

分庫分表實現

通過用數據庫分庫分表中間件,比如:ShardingSphere、MyCat... 等,開發者可以方便地實現:分庫分表。

分庫分表旨在,通過將大表、或大數據庫的數據,切分爲多個較小的部分,從而提升性能。

如下圖所示:

核心步驟,如下:

第一步:首先分析數據

確定分庫分表的必要性,比如:分析當前數據庫的性能瓶頸,確定是否需要進行分庫分表。

以及,評估數據量的增長趨勢、和未來的擴展需求。

第二部:確定拆分類型

然後,根據業務特點,選擇合適的分片策略(如:哈希分片、範圍分片、列表分片........ 等)。

哈希分片(Hash Sharding)

根據某個字段(如用戶 ID),進行哈希運算,將數據均勻分佈到不同的分片中。

適用於:需要均勻分佈數據,且無法預知數據分佈特點的場景。

範圍分片(Range Sharding)

根據某個字段的值範圍進行分片,例如按時間範圍(比如:年、月、日)、或按數值範圍進行分片。

適用於:數據有明顯的範圍劃分的場景。

列表分片(List Sharding)

根據字段的具體值進行分片,例如:按地區、類別等。

適用於:數據有明確分類的場景。

組合分片(Composite Sharding)

結合多種分片策略,例如:先按地域分片,再按用戶 ID 哈希分片。

第三步:實現數據拆分

採用數據庫分庫分表中間件,如 ShardingSphere..... 等,簡化分庫分表的實現。

ShardingSphere 是一個分佈式數據庫中間件解決方案,支持:分庫分表、讀寫分離、和數據治理...... 等方案。

假設有一個電子商務系統,包括:用戶信息表(users)和訂單信息表(orders),我們希望將用戶信息表和訂單信息表分別存儲在兩個不同的數據庫中。

如下所示:

可以通過 ShardingSphere 的配置文件定義數據源和實際數據節點,實現表的垂直拆分:

schemaName: ecommerce
dataSources:
  user_db:
    url: jdbc:mysql://localhost:3306/user_db
    username: root
    password: password
  order_db:
    url: jdbc:mysql://localhost:3306/order_db
    username: root
    password: password
shardingRule:
  tables:
    users:
      actualDataNodes: user_db.users
    orders:
      actualDataNodes: order_db.orders

然後,在應用層通過 ShardingSphere 提供的 DataSource 連接不同的數據庫,進行數據操作。

// 加載垂直拆分配置文件
        DataSource dataSource = YamlShardingSphereDataSourceFactory.createDataSource(new File("vertical-sharding.yml"));
        // 查詢用戶信息
        String userSql = "SELECT * FROM users WHERE user_id = ?";
        try (Connection conn = dataSource.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(userSql)) {
            pstmt.setLong(1, 1L);
            try (ResultSet rs = pstmt.executeQuery()) {
                while (rs.next()) {
                    System.out.println("User ID: " + rs.getLong("user_id") + ", Username: " + rs.getString("username"));
                }
            }
        }

這裏需要注意,以下幾點:

  1. 數據均勻分佈:確保分片策略能夠均勻分佈數據,避免出現單個分片過熱的情況。

  2. 事務處理:處理跨分片事務的一致性問題,可以採用分佈式事務管理器(如:Seata)。

  3. 分佈式 ID 生成:確保全局唯一 ID,可以採用 Snowflake 算法...... 等分佈式 ID 生成方案。

總之,通過合理的分片策略、和中間件配置,可以顯著提升系統的性能、和擴展性。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/YtOVz_xDiqpfeSBK6OjyiA