[轉載]基于Aaf的數據拆分

(本文適于使用Aaf框架的開發者閱讀)

1. 基本原理

  在Aaf框架中,“對象”和“存儲”的關系映射有一個關鍵的紐帶StorageAlias,即“存儲別名”,同樣一個類型,在不同的存儲別名下,可以自由映射到任意存儲“位置”。
  “位置”有兩個元素決定,一個是存儲上下文StoargeContext,另外一個是數據表名TableName。缺省的StorageContext在Persistence.Config中配置,缺省的數據表名就是類的名稱。
   所有的映射關系,存儲在兩個地方,一個地方是TypeDescription的ExtendedAttributes屬性中,這里存儲的映射主要來源于 配置文件Persistence.Config中的配置。關系的建立是在Aaf啟動階段,由PersistenceMappingService初始化完 成,調用StorageContextMappingService中的GetStorageAliases方法取得 Persistence.Config中的存儲別名的配置信息。此外,默認的存儲上下文和默認的表名,也初始在此擴展特性中。

  通過Persistence.Config方式配置的映射,是“相對穩定”的映射,數量也在一個非常有限的級別上,例如我們可以將訂單信息按照 交易類型的不同,存儲到不同的數據庫上,也可以將交易完畢的訂單信息搬遷到歷史庫上,我們就可以定義出來形如 “EscortOrderByHistory”這樣的存儲別名,一看就知道是“擔保交易的歷史交易數據”。

  另外一個存儲映射關系的地方是存儲別名信息助手StorageAliasesInfoAssistant,助手的映射關系有三個來源:IStorageAliasTeller提供、手動動態添加、數據庫參數配置

  通過IStorageAliasTeller方式,我們可以根據系統要求,動態 的解析一個存儲別名,不僅如此,我們還可以根據AgileObject.Id自定義規則,推導出其對應的存儲別名,例如我們可以將用戶按照一定規則分表存 儲,然后在用戶的Id中包含存儲別名的信息,這樣,我們就可以非常方便的將海量用戶拆分到若干分表當中,實現數據的分表存儲。此外,與IDataRadiationClassifier搭 配起來,還可以實現“多維存儲”, 就是將同樣一份數據,按照不同的應用需要,散射到多個存儲位置(有可能是散射到不同的數據庫上,例如商品信息散射出一個專門供查詢的庫上;也有可能是同一 數據庫的不同表上,例如訂單信息根據買賣不同散射到特定的數據表上。),同時自動維護各個數據庫上數據的一致性。這樣就可以分身有術,讓多個的數據庫分擔 查詢壓力。

  手動動態添加,是通過IStorageAliasesInfoAssistantRegisterDynamicStorageAlias方法,將已知存儲位置添加到映射表中,同時返回一個GUID碼作為存儲別名。

  數據庫參數配置,這種情形是存儲映射信息是以參數的形式存儲在數據庫中的, 在Aaf.ParaService加載過程中,會自動生成一個Aaf.StorageAliases的配置節點,節點路徑是Aaf.StorageAliases/[StorageAlias](存儲別名,可配多個),節點配置格式是:
[

StorageContext1,TableName1 \n

AppId1: StorageContext2,TableName2 \n

AppId2: StorageContext3,TableName3 \n

]

  其特別的地方是在分布式環境中,根據AppID的不同將數據持久化到特定的存儲上。

?

?

2. 應用實例

  在5173系統中,有許多應用,尤其以用戶、發布單、訂單及資金明細比較典型。下面我們一起去看看。

2.1. 用戶數據分拆

  用戶數據是基礎數據,而且是一種會持續增長的基礎數據,這種數據的膨脹會讓其性能表現越來越差,因為是基礎數據又不能刪除或者搬移,我們處理這種數據的基本策略是將所有用戶按照一定的策略散射到多個數據表中,以緩解單表的壓力,下面我們分析一下實現過程:

1、 將所有用戶數據按照注冊日期段分組,每一個分組共用一個獨立的數據表,分拆存儲,分拆策略啟用有一個時間基線,之前的數據依然存儲在UserInfo中, 自此時間基線之后的數據便存儲在形如UserInfo_X的數據表中。例如,設立時間基線為2009-5-22,每隔90天建立一個新組,某用戶注冊時間 為2009-12-2號,與時間基線相差194 天,除以90得2,存儲在UserInfo_2中。

2、 創建一個類UserInfoSaTeller,實現IStorageAliasTeller接口

3、 將UserInfoSaTeller注冊到別名信息助手,注冊方法如下: PersistenceMappingService.StorageAliasesInfoAssistant.RegisterTeller(typeof(User), new UserInfoSaTeller()),這個注冊在UserService的Run方法中。

