? ? ??DDD就是解決了這個(gè)確定業(yè)務(wù)邊界的問題,是一種架構(gòu)模式,也是一種劃分業(yè)務(wù)領(lǐng)域范圍的方法論。常見的領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)架構(gòu)有經(jīng)典的三層架構(gòu)、REST架構(gòu)、事件驅(qū)動(dòng)架構(gòu)、CQRS架構(gòu)、六邊形架構(gòu)等.領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)是一種由域模型來驅(qū)動(dòng)著系統(tǒng)設(shè)計(jì)的思想,不是通過存儲(chǔ)數(shù)據(jù)詞典(DB表字段、ES Mapper字段等等)來驅(qū)動(dòng)系統(tǒng)設(shè)計(jì)。領(lǐng)域模型是對(duì)業(yè)務(wù)模型的抽象,DDD是把業(yè)務(wù)模型翻譯成系統(tǒng)架構(gòu)設(shè)計(jì)的一種方式。
? ? ? ? DDD 強(qiáng)調(diào)領(lǐng)域模型和微服務(wù)設(shè)計(jì)的一體性,先有領(lǐng)域模型然后才有微服務(wù),而不是脫離領(lǐng)域模型來談微服務(wù)設(shè)計(jì)。所謂的領(lǐng)域模型,實(shí)際上就是將一個(gè)業(yè)務(wù)按照DDD模型拆分,呈現(xiàn)層次化、結(jié)構(gòu)化。模型拆分的最小粒度就是值對(duì)象、實(shí)體。從技術(shù)角度看,最小粒度就是某張數(shù)據(jù)庫表或字段,從產(chǎn)品角度看,就是某個(gè)最小的功能細(xì)節(jié)。
? ? ? ? 基于通用語言,進(jìn)行用戶旅程、事件風(fēng)暴、用戶故事等信息輸入后,拆分出領(lǐng)域模型。領(lǐng)域故事是什么呢?實(shí)際上就是用通用語言,描述用戶體驗(yàn),或用戶操作流程,或某個(gè)功能的使用過程。每個(gè)過程可能會(huì)產(chǎn)生一些事件,比如用戶打賞主播,則可以認(rèn)為產(chǎn)生了送禮事件。而這些事件可能會(huì)其他過程依賴,跑核心領(lǐng)域故事的過程會(huì)自然產(chǎn)生事件風(fēng)暴,彼此的依賴關(guān)系也可以逐漸清晰。
DDD 涉及的關(guān)鍵字
領(lǐng)域、子域、核心域、通用域、支撐域、限界上下文、聚合、聚合根、實(shí)體、值對(duì)象

