完整分庫分表流程demo


完整分庫分表流程demo

 

一、 技術

 

二、 模擬訂單表分庫分表遷移流程

1. 確認分庫分表鍵

  • 可以統計查詢訂單表的where條件

    選用命中率高的, 減輕主要查詢壓力

  • 需要考慮分布式事務

    t_order表和t_order_item表, 保存一次訂單,確保分庫后order和order_item都放在同一個庫中,
    這樣就可以使用本地事務了。一般選用user_id, 選用order_id也可以, 本demo使用user_id

    注意事項,選用了user_id做分片鍵,則原先使用order_id查詢的接口會遍歷各個分庫查詢數據
     a. 如果數據量不是特別大,可以不處理  b. 本demo將user_id和order_id映射關系保存到t_order_mapping表中,使用order_id查詢時先查詢一次user_id,然后帶上user_id查詢訂單  c. 基因id 處理,參考美團訂單分庫分表實現,定制order_id,中間嵌入user_id后幾位數字,分片查詢時根據user_id基因數字路由,這種改造工程比較大  d. 多列分庫分表,在將user_id做一次分庫分表的同時,也將order_id做一次分庫分表,存了兩份數據,存儲較大

 

2. 分片算法

  • range

    按時間或id范圍划分,如[1-10000]放到1庫,[10001-20000]放到2庫
    優點:單表大小可控,天然水平擴展。
    缺點:無法解決集中寫入瓶頸的問題。

  • hash

    hash取模 2^n
    分2(庫) * 4 (表), 即分2個庫,每個庫4張表
    則 路由規則是 庫號= user_id % 2, 表號= (user_id/2) % 4

    優點: 易擴展,解決集中寫入瓶頸的問題
    缺點: 擴容麻煩,需要重新hash,(注意避免在同一張表的數據,重新hash到不同的表), 需要遷移數據

    (本demo采用該方法)

 

3. 確定容量,考慮擴容

  • 生產中一次性分夠,夠用好幾年,不用考慮擴容

    分32(庫) * 32 (表) , 分成32個庫,每個庫32張表, 共1024張表(也可以16*64)
    路由規則是 庫號= user_id % 32, 表號= (user_id/32) % 32

  • 初始邏輯分庫,實際上可以部署4台機器,每台機器8庫, 每個庫32表

    當表數據超過單機限制后,可以部署8台機器,每台機器4各庫,每個庫32表 最多可以部署1024台機器,每台機器1張表

    擴容時,僅僅是改一下配置,遷移數據就可以了, 原來在同一張表的數據,擴容之后,還在同一張表

    更具體的介紹看美團實現

 

4. 唯一id

  • uuid 字符串

    占用空間較多, 不能做到遞增

  • 雪花算法

    可以做到遞增,性能較好
    維護workId比較麻煩
    存在時鍾回撥問題
    其他的實現一般都是基於雪花算法進行改造

  • 美團leaf唯一id實現

    比較復雜,暫不考慮

  • 百度uid-generator

    比較簡單,解決workId維護問題,解決了時鍾回撥問題,暫未提供workId重用實現

    本demo采用該實現,已實現復用workId

    ecp-uid整合了美團leaf、百度UidGenerator、原生snowflake 實現,可以參考,
    由於直接使用uid-generator足夠簡單,且有效使用,暫不采用ecp-uid

 

5. 單庫表 遷移 到分庫

參考美團雙寫實現

  • ① 原系統中將需要訂單表的關聯查詢(join)去掉

    改成在應用中用代碼處理join, 為后續分庫分表做准備

  • ② 改造系統中訂單id的實現,統一使用uid-generator生成的唯一id

  • ③ 數據庫雙寫(先寫單庫,后寫分庫,事務以單庫為主,讀數據以單庫為主 ),同步訂單歷史數據到分庫,然后校驗補償分庫數據

    a. 先寫單庫,后寫分庫,事務以單庫為主,讀數據以單庫為主

    b. 同時,使用datax同步歷史訂單數據到分庫

    c. 校驗單庫和分庫數據,補償數據到分庫(插入或根據更新時間比較更新)

  • ④ 在③步驟數據補平后,數據仍雙寫(先寫分庫,后寫單庫,事務以分庫為主,讀數據以分庫為主),同時校驗補償單庫數據

    a. 先寫分庫,后寫單庫,事務以分庫為主,讀數據以分庫為主
    (如果服務眾多,可以切一小部分服務灰度嘗試讀寫, 如果有問題,可以回退到③)

    b. 校驗單庫和分庫數據,補償數據到單庫(插入或根據更新時間比較更新)

  • ⑤ 觀察幾天沒問題后,下線單庫訂單表

 

6. 分庫分表中間件

    • mycat

      基於數據庫代理實現,存在單點問題

    • shardingsphere

      目前成為apache頂級項目, 從前景上說,采用該技術應是最好的

      • sharding-jdbc

        shardingsphere子項目, jdbc代理

        a. 不存在單點問題
        b. 可能會存在多份配置
        c. 升級比較麻煩,需要統一升級
        d. 只能應用於java語言

      • sharding-proxy

        shardingsphere子項目, 數據庫代理

        a. 存在單點問題
        b. 兼容性問題
        c. 優點是沒有語言限制

      目前demo采用sharding-jdbc實現為主,sharding-proxy運維為輔

 

