如何保證分佈式系統中接口調用的順序性?

如何保證分佈式系統中接口調用的順序性?

分佈式是當下比較流行的一個話題,很多大型的互聯網公司都是分佈式系統,將一個大而全的系統拆分成多個小而精的一個個的功能單一、職責集中的子系統,系統之間通過約定好的協議、規則進行調用,降低系統之間的耦合度,避免牽一髮而動全身。

雖然分佈式系統的架構有很多的好處,但不得不說它也存在很多需要特別注意的問題。我們今天要講的分佈式系統中接口的調用順序,就是其中一個很常見的問題。

問題引入

一般來說,我們多個接口的調用是不用保證順序的,但是有的時候,有的業務場景可能確實是需要嚴格的順序來保證系統的準確性。

舉個例子,分佈式架構中的服務A調用服務B,發了兩個請求,一個插入操作一個刪除操作,本來是先插入再刪除。但是很可能倆請求過去了,集羣部署的情況下落在了不同機器上,可能插入請求因爲某些原因執行慢了一些,導致刪除請求先執行了,此時因爲沒數據所以沒有啥效果沒有啥影響;接着這個時候插入執行完了,好,把數據插入進去了,這不就完全錯了嘛。

本來應該是插入 -> 刪除,最終這條數據應該沒了,結果現在是刪除 -> 插入,導致最後數據還存在,然後你死都想不明白是怎麼回事。你只能通過不同機器上的日誌去看,費半天勁去查,最後比對倆操作的執行時間,可能最後也能查出來問題所在。

這,就是分佈式系統中一個很常見的問題,那我們該如何保證接口的調用順序呢?

解決方案分析

1、儘量避免引入順序性

首先,一般來說,我個人給你的建議是,你們從業務邏輯上最好設計的這個系統不需要這種順序性的保證,因爲一旦引入順序性保障,我們就需要引入一些的別的、複雜的技術(如分佈式鎖)來保證,這樣會導致系統的複雜度上升,而且會導致系統性能下降,吞吐量降低,熱點數據壓力過大等問題。

2、一致性hash+內存隊列

其次,如果不得不保證順序性的話,下面給個我們用過的方案吧。

簡單來說,首先你得用一致性hash負載均衡策略,將比如同一個訂單id對應的請求都給分發到同一個機器上去。接着就是在那個機器上,因爲可能還是多線程併發執行的,你就得將這個訂單id對應的請求扔進一個內存隊列裏去,強制排隊,這樣來確保他們的順序性。

如下圖所示:

3、分佈式鎖

複雜點的,使用基於zookeeper的分佈式鎖來實現接口調用的強順序性。

首先服務A發送的三個有序請求請求1、2、3,依次發送到消息對列,然後服務B的多個實例從消息對列消費。假如分別是三個實例拿到了1/2/3三個請求,那麼當請求執行時需要小從zookeeper獲取鎖,才能執行。所以此時我們的服務A還要指明這三個請求的執行順序,即seq=1/2/3,服務B才能知道執行順序。

這時候三個請求都來獲取鎖,假如請求3先獲取到鎖,然後看Redis這個list是不是有比自己小的序號,有則釋放鎖。然後如果請求1拿到了鎖,也去Redis判斷是不是有比自己小的序號,一看沒有,就執行請求1,然後從Redis的list裏刪掉這個序號。。。依次這樣來獲取鎖->判斷->刪除redis裏的序號。。。來保證接口的順序性。

如下圖所示:

結語

你看看,上面爲了保證接口調用的順序性是不是又引入了很多複雜的技術,所以這樣後續就會引發很多問題。比如說要是某個訂單對應的請求特別多,造成某臺機器成熱點怎麼辦?這樣系統的增加了系統的複雜度,同時系統的性能、吞吐量也會明顯降低,引入zookeeper分佈式鎖這種很重的機制,勢必會帶來這些副作用。而解決這些問題又要開啓後續一連串的複雜技術方案。。。

曾經這類問題弄的我們頭疼不已,所以,還是建議什麼呢?建議儘量避免引入順序性,在系統設計時就避免這個問題,或者最好是像剛纔那樣一個訂單的插入和刪除操作,能不能合併成一個操作,就是一個刪除,或者是什麼,避免這種問題的產生。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章