4、 保存新用戶時,內核將調用UserInfoSaTeller的GetPrimarySaveStorageAlias方法,取得存儲別名,傳入參數是靈便對象的Id號,因此我們需要構建一個含有分表特征信息的Id,我們現用的Id為“US09120282660351-00F7”,其中紅色加粗部分為注冊日期,通過注冊日期,我們可以計算出一個特定的存儲別名,UserInfo$2, 內核將繼續調用UserInfoSaTeller的GetTableName,傳入參數就是GetPrimarySaveStorageAlias計算出 來的“UserInfo$2”,很顯然我們輕易可以得出實際的存儲表名“UserInfo_2”。可見,我們只要按照規則構造好用戶的Id,程序便可以自 動識別出來應該放到哪里存儲。

5、 根據Id號取用戶實例的過程與保存過程基本類似,內核調用UserInfoSaTeller的GetPrimaryLoadStorageAliases方法,取得加載時存儲別名,之后的映射關系與對象創建時相同。對于用戶數據,保存和獲取時的存儲別名是一致的。

6、 登陸時怎么辦?登陸使用的用戶名進行登陸,而不是用戶Id。沒什么太好的辦法,基本思路還是遍歷所有分表,好在,我們的分表時間區間都是以月為單位,十年 下來也不過一百多個表。此外,當一次遍歷完成之后,我們可以將此用戶對應的存儲別名狀態記錄在某個地方,例如Cookie中,這樣減少遍歷的頻度。

2.2. 發布單數據分拆

  發布單數據的拆分策略稍微復雜一點。根據實際應用需要,除了發布單默認的存儲位置之外,發布單還有幾種存儲形態:根據用戶分組、根據游戲、交易 完成的歷史數據。根據用戶分組分拆,是指把所有用戶在邏輯上分成若干個用戶組,每個用戶組共用一個存儲表;根據游戲更容易理解,即每一款游戲共用一個存儲 表;交易完成的歷史數據,就是那些單子不會再發生變化,這種數據,主要通過數據庫Job定期搬移的。與用戶數據分拆不同的是,發布單是一份數據在不同的地 方用不同的策略存儲,即多維存儲(游戲維度、用戶分組維度)。下面我們分析一下數據創建和加載的過程:

1、 先看創建過程。因為是多維存儲,BizOffer需要實現IDataRadiationClassifier接口,Aaf內核在工作時將調用其中的GetDataRadiationClasses方法,來獲取每個維度的維度標識

2、 使用維度標識,調用IStorageAliasTeller的GetDimensionStorageAlias方法,翻譯出維度對應的存儲別名,形如:Search$0043和BizOfferBy023F-Escort,加黑的分別是“游戲標識”和“用戶邏輯分組標識”。

3、 解釋下用戶邏輯分組的來歷,我們將用戶分成1000個邏輯小組,分組的方法依然與注冊時間、時間基線相關,用兩個時間的差(天數)對1000取模,這樣就 會得到一組數字,將這組數字用四位16進制格式化,就是散射用戶的邏輯分組標記,這個標記,我們也在用戶Id中記錄了,“US09120282660351-00F7”,即藍色加粗部分。當一個用戶創建發布單的時候,我們便知道其邏輯分組為00F7。游戲標識要簡單一些,每一款游戲都會有一個自增長的表號,此表號也是用四位16進制表示。注意,用戶分組目前是固定為1000個組的,而游戲分組是不斷增長的。

4、 接下來就是分別對每個維度的存儲別名進行存儲動作,通過IStorageAliasTeller的GetContextName和GetTableName,取得實際的存儲位置信息。

兩個維度路徑是:

存儲別名–>存儲上下文名稱–>數據庫名稱–>數據表名

游戲散射:Search$0043–> RadiationOffer1–> SearchOffer–> BizOfferby0043

用戶散射:BizOfferBy023F-Escort–>OfferDataRadiations–>OfferDR–>BizOfferBy023F

5、 還有一個維度是歷史庫的發布單數據,這個是Job搬遷創造的,數據表的命名規則是一個月三張表,按旬存儲,形如:BizOfferby200607_1
。雖然創建過程不是Aaf做的,但查詢數據時是Aaf做的,后面我們在做查詢分析的時候要考慮這部分數據。

6、 在單條數據加載的時候,重點是確定查詢策略了,就是什么數據該先從哪個維度去找,策略確定之后,就是拼存儲別名來定位查詢的數據庫表了。我們現在的查詢策 略是先查找當前庫,拼EscortByCurrent的存儲別名,此存儲別名在Persistence.Config中配置了映射關系;接著檢查“用戶分 組維度”;再接著,查找歷史庫。

