自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

SpringBoot與CQRS的完美結(jié)合:構(gòu)建高效、可擴(kuò)展的應(yīng)用程序

開(kāi)發(fā) 前端
CQRS 提供了一種獨(dú)特的方式來(lái)擴(kuò)展和組織微服務(wù)。當(dāng)與 Spring 的生態(tài)系統(tǒng)結(jié)合時(shí),它可以提供強(qiáng)大的工具包來(lái)構(gòu)建健壯、可擴(kuò)展和可維護(hù)的系統(tǒng)。然而,與所有架構(gòu)決策一樣,必須權(quán)衡利弊并確保它適合您的特定用例。

微服務(wù)的興起以及現(xiàn)代軟件架構(gòu)對(duì)可擴(kuò)展性、靈活性和可維護(hù)性的需求導(dǎo)致開(kāi)發(fā)人員接受各種設(shè)計(jì)模式。

近年來(lái)備受關(guān)注的一種模式是命令查詢職責(zé)分離 (CQRS) 模式。CQRS 特別適合命令(改變狀態(tài))和查詢(讀取狀態(tài))之間有明顯區(qū)別的系統(tǒng)。在本文中,我們將深入研究 CQRS 并了解如何使用 Spring 微服務(wù)來(lái)實(shí)現(xiàn)它。

了解 CQRS

什么是 CQRS?

命令查詢職責(zé)分離(CQRS)是一種架構(gòu)模式,建議將數(shù)據(jù)修改操作(命令)與數(shù)據(jù)檢索操作(查詢)分離。這種分離允許開(kāi)發(fā)專門(mén)的模型來(lái)查詢和更新數(shù)據(jù),從而增強(qiáng)應(yīng)用程序的清晰度和可擴(kuò)展性。

CQRS 的核心目標(biāo)是通過(guò)確保每個(gè)任務(wù)負(fù)責(zé)單個(gè)操作(命令或查詢,但絕不會(huì)同時(shí)負(fù)責(zé)兩者)來(lái)簡(jiǎn)化任務(wù)。

起源與演變

CQRS 并不是一個(gè)全新的概念。它的根源可以追溯到 CQS(命令查詢分離),這是 Eiffel 編程語(yǔ)言的創(chuàng)建者 Bertrand Meyer 推廣的一項(xiàng)原則。雖然 CQS 主要是關(guān)于方法——聲明方法應(yīng)該執(zhí)行命令或回答查詢,但 CQRS 將這一原則擴(kuò)展到應(yīng)用程序的架構(gòu)級(jí)別,建議不同的架構(gòu)組件處理命令和查詢。

為什么使用 CQRS?

  • 可擴(kuò)展性: CQRS 允許水平可擴(kuò)展性,因?yàn)槟梢愿鶕?jù)需求部署命令或查詢服務(wù)的多個(gè)實(shí)例。讀取密集型和寫(xiě)入密集型操作可以獨(dú)立擴(kuò)展,從而優(yōu)化資源利用率。
  • 靈活性: 命令和查詢之間的明確區(qū)別意味著開(kāi)發(fā)人員可以為每個(gè)命令和查詢使用最合適的持久性機(jī)制、策略和優(yōu)化。例如,雖然關(guān)系數(shù)據(jù)庫(kù)可能用于事務(wù)命令操作,但非規(guī)范化視圖存儲(chǔ)甚至全文搜索引擎都可以提供查詢服務(wù)。
  • 可維護(hù)性: 實(shí)施良好的 CQRS 模式簡(jiǎn)化了代碼庫(kù)。通過(guò)讀取和寫(xiě)入操作的單獨(dú)模型,開(kāi)發(fā)人員可以專注于每個(gè)操作的細(xì)節(jié),而不會(huì)分散不相關(guān)問(wèn)題的注意力。這種隔離通常會(huì)產(chǎn)生更清晰的代碼,更容易維護(hù)和擴(kuò)展。
  • 增強(qiáng)的安全性: CQRS 本質(zhì)上促進(jìn)了更好的安全實(shí)踐。通過(guò)分離命令和查詢操作,可以更輕松地對(duì)寫(xiě)入操作實(shí)施嚴(yán)格的驗(yàn)證和授權(quán)檢查,同時(shí)優(yōu)化讀取操作的性能。

微服務(wù)中的 CQRS