域
? ? ? 一塊有明顯邊界的區(qū)域。有決定性作用的子域:核心域。被公共依賴的:通用域(如賬號(hào))。相對(duì)核心的:支撐域。而域里面通常會(huì)包含許多子域,核心域、通用域、支撐域也屬于子域。
限界上下文
? ? ? ? 每個(gè)領(lǐng)域都會(huì)有邊界,每個(gè)域可以在內(nèi)部形成一個(gè)獨(dú)立自洽的上下文環(huán)境,這就是限界上下文。本質(zhì)來說,限界上下文是一種約定。
聚合
? ? ? ? 用于表達(dá)一個(gè)有完整功能的對(duì)象。而聚合跟就是這個(gè)聚合的主體(聚合根代表聚合,統(tǒng)一做信息收口,從技術(shù)上統(tǒng)一提供數(shù)據(jù)的讀寫,保證一致性,或?qū)ν馄帘螐?fù)雜性。(聚合根通常也用充血模型來實(shí)現(xiàn)));實(shí)體是多個(gè)屬性、操作或行為的載體;值對(duì)象是 DDD 領(lǐng)域模型中的一個(gè)基礎(chǔ)對(duì)象,它跟實(shí)體一樣,都包含了若干個(gè)屬性,它與實(shí)體一起構(gòu)成聚合(例如:聚合中有地址,引用的值對(duì)象是某個(gè)地址)。
? ? ? 實(shí)體的數(shù)據(jù)庫形態(tài):在領(lǐng)域模型映射到數(shù)據(jù)模型時(shí),一個(gè)實(shí)體可能對(duì)應(yīng) 0 個(gè)、1 個(gè)或者多個(gè)數(shù)據(jù)庫持久化對(duì)象。大多數(shù)情況下實(shí)體與持久化對(duì)象是一對(duì)一。在某些場景中,有些實(shí)體只是暫駐靜態(tài)內(nèi)存的一個(gè)運(yùn)行態(tài)實(shí)體,它不需要持久化。
領(lǐng)域服務(wù)
單個(gè)聚合或多個(gè)聚合或者其他事件服務(wù)。
CQRS架構(gòu)(消息驅(qū)動(dòng)的架構(gòu))
查詢(query)/變更(command)
1、查詢 --? 網(wǎng)關(guān)路由 --? 監(jiān)聽器(query) -- 處理器 -- 返回resultDTO
2、數(shù)據(jù)變更 --? 監(jiān)聽器(監(jiān)聽所有) -- 領(lǐng)域模型(定義命令與領(lǐng)域、以及領(lǐng)域聚合的關(guān)系)-- 監(jiān)聽器(command) -- command編排器 - -command轉(zhuǎn)換器? -- command處理器 -- 保存到限界上下文 -- 監(jiān)聽聚合根的變化 -- domain --監(jiān)聽器(event) -- event編排器 -- event處理器
? ? 2-1、event處理器 -- event溯源(ES)
? ? 2-2、event處理器 -- db(分布式事務(wù)seata)-- Command總監(jiān)聽器 -- 返回resultDTO
DDD ? ?領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)思想
? ? ? ? 不管是貧血模型還是充血模型但都不徹底,真正的面向?qū)ο缶幊讨械膶?duì)象應(yīng)該是一個(gè)“活”的具有主觀能動(dòng)性的存在于內(nèi)存中的客觀存在,它們不僅有狀態(tài)而且還有自主行為。
? ? ? ? 對(duì)象的狀態(tài)可以表現(xiàn)出來被其他對(duì)象看到,但是必須是只讀的,沒有人可以直接去修改一個(gè)對(duì)象的狀態(tài),它的狀態(tài)必須是有它自己的行為導(dǎo)致自己的狀態(tài)改變。對(duì)象的行為就是對(duì)象所具有某種能力(或者說是某種功能)。對(duì)象的行為本質(zhì)上應(yīng)該是對(duì)某個(gè)消息的主動(dòng)響應(yīng),這里強(qiáng)調(diào)的是主動(dòng),就是說對(duì)象的行為不可以被別人使用,而只能自己主動(dòng)的去表現(xiàn)出該行為。
貧血模型和充血模型1、貧血模型:
? ? ? 定義對(duì)象的簡單的屬性值,在屬性值上直接get、set2、充血模型
? ? ? 充血模型也就是我們?cè)诙x屬性的同時(shí)也會(huì)定義方法,我們的屬性是可以通過某些方式直接得到屬性值,那我們也就可以在對(duì)象中嵌入方法直接創(chuàng)建出一個(gè)具有屬性值的對(duì)象。關(guān)于DDD和充血模型的關(guān)系? ? ? ? 我們?cè)谄綍r(shí)進(jìn)行web開發(fā)的時(shí)候,就是定義DTO,定義數(shù)據(jù)庫Model,BO等,對(duì)其進(jìn)行g(shù)et set方法,然后通過service 對(duì)Bo對(duì)象進(jìn)行操作,最后通過copy屬性持久化數(shù)據(jù)庫和DTO傳輸。但是如果是充血模型的話,就不用在service進(jìn)行屬性賦值,而是在創(chuàng)建這個(gè)對(duì)象的時(shí)候,進(jìn)行業(yè)務(wù)操作,賦予其屬性值。這里也就是DDD的思想,這個(gè)對(duì)象也就是DDD所定義的Entity 或者 value 。Service也就是domianService,由多個(gè)Entity 和value 組成,構(gòu)造最終的領(lǐng)域模型。
? ? ? ? DDD的開發(fā)模式也就是充分的遵循OOP發(fā)三大特性(或者四大特性,封裝,繼承,多態(tài),(抽象))。通過設(shè)計(jì)模式,和業(yè)務(wù)邏輯細(xì)分進(jìn)行解決。
? ? ? ? ? 引發(fā)的問題:如果要滿足這種主動(dòng)性的,需要專門去監(jiān)聽,然后認(rèn)領(lǐng)去處理。
特性
1)支持分布式,基于隊(duì)列的水平擴(kuò)展。
2)面向高并發(fā)設(shè)計(jì)。通過用消息中間件實(shí)現(xiàn)服務(wù)器之間的消息路由;通過單機(jī)內(nèi)部實(shí)現(xiàn)類似Actor Mailbox的設(shè)計(jì),從而避免并發(fā)的產(chǎn)生。提高CQRS架構(gòu)C端的整體寫入吞吐量;即便在某些極端情況下出現(xiàn)并發(fā)問題,也支持自動(dòng)的樂觀檢測,并自動(dòng)重試;
3)嚴(yán)謹(jǐn)?shù)南绲忍幚碇С帧?/p>
4)框架整合saga中間件。一個(gè)事務(wù)包含若干個(gè)聚合根以及一個(gè)(通常)流程管理器。
5)采用Event Sourcing(簡稱ES)的方式來持久化聚合根狀態(tài);通過ES實(shí)現(xiàn)聚合根狀態(tài)的還原以及通用的并發(fā)控制,通過聚合根ID+事件版本號(hào)作為唯一索引的思路實(shí)現(xiàn)樂觀并發(fā)控制;
CQRS ? 命令查詢的責(zé)任分離
? ? ? ? 1) 命令(Command):不返回任何結(jié)果(void),但會(huì)改變對(duì)象的狀態(tài)。
? ? ? ? 2) 查詢(Query):返回結(jié)果,但是不會(huì)改變對(duì)象的狀態(tài),對(duì)系統(tǒng)沒有副作用
? ? ? ? 3) Q端輕量級(jí)查詢,多種不同的查詢視圖通過訂閱事件來更新
? ? ? ? 4) C端通過分布式消息隊(duì)列水平擴(kuò)展,天然支持削峰
CQRS架構(gòu)的缺點(diǎn)
1)不是強(qiáng)一致性,而是面向最終一致性
2)強(qiáng)依賴高性能可靠的分布式消息隊(duì)列
3)必須有強(qiáng)大可靠的CQRS框架,從頭做起成本高、風(fēng)險(xiǎn)大
4)最好結(jié)合Event Sourcing模式,否則CQ分離意義不大
使用約束
1)命令一次只能修改一個(gè)或者多個(gè)聚合根(看領(lǐng)域模型定義)
2)聚合間是否只能通過領(lǐng)域消息交互(看框架底層設(shè)計(jì),底層如果隱式轉(zhuǎn)換處理那么后續(xù)引發(fā)的事務(wù)相關(guān)問題相對(duì)少,局限性?。?/p>
3)聚合內(nèi)強(qiáng)一致性
4)聚合間最終一致性
框架特色
1)實(shí)現(xiàn)CQRS架構(gòu),解決CQRS架構(gòu)的C端的高并發(fā)寫的問題,以及CQ兩端數(shù)據(jù)同步的順序性保證和冪等性,支持C端完成后立即返回Command的結(jié)果,也支持CQ兩端都完成后才返回Command的結(jié)果
2)聚合根常駐內(nèi)存(In-Memory Domain Model),設(shè)計(jì)上盡可能的避免了聚合根重建,可以完全以O(shè)O的方式來設(shè)計(jì)實(shí)現(xiàn)聚合根,不必為ORM的阻抗失衡而煩惱
3) 基于聚合根ID + 事件版本號(hào)的唯一索引,實(shí)現(xiàn)聚合根的樂觀并發(fā)控制
4) 通過聚合根ID對(duì)命令或事件進(jìn)行路由,聚合根的處理基于Actor思想,做到最小的并發(fā)沖突、最大的并行處理,Group Commit Domain event
5)架構(gòu)層面嚴(yán)格規(guī)范了開發(fā)人員該如何寫代碼,和DDD開發(fā)緊密結(jié)合,嚴(yán)格遵守聚合內(nèi)強(qiáng)一致性、聚合之間最終一致性的原則
6) 先進(jìn)的Saga機(jī)制,以事件驅(qū)動(dòng)的流程管理器(Process Manager)的方式支持一個(gè)用戶操作跨多個(gè)聚合根的業(yè)務(wù)場景,如訂單處理,從而避免分布式事務(wù)的使用
7) 基于ES(Event Sourcing)的思想持久化C端的聚合根的狀態(tài),讓C端的數(shù)據(jù)持久化變得通用化,具有一切ES的優(yōu)點(diǎn)
8)在設(shè)計(jì)上完全與IoC容器解耦,同時(shí)保留了擴(kuò)展性,可以適配了SpringCloud
9)通過基于分布式消息隊(duì)列橫向擴(kuò)展的方式實(shí)現(xiàn)系統(tǒng)的可伸縮性(基于隊(duì)列的動(dòng)態(tài)擴(kuò)容/縮容),接口抽象極簡,只要求最基礎(chǔ)的隊(duì)列能力,目前適配了Kafka、RocketMQ(ONS)、Pulsar
10)EventStore內(nèi)置適配了JDBC、MySQL、PostgreSQL、MongoDB存儲(chǔ),可針對(duì)性實(shí)現(xiàn)對(duì)應(yīng)擴(kuò)展
三、EDA 事件驅(qū)動(dòng)架構(gòu)(專注于微服務(wù))
? ? ? ? 經(jīng)典 EDA 事件驅(qū)動(dòng):事件總線(EventBridge)最重要的能力是通過連接應(yīng)用程序,云服務(wù)和 Serverless 服務(wù)構(gòu)建 EDA(Event-driven Architectures) 事件驅(qū)動(dòng)架構(gòu),驅(qū)動(dòng)應(yīng)用與應(yīng)用,應(yīng)用與云的連接。
? ? ? ? 流式 ETL 場景。EventBridge 另一個(gè)核心能力是為流式的數(shù)據(jù)管道的責(zé)任,提供基礎(chǔ)的過濾和轉(zhuǎn)換的能力,在不同的數(shù)據(jù)倉庫之間、數(shù)據(jù)處理程序之間、數(shù)據(jù)分析和處理系統(tǒng)之間進(jìn)行數(shù)據(jù)同步/跨地域備份等場景,連接不同的系統(tǒng)與不同服務(wù)。
? ? ? ? 統(tǒng)一事件通知服務(wù):EventBridge 提供豐富的云產(chǎn)品事件源與事件的全生命周期管理工具,您可以通過總線直接監(jiān)聽云產(chǎn)品產(chǎn)生的數(shù)據(jù),并上報(bào)至監(jiān)控,通知等下游服務(wù)。
四、ES 分布式搜索引擎/分布式文檔數(shù)據(jù)庫(用于解決數(shù)據(jù)量多,分布式查詢問題)
CQRS與Event Sourcing的關(guān)系? ? ? ? 在CQRS中,查詢方面,直接通過方法查詢數(shù)據(jù)庫,然后通過DTO將數(shù)據(jù)返回。在操作(Command)方面,是通過發(fā)送Command實(shí)現(xiàn),由CommandBus處理特定的Command,然后由Command將特定的Event發(fā)布到EventBus上,然后EventBus使用特定的Handler來處理事件,執(zhí)行一些諸如,修改,刪除,更新等操作。這里,所有與Command相關(guān)的操作都通過Event實(shí)現(xiàn)。這樣我們可以通過記錄Event來記錄系統(tǒng)的運(yùn)行歷史記錄,并且能夠方便的回滾到某一歷史狀態(tài)。Event Sourcing就是用來進(jìn)行存儲(chǔ)和管理事件的。————————————————CQRS的架構(gòu)實(shí)現(xiàn)? ? ? ? CQRS在讀寫方面的分離,在讀方面,通過QueryFacade到數(shù)據(jù)庫里去讀取數(shù)據(jù),這個(gè)庫有可能是ReportingDB。在寫方面,操作通過Command發(fā)送到CommandBus上,然后特定的CommandHandler處理請(qǐng)求,產(chǎn)生對(duì)應(yīng)的Event,將Eevnt持久化后,通過EventBus特定的EevntHandler對(duì)數(shù)據(jù)庫進(jìn)行修改等操作?!?/p>
EDA 事件驅(qū)動(dòng)架構(gòu)
? ? ? ? EDA 事件驅(qū)動(dòng)架構(gòu)( Event-Driven Architecture ) 是一種系統(tǒng)架構(gòu)模型,它的核心能力在于能夠發(fā)現(xiàn)系統(tǒng)“事件”或重要的業(yè)務(wù)時(shí)刻(例如交易節(jié)點(diǎn)、站點(diǎn)訪問等)并實(shí)時(shí)或接近實(shí)時(shí)地對(duì)相應(yīng)的事件采取必要行動(dòng)。這種模式取代了傳統(tǒng)的“ request/response ”模型,在這種傳統(tǒng)架構(gòu)中,服務(wù)必須等待回復(fù)才能進(jìn)入下一個(gè)任務(wù)。事件驅(qū)動(dòng)架構(gòu)的流程是由事件提供運(yùn)行的
————————————————
Saga(事務(wù))的兩種模式
? ? ? a) 編排(Choreography) 參與者(子事務(wù))之間的調(diào)用、分配、決策和排序,通過交換事件進(jìn)行進(jìn)行。是一種去中心化的模式,參與者之間通過消息機(jī)制進(jìn)行溝通,通過監(jiān)聽器的方式監(jiān)聽其他參與者發(fā)出的消息,從而執(zhí)行后續(xù)的邏輯處理。
? ? ? ? b) 控制(Orchestration) 提供一個(gè)控制類,方便參與者之間的協(xié)調(diào)工作。事務(wù)執(zhí)行的命令從控制類發(fā)起,按照邏輯順序請(qǐng)求 事務(wù) 的參與者,從參與者那里接受到反饋以后,控制類在發(fā)起向其他參與者的調(diào)用。所有 事務(wù) 的參與者都圍繞這個(gè)控制類進(jìn)行溝通和協(xié)調(diào)工作
————————————————
?Command Bus(命令總線):在 Command Handler 之前,可以看作是 Command 發(fā)布者。?Command Handler(命令處理器):處理來自 Command Bus 分發(fā)的請(qǐng)求,可以看作是 Command 訂閱者、處理者。
CommandConsumer (作用對(duì)應(yīng)applicationservice的編排,與commandhandler協(xié)調(diào)完成命令的消費(fèi))
?Event Bus(事件總線):一般在 Command Handler 完成之后,可以看作是 Event 發(fā)布者。Event Handler(事件處理器):處理來自 Event Bus 分發(fā)的請(qǐng)求,可以看作是 Event 訂閱者、處理者。要放置在可以處理事件的方法上的注釋
EventConsumer (作用是在所有的UI-command經(jīng)框架轉(zhuǎn)換成comsumer-command -> domain-commad后,需要完成的同步saga的同步業(yè)務(wù)編排)
?Event Store(事件存儲(chǔ)):對(duì)應(yīng)概念 Event Sourcing(事件溯源),可以用于事件回放處理,還原指定對(duì)象狀態(tài)。
EventSourcingHandler ? 將聚合(根或?qū)嶓w)中的方法標(biāo)記為該聚合生成的事件的處理程序的注釋。
QueryHandler ?? 可以標(biāo)記在對(duì)象的任何方法上。
Comsumer Command??大致分為五類command, domain-event,query外,還有exception message, application message.