幾個查詢路徑如下:

當前庫:EscortByCurrent–>ConsignmentByCurrent–>Consignment–>BizOffer

用戶散射:BizOfferBy023F-Escort–>OfferDataRadiations–>OfferDR–>BizOfferBy023F

按發布單結束時間歷史庫(后臺使用):Escort|200912_1–>OfferHistory–>OfferHistory–> BizOfferby200912_1

按發布單創建時間歷史庫(前臺使用):
Escort~200912_1–> OfferHistorybyCreatedDate–> OfferHistorybyCreatedDate–> BizOfferby200912_1

7、 接下來我們梳理一下各種發布單列表是怎么出來的,當一個查詢過來的時候,我們首先判斷查詢條件中是否含有用戶信息,如果有,直接走“用戶分組維度”。如果 沒有用戶信息,至少會包含一個游戲信息,即GameId,走游戲維度的存儲。注意,列表查詢沒有走“默認維度”,這樣默認維度就可以專心用于交易了。

8、 8、 有關發布單查詢,還沒有結束。就是另有一個發布單搜索對象BizOfferSearch,這個是另外生成的一份數據,專門供搜索用,與當前交易平臺隔離。同樣也有兩個維度:

存儲別名–>存儲上下文名稱–>數據庫名稱–>數據表名

游戲散射:Search$0043–> RadiationOffer1–> SearchOffer–> BizOfferSearchby0043

用戶散射:BizOfferSearchBy023F-Escort–>OfferDataRadiations–>OfferDR–>BizOfferSearchBy023F

2.3. 訂單數據分拆

  訂單的數據分拆方法類似,根據實際應用需要,除默認存儲外,也有幾個維度的存儲:買家分組散射、賣家分組散射、歷史庫數據。從技術實現方式來講完全一個套路。。

1、 訂單創建過程與發布單雷同,不再贅述。需要注意的是,買賣維度的數據表名中也是附加了用戶分組標識。一筆訂單,會因為買家和賣家的分組不同,而存在于不同標識的分表中。

2、 訂單取得過程,先從默認庫查找,找不到再去買家維度找,找不到再去賣家維度找,還找不到就到歷史庫中找。

維度路徑是:

存儲別名–>存儲上下文名稱–>數據庫名稱–>數據表名

買家散射:OrderByBuyer023F-Escort–> OrderDataRadiations–> OrderDR –> OrderByBuyer023F

賣家散射:OrderBySeller009B-Escort–> OrderDataRadiations–>OrderDR–> OrderBySeller0339

歷史庫:Escort|200912_1–>OrderHistory–>OrderHistory–> Orderby200912_1

3、 在前臺列表查詢中,買賣雙方呈現自己的訂單時,是分別從買賣維度即OrderDR這個庫中取數據的。后臺列表查詢,走的是默認維度的訂單庫。同時,對于交易完成的數據,到歷史庫OrderHistory中查詢。

2.4. 資金分表

  AccountDetail,除默認在外,還有用戶分組維度、歷史庫維度。

1、 多維存儲路徑:

存儲別名–>存儲上下文名稱–>數據庫名稱–>數據表名

用戶散射:AccountDetailBy00F7–>DataRadiations–>BkDR–> AccountDetailBy00F7

歷史庫:200912_1–>BkHistory–> BkHistory–> AccountDetailBy200912_1

2、 特別要說明的是,每種資金類型都有自己的獨立的類,他們如何共用AccountDetail這樣一個存儲的呢?原來所有的獨立的資金類型都派生自 AccountDetail,而AccountDetail中設置的“[AgileObjectStorage(TableName = "AccountDetail", ContextName="BkUser")]”,也被繼承下來了。其實更重要的是它們也繼承了的IDataRadiationClassifier實 現,此外,在PaymentService的Run方法中,幾乎所有類型都注冊了AccountDetailSaTeller,于是實現了所有類型的存儲 規則統一。

2.5. 映射列表

以下是開發環境中的映射關系列表:

對于這些類型,如果要修改字段,每一個關聯維度上對應的分表都要變更,我們經常碰到的缺字段,就是某個維度上有缺失。

類型

數據庫名

數據表名

存儲上下文名

存儲別名

UserBkUser
(默認主庫)
UserInfo_1
UserInfo_2…

UserInfo_n

BkUserUserInfo$1
UserInfo$2…

UserInfo$n