微服務(wù)架構(gòu)的興起放大了 CQRS 的必要性。在分布式系統(tǒng)中,服務(wù)通常需要自治和高度解耦,CQRS 提供了一條清晰的路徑。每個(gè)微服務(wù)都可以采用 CQRS 模式,確保其處理命令和查詢的內(nèi)部機(jī)制從其他服務(wù)中抽象出來(lái)。這也與領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(DDD)非常吻合,其中領(lǐng)域事件可以觸發(fā)不同微服務(wù)中的命令。

潛在的陷阱

雖然 CQRS 提供了許多好處,但它也面臨著挑戰(zhàn):

  • 復(fù)雜性增加: 引入 CQRS 會(huì)增加開(kāi)銷,尤其是在讀取和寫(xiě)入之間的區(qū)別不明顯的系統(tǒng)中??赡懿⒉豢偸切枰獙⒚總€(gè)讀取和寫(xiě)入操作分開(kāi),這樣做可能會(huì)導(dǎo)致不必要的復(fù)雜性增加。
  • 一致性: 鑒于寫(xiě)入存儲(chǔ)和讀取存儲(chǔ)可能不同,確保它們之間的數(shù)據(jù)一致性可能具有挑戰(zhàn)性,尤其是在分布式系統(tǒng)中。

CQRS 與 Spring 微服務(wù)

Spring 生態(tài)系統(tǒng)擁有豐富的工具和框架,非常適合在微服務(wù)環(huán)境中實(shí)現(xiàn) CQRS 模式。

設(shè)置 Spring 引導(dǎo)

第一步是建立一個(gè)基本的 Spring Boot 項(xiàng)目。如果您是 Spring Boot 新手,您可以使用Spring Initializr輕松初始化您的項(xiàng)目?;疽蕾図?xiàng)包括 Spring Web、Spring Data JPA 以及您喜歡的任何數(shù)據(jù)庫(kù)連接器。

命令、命令處理程序和聚合

在基于 Spring 的 CQRS 系統(tǒng)中,命令表示更改某些狀態(tài)的意圖,命令處理程序處理這些命令。

示例命令:

public class CreateUserCommand {
    private final String userId;
    private final String username;

    // Constructor, getters, and other methods...
}

對(duì)于每個(gè)命令,都定義了相應(yīng)的命令處理程序。該處理程序包含處理命令的實(shí)際邏輯:

@Service
public class CreateUserCommandHandler implements CommandHandler<CreateUserCommand> {
    
    @Autowired
    private UserRepository userRepository;

    @Override
    public void handle(CreateUserCommand command) {
        User user = new User(command.getUserId(), command.getUsername());
        userRepository.save(user);
    }
}

在領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)(DDD)的背景下,狀態(tài)突變通常發(fā)生在聚合上。這些聚合可確保在保留任何更改之前遵守所有域規(guī)則。

查詢和查詢處理程序

類似地,查詢表示讀取某些狀態(tài)的請(qǐng)求,查詢處理程序處理這些請(qǐng)求。

查詢示例:

public class GetUserByIdQuery {
    private final String userId;

    // Constructor, getters, and other methods...
}

對(duì)應(yīng)的查詢處理程序:

@Service
public class GetUserByIdQueryHandler implements QueryHandler<GetUserByIdQuery, User> {
    
    @Autowired
    private UserRepository userRepository;

    @Override
    public User handle(GetUserByIdQuery query) {
        return userRepository.findById(query.getUserId()).orElse(null);
    }
}

將事件溯源與 Axon 框架集成

雖然 CQRS 提供了隔離機(jī)制,但可以使用事件源來(lái)簡(jiǎn)化命令和查詢之間狀態(tài)的維護(hù)。Axon 框架是一種有助于使用 Spring 實(shí)現(xiàn) CQRS 和事件溯源的流行框架。

對(duì)于 Axon,事件在命令處理后發(fā)布。這些事件可以被持久化,然后用于重新創(chuàng)建聚合的狀態(tài)。它還有助于保持查詢端與命令端同步。

與 Apache Kafka 的異步通信

鑒于微服務(wù)的分布式特性,在服務(wù)之間實(shí)現(xiàn)異步通信通常是有益的。Apache Kafka 可以集成到 Spring 生態(tài)系統(tǒng)中,以實(shí)現(xiàn)強(qiáng)大的事件驅(qū)動(dòng)架構(gòu),這在 CQRS 設(shè)置中特別有用。

命令端產(chǎn)生的事件可以推送到Kafka主題中,查詢端可以使用這些事件來(lái)更新自己的數(shù)據(jù)存儲(chǔ)。這確保了命令端和查詢端之間的解耦,使系統(tǒng)更具彈性和可擴(kuò)展性。

事件溯源和 CQRS

