成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

你知道微服務架構中的“發件箱模式”嗎

開發 架構
發件箱模式雖然聽上去可能很簡單,但是在平時開發中可能會忽略掉。如果還不能理解,我們可以將它類比到生活的場景,寄信人只需要寫好信件,放入收件箱,之后就不用管了。送信的人會來收件箱取走信件,根據信件里需要送到的地址,將信件送至目的地。這樣做的好處就是,寄信人寫好信之后,就不需要等待收信人有空的時候才能寄信,只需要往發件箱里丟就好了。

?前言

微服務架構如今非常的流行,這個架構下可能經常會遇到“雙寫”的場景。雙寫是指您的應用程序需要在兩個不同的系統中更改數據的情況,比如它需要將數據存儲在數據庫中并向消息隊列發送事件。您需要保證這兩個操作都會成功。如果兩個操作之一失敗,您的系統可能會變得不一致。那針對這樣的情況有什么好的方法或者設計保證呢?本文就和大家分享一個“發件箱模式”, 可以很好的避免此類問題。

下訂單的例子

假設我們有一個 OrderService 類,它在創建新訂單時被調用,此時它應該將訂單實體保存在數據庫中并向交付微服務發送一個事件,以便交付部門可以開始計劃交付。

你的代碼可能是下面這樣子的:

@Service
public record OrderService(
IDeliveryMessageQueueService deliveryMessageQueueService,
IOrderRepository orderRepository,
TransactionTemplate transactionTemplate) implements IOrderService {

@Override
public void create(int id, String description) {
String message = buildMessage(id, description);

transactionTemplate.executeWithoutResult(transactionStatus -> {
// 保存訂單
orderRepository.save(id, description);
});

// 發送消息
deliveryMessageQueueService.send(message);
}

private String buildMessage(int id, String description) {
// ...
}
}

可以看到我們在事務中將訂單保存在數據庫中,然后我們使用消息隊列將事件發送到交付服務。這是雙寫的一個場景。

這么寫,會遇到什么問題呢?

首先,如果我們保存了訂單但是發送消息失敗了怎么辦?送貨服務永遠不會收到消息。

那你可能想到把保存訂單和發消息放到同一個事務中不就可以了嗎,就是是將 deliveryMessageQueueService#send? 移動到與 orderRepository#save相同的事務中,如下圖:

transactionTemplate.executeWithoutResult(transactionStatus -> {
// 保存訂單
orderRepository.save(id, description);
// 發送消息
deliveryMessageQueueService.send(message);
});

實際上,在數據庫事務內部建立 TCP 連接是一種糟糕的做法,我們不應該這樣做。

有沒有更好的方法呢?

我們可以訂單表所在的同一數據庫中有一個表“發件箱”(在最簡單的情況下,它可以有一個列“消息”和當前時間戳)。保存訂單時,在同一個事務中,我們在“發件箱”表中保存了一條消息。消息一發送,我們就可以將其從發件箱表中刪除,代碼如下:

@Service
public record OrderService(
IDeliveryMessageQueueService deliveryMessageQueueService,
IOrderRepository orderRepository,
IOutboxRepository outboxRepository,
TransactionTemplate transactionTemplate) implements IOrderService {

@Override
public void create(int id, String description) {
UUID outboxId = UUID.randomUUID();
String message = buildMessage(id, description);

transactionTemplate.executeWithoutResult(transactionStatus -> {
// 保存訂單
orderRepository.save(id, description);
// 保存到發件箱
outboxRepository.save(new OutboxEntity(outboxId, message));
});

deliveryMessageQueueService.send(message);

// 刪除
outboxRepository.delete(outboxId);
}

private String buildMessage(int id, String description) {
// ...
}
}

可以看到,我們在一次事務中將訂單和發件箱實體保存在我們的數據庫中。然后我們發送一條消息,如果成功,我們刪除這條消息。

如果 deliveryMessageQueueService#send? 失敗會怎樣?(例如,您的應用程序被終止或消息隊列或數據庫不可用)。在這種情況下,outboxRepository#delete 將不會運行,我們必須重試發送消息。

它可以使用將在后臺運行的計劃任務來完成,該任務將嘗試發送在表發件箱中顯示超過 X 秒(例如 10 秒)的消息,如下面的代碼。

@Service
public record OutboxRetryTask(IOutboxRepository outboxRepository,
IDeliveryMessageQueueService deliveryMessageQueueService) {

@Scheduled(fixedDelayString = "10000")
public void retry() {
List<OutboxEntity> outboxEntities = outboxRepository.findAllBefore(Instant.now().minusSeconds(60));
for (OutboxEntity outbox : outboxEntities) {
deliveryMessageQueueService.send(outbox.message());
outboxRepository.delete(outbox.id());
}
}
}

在這里你可以看到,我們每 10 秒運行一個任務,并發送之前沒有發送過的消息。如果消息成功發送到消息隊列,但發件箱實體沒有從數據庫中刪除(例如因為數據庫問題),那么下次該后臺任務將嘗試再次將此消息發送到消息隊列。但這也意味著我們消息的消費者必須做好冪等處理,因為可能會多次接收相同的消息。

發件箱模式

通過上面的例子,我們可以抽象出“發件箱模式”。

圖片

  • 在數據庫里面額外增加一個outbox表用于存儲需要發送的event
  • 把直接發送event的步驟換成先把event存儲到數據庫outbox表
  • 程序啟動一個 job 不斷去抓取 outbox 表里面的記錄,通過推送線程完成不同業務的推送
  • 最后刪除發送成功的記錄
  • 提醒消息消費端要做好冪等處理

總結

發件箱模式雖然聽上去可能很簡單,但是在平時開發中可能會忽略掉。如果還不能理解,我們可以將它類比到生活的場景,寄信人只需要寫好信件,放入收件箱,之后就不用管了。送信的人會來收件箱取走信件,根據信件里需要送到的地址,將信件送至目的地。這樣做的好處就是,寄信人寫好信之后,就不需要等待收信人有空的時候才能寄信,只需要往發件箱里丟就好了。

責任編輯:武曉燕 來源: JAVA旭陽
相關推薦

2025-05-26 09:10:00

微服務系統發件箱模式

2025-06-04 08:10:00

發件箱模式.NET數據庫

2018-10-28 18:09:22

微服務Microservic架構

2019-09-29 10:29:02

緩存模式微服務架構

2024-06-04 07:58:31

架構本質微服務

2021-08-13 22:42:14

微服務架構開發

2024-06-12 08:05:06

2019-07-12 08:45:07

開源微服務框架

2022-08-14 07:04:44

微服務架構設計模式

2019-02-12 11:15:15

Spring設計模式Java

2022-08-08 13:55:47

通信設計模式微服務

2022-08-07 22:11:25

微服務架構

2019-12-02 10:16:46

架構設計模式

2023-12-14 08:01:47

環境復制微服務

2024-02-21 07:24:21

微服務單體架構MVC

2016-09-26 14:45:46

微服務

2022-04-23 16:58:24

微服務微服務架構

2022-09-22 14:55:31

前端JavaScripthis

2022-09-26 13:10:17

JavaScriptthis

2022-06-29 08:32:04

游標MySQL服務器
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲视频在线播放 | 在线午夜 | 伊人热久久 | 国产美女福利在线观看 | jⅰzz亚洲| 国产黄色在线观看 | 国产av毛片 | 成人av网页 | 久久精品毛片 | av一二三四 | 国产一区二区在线视频 | 欧美 日韩 亚洲91麻豆精品 | av中文字幕在线观看 | 超黄视频网站 | 欧美日韩国产一区 | 日韩中文字幕在线免费 | 黄色成人免费看 | 午夜精品一区二区三区三上悠亚 | 亚欧精品一区 | 在线91 | 国产美女在线免费观看 | 欧美区日韩区 | 国产精品永久免费视频 | 国产综合久久久久久鬼色 | 国产精品1区| 五月天婷婷综合 | av在线一区二区三区 | 亚洲精品久久久一区二区三区 | 国产女人叫床高潮大片免费 | 亚洲欧美精品 | 午夜精品福利视频 | 国产亚洲精品综合一区 | 成人亚洲一区 | 亚洲精品久久久久久久久久久久久 | 久久国产精品久久久久 | av在线免费播放 | 超碰免费在 | 亚洲日日夜夜 | 亚洲激情一区二区 | 秋霞a级毛片在线看 | 欧美精品久久久 |