BizOfferConsignment
(默認主庫)
BizOfferConsignmentByCurrentEscortByCurrent
SearchOffer
(游戲散射)
BizOfferby0000

BizOfferBy07D0…
RadiationOffer1Search$0000

Search$07D0…
OfferDR
(用戶散射)
BizOfferBy0000

BizOfferBy03E8
OfferDataRadiationsBizOfferBy0000-Escort

BizOffeBy03E8-Escort
OfferHistory
(歷史庫By交易完成時間)

BizOfferby200912_1
BizOfferby200912_2
BizOfferby200912_3
OfferHistory
Escort|200912_1
Escort|200912_2
Escort|200912_3…
OfferHistorybyCreatedDate
(歷史庫By創建時間)

BizOfferby200911_1
BizOfferby200911_2
BizOfferby200911_3
OfferHistorybyCreatedDate
Escort~200911_1
Escort~200911_2
Escort~200911_3…
BizOfferSearchConsignment
(默認主庫)
BizOfferSearchConsignmentByCurrentEscortByCurrent
SearchOffer
(游戲散射)
BizOfferSearchby0000

BizOfferSearchBy07D0
RadiationOffer1Search$0000

Search$07D0
OfferDR
(用戶散射)
BizOfferSearchBy0000

BizOfferSearchBy03E8
OfferDataRadiationsBizOfferSearchBy0000-Escort

BizOfferSearchBy03E8-Escort
OrderConsignment
(默認主庫)
OrderConsignmentByCurrentEscortByCurrent
OrderDR
(買家散射)
OrderByBuyer0000

OrderByBuyer03E8
OrderDataRadiationsOrderByBuyer0000-Escort

OrderByBuyer03E8-Escort
OrderDR
(賣家散射)
OrderBySeller0000

OrderBySeller03E8
OrderDataRadiationsOrderBySeller0000-Escort

OrderBySeller03E8-Escort
OrderHistory
(歷史庫)

Orderby200912_1
Orderby200912_2
Orderby200912_3
OrderHistory
Escort|200912_1
Escort|200912_2
Escort|200912_3
AccountDetailBkUser
(默認主庫)
AccountDetailBkUserCurrent
BkDR
(用戶散射)
AccountDetailBy0000

AccountDetailBy03E8
DataRadiationsAccountDetailBy0000

AccountDetailBy03E8
BkHistory
(歷史庫)
..
.
AccountDetailBy200912_1
AccountDetailBy200912_2
AccountDetailBy200912_3
BkHistory
200912_1
200912_2
200912_3…
說明: Escort,是交易類型,此處只是舉例,應用中可能是其它標識。

  除了上面的映射,自定義映射還有一些,順著IstorageAliasTeller的實現類去尋找吧。

轉載于:https://www.cnblogs.com/hb_cattle/articles/2029325.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/448299.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/448299.shtml
英文地址,請注明出處:http://en.pswp.cn/news/448299.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

靠邊停車

什么是靠邊停車 靠邊停車是大路考中一個指標很明確的考核項目,要求學員駕駛車輛使之靠邊停下。 操作方法 1、停車前,要通過內、外后視鏡觀察后方和右側交通情況,開右轉向燈。 2、適量踩下制動踏板。 3、向右轉動方向盤(第一把輪…

RuntimeException 和 Exception 區別、異常的子父級關系

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 1.java 將所有的錯誤封裝為一個對象,其根本父類為Throwable, Throwable 有兩個子類:Error 和 Exception。 2.Err…

通過路口

操作方法 1、讓車減速 2、觀察路口的情況 3、通過路口 注意事項 1、不要搶黃燈 2、不要開英雄車,即紅燈亮起時通過路口的最后一輛車 3、控制車速,控制在50km/h以下 4、看到左右車都減速時,也馬上減速 5、要左轉…

C語言筆記(關鍵字)

gdb調試 gcc 源程序 -g;加gdb調試信息gdb可執行程序;(gdb調試)l(ist):查看源碼,按一下從main開始10行以此往后l n:查看n處上下10行的源碼run:運行程序b&…

自定義 Git - Git 鉤子 (自動部署)

Git 鉤子 前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 和其它版本控制系統一樣,Git 能在特定的重要動作發生時觸發自定義腳本。 有兩組這樣的鉤子:客戶端的和…

變更車道

操作方法 1、觀察與判斷觀察車輛后方、側方和準備變更的車道上的交通流情況; 2、確認安全后,打開轉向指示燈示意,并再次通過后視鏡觀察兩側道路上有無車輛超越,確認準備駛入的車道是否允許留有安全距離; 3…

C語言筆記(符號)

注釋符號 幾個似非而是的注釋問題 例子: (A) int / * ... * /i; (B) char * s "abcdefgh //hijklmn"; (C) //Is it a \valid comment? (D) in/ * ... * /t i; 我們知道C語言里可以有兩種注釋方式:“/* */” 和 “ // ”。那么上面幾條…

直線行駛

考核要求 保證跟車安全速度和安全距離,了解車輛行駛速度、注意觀察路面狀況,采取相應措施。不能有左右擺動、方向不穩的現象。 考試口訣 一.尋找中心 二.雙眼鎖定本車能通行的中心 三.心理想著走中間 四.雙眼從本車前面最突出點的.中心…

java 命令: jmap 命令使用 ( 查看內存使用、設置 )

jdk安裝后會自帶一些小工具,jmap命令(Java Memory Map)是其中之一。主要用于打印指定Java進程(或核心文件、遠程調試服務器)的共享對象內存映射或堆內存細節。 jmap命令可以獲得運行中的jvm的堆的快照,從而可以離線分析堆,以檢查內存泄漏&am…

第一節 接口概述 [轉貼]

接口(interface)用來定義一種程序的協定。實現接口的類或者結構要與接口的定義嚴格一致。有了這個協定,就可以拋開編程語言的限制(理論上)。接口可以從多個基接口繼承,而類或結構可以實現多個接口。接口可以…

獲取本機用戶名、MAC地址、IP地址、硬盤ID、CPU序列號、系統名稱、物理內存

我們在利用C#開發桌面程序(Winform)程序的時候,經常需要獲取一些跟系統相關的信息,例如用戶名、MAC地址、IP地址、硬盤ID、CPU序列號、系統名稱、物理內存等。 首先需要引入命名空間: using System.Management; //…

只用一套解決方案,就可解決80%的交通物流行業信息難題

行業背景 新中國成立70多年來,中國交通運輸總體上已經形成了多節點、全覆蓋的綜合運輸網絡,“五縱五橫”綜合運輸大通道基本貫通,一大批綜合客運、貨運樞紐站場(物流園區)投入運營,取得了一系列矚目成果&am…

起步

什么是開車起步 起步,即發動汽車,使汽車開始走動。 操作方法 1、“踩”離合器 2、“掛”一檔 3、“打”左轉向燈(提醒后車駕駛員注意安全避讓) 4、“鳴”號(引起車輛周圍的行人或機動車等注意&…

Linux 使用 jstat 命令查看 jvm 的 GC 情況

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 Options,選項,我們一般使用 -gcutil 查看gc情況 vmid,VM的進程號,即當前運行的java進程號…

WKWebview加載本地圖片時出現路徑問題

出現問題情況是:將uiwebview換成wkwebview之后,之前將webview上那些圖片放回本地下載后緩存的圖片沒辦法在webview上找到,最后排查出原因是,wkwebview需要將圖片和網頁文件放在同個路徑下。 具體實現方法如下(獲取圖片緩存的路徑&…

上車準備

上車準備一 1、環視車輛、確保安全。 2、調整駕駛座。身體坐正,雙手向前伸直,以手腕剛好能放在方向盤上為準。左腳擱在離合器上,右腳擱在剎車上,小腿和大腿成90度。左腳可以輕松把離合器踩到底。身體離方向盤20—25厘米。 …

C++復習

register關鍵字請求“編譯器”將局部變量存儲于寄存器中 C語言中無法取得register變量地址 在C中依然支持register關鍵字 1、C編譯器有自己的優化方式,不使用register也可能做優化 2、C中可以取得register變量的地址 C編譯器發現程序中需要取register變量的地址…

Docker 方式安裝 Nginx 、阿里云服務器上裝 Ngnix

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 非 Docker 方式安裝,直接 Linux 安裝見另一文:Linux 上 安裝 nginx 、阿里云服務器上安裝 nginx 1. 直接從鏡像倉…

C#實現A*算法

理解A*尋路算法具體過程 這兩天研究了下 A* 尋路算法, 主要學習了這篇文章, 但這篇翻譯得不是很好, 我花了很久才看明白文章中的各種指代. 特寫此篇博客用來總結, 并寫了尋路算法的代碼, 覺得有用的同學可以看看. 另外因為圖片制作起來比較麻煩, 所以我用的是原文里的圖片. 當…

路考口訣

路考口訣一 一踩(踩離合)、二掛(掛一檔)、三看(看倒車鏡)、四轉(轉向燈)、五按(按喇叭)、六手剎、七走 路考口訣二 01.路考之道很輕松,牢…