[转载]基于Aaf的数据拆分
(本文適于使用Aaf框架的開發(fā)者閱讀)
1. 基本原理
在Aaf框架中,“對(duì)象”和“存儲(chǔ)”的關(guān)系映射有一個(gè)關(guān)鍵的紐帶StorageAlias,即“存儲(chǔ)別名”,同樣一個(gè)類型,在不同的存儲(chǔ)別名下,可以自由映射到任意存儲(chǔ)“位置”。
“位置”有兩個(gè)元素決定,一個(gè)是存儲(chǔ)上下文StoargeContext,另外一個(gè)是數(shù)據(jù)表名TableName。缺省的StorageContext在Persistence.Config中配置,缺省的數(shù)據(jù)表名就是類的名稱。
所有的映射關(guān)系,存儲(chǔ)在兩個(gè)地方,一個(gè)地方是TypeDescription的ExtendedAttributes屬性中,這里存儲(chǔ)的映射主要來源于 配置文件Persistence.Config中的配置。關(guān)系的建立是在Aaf啟動(dòng)階段,由PersistenceMappingService初始化完 成,調(diào)用StorageContextMappingService中的GetStorageAliases方法取得 Persistence.Config中的存儲(chǔ)別名的配置信息。此外,默認(rèn)的存儲(chǔ)上下文和默認(rèn)的表名,也初始在此擴(kuò)展特性中。
通過Persistence.Config方式配置的映射,是“相對(duì)穩(wěn)定”的映射,數(shù)量也在一個(gè)非常有限的級(jí)別上,例如我們可以將訂單信息按照 交易類型的不同,存儲(chǔ)到不同的數(shù)據(jù)庫(kù)上,也可以將交易完畢的訂單信息搬遷到歷史庫(kù)上,我們就可以定義出來形如 “EscortOrderByHistory”這樣的存儲(chǔ)別名,一看就知道是“擔(dān)保交易的歷史交易數(shù)據(jù)”。
另外一個(gè)存儲(chǔ)映射關(guān)系的地方是存儲(chǔ)別名信息助手StorageAliasesInfoAssistant,助手的映射關(guān)系有三個(gè)來源:IStorageAliasTeller提供、手動(dòng)動(dòng)態(tài)添加、數(shù)據(jù)庫(kù)參數(shù)配置。
通過IStorageAliasTeller方式,我們可以根據(jù)系統(tǒng)要求,動(dòng)態(tài) 的解析一個(gè)存儲(chǔ)別名,不僅如此,我們還可以根據(jù)AgileObject.Id自定義規(guī)則,推導(dǎo)出其對(duì)應(yīng)的存儲(chǔ)別名,例如我們可以將用戶按照一定規(guī)則分表存 儲(chǔ),然后在用戶的Id中包含存儲(chǔ)別名的信息,這樣,我們就可以非常方便的將海量用戶拆分到若干分表當(dāng)中,實(shí)現(xiàn)數(shù)據(jù)的分表存儲(chǔ)。此外,與IDataRadiationClassifier搭 配起來,還可以實(shí)現(xiàn)“多維存儲(chǔ)”, 就是將同樣一份數(shù)據(jù),按照不同的應(yīng)用需要,散射到多個(gè)存儲(chǔ)位置(有可能是散射到不同的數(shù)據(jù)庫(kù)上,例如商品信息散射出一個(gè)專門供查詢的庫(kù)上;也有可能是同一 數(shù)據(jù)庫(kù)的不同表上,例如訂單信息根據(jù)買賣不同散射到特定的數(shù)據(jù)表上。),同時(shí)自動(dòng)維護(hù)各個(gè)數(shù)據(jù)庫(kù)上數(shù)據(jù)的一致性。這樣就可以分身有術(shù),讓多個(gè)的數(shù)據(jù)庫(kù)分擔(dān) 查詢壓力。
手動(dòng)動(dòng)態(tài)添加,是通過IStorageAliasesInfoAssistant的RegisterDynamicStorageAlias方法,將已知存儲(chǔ)位置添加到映射表中,同時(shí)返回一個(gè)GUID碼作為存儲(chǔ)別名。
數(shù)據(jù)庫(kù)參數(shù)配置,這種情形是存儲(chǔ)映射信息是以參數(shù)的形式存儲(chǔ)在數(shù)據(jù)庫(kù)中的, 在Aaf.ParaService加載過程中,會(huì)自動(dòng)生成一個(gè)Aaf.StorageAliases的配置節(jié)點(diǎn),節(jié)點(diǎn)路徑是Aaf.StorageAliases/[StorageAlias](存儲(chǔ)別名,可配多個(gè)),節(jié)點(diǎn)配置格式是:
[
StorageContext1,TableName1 \n
AppId1: StorageContext2,TableName2 \n
AppId2: StorageContext3,TableName3 \n
]
其特別的地方是在分布式環(huán)境中,根據(jù)AppID的不同將數(shù)據(jù)持久化到特定的存儲(chǔ)上。
?
?
2. 應(yīng)用實(shí)例
在5173系統(tǒng)中,有許多應(yīng)用,尤其以用戶、發(fā)布單、訂單及資金明細(xì)比較典型。下面我們一起去看看。
2.1. 用戶數(shù)據(jù)分拆
用戶數(shù)據(jù)是基礎(chǔ)數(shù)據(jù),而且是一種會(huì)持續(xù)增長(zhǎng)的基礎(chǔ)數(shù)據(jù),這種數(shù)據(jù)的膨脹會(huì)讓其性能表現(xiàn)越來越差,因?yàn)槭腔A(chǔ)數(shù)據(jù)又不能刪除或者搬移,我們處理這種數(shù)據(jù)的基本策略是將所有用戶按照一定的策略散射到多個(gè)數(shù)據(jù)表中,以緩解單表的壓力,下面我們分析一下實(shí)現(xiàn)過程:
1、 將所有用戶數(shù)據(jù)按照注冊(cè)日期段分組,每一個(gè)分組共用一個(gè)獨(dú)立的數(shù)據(jù)表,分拆存儲(chǔ),分拆策略啟用有一個(gè)時(shí)間基線,之前的數(shù)據(jù)依然存儲(chǔ)在UserInfo中, 自此時(shí)間基線之后的數(shù)據(jù)便存儲(chǔ)在形如UserInfo_X的數(shù)據(jù)表中。例如,設(shè)立時(shí)間基線為2009-5-22,每隔90天建立一個(gè)新組,某用戶注冊(cè)時(shí)間 為2009-12-2號(hào),與時(shí)間基線相差194 天,除以90得2,存儲(chǔ)在UserInfo_2中。
2、 創(chuàng)建一個(gè)類UserInfoSaTeller,實(shí)現(xiàn)IStorageAliasTeller接口
3、 將UserInfoSaTeller注冊(cè)到別名信息助手,注冊(cè)方法如下: PersistenceMappingService.StorageAliasesInfoAssistant.RegisterTeller(typeof(User), new UserInfoSaTeller()),這個(gè)注冊(cè)在UserService的Run方法中。
4、 保存新用戶時(shí),內(nèi)核將調(diào)用UserInfoSaTeller的GetPrimarySaveStorageAlias方法,取得存儲(chǔ)別名,傳入?yún)?shù)是靈便對(duì)象的Id號(hào),因此我們需要構(gòu)建一個(gè)含有分表特征信息的Id,我們現(xiàn)用的Id為“US09120282660351-00F7”,其中紅色加粗部分為注冊(cè)日期,通過注冊(cè)日期,我們可以計(jì)算出一個(gè)特定的存儲(chǔ)別名,UserInfo$2, 內(nèi)核將繼續(xù)調(diào)用UserInfoSaTeller的GetTableName,傳入?yún)?shù)就是GetPrimarySaveStorageAlias計(jì)算出 來的“UserInfo$2”,很顯然我們輕易可以得出實(shí)際的存儲(chǔ)表名“UserInfo_2”。可見,我們只要按照規(guī)則構(gòu)造好用戶的Id,程序便可以自 動(dòng)識(shí)別出來應(yīng)該放到哪里存儲(chǔ)。
5、 根據(jù)Id號(hào)取用戶實(shí)例的過程與保存過程基本類似,內(nèi)核調(diào)用UserInfoSaTeller的GetPrimaryLoadStorageAliases方法,取得加載時(shí)存儲(chǔ)別名,之后的映射關(guān)系與對(duì)象創(chuàng)建時(shí)相同。對(duì)于用戶數(shù)據(jù),保存和獲取時(shí)的存儲(chǔ)別名是一致的。
6、 登陸時(shí)怎么辦?登陸使用的用戶名進(jìn)行登陸,而不是用戶Id。沒什么太好的辦法,基本思路還是遍歷所有分表,好在,我們的分表時(shí)間區(qū)間都是以月為單位,十年 下來也不過一百多個(gè)表。此外,當(dāng)一次遍歷完成之后,我們可以將此用戶對(duì)應(yīng)的存儲(chǔ)別名狀態(tài)記錄在某個(gè)地方,例如Cookie中,這樣減少遍歷的頻度。
2.2. 發(fā)布單數(shù)據(jù)分拆
發(fā)布單數(shù)據(jù)的拆分策略稍微復(fù)雜一點(diǎn)。根據(jù)實(shí)際應(yīng)用需要,除了發(fā)布單默認(rèn)的存儲(chǔ)位置之外,發(fā)布單還有幾種存儲(chǔ)形態(tài):根據(jù)用戶分組、根據(jù)游戲、交易 完成的歷史數(shù)據(jù)。根據(jù)用戶分組分拆,是指把所有用戶在邏輯上分成若干個(gè)用戶組,每個(gè)用戶組共用一個(gè)存儲(chǔ)表;根據(jù)游戲更容易理解,即每一款游戲共用一個(gè)存儲(chǔ) 表;交易完成的歷史數(shù)據(jù),就是那些單子不會(huì)再發(fā)生變化,這種數(shù)據(jù),主要通過數(shù)據(jù)庫(kù)Job定期搬移的。與用戶數(shù)據(jù)分拆不同的是,發(fā)布單是一份數(shù)據(jù)在不同的地 方用不同的策略存儲(chǔ),即多維存儲(chǔ)(游戲維度、用戶分組維度)。下面我們分析一下數(shù)據(jù)創(chuàng)建和加載的過程:
1、 先看創(chuàng)建過程。因?yàn)槭嵌嗑S存儲(chǔ),BizOffer需要實(shí)現(xiàn)IDataRadiationClassifier接口,Aaf內(nèi)核在工作時(shí)將調(diào)用其中的GetDataRadiationClasses方法,來獲取每個(gè)維度的維度標(biāo)識(shí)。
2、 使用維度標(biāo)識(shí),調(diào)用IStorageAliasTeller的GetDimensionStorageAlias方法,翻譯出維度對(duì)應(yīng)的存儲(chǔ)別名,形如:Search$0043和BizOfferBy023F-Escort,加黑的分別是“游戲標(biāo)識(shí)”和“用戶邏輯分組標(biāo)識(shí)”。
3、 解釋下用戶邏輯分組的來歷,我們將用戶分成1000個(gè)邏輯小組,分組的方法依然與注冊(cè)時(shí)間、時(shí)間基線相關(guān),用兩個(gè)時(shí)間的差(天數(shù))對(duì)1000取模,這樣就 會(huì)得到一組數(shù)字,將這組數(shù)字用四位16進(jìn)制格式化,就是散射用戶的邏輯分組標(biāo)記,這個(gè)標(biāo)記,我們也在用戶Id中記錄了,“US09120282660351-00F7”,即藍(lán)色加粗部分。當(dāng)一個(gè)用戶創(chuàng)建發(fā)布單的時(shí)候,我們便知道其邏輯分組為00F7。游戲標(biāo)識(shí)要簡(jiǎn)單一些,每一款游戲都會(huì)有一個(gè)自增長(zhǎng)的表號(hào),此表號(hào)也是用四位16進(jìn)制表示。注意,用戶分組目前是固定為1000個(gè)組的,而游戲分組是不斷增長(zhǎng)的。
4、 接下來就是分別對(duì)每個(gè)維度的存儲(chǔ)別名進(jìn)行存儲(chǔ)動(dòng)作,通過IStorageAliasTeller的GetContextName和GetTableName,取得實(shí)際的存儲(chǔ)位置信息。
兩個(gè)維度路徑是:
存儲(chǔ)別名–>存儲(chǔ)上下文名稱–>數(shù)據(jù)庫(kù)名稱–>數(shù)據(jù)表名
游戲散射:Search$0043–> RadiationOffer1–> SearchOffer–> BizOfferby0043
用戶散射:BizOfferBy023F-Escort–>OfferDataRadiations–>OfferDR–>BizOfferBy023F
5、 還有一個(gè)維度是歷史庫(kù)的發(fā)布單數(shù)據(jù),這個(gè)是Job搬遷創(chuàng)造的,數(shù)據(jù)表的命名規(guī)則是一個(gè)月三張表,按旬存儲(chǔ),形如:BizOfferby200607_1
。雖然創(chuàng)建過程不是Aaf做的,但查詢數(shù)據(jù)時(shí)是Aaf做的,后面我們?cè)谧霾樵兎治龅臅r(shí)候要考慮這部分?jǐn)?shù)據(jù)。
6、 在單條數(shù)據(jù)加載的時(shí)候,重點(diǎn)是確定查詢策略了,就是什么數(shù)據(jù)該先從哪個(gè)維度去找,策略確定之后,就是拼存儲(chǔ)別名來定位查詢的數(shù)據(jù)庫(kù)表了。我們現(xiàn)在的查詢策 略是先查找當(dāng)前庫(kù),拼EscortByCurrent的存儲(chǔ)別名,此存儲(chǔ)別名在Persistence.Config中配置了映射關(guān)系;接著檢查“用戶分 組維度”;再接著,查找歷史庫(kù)。
幾個(gè)查詢路徑如下:
當(dāng)前庫(kù):EscortByCurrent–>ConsignmentByCurrent–>Consignment–>BizOffer
用戶散射:BizOfferBy023F-Escort–>OfferDataRadiations–>OfferDR–>BizOfferBy023F
按發(fā)布單結(jié)束時(shí)間歷史庫(kù)(后臺(tái)使用):Escort|200912_1–>OfferHistory–>OfferHistory–> BizOfferby200912_1
按發(fā)布單創(chuàng)建時(shí)間歷史庫(kù)(前臺(tái)使用):
Escort~200912_1–> OfferHistorybyCreatedDate–> OfferHistorybyCreatedDate–> BizOfferby200912_1
7、 接下來我們梳理一下各種發(fā)布單列表是怎么出來的,當(dāng)一個(gè)查詢過來的時(shí)候,我們首先判斷查詢條件中是否含有用戶信息,如果有,直接走“用戶分組維度”。如果 沒有用戶信息,至少會(huì)包含一個(gè)游戲信息,即GameId,走游戲維度的存儲(chǔ)。注意,列表查詢沒有走“默認(rèn)維度”,這樣默認(rèn)維度就可以專心用于交易了。
8、 8、 有關(guān)發(fā)布單查詢,還沒有結(jié)束。就是另有一個(gè)發(fā)布單搜索對(duì)象BizOfferSearch,這個(gè)是另外生成的一份數(shù)據(jù),專門供搜索用,與當(dāng)前交易平臺(tái)隔離。同樣也有兩個(gè)維度:
存儲(chǔ)別名–>存儲(chǔ)上下文名稱–>數(shù)據(jù)庫(kù)名稱–>數(shù)據(jù)表名
游戲散射:Search$0043–> RadiationOffer1–> SearchOffer–> BizOfferSearchby0043
用戶散射:BizOfferSearchBy023F-Escort–>OfferDataRadiations–>OfferDR–>BizOfferSearchBy023F
2.3. 訂單數(shù)據(jù)分拆
訂單的數(shù)據(jù)分拆方法類似,根據(jù)實(shí)際應(yīng)用需要,除默認(rèn)存儲(chǔ)外,也有幾個(gè)維度的存儲(chǔ):買家分組散射、賣家分組散射、歷史庫(kù)數(shù)據(jù)。從技術(shù)實(shí)現(xiàn)方式來講完全一個(gè)套路。。
1、 訂單創(chuàng)建過程與發(fā)布單雷同,不再贅述。需要注意的是,買賣維度的數(shù)據(jù)表名中也是附加了用戶分組標(biāo)識(shí)。一筆訂單,會(huì)因?yàn)橘I家和賣家的分組不同,而存在于不同標(biāo)識(shí)的分表中。
2、 訂單取得過程,先從默認(rèn)庫(kù)查找,找不到再去買家維度找,找不到再去賣家維度找,還找不到就到歷史庫(kù)中找。
維度路徑是:
存儲(chǔ)別名–>存儲(chǔ)上下文名稱–>數(shù)據(jù)庫(kù)名稱–>數(shù)據(jù)表名
買家散射:OrderByBuyer023F-Escort–> OrderDataRadiations–> OrderDR –> OrderByBuyer023F
賣家散射:OrderBySeller009B-Escort–> OrderDataRadiations–>OrderDR–> OrderBySeller0339
歷史庫(kù):Escort|200912_1–>OrderHistory–>OrderHistory–> Orderby200912_1
3、 在前臺(tái)列表查詢中,買賣雙方呈現(xiàn)自己的訂單時(shí),是分別從買賣維度即OrderDR這個(gè)庫(kù)中取數(shù)據(jù)的。后臺(tái)列表查詢,走的是默認(rèn)維度的訂單庫(kù)。同時(shí),對(duì)于交易完成的數(shù)據(jù),到歷史庫(kù)OrderHistory中查詢。
2.4. 資金分表
AccountDetail,除默認(rèn)在外,還有用戶分組維度、歷史庫(kù)維度。
1、 多維存儲(chǔ)路徑:
存儲(chǔ)別名–>存儲(chǔ)上下文名稱–>數(shù)據(jù)庫(kù)名稱–>數(shù)據(jù)表名
用戶散射:AccountDetailBy00F7–>DataRadiations–>BkDR–> AccountDetailBy00F7
歷史庫(kù):200912_1–>BkHistory–> BkHistory–> AccountDetailBy200912_1
2、 特別要說明的是,每種資金類型都有自己的獨(dú)立的類,他們?nèi)绾喂灿肁ccountDetail這樣一個(gè)存儲(chǔ)的呢?原來所有的獨(dú)立的資金類型都派生自 AccountDetail,而AccountDetail中設(shè)置的“[AgileObjectStorage(TableName = "AccountDetail", ContextName="BkUser")]”,也被繼承下來了。其實(shí)更重要的是它們也繼承了的IDataRadiationClassifier實(shí) 現(xiàn),此外,在PaymentService的Run方法中,幾乎所有類型都注冊(cè)了AccountDetailSaTeller,于是實(shí)現(xiàn)了所有類型的存儲(chǔ) 規(guī)則統(tǒng)一。
2.5. 映射列表
以下是開發(fā)環(huán)境中的映射關(guān)系列表:
對(duì)于這些類型,如果要修改字段,每一個(gè)關(guān)聯(lián)維度上對(duì)應(yīng)的分表都要變更,我們經(jīng)常碰到的缺字段,就是某個(gè)維度上有缺失。
| 類型 | 數(shù)據(jù)庫(kù)名 | 數(shù)據(jù)表名 | 存儲(chǔ)上下文名 | 存儲(chǔ)別名 |
| User | BkUser (默認(rèn)主庫(kù)) | UserInfo_1 UserInfo_2… UserInfo_n | BkUser | UserInfo$1 UserInfo$2… UserInfo$n |
| BizOffer | Consignment (默認(rèn)主庫(kù)) | BizOffer | ConsignmentByCurrent | EscortByCurrent |
| SearchOffer (游戲散射) | BizOfferby0000 … BizOfferBy07D0… | RadiationOffer1 | Search$0000 … Search$07D0… | |
| OfferDR (用戶散射) | BizOfferBy0000 … BizOfferBy03E8 | OfferDataRadiations | BizOfferBy0000-Escort … BizOffeBy03E8-Escort | |
| OfferHistory (歷史庫(kù)By交易完成時(shí)間) | … BizOfferby200912_1 BizOfferby200912_2 BizOfferby200912_3 … | OfferHistory | … Escort|200912_1 Escort|200912_2 Escort|200912_3… | |
| OfferHistorybyCreatedDate (歷史庫(kù)By創(chuàng)建時(shí)間) | … BizOfferby200911_1 BizOfferby200911_2 BizOfferby200911_3 … | OfferHistorybyCreatedDate | … Escort~200911_1 Escort~200911_2 Escort~200911_3… | |
| BizOfferSearch | Consignment (默認(rèn)主庫(kù)) | BizOfferSearch | ConsignmentByCurrent | EscortByCurrent |
| SearchOffer (游戲散射) | BizOfferSearchby0000 … BizOfferSearchBy07D0 … | RadiationOffer1 | Search$0000 … Search$07D0 … | |
| OfferDR (用戶散射) | BizOfferSearchBy0000 … BizOfferSearchBy03E8 | OfferDataRadiations | BizOfferSearchBy0000-Escort … BizOfferSearchBy03E8-Escort | |
| Order | Consignment (默認(rèn)主庫(kù)) | Order | ConsignmentByCurrent | EscortByCurrent |
| OrderDR (買家散射) | OrderByBuyer0000 … OrderByBuyer03E8 | OrderDataRadiations | OrderByBuyer0000-Escort … OrderByBuyer03E8-Escort | |
| OrderDR (賣家散射) | OrderBySeller0000 … OrderBySeller03E8 | OrderDataRadiations | OrderBySeller0000-Escort … OrderBySeller03E8-Escort | |
| OrderHistory (歷史庫(kù)) | … Orderby200912_1 Orderby200912_2 Orderby200912_3 … | OrderHistory | … Escort|200912_1 Escort|200912_2 Escort|200912_3 … | |
| AccountDetail | BkUser (默認(rèn)主庫(kù)) | AccountDetail | BkUser | Current |
| BkDR (用戶散射) | AccountDetailBy0000 … AccountDetailBy03E8 | DataRadiations | AccountDetailBy0000 … AccountDetailBy03E8 | |
| BkHistory (歷史庫(kù)) | .. . AccountDetailBy200912_1 AccountDetailBy200912_2 AccountDetailBy200912_3 … | BkHistory | … 200912_1 200912_2 200912_3… | |
| 說明: | Escort,是交易類型,此處只是舉例,應(yīng)用中可能是其它標(biāo)識(shí)。 | |||
除了上面的映射,自定義映射還有一些,順著IstorageAliasTeller的實(shí)現(xiàn)類去尋找吧。
轉(zhuǎn)載于:https://www.cnblogs.com/hb_cattle/articles/2029325.html
總結(jié)
以上是生活随笔為你收集整理的[转载]基于Aaf的数据拆分的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android 布局: LinearLa
- 下一篇: Windows 下开发PHP扩展资源