概述
- 我們的業務場景是可以允許我們一段時間有不一致的消息的狀態的,并沒有說必須特別高的這個消息的一致性
- 比如說在TCC這個架構中,如果采用了消息的最終一致性,整體架構設計要輕松好多
- 即便我們庫存服務掛了,或者我們積分服務掛了也沒有關系,只要我們有中間的這個消息,那就是沒有問題的
- 因為你在消息消費中,如果你你沒有消費成功,那么消息就會一直存在在這個消息隊列里
場景

- 看看這個我們的這個具體的案例的場景是什么樣的?還是以這個訂單服務和庫存服務,還有積分服務為例
- 比如說,現在要下個訂單,直接就在訂單服務里,把它搞定了,我們就正常下訂單
- 建立我們的訂單表和我們的訂單產品表,然后,這時候發送一條消息到這個消息隊列里
- 那么我們說這個如果我們發送失敗了,我們本地這個訂單服務也能感知到,它就進行回滾就可以了
- 但是我們說突然的這個停電,這個我們就沒辦法感知到了
- 另一種情況,說你發送這個成功了,比如說我們建這個訂單單服務,然后訂單生成了訂單產品表,也生成了, 消息發送也成功了
- 但是消息隊列給我回消息的時候,由于網絡的擁塞或者是抖動,這都很正常
- 然后,我們這個訂單服務,肯定是要有超時機制的,它就超時了,訂單就要回滾
- 但是這個這個消息隊列是消息,可是真的到消息隊列里存在了
- 那我下游的就庫存,還有積分服務就拿著這個消息去做自己的業務了,該扣減庫存就扣減庫存,該增加積分就增加積分
- 但是,這個時候訂單已經回滾了,那老板或者業務就會問了,這訂單都沒有了,你這個庫存的積分增加是個什么意思
- 那我們要怎么解決這個問題呢?

- 那我們就是在我們這個訂單服務增加訂單的時候,我們不先去給他發這個消息
- 我們是先在本地表里頭建立一個消息發送這個各種情況的一張表
- 比如說, 我這個訂單服務,我建立了一條消息,但是這個消息沒有返回來
- 有沒有返回來也沒有關系,這個表里已經記錄了,說可以定一種狀態,說就是未發送成功
- 我們這里這個本地消息表,就以發送成功的這個狀態為準
- 只要是你能記錄到這個表里的,沒有發送成功的,我們就把它這個狀態記錄上
- 我們下次啟動的時候,在這個訂單服務里增加一個循環的這種定時任務
- 我們一般是做成異步的,因為你要是同步的話,相當于本地的這個數據庫也是也有造成一定的壓力的
- 我們就掃描這個之前沒有發送成功的這個消息,那就是說直到我們這個定時任務,一直發送這個消息隊列發送成功為止
- 所以他一定是能達到最終一致性的,我們這個里面就有一個問題,說你沒發送成功,我記錄一條可以沒問題
- 那我下次一發送這個消息隊列就成功了, 我回寫消息本地這個表就記錄了這條消息成功
- 如果,遇到我們的這個庫存服務了,或者積分服務掛了都沒有問題
- 因為你不消費消息隊列里的這個消息,你就不會確認,你不會確認的這個消息就永遠在消息隊列里,這個就沒有問題
- 但是還有一種情況,比如我這個消息,可能發很多次都有問題,可能是消息隊列問題或者網絡等問題
- 這樣,重復發送就帶來一個風險,比如下游如果重復消費怎么辦?這個就是我們下游服務要解決的問題
- 本地消息的最終一致性,比TCC要簡單很多,但是在某些高并發的場景,它也是有自己的問題的
- 如果一切正常,就發送,讓消息隊列讓消費者去消費就可以了
- 如果有問題,就建立一張本地的這個消息發送表,記錄各種情況,它最后能保證我們消息的最終一致性,但是要解決重復消費消息的這種情況