2017-03-02 76 views
1

讓我首先說,我沒有CQRS的實際經驗,這就是這個問題的基礎。CQRS和事件源與關係數據庫設計結合

背景: 我建立一個系統,一個新的關鍵要求是允許管理員爲「回放」用戶操作(管理員希望能夠步每一個發生在一個系統中任何特定點的動作) 。需要注意的是,該公司已經有了從當前SQL數據庫生成的報表,它們不會更改(至少不會與此新需求並行),因此記錄的存儲將是SQL。我無法訪問SQL的更改數據捕獲,因此創建一大堆帶觸發器的歷史記錄表將非常難以維護,所以我想盡可能避免這種情況。最後,目前可能(目前還沒有)很多數據入口點會經過版本生命週期,導致SQL db的更改(添加/刪除字段),所以如果我試圖在SQL中實現更改跟蹤,我會必須維護處理舊版本數據的表格(噩夢)。

潛在的解決方案 我正在考慮使用的NoSQL(天青DocumentDB)來處理數據存儲(寫入),然後有命令處理程序處理更新當前SQL(Azure的SQL)的有關數據進行查詢(讀取) 。通過這種方式創建了審計跟蹤,並且可以處理「回放」的想法,同時不會干擾當前提供的後端功能。

這種方法將滿足要求並滿足注意事項。我不會爲整個應用程序使用CQRS,只是爲了我需要這種「回放」功能的部分。我知道我必須緩解客戶端的故障點 - >寫入DocumentDB - >用成功/失敗響應用戶 - >寫入成功的SQL寫入DocumentDB路徑,但我的新手CQRS的眼睛看不到原因爲什麼這不是一個很好的方法來處理這個問題。

任何意見將不勝感激。

+1

[Change Feed](https://docs.microsoft.com/en-us/azure/documentdb/documentdb-change-feed)是否允許您偵聽更改並將其應用於SQL數據庫? –

+0

更改Feed似乎正是我正在尋找的。我認爲Dogu的回答更徹底地充實了可以解決我的問題的架構。我將使用ChangeFeed作爲「消息隊列」和一個監視該隊列並相應地處理事務的輔助角色。 – JakeHova

回答

0

一個可能的方式來思考這個問題是創建一個具有唯一ID並代表需要完成的工作的事務對象。這種情況下的事務將寫入一個對象到文檔數據庫或寫入一個對象到SQL DB。它可能包含要寫入的內存對象和目標數據庫(doc db,sql等)連接參數。

一旦您定義了您的交易,您需要調整您的工作流程以獲得適當的CQRS。客戶不是直接向docdb寫入數據並等待此調用的結果,而是讓客戶創建一個具有唯一標識的事務 - 可能類似於Date Time滴答計數或增量事務標識,然後編寫此事務到一個像天青隊列或服務總線的消息隊列。一旦將事務寫入隊列,就會在此時向用戶返回成功。創建工作人員角色,從該隊列讀取事務消息並處理它們,將對象寫入文檔數據庫。這不會覆蓋doc db中的同一個實體,而只是將具有唯一增量id的事務寫入該實體的doc db。你也可以使用天藍色表格存儲這個afaik。

成功更新doc db事務後,同一個worker角色可以將此事務寫入不同的消息隊列,該消息隊列將由其自己的一組工作角色處理,該角色將更新sql db中的實體。如果在此期間出現任何問題,請保留錯誤表並更新該錯誤表中的錯誤以便稍後進行查詢和重試。

+0

這對我很有趣。我喜歡你描述的體系結構佈局(隊列供稿數據存儲)。是否有理由在寫入DocumentDB之前寫入消息隊列,而不是直接寫入DocumentDB(使用您提到的事務對象)並監視DocumentDB的ChangeFeed隊列(建議使用@Matias)來處理事務本身? – JakeHova

+0

確實的隊列提供了現成的功能來擴展由工作者角色處理消息,諸如消息可見性等功能,允許安全地處理客戶端代碼不需要處理的消息。當然,在你的情況下,你的情況下,沒有太多的計算,但將實體寫入分貝,所以你可以說將這個加載到隊列中的好處是微乎其微的 –

0

本文解釋了CQRS pattern並提供了一個CQRS實現的例子請參考它。

我想使用的NoSQL(天青DocumentDB)來處理數據存儲(寫入),然後有命令處理程序處理更新當前SQL(SQL Azure中)與相關數據進行查詢(讀取)。

這裏是我的建議,當用戶編寫操作來更新記錄時,我們總是可以在admin審計用戶的操作之前做插入操作。例如,如果用戶想更新記錄,我們可以插入更新實體,其中包含一個屬性,用於指示當前操作是否由管理員審覈,而不是直接更新記錄。在文件

{ 
    "version1_data": { 
    "data": { 
     "id": "1", 
     "name": "jack", 
     "age": 28 
    }, 
    "isaudit": true 
    } 
} 

對於更新age

原始數據,我們可以插入的最新信息,而不是直接更新原始數據實體。

{ 
    "version1_data": { 
    "data": { 
     "id": "1", 
     "name": "jack", 
     "age": 28 
    }, 
    "isaudit": true 
    }, 
    "version2_data": { 
    "data": { 
     "id": "1", 
     "name": "jack", 
     "age": 29 
    }, 
    "isaudit": false 
    } 
} 

然後管理員可以檢查當前的文檔來審計用戶的操作並確定更新是否可以寫入SQL數據庫。