雖然 CQRS 專注于分離命令和查詢職責(zé),但事件溯源可確保應(yīng)用程序狀態(tài)的每次更改都被捕獲在事件對(duì)象中,并按照它們應(yīng)用于同一聚合的順序存儲(chǔ)。這種方法允許您重建過(guò)去的狀態(tài),并且與 CQRS 結(jié)合使用時(shí)特別有利。

事件溯源的本質(zhì)

事件溯源是關(guān)于持久化域事件而不是狀態(tài)本身。這些事件捕獲狀態(tài)轉(zhuǎn)換。通過(guò)重放它們,可以重建聚合的當(dāng)前狀態(tài)。

例如,您將存儲(chǔ)所有交易(例如存款和取款等事件),而不是存儲(chǔ)銀行帳戶的當(dāng)前余額。通過(guò)重播這些事件可以得出當(dāng)前余額。

事件溯源的好處

  • 審計(jì)跟蹤: 事件溯源提供了自然的變更審計(jì)日志。這對(duì)于可追溯性和歷史記錄至關(guān)重要的領(lǐng)域至關(guān)重要。
  • 臨時(shí)查詢: 您可以確定系統(tǒng)在任何時(shí)間點(diǎn)的狀態(tài)。這對(duì)于調(diào)試和理解過(guò)去的狀態(tài)非常有價(jià)值。
  • 事件重播: 通過(guò)重播事件,您可以重新生成讀取優(yōu)化的視圖。當(dāng)您想要?jiǎng)?chuàng)建新的投影或重建損壞的投影時(shí),這尤其有用。

將事件溯源與 CQRS 集成

CQRS 和事件溯源通過(guò)以下方式相互補(bǔ)充:

  • 解耦: 正如命令和查詢?cè)?CQRS 中解耦一樣,通過(guò)事件源,事件(表示狀態(tài)更改)與實(shí)際狀態(tài)解耦。這促進(jìn)了松散耦合的架構(gòu)。
  • 可擴(kuò)展性: CQRS 中讀取和寫(xiě)入的隔離性質(zhì)非常適合事件驅(qū)動(dòng)系統(tǒng)。命令模型處理命令并生成事件,而查詢模型處理查詢并可以通過(guò)偵聽(tīng)這些事件來(lái)更新。
  • 彈性: 通過(guò)重放事件的能力,可以在發(fā)生故障時(shí)重建系統(tǒng)狀態(tài),甚至可以遷移到全新的系統(tǒng)。

使用 Spring 和 Axon 框架實(shí)現(xiàn)

如前所述,Axon 框架提供了一種在 Spring 應(yīng)用程序中實(shí)現(xiàn) CQRS 和事件源的無(wú)縫方法:

聚合和事件處理: 在 Axon 中,聚合負(fù)責(zé)命令處理和事件生成。處理命令后,它們應(yīng)用導(dǎo)致?tīng)顟B(tài)更改的事件。

@Aggregate
public class Account {
    @AggregateIdentifier
    private String accountId;
    private int balance;

    @CommandHandler
    public void handle(WithdrawMoneyCommand cmd) {
        if (cmd.getAmount() > balance) {
            throw new InsufficientFundsException();
        }
        apply(new MoneyWithdrawnEvent(cmd.getAccountId(), cmd.getAmount()));
    }

    @EventSourcingHandler
    public void on(MoneyWithdrawnEvent evt) {
        this.balance -= evt.getAmount();
    }
}

事件存儲(chǔ): Axon 提供了一種存儲(chǔ)和檢索事件的機(jī)制。可以重播這些事件以重建聚合的狀態(tài)。

投影: Axon 中的投影提供了 CQRS 的查詢端。他們監(jiān)聽(tīng)事件并更新讀取優(yōu)化視圖。這樣,您的查詢模型始終會(huì)根據(jù)最新更改保持更新。

挑戰(zhàn)和考慮因素

雖然 CQRS 和事件溯源可以提供巨大的好處,但它們也具有復(fù)雜性。意識(shí)到這些挑戰(zhàn)將確保更明智、更順利的實(shí)施。

復(fù)雜性開(kāi)銷

架構(gòu)復(fù)雜性: CQRS 和事件源向系統(tǒng)引入了額外的層和組件,例如事件存儲(chǔ)、命令和事件總線以及同步機(jī)制。

學(xué)習(xí)曲線: 對(duì)于剛接觸這些模式的團(tuán)隊(duì),將有一個(gè)學(xué)習(xí)階段。從傳統(tǒng)的基于 CRUD 的系統(tǒng)的概念轉(zhuǎn)變可能具有挑戰(zhàn)性。