完整demo源碼

 

三、本demo使用流程

1. 創建單庫

create database db_lab;

 

2. 運行數據初始數據庫腳本

db_lab_table.sql 用於創建數據表
db_lab_data.sql 用於創建測試數據,里面有3萬訂單(t_order)數據,和9萬訂單項(t_order_item)數據

3. 創建2個分庫

create database db_lab_orders_0;
create database db_lab_orders_1;

 


4. 配置uid-generator數據庫

  • 創建uid數據庫

    create database uid; 
  • 創建uid數據表

    DROP TABLE IF EXISTS WORKER_NODE;
    CREATE TABLE WORKER_NODE
    (
    ID BIGINT NOT NULL AUTO_INCREMENT COMMENT 'auto increment id',
    HOST_NAME VARCHAR(64) NOT NULL COMMENT 'host name',
    PORT VARCHAR(64) NOT NULL COMMENT 'port',
    TYPE INT NOT NULL COMMENT 'node type: ACTUAL or CONTAINER',
    LAUNCH_DATE DATE NOT NULL COMMENT 'launch date',
    MODIFIED TIMESTAMP NOT NULL COMMENT 'modified time',
    CREATED TIMESTAMP NOT NULL COMMENT 'created time',
    PRIMARY KEY(ID)
    )
     COMMENT='DB WorkerID Assigner for UID Generator',ENGINE = INNODB;

     

  • 修改uid數據庫配置用戶名密碼

5. 修改對應數據庫配置,用戶名密碼等

6. 搭建sharding-proxy后, 復制proxy配置, 啟動運行

使用shrding-proxy創建分庫分表后的訂單表

CREATE TABLE `t_order` (
  `order_id` bigint(20) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `address_id` bigint(20) NOT NULL,
  `status` varchar(50) DEFAULT NULL,
  `create_time` datetime NOT NULL,
  `update_time` datetime NOT NULL,
  PRIMARY KEY (`order_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8

 

CREATE TABLE `t_order_item` (
  `order_item_id` bigint(20) NOT NULL AUTO_INCREMENT,
  `order_id` bigint(20) DEFAULT NULL,
  `user_id` int(11) NOT NULL,
  `status` varchar(50) DEFAULT NULL,
  `create_time` datetime NOT NULL,
  `update_time` datetime NOT NULL,
  PRIMARY KEY (`order_item_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8

 

7. 啟動single-datasource-lab項目,用於模擬原使用單庫web應用

注意以下配置,用於分庫分表遷移的切換

# 1 使用uid的初始下單  2 下單雙寫,以單庫讀寫為主  3  下單雙寫, 以分庫讀寫為主 4 下單只寫在分庫
transfrom.step=2

可以打包放到idea外部部署運行,高配機器可以忽略

8. 啟動single-datasource-lab中的模擬客戶端

模擬用戶訪問訂單服務

9. 下載datax部署同步訂單歷史數據

本項目使用datax+sharding-jdbc同步訂單歷史數據,查看使用方法

  • 復制配置到本機datx/job目錄下,並修改對應賬號密碼
  • 使用命令運行'job-order.json','job-order_item.json'同步歷史數據到分庫,其中'job-order_mapping.json'是用於同步order_id和User_id的關系數據

10. 數據庫雙寫(step=2)時,啟動validate-step2校驗補償訂單

在single-datasource-lab項目運行時配置是'transfrom.step=2'時, 啟動 validate-step2項目,用於校驗補償分庫訂單數據

11. 校驗補平分庫數據后,切換數據庫雙寫,此時以分庫事務為主,讀數據以分庫為主

修改single-datasource-lab配置'transfrom.step=3',並重啟 觀察是否有問題,如果有問題,則回退到step=2

12. 重啟validate-step2項目,做分庫最后一次校驗

因為step2啟動時,會讀取當前最大的訂單id, 進行校驗,重啟是為了防止遺漏

13. 啟動 validate-step3項目,進行驗證單庫數據校驗

這里主要是為了可回滾

14. 繼續觀察single-datasource-lab,確認沒問題后,下線單庫訂單表

真實項目需持續觀察幾天, 沒有問題,則修改配置為'transfrom.step=4', 重啟下線單庫訂單
有問題,則回退到step2, 注意,回退后,validate-step2也需重新運行校驗

 

四、常見問題

  1. no table route info
    根據路由規則得到的表名在數據庫中不存在,檢查配置
    可以開啟sharding日志進行排查
      props:
        sql:
          show: true # 打印 SQL

     

 

 

 完整demo源碼

 

 

 

后記

   分庫分表是突破單機性能的重要手段,但分庫分表實現比較復雜,不到萬不得已不可輕易使用

   本demo尚未在真實項目中使用,僅供學習和參考

 

參考資料

      大眾點評訂單系統分庫分表實踐

      Java互聯網架構-Mysql分庫分表訂單生成系統實戰分析

     分庫分表面試准備

    分庫分表技術演進&最佳實踐-修訂篇

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM