1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        一個(gè)經(jīng)典的網(wǎng)絡(luò)通信問題

        共 5554字,需瀏覽 12分鐘

         ·

        2022-05-26 22:33

        想象一下山谷中有一座城市。在山谷的兩邊,各有一支軍隊(duì)。左邊的山上站著愛麗絲將軍和她的軍隊(duì);右邊的山上是鮑勃將軍和他的軍隊(duì)。愛麗絲和鮑勃都想占領(lǐng)這座城市,但雙方都沒有足夠的軍隊(duì)單獨(dú)行動(dòng)。因此,愛麗絲和鮑勃必須同時(shí)攻打這座城市,這樣才有機(jī)會(huì)拿下這座城市。


        然而,問題來了,愛麗絲和鮑勃只能經(jīng)過山谷發(fā)送信息來交流。負(fù)責(zé)傳遞信息的信使有可能被城里的軍隊(duì)俘虜。同時(shí),愛麗絲和鮑勃只有在確信對(duì)方會(huì)同時(shí)進(jìn)攻的情況下才會(huì)真的發(fā)起進(jìn)攻,那么,愛麗絲和鮑勃該如何協(xié)調(diào)他們的進(jìn)攻呢?

        假設(shè)愛麗絲決定采取主動(dòng)行動(dòng)。她給鮑勃發(fā)送了一條信息,內(nèi)容如下:

        “讓我們?cè)?月17日發(fā)起進(jìn)攻。讓信使把你的回復(fù)發(fā)過來?!獝埯惤z”


        如果信使沒能通過,愛麗絲就不會(huì)進(jìn)攻,顯然鮑勃也不會(huì)。如果消息到達(dá)鮑勃,他將發(fā)送他的回復(fù):

        “好吧,就這么辦。就在5月17日!——鮑勃。”


        現(xiàn)在是有趣的部分來了,鮑勃的回復(fù)是否能收到并不重要。不管怎樣,鮑勃都不會(huì)攻擊。記住,因?yàn)轷U勃只有在確信愛麗絲也會(huì)攻擊的情況下才會(huì)進(jìn)攻。鮑勃知道愛麗絲只有在得到他的回復(fù)后才會(huì)攻擊,但是鮑勃不知道他的回復(fù)是否送到了愛麗絲那里。

        如果沒有,她就不會(huì)進(jìn)攻,如果他不帶她進(jìn)攻,他的軍隊(duì)就會(huì)全軍覆沒。因?yàn)轷U勃不知道他的信息是否被愛麗絲收到了,所以他就這么等著,什么也不會(huì)發(fā)生。

        這種情況,我們能做點(diǎn)什么嗎?來我們?cè)囍囊幌虏呗?,就是,讓鮑勃要求愛麗絲發(fā)送確認(rèn)信,表示她收到了他的回復(fù)。因此,發(fā)了這封信:

        “好吧,就這么辦。確定5月17日!同時(shí),請(qǐng)你再發(fā)送另一封信來確保你收到了這封信?!U勃?!?/span>

        現(xiàn)在愛麗絲發(fā)送消息,鮑勃發(fā)送他的回復(fù),愛麗絲準(zhǔn)備發(fā)送她收到了他的回復(fù)的確認(rèn)消息。但她意識(shí)到,她無法知道他是否會(huì)得到確認(rèn)。如果他拿不到,他就不會(huì)進(jìn)攻,她的軍隊(duì)就會(huì)被打敗。所以她決定發(fā)出這樣的信息:

        “我明白你的回答。請(qǐng)?jiān)侔l(fā)送一封信使來確認(rèn)這個(gè)確認(rèn)?!獝埯惤z”

        總結(jié)一下,現(xiàn)在我們有了一條消息、一個(gè)回復(fù)、一個(gè)回復(fù)的確認(rèn)和一個(gè)確認(rèn)的確認(rèn)。



        假設(shè)鮑勃收到確認(rèn)信息并準(zhǔn)備發(fā)送確認(rèn)信息的確認(rèn)信息。但是等等!他意識(shí)到他沒有辦法知道愛麗絲是否會(huì)得到確認(rèn)。如果她沒有得到它,她就不會(huì)進(jìn)攻,所以鮑勃決定發(fā)送:

        “我確認(rèn)你的確認(rèn)。請(qǐng)?jiān)侔l(fā)送一封信來確認(rèn)這個(gè)確認(rèn)?!U勃?!?/span>

        明白這是怎么回事了嗎?不管我們添加多少層級(jí)的確認(rèn),最后一個(gè)發(fā)送信息的人永遠(yuǎn)不可能知道那個(gè)信息是否通過了。因此,最后一個(gè)送信的人永遠(yuǎn)不會(huì)相信對(duì)方會(huì)發(fā)起進(jìn)攻,所以也永遠(yuǎn)不會(huì)進(jìn)攻。


        ?
        1?
        “兩將軍問題”的解法


        上面這個(gè)問題叫做“兩將軍問題”,這個(gè)問題是無解的。那,是否存在較少的約束規(guī)則,這樣問題是不是就可解了?如果答案是否定的,本文就沒法繼續(xù)下去了;是的,確實(shí)存在的。如果我們?nèi)∠p方將軍必須百分百確信對(duì)方會(huì)進(jìn)攻的條件,意思就是如果我們改變一些其他的點(diǎn),我們就可以在大多數(shù)情況下解決這個(gè)問題。雖然我們?nèi)匀粺o法完全保證兩名將軍都會(huì)進(jìn)攻,但至少我們可以相當(dāng)肯定他們會(huì)這么做。

        在這個(gè)問題的新版本中,愛麗絲是領(lǐng)導(dǎo)。她決定什么時(shí)候攻擊,一旦她決定了什么時(shí)候攻擊,無論如何她都會(huì)攻擊。如果鮑勃得到一條消息說他應(yīng)該在特定的時(shí)間進(jìn)行進(jìn)攻,他就必須這樣做。我們繼續(xù)來看這個(gè)例子。

        愛麗絲決定進(jìn)攻。她知道她不可能100%肯定鮑勃也會(huì)攻擊,但她篤定鮑勃99%會(huì)。愛麗絲知道信使穿過山谷需要多長(zhǎng)時(shí)間,她也知道存在信使被抓住的可能性。


        知道了這兩件事,她計(jì)算出多少個(gè)信使能使信息以99%的概率通過并送達(dá)。然后,她計(jì)算發(fā)送這么多信使需要多長(zhǎng)時(shí)間,從而來設(shè)定足夠的攻擊時(shí)間來滿足這一點(diǎn)。

        接下來愛麗絲發(fā)送了一個(gè)帶有以下消息的信使:

        “下周四上午9點(diǎn)襲擊。請(qǐng)派信使回來,確認(rèn)你收到了這條消息?!?/span>

        然后,愛麗絲等待足夠的時(shí)間,讓信使到達(dá)鮑勃,并讓鮑勃的確認(rèn)信使到達(dá)她這里。如果信使到達(dá),愛麗絲停止發(fā)送信使,愛麗絲和鮑勃都在等待,直到下周四上午9點(diǎn)他們協(xié)同攻擊。

        如果確認(rèn)消息沒有到達(dá),愛麗絲發(fā)送另一個(gè)具有相同消息的信使:

        “下周四上午9點(diǎn)襲擊。請(qǐng)派信使回來,確認(rèn)您收到了這條消息?!?/span>

        她會(huì)不斷重復(fù)這個(gè)過程,直到收到回復(fù),或者是在下周四上午9點(diǎn),在這個(gè)時(shí)間,不管消息是否通過,她都會(huì)攻擊。因?yàn)閻埯惤z選擇了未來足夠充裕的時(shí)間(基于消息的失敗率),有99%的機(jī)會(huì)至少有一個(gè)信使在攻擊時(shí)間之前到達(dá)鮑勃。

        我們知道下周四上午九點(diǎn)兩位將軍都有99%的可能發(fā)動(dòng)襲擊。我們能增加這個(gè)確定數(shù)字嗎?是的,我們可以。愛麗絲可以通過將攻擊時(shí)間設(shè)置得越來越遠(yuǎn)而接近100%。然而,如果不將攻擊時(shí)間設(shè)置為無限遠(yuǎn)的未來,她就永遠(yuǎn)無法達(dá)到100%(這意味著它永遠(yuǎn)不會(huì)發(fā)生,所以這是沒有用的)。

        這里還有一點(diǎn)需要指出。如果我們不在乎攻擊是否同時(shí)發(fā)生,愛麗絲可以發(fā)送一條信息:

        “現(xiàn)在就發(fā)動(dòng)進(jìn)攻。發(fā)送信使來確認(rèn)你收到了這條消息?!?/span>


        在這種情況下,愛麗絲可以不斷地發(fā)送消息,直到她收到確認(rèn),并等待確認(rèn),然后攻擊。

        這種方法確實(shí)保證了雙方最終都會(huì)攻擊,但關(guān)鍵是,他們不會(huì)同時(shí)攻擊。愛麗絲攻擊的時(shí)間會(huì)比鮑勃晚,至少是信使從鮑勃到達(dá)愛麗絲那么久,而且,到底晚多久這取決于有多少信使被捕獲。


        ?
        2?
        一個(gè)更實(shí)際的例子


        讓我們看一個(gè)更實(shí)際的例子。假設(shè)你正在設(shè)計(jì)一個(gè)系統(tǒng),該系統(tǒng)需要通過第三方服務(wù)預(yù)訂航班,并向用戶發(fā)送電子郵件說明航班已經(jīng)預(yù)訂。

        起初,這聽起來是個(gè)簡(jiǎn)單的問題。給機(jī)票預(yù)訂系統(tǒng)發(fā)送一個(gè)網(wǎng)絡(luò)調(diào)用。如果返回OK狀態(tài),則發(fā)送郵件。如果它返回一個(gè)錯(cuò)誤狀態(tài),就不發(fā)送電子郵件(或發(fā)送一封說稍后再試的郵件)。


        但請(qǐng)記住,網(wǎng)絡(luò)調(diào)用是不可靠的,所以實(shí)際上這就是——不標(biāo)準(zhǔn)的兩將軍問題。如果網(wǎng)絡(luò)調(diào)用返回一個(gè)OK或一個(gè)錯(cuò)誤狀態(tài),那么我們就沒問題了,但是網(wǎng)絡(luò)調(diào)用也可能因?yàn)闆]有收到響應(yīng)而超時(shí)(就像捕獲了一個(gè)信使一樣)。這種情況下我們?cè)撛趺醋觯?/span>

        就像在兩將軍問題解法中一樣,我們可以繼續(xù)重試這些消息,直到得到響應(yīng)。只有得到回應(yīng),我們才能決定下一步做什么。如果響應(yīng)是好的,我們發(fā)送電子郵件。如果響應(yīng)是一個(gè)錯(cuò)誤,我們就不發(fā)送。

        你覺得這種方法有什么問題嗎?如果網(wǎng)絡(luò)出了問題,我們沒有得到響應(yīng)怎么辦?我們只是不斷地重試,潛在地阻塞資源,直到有人注意到問題并手動(dòng)終止任務(wù)嗎?

        我們可以使用原來的兩將軍問題的部分解決方案來解決這個(gè)問題。我們會(huì)添加一個(gè)計(jì)時(shí)器。具體來說,我們可以向重試過程添加超時(shí)設(shè)定。第一次發(fā)送消息預(yù)訂航班時(shí),我們將啟動(dòng)計(jì)時(shí)器。然后,我們將不斷地重新嘗試消息(只要我們沒有得到響應(yīng)),直到計(jì)時(shí)器計(jì)數(shù)為零。一旦計(jì)時(shí)器完成,我們將停止發(fā)送消息并采取行動(dòng)。


        該定時(shí)器的長(zhǎng)度相當(dāng)于在給鮑勃的消息中聲明攻擊時(shí)間。如果我們?cè)谥苋衔?點(diǎn)開始發(fā)送消息,而愛麗絲決定在周四上午9點(diǎn)發(fā)起攻擊,我們有一個(gè)24小時(shí)的超時(shí)定時(shí)器。就像設(shè)置攻擊時(shí)間一樣,我們可以通過增加超時(shí)的長(zhǎng)度來增加消息通過的機(jī)會(huì)。然而,我們必須權(quán)衡不讓系統(tǒng)過多占用資源來平衡這一點(diǎn)。

        我們知道在暫停之后我們會(huì)采取行動(dòng),但我們還沒有說行動(dòng)是什么。由于沒有得到回復(fù),我們不知道航班是否預(yù)定了。我們可以發(fā)送一封電子郵件說它已經(jīng)被預(yù)訂,或者發(fā)送一封電子郵件說它可能已經(jīng)被預(yù)訂,或者什么也不發(fā)送(并記錄一個(gè)超時(shí)錯(cuò)誤)。最好的決定是視情況而定,但在我們的情況下,我們會(huì)選擇發(fā)送一封電子郵件,說航班可能已經(jīng)預(yù)訂了。用戶可以繼續(xù)下一步了。


        為了讓我們的解決方案起作用,我們必須處理另一個(gè)復(fù)雜的問題,這是由兩將軍問題引發(fā)的直接后果——在一個(gè)不可靠的網(wǎng)絡(luò)上,信息傳遞是不可能的。我們可以發(fā)送一條消息一次,并希望它到達(dá)(但它可能不會(huì)),或者我們可以發(fā)送一條消息多次。在這種情況下,它可能會(huì)到達(dá)不止一次(可能很多次)。

        假設(shè)一個(gè)信使在去找鮑勃的路上迷路了。然后另一個(gè)信使被派遣并直接到達(dá)目的地。在第二個(gè)信使到達(dá)之后,第一個(gè)信使設(shè)法找到了去鮑勃那里的路。同樣的事情也可能發(fā)生在計(jì)算機(jī)網(wǎng)絡(luò)上。消息非但不會(huì)丟失,反而會(huì)在傳遞過程中卡在緩沖區(qū)中。

        在我們的機(jī)票預(yù)訂系統(tǒng)中,這可能是一個(gè)大問題。如果到達(dá)多個(gè)消息要求預(yù)訂一個(gè)航班,系統(tǒng)可能會(huì)預(yù)訂多個(gè)航班。要解決這個(gè)問題,預(yù)定航班請(qǐng)求必須是冪等的。等冪的意思是,如果一個(gè)請(qǐng)求被多次發(fā)出,那么該請(qǐng)求的效果只能出現(xiàn)一次。

        有幾種方法可以使預(yù)定航班請(qǐng)求冪等。一種方法是在請(qǐng)求中包含一個(gè)唯一的ID。只要我們的系統(tǒng)在每次重試時(shí)發(fā)送相同的ID,預(yù)定系統(tǒng)就可以存儲(chǔ)該ID,并使它忽略它收到的第一個(gè)消息以外的所有消息。


        ?
        3?
        添加第二個(gè)分布式操作


        到目前為止,我們似乎已經(jīng)解決了所有的問題。然而,如果我們添加第二個(gè)分布式操作,我們的系統(tǒng)就會(huì)崩潰。如果我們希望我們的系統(tǒng)也能處理酒店預(yù)訂,會(huì)發(fā)生什么?新的要求是我們應(yīng)該一起訂機(jī)票和酒店。也就是說,只有在航班預(yù)訂成功的情況下,我們才能預(yù)定酒店,或者酒店預(yù)訂成功的情況下,我們才能預(yù)定航班。在我們預(yù)訂了他們兩個(gè)之后,我們會(huì)發(fā)送一封更新狀態(tài)的電子郵件。

        即使忽略超時(shí),都要預(yù)訂或都不預(yù)訂的需求也會(huì)增加復(fù)雜性。我們可以用幾種不同的方法來處理這種復(fù)雜性,但最直接的方法是確保我們的系統(tǒng)能夠處理撤銷任意一個(gè)操作。這種方法被稱為分布式SAGA。

        我們的航班和酒店預(yù)訂系統(tǒng)的分布式SAGA是這樣的(忽略超時(shí)和丟失的消息):首先,我們發(fā)送一條消息來預(yù)訂航班。如果得到錯(cuò)誤響應(yīng),則中止整個(gè)過程。如果航班預(yù)訂系統(tǒng)返回成功,則發(fā)送一條消息預(yù)訂酒店。如果成功了,我們就完成了,我們可以發(fā)送成功的電子郵件。

        但是,如果酒店系統(tǒng)返回一個(gè)錯(cuò)誤,我們必須通過調(diào)用航班系統(tǒng)來撤銷預(yù)訂的航班,并發(fā)送一條消息告訴它取消我們剛剛預(yù)訂的航班。這就是所謂的回滾SAGA。在回滾SAGA之后,我們可以發(fā)送適當(dāng)?shù)南⒒蛴涗涘e(cuò)誤。

        下面是偽代碼:


        在實(shí)際實(shí)現(xiàn)中,我們實(shí)際上不能忽略丟失的消息。在我們的故事中,SAGA如何處理這種可能性?每個(gè)分布式操作(預(yù)訂航班和預(yù)訂酒店)必須有相應(yīng)的補(bǔ)償操作(取消航班預(yù)訂和取消酒店預(yù)訂)。我們可以在調(diào)用原始操作時(shí)使用補(bǔ)償操作來處理丟失的消息。例如:

        我們開啟SAGA,并發(fā)送預(yù)訂機(jī)票的信息。如果預(yù)定系統(tǒng)網(wǎng)絡(luò)超時(shí),我們可以回滾SAGA,而不是重新嘗試。同時(shí),我們使用與原預(yù)訂航班請(qǐng)求的ID來一起調(diào)用航班的取消。


        ?
        4?
        處理超時(shí)和消息丟失


        你可能已經(jīng)注意到一個(gè)問題。我們不知道預(yù)訂航班的請(qǐng)求是否通過了。如果沒有,我們?nèi)匀话l(fā)送取消航班預(yù)訂請(qǐng)求么?同樣,預(yù)訂航班請(qǐng)求必須是冪等的,預(yù)訂航班和取消航班預(yù)訂的組合必須是可交換的。機(jī)票預(yù)訂系統(tǒng)接收他們的順序應(yīng)該是無關(guān)緊要的。

        如果取消航班預(yù)訂消息首先到達(dá),那么航班預(yù)訂系統(tǒng)必須存儲(chǔ)請(qǐng)求ID,并隨后阻止帶有該ID的任何預(yù)訂航班請(qǐng)求。如果取消航班預(yù)訂消息在預(yù)訂航班消息之后到達(dá),那么航班預(yù)訂系統(tǒng)必須撤消原來的操作。

        我們已經(jīng)通過將問題轉(zhuǎn)移到補(bǔ)償操作來處理航班預(yù)訂操作的丟失消息,但是如果補(bǔ)償操作請(qǐng)求丟失了會(huì)發(fā)生什么呢?

        補(bǔ)償行為一定不能失敗。它們永遠(yuǎn)不會(huì)返回錯(cuò)誤代碼。這意味著它們失敗的唯一方式是超時(shí)。因此,我們可以繼續(xù)重試補(bǔ)償操作,直到它成功(在實(shí)踐中,我們可能希望這里有一個(gè)超時(shí)來放棄,并最終拋出報(bào)警,某些地方出了問題)。

        如果預(yù)訂機(jī)票成功了,我們就去預(yù)訂酒店。如果失敗,則回滾上一步。如果超時(shí),我們通過調(diào)用取消酒店預(yù)訂來回滾當(dāng)前步驟,然后回滾上一個(gè)步驟,取消SAGA并退出。如果一切順利,我們繼續(xù)發(fā)送電子郵件。

        在偽代碼中,我們最后的SAGA是這樣的:


        ?
        5?
        生產(chǎn)系統(tǒng)中的注意事項(xiàng)


        對(duì)于生產(chǎn)系統(tǒng),還有一些值得注意的地方。我們已經(jīng)處理了遠(yuǎn)程系統(tǒng)的故障,但還沒有處理本地系統(tǒng)的故障。我們還需要存儲(chǔ)我們?cè)诋?dāng)前事件中的位置節(jié)點(diǎn),以便在系統(tǒng)中途崩潰時(shí)能夠及時(shí)恢復(fù)。

        此外,大多數(shù)關(guān)于分布式SAGA的文檔都將像我剛才做的那樣會(huì)提到交換律,但交換律還不夠強(qiáng),不足以描述需要什么。

        讓我們以SAGA中的一個(gè)叫做Increment的動(dòng)作和它的補(bǔ)償動(dòng)作叫做Decrement為例。Increment使數(shù)字增加1,Decrement使數(shù)字減少1。這些動(dòng)作合在一起是可交換的。從計(jì)數(shù)器的0開始,Increment然后Decrement=Decrement然后Increment=0。

        0+1-1=0-1+1=0

        不管順序如何,最終的結(jié)果都是一樣的。但在SAGA中的補(bǔ)償動(dòng)作也必須在補(bǔ)償動(dòng)作信息到達(dá)目的地時(shí)才能發(fā)揮作用。

        也就是說,從0開始,遞增然后遞減=遞減然后遞增=遞減=0。

        我不是說動(dòng)作和它的補(bǔ)償動(dòng)作必須是可交換的,而是說補(bǔ)償動(dòng)作必須支配動(dòng)作。Increment和Decrement也必須都是冪等的,因此無論到達(dá)多少條消息(具有相同的ID),只要到達(dá)了一個(gè)Decrement,最終的結(jié)果必須與SAGA開始之前相同。

        另一個(gè)從0開始的例子:

        Increment->Decrement->Increment=0=Decrement->Increment->Decrement

        這些屬性,對(duì)于補(bǔ)償操作來說Decrement并不是一個(gè)好名字。最好叫它“補(bǔ)償增量(Compensation Increment)”。

        實(shí)現(xiàn)這個(gè)的一種方法是讓Compensation Increment與Increment共享它的ID。當(dāng)服務(wù)器處理Compensate Increment時(shí),它將檢查是否已經(jīng)處理了任何具有該ID的Increment消息。如果是,服務(wù)器將減少該值以進(jìn)行補(bǔ)償。如果不是,則保持值不變。然后,在前面的兩種情況下,它都會(huì)保存ID,以便將來任何帶有該ID的消息都將被忽略。

        有些SAGA的文檔中還將分布式SAGA中的每個(gè)步驟稱為事務(wù),但我在這里將它們稱為操作,以避免與其他并發(fā)控制方法混淆。

        轉(zhuǎn)自:分布式實(shí)驗(yàn)室
        原文鏈接:https://mp.weixin.qq.com/s/wFWdOzDtljyXoLethngb8A



        瀏覽 28
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            爱搞搞就要搞搞 | 新婚之夜初尝高潮电影 | 国产精品自拍偷拍视频 | A日本免费 | 婷婷五月六月婷婷综合激情 | 猫咪AV大香蕉 | 俺来俺也去www色在线观看 | 欧美性猛交XXXXX乱大交3免费 | 激情小说激情图片 | 国产65一二三区 |