項目背景
注:因涉及公司保密協議,會隱藏代碼,只說明設計思路。
本人所在公司是做saas軟件服務的,在做一個大客戶專項時遇到集團企業需要管控子公司,希望可以誇租戶管理。
也就是說,有一個集團租戶,可以管理多個子租戶。配置數據都由集團租戶下發,子租戶只能使用。子租戶還要定時上報業務數據,集團要統計查看各子租戶數據。
按現有架構是無法支持該模式的,所以初步打算保持原有租戶(之後簡稱子租戶)不變的情況,再將現有系統複製出一套,用於開發集團租戶(之後簡稱主租戶),這樣業務只要核心開發主租戶方向的新需求,子租戶增加權限控制就可實現該需求。
遇到的問題
1. 業務模塊多,每天都在增加新的模塊與表結構(現有表400多張)
2. 主租戶下發的配置數據主鍵如何在多個子租戶唯一,並保持與主租戶配置數據的關係
3. 如何確保子租戶上報的數據主鍵唯一
4. 大數據量不同表,如果確保數據一致性
5. 時間
因爲項目有時間壓力,在開發時分多個階段執行。
階段 | 說明 |
---|---|
驗證方案 | 直接修改部分表數據,驗證子租戶功能是否有問題 |
SQL版 Demo | 根據驗證的方案,出一個直接生成新的子租戶所有表SQL快速驗證版,測試大部分功能是否可用 |
主租戶開通流程 | 傳輸工具完成新的主租戶開通流程 |
完整全流程 | 主租戶按模塊下發、子租戶數據上報 |
性能優化 | 優化性能與穩定性 |
在驗證方案可行之後,需要快速實現,給業務開發提供接口,保證業務開發不阻塞,所以初始方案與最終方案會有一些差異,但核心思路相同。
核心思路
1. 使用功能模塊 + SQL實現各功能模塊的數據下發或上報。
調用方指定模塊,業務無需關注具體SQL,一次配置好,如後續有修改也只需要負責該模塊的開發調整SQL就可以,無需調整調用邏輯。
2. 更改主鍵ID規則,使用《租戶ID + "特殊字符" + 源數據ID》形式,並替換引用字段ID,如staff表引用部門ID,也會將部門ID轉換爲新ID規則
3. 定義主子任務機制,兼容多業務場景,如任務1完成後,執行任務2修改某些數據等複雜場景。
4. 使用任意載體可將數據做雙向傳輸。
主租戶與子租戶數據存儲方案
前置條件說明
1. 所有表的ID主鍵都是字符串
2. 每張表都有一個字段存放租戶ID
3. 因內部技術架構原因,所有數據結構都是以mysql 的json結構存放。
所以一個表一般只有主鍵ID與數據一個大json存放,索引都是使用json中的虛擬列實現。
方案不同的地方
問題 | 初始方案 | 最終方案 | 替換原因 |
---|---|---|---|
引用ID替換問題 | 傳輸前查出所有主鍵ID,使用DFA算法替換數據中的引用ID | 更改ID生成規則,可識別數據中哪些數據是ID | 性能原因 |
數據傳輸方式 | 使用CSV文件作爲一個任務數據的載體,先傳輸到自建minio,接收方下載後解析入庫執行 | 使用RESTful接口一個任務分批多次傳輸,傳輸完成後一起執行 | 減少歷史無用文件,傳輸時壓縮數據大小 |
程序設計
以上基本把本次數據傳輸的業務需求與方案做了說明。 接下來具體到程序設計階段。
技術需求
1. 爲了可以更好的維護與部署,最好在一個程序中,只通過修改配置實現雙向不同地址的傳輸。
2. 用什麼方式獲取數據庫所有表,避免因業務新增表缺少同步數據。
3. 如何確保之後的擴展性?如初期使用minio做爲數據載體,之後需要擴展爲RESTful接口形式。
4. 如何解決數據庫事務與單表大事物問題。
5. 整個數據變更與傳輸儘量減少業務開發參與,業務只專注在業務開發上。
整個項目,選用了以下相關工具包:
jiar包 | 版本 | 說明 |
---|---|---|
spring cloud | 2.2.2 | 基礎服務 |
hutool | 5.4.3 | 使用DB操作 |
druid | 1.1.22 | DB連接池 |
lombok | 1.18.12 | |
okhttp | 3.14.4 | RESTful傳輸數據使用(數據壓縮gzip) |
用主企業開通的業務流程來做例子說明:
上圖簡易描述了一個新的租戶,如何從一個普通租戶轉換爲一個集團主租戶的流程。可以看到無論在主租戶還是子租戶中,都是有很多步驟,再具體到代碼層還會有更多。
數據傳輸是可以雙向傳輸,所以按數據發送方、接收方定義。一個完整的執行流程大致與下圖:
雙方分別使用發送方與接收方責任鏈來實現整體流程。因有特殊業務所以在責任鏈中增加了特殊業務處理。
下邊接着說明數據傳輸所用到的數據模型:
表名 | 說明 | 作用 |
---|---|---|
transfer_application | 應用配置表 | 該表通過只允許一個active的數據,確保當前應用的配置如URL、AK、SK等 |
transfer_model | 業務模塊 | 抽象業務模塊,爲業務開發聚合分類(預定義) |
transfer_modelItem | 業務模塊SQL | 對應業務模塊SQL語句(預定義) |
transfer_modelItemCondition | 業務模塊SQL條件 | 爲sql語句定義動態添加的條件 |
transfer_taskInfo | 數據傳輸主任務 | 一次調用請求生成一次主任務(包含子任務總數量) |
transfer_subtask | 數據傳輸子任務 | 一個主任務可以支持多個子任務,可支持子任務按順序執行(包含子任務傳輸數據總數量) |
transfer_data | 臨時數據存儲 | 因數據分批傳入,整個任務全部傳輸後再做數據最終落庫。 |
在配置業務模塊SQL時,大部分核心配置都是查詢語句,只有特殊業務對會需要配置其他類型SQL。主要是因爲數據發起的邏輯都是以發起方已修改好的最終數據進行傳輸,在到達接收方時需要根據實際情況進行insert or update的不同進行操作。
項目總結
以上就是該項目整體的核心設計思路,項目主要麻煩的地方就是在前邊提到的ID轉換,因爲數據是增量的,在用DFA搜索替換會導致使用時間越久導致傳輸效率越差。
舊方案單任務傳輸110W並轉換數據大概需要1小時20分左右,修改替換數據方案後110W數據大概需要10分左右,極大的提升了性能。