數(shù)據(jù)一致性

最終一致性: 鑒于命令和查詢模型的隔離性質(zhì),通常會(huì)為了最終一致性而犧牲即時(shí)一致性。這意味著在命令端所做的更改反映在查詢端之前可能會(huì)有延遲。

事件排序: 確保事件按照生成的順序進(jìn)行處理,尤其是在分布式系統(tǒng)中,可能很棘手,但對(duì)于保持一致的狀態(tài)至關(guān)重要。

事件版本控制

隨著時(shí)間的推移,事件的結(jié)構(gòu)或語(yǔ)義可能會(huì)發(fā)生變化,從而導(dǎo)致以下挑戰(zhàn):

  • 版本不匹配: 處理同一事件類型的不同版本可能會(huì)變得復(fù)雜。
  • 事件升級(jí): 隨著事件的發(fā)展,系統(tǒng)必須能夠?qū)⑴f事件升級(jí)為新版本,而不改變存儲(chǔ)的事件。

數(shù)據(jù)存儲(chǔ)和重放

存儲(chǔ)注意事項(xiàng): 由于存儲(chǔ)所有事件,事件存儲(chǔ)可能會(huì)快速增長(zhǎng),從而導(dǎo)致存儲(chǔ)成本增加和潛在的性能問(wèn)題。

重播持續(xù)時(shí)間: 通過(guò)重播長(zhǎng)期歷史事件來(lái)重建系統(tǒng)狀態(tài)可能非常耗時(shí),會(huì)影響系統(tǒng)恢復(fù)和初始化時(shí)間。

與其他系統(tǒng)集成

將使用 CQRS 和事件源的系統(tǒng)與不遵循這些模式的外部系統(tǒng)集成可能具有挑戰(zhàn)性,特別是在數(shù)據(jù)同步和事務(wù)管理方面。

確定邊界

粒度決策: 決定應(yīng)用 CQRS 和事件溯源的粒度至關(guān)重要。在微觀層面上實(shí)施它們可能會(huì)導(dǎo)致過(guò)于復(fù)雜化,而過(guò)于廣泛地實(shí)施可能會(huì)削弱好處。

域復(fù)雜性: 這些模式對(duì)于簡(jiǎn)單域來(lái)說(shuō)可能有點(diǎn)過(guò)分了。它們更適合復(fù)雜的領(lǐng)域,其好處超過(guò)了實(shí)施和維護(hù)成本。

工具和基礎(chǔ)設(shè)施

雖然有像 Axon 和框架這樣的工具支持 CQRS 和事件溯源,但它們可能并不總是適合所有場(chǎng)景??赡苄枰远x實(shí)現(xiàn),這會(huì)增加項(xiàng)目的復(fù)雜性和持續(xù)時(shí)間。

結(jié)論

CQRS 提供了一種獨(dú)特的方式來(lái)擴(kuò)展和組織微服務(wù)。當(dāng)與 Spring 的生態(tài)系統(tǒng)結(jié)合時(shí),它可以提供強(qiáng)大的工具包來(lái)構(gòu)建健壯、可擴(kuò)展和可維護(hù)的系統(tǒng)。然而,與所有架構(gòu)決策一樣,必須權(quán)衡利弊并確保它適合您的特定用例。

責(zé)任編輯:武曉燕 來(lái)源: 一安未來(lái)
相關(guān)推薦

2024-02-26 00:01:01

RedisGolang應(yīng)用程序

2023-07-26 16:20:36

云原生云計(jì)算

2011-11-23 10:06:32

Azure微軟移動(dòng)應(yīng)用

2024-06-20 08:00:00

云原生Apache Kaf

2023-09-25 12:18:48

2010-08-11 09:36:12

Flex組件

2018-12-28 14:10:57

開(kāi)發(fā)工具 移動(dòng)應(yīng)用

2025-03-21 07:30:00

Java

2012-04-19 09:34:21

ibmdw

2012-06-14 10:14:46

ibmdw

2023-10-30 09:27:41

Docker程序

2020-09-04 14:56:23

應(yīng)用程序疫情

2015-01-06 09:59:59

云應(yīng)用程序Java開(kāi)發(fā)SQL

2012-05-14 17:35:28

移動(dòng)Web

2024-05-10 13:14:41

技巧云原生應(yīng)用

2009-01-03 14:25:10

ibmdwWeb

2020-03-30 10:49:36

物聯(lián)網(wǎng)應(yīng)用程序IOT

2024-12-10 08:01:38

2014-02-19 15:38:42

2012-11-14 15:25:58

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)