自從我寫完這個話題的上半部分以後,就感受頭腦中出現了許多細小的聲音,久久揮之不去。它們就像是在爲了一些雞毛蒜皮的小事而相互爭吵個不停。的確,有關分佈式的話題就是這樣,瑣碎異常,並且每一個人說的話聽起來彷佛都有道理。html
今天,咱們就繼續探討這個話題的後半部分。本文中,咱們將從antirez反駁Martin Kleppmann的觀點開始講起,而後會涉及到Hacker News上出現的一些討論內容,接下來咱們還會討論到基於Zookeeper和Chubby的分佈式鎖是怎樣的,並和Redlock進行一些對比。最後,咱們會提到Martin對於這一事件的總結。node
尚未看過上半部分的同窗,請先閱讀:web
Martin在發表了那篇分析分佈式鎖的blog (How to do distributed locking)以後,該文章在Twitter和Hacker News上引起了普遍的討論。但人們更想聽到的是Redlock的做者antirez對此會發表什麼樣的見解。redis
Martin的那篇文章是在2016-02-08這一天發表的,但據Martin說,他在公開發表文章的一星期以前就把草稿發給了antirez進行review,並且他們之間經過email進行了討論。不知道Martin有沒有意料到,antirez對於此事的反應很快,就在Martin的文章發表出來的次日,antirez就在他的博客上貼出了他對於此事的反駁文章,名字叫」Is Redlock safe?」,地址以下:算法
這是高手之間的過招。antirez這篇文章也條例很是清晰,而且中間涉及到大量的細節。antirez認爲,Martin的文章對於Redlock的批評能夠歸納爲兩個方面(與Martin文章的先後兩部分對應):apache
antirez對這兩方面分別進行了反駁。安全
首先,關於fencing機制。antirez對於Martin的這種論證方式提出了質疑:既然在鎖失效的狀況下已經存在一種fencing機制能繼續保持資源的互斥訪問了,那爲何還要使用一個分佈式鎖而且還要求它提供那麼強的安全性保證呢?即便退一步講,Redlock雖然提供不了Martin所講的遞增的fencing token,但利用Redlock產生的隨機字符串(my_random_value
)能夠達到一樣的效果。這個隨機字符串雖然不是遞增的,但倒是惟一的,能夠稱之爲unique token。antirez舉了個例子,好比,你能夠用它來實現「Check and Set」操做,原話是:服務器
When starting to work with a shared resource, we set its state to 「
<token>
」, then we operate the read-modify-write only if the token is still the same when we write.
(譯文:當開始和共享資源交互的時候,咱們將它的狀態設置成「<token>
」,而後僅在token沒改變的狀況下咱們才執行「讀取-修改-寫回」操做。)網絡
第一遍看到這個描述的時候,我我的是感受沒太看懂的。「Check and Set」應該就是咱們日常聽到過的CAS操做了,但它如何在這個場景下工做,antirez並無展開說(在後面講到Hacker News上的討論的時候,咱們還會提到)。session
而後,antirez的反駁就集中在第二個方面上:關於算法在記時(timing)方面的模型假設。在咱們前面分析Martin的文章時也提到過,Martin認爲Redlock會失效的狀況主要有三種:
antirez確定意識到了這三種狀況對Redlock最致命的實際上是第一點:時鐘發生跳躍。這種狀況一旦發生,Redlock是無法正常工做的。而對於後兩種狀況來講,Redlock在當初設計的時候已經考慮到了,對它們引發的後果有必定的免疫力。因此,antirez接下來集中精力來講明經過恰當的運維,徹底能夠避免時鐘發生大的跳動,而Redlock對於時鐘的要求在現實系統中是徹底能夠知足的。
Martin在提到時鐘跳躍的時候,舉了兩個可能形成時鐘跳躍的具體例子:
antirez反駁說:
而Redlock對時鐘的要求,並不須要徹底精確,它只須要時鐘差很少精確就能夠了。好比,要記時5秒,但可能實際記了4.5秒,而後又記了5.5秒,有必定的偏差。不過只要偏差不超過必定範圍,這對Redlock不會產生影響。antirez認爲呢,像這樣對時鐘精度並非很高的要求,在實際環境中是徹底合理的。
好了,到此爲止,若是你相信antirez這裏關於時鐘的論斷,那麼接下來antirez的分析就基本上瓜熟蒂落了。
關於Martin提到的能使Redlock失效的後兩種狀況,Martin在分析的時候剛好犯了一個錯誤(在本文上半部分已經提到過)。在Martin給出的那個由客戶端GC pause引起Redlock失效的例子中,這個GC pause引起的後果至關於在鎖服務器和客戶端之間發生了長時間的消息延遲。Redlock對於這個狀況是能處理的。回想一下Redlock算法的具體過程,它使用起來的過程大致能夠分紅5步:
在Martin舉的例子中,GC pause或網絡延遲,實際發生在上述第1步和第3步之間。而無論在第1步和第3步之間因爲什麼緣由(進程停頓或網絡延遲等)致使了大的延遲出現,在第4步都能被檢查出來,不會讓客戶端拿到一個它認爲有效而實際卻已通過期的鎖。固然,這個檢查依賴系統時鐘沒有大的跳躍。這也就是爲何antirez在前面要對時鐘條件進行辯護的緣由。
有人會說,在第3步以後,仍然可能會發生延遲啊。沒錯,antirez認可這一點,他對此有一段頗有意思的論證,原話以下:
The delay can only happen after steps 3, resulting into the lock to be considered ok while actually expired, that is, we are back at the first problem Martin identified of distributed locks where the client fails to stop working to the shared resource before the lock validity expires. Let me tell again how this problem is common with all the distributed locks implementations, and how the token as a solution is both unrealistic and can be used with Redlock as well.
(譯文:延遲只能發生在第3步以後,這致使鎖被認爲是有效的而實際上已通過期了,也就是說,咱們回到了Martin指出的第一個問題上,客戶端沒可以在鎖的有效性過時以前完成與共享資源的交互。讓我再次申明一下,這個問題對於全部的分佈式鎖的實現是廣泛存在的,並且基於token的這種解決方案是不切實際的,但也能和Redlock一塊兒用。)
這裏antirez所說的「Martin指出的第一個問題」具體是什麼呢?在本文上半部分咱們提到過,Martin的文章分爲兩大部分,其中前半部分與Redlock沒有直接關係,而是指出了任何一種帶自動過時功能的分佈式鎖在沒有提供fencing機制的前提下都有可能失效。這裏antirez所說的就是指的Martin的文章的前半部分。換句話說,對於大延遲給Redlock帶來的影響,剛好與Martin在文章的前半部分針對全部的分佈式鎖所作的分析是一致的,而這種影響不僅僅針對Redlock。Redlock的實現已經保證了它是和其它任何分佈式鎖的安全性是同樣的。固然,與其它「更完美」的分佈式鎖相比,Redlock彷佛提供不了Martin提出的那種遞增的token,但antirez在前面已經分析過了,關於token的這種論證方式自己就是「不切實際」的,或者退一步講,Redlock能提供的unique token也可以提供徹底同樣的效果。
另外,關於大延遲對Redlock的影響,antirez和Martin在Twitter上有下面的對話:
antirez:
@martinkl so I wonder if after my reply, we can at least agree about unbound messages delay to don’t cause any harm.Martin:
@antirez Agree about message delay between app and lock server. Delay between app and resource being accessed is still problematic.(譯文:
antirez問:我想知道,在我發文回覆以後,咱們可否在一點上達成一致,就是大的消息延遲不會給Redlock的運行形成損害。
Martin答:對於客戶端和鎖服務器之間的消息延遲,我贊成你的觀點。但客戶端和被訪問資源之間的延遲仍是有問題的。)
經過這段對話能夠看出,對於Redlock在第4步所作的鎖有效性的檢查,Martin是予以確定的。但他認爲客戶端和資源服務器之間的延遲仍是會帶來問題的。Martin在這裏說的有點模糊。就像antirez前面分析的,客戶端和資源服務器之間的延遲,對全部的分佈式鎖的實現都會帶來影響,這不僅僅是Redlock的問題了。
以上就是antirez在blog中所說的主要內容。有一些點值得咱們注意一下:
討論進行到這,Martin和antirez之間誰對誰錯其實並非那麼重要了。只要咱們可以對Redlock(或者其它分佈式鎖)所能提供的安全性的程度有充分的瞭解,那麼咱們就能作出本身的選擇了。
針對Martin和antirez的兩篇blog,不少技術人員在Hacker News上展開了激烈的討論。這些討論所在地址以下:
在Hacker News上,antirez積極參與了討論,而Martin則始終置身事外。
下面我把這些討論中一些有意思的點拿出來與你們一塊兒分享一下(集中在對於fencing token機制的討論上)。
關於antirez提出的「Check and Set」操做,他在blog裏並無詳加說明。果真,在Hacker News上就有人出來問了。antirez給出的答覆以下:
You want to modify locked resource X. You set X.currlock = token. Then you read, do whatever you want, and when you write, you 「write-if-currlock == token」. If another client did X.currlock = somethingelse, the transaction fails.
翻譯一下能夠這樣理解:假設你要修改資源X,那麼遵循下面的僞碼所定義的步驟。
隨後Hacker News上一位叫viraptor的用戶提出了異議,它給出了這樣一個執行序列:
到了最後兩步,兩個客戶端A和B同時進行寫操做,衝突了。不過,這位用戶應該是理解錯了antirez給出的修改過程了。按照antirez的意思,判斷X.currlock是否修改過和對資源的寫操做,應該是一個原子操做。只有這樣理解才能合乎邏輯,不然的話,這個過程就有嚴重的破綻。這也是爲何antirez以前會對fencing機制產生質疑:既然資源服務器自己都能提供互斥的原子操做了,爲何還須要一個分佈式鎖呢?所以,antirez認爲這種fencing機制是很累贅的,他之因此仍是提出了這種「Check and Set」操做,只是爲了證實在提供fencing token這一點上,Redlock也能作到。可是,這裏仍然有一些不明確的地方,若是將」write-if-currlock == token」看作是原子操做的話,這個邏輯勢必要在資源服務器上執行,那麼第二步爲何還要「讀出資源X」呢?除非這個「讀出資源X」的操做也是在資源服務器上執行,它包含在「判斷-寫回」這個原子操做裏面。而假如不這樣理解的話,「讀取-判斷-寫回」這三個操做都放在客戶端執行,那麼看不出它們如何才能實現原子性操做。在下面的討論中,咱們暫時忽略「讀出資源X」這一步。
這個基於random token的「Check and Set」操做,若是與Martin提出的遞增的fencing token對比一下的話,至少有兩點不一樣:
對於前一點不一樣,咱們在後面的分析中會看到,若是資源服務器也是分佈式的,那麼使用遞增的fencing token也要變成兩步。
而對於後一點操做順序上的不一樣,antirez認爲這個順序沒有意義,關鍵是能互斥訪問就好了。他寫下了下面的話:
So the goal is, when race conditions happen, to avoid them in some way.
……
Note also that when it happens that, because of delays, the clients are accessing concurrently, the lock ID has little to do with the order in which the operations were indented to happen.
(譯文: 咱們的目標是,當競爭條件出現的時候,可以以某種方式避免。
……
還須要注意的是,當那種競爭條件出現的時候,好比因爲延遲,客戶端是同時來訪問的,鎖的ID的大小順序跟那些操做真正想執行的順序,是沒有什麼關係的。)
這裏的lock ID,跟Martin說的遞增的token是一回事。
隨後,antirez舉了一個「將名字加入列表」的操做的例子:
你看,兩個客戶端(實際上是Web服務器)執行「添加名字」的操做,A原本是排在B前面的,但得到鎖的順序倒是B排在A前面。所以,antirez說,鎖的ID的大小順序跟那些操做真正想執行的順序,是沒有什麼關係的。關鍵是能排出一個順序來,能互斥訪問就好了。那麼,至於鎖的ID是遞增的,仍是一個random token,天然就不那麼重要了。
Martin提出的fencing token機制,給人留下了無盡的疑惑。這主要是由於他對於這一機制的描述缺乏太多的技術細節。從上面的討論能夠看出,antirez對於這一機制的見解是,它跟一個random token沒有什麼區別,並且,它須要資源服務器自己提供某種互斥機制,這幾乎讓分佈式鎖自己的存在失去了意義。圍繞fencing token的問題,還有兩點是比較引人注目的,Hacker News上也有人提出了相關的疑問:
關於上述問題(1),Hacker News上有一位叫dwenzek的用戶發表了下面的評論:
…… the issue around the usage of fencing tokens to reject any late usage of a lock is unclear just because the protected resource and its access are themselves unspecified. Is the resource distributed or not? If distributed, does the resource has a mean to ensure that tokens are increasing over all the nodes? Does the resource have a mean to rollback any effects done by a client which session is interrupted by a timeout?
(譯文:…… 關於使用fencing token拒絕掉延遲請求的相關議題,是不夠清晰的,由於受保護的資源以及對它的訪問方式自己是沒有被明肯定義過的。資源服務是否是分佈式的呢?若是是,資源服務有沒有一種方式能確保token在全部節點上遞增呢?對於客戶端的Session因爲過時而被中斷的狀況,資源服務有辦法將它的影響回滾嗎?)
這些疑問在Hacker News上並無人給出解答。而關於分佈式的資源服務器架構如何處理fencing token,另一名分佈式系統的專家Flavio Junqueira在他的一篇blog中有所說起(咱們後面會再提到)。
關於上述問題(2),Hacker News上有一位叫reza_n的用戶發表了下面的疑問:
I understand how a fencing token can prevent out of order writes when 2 clients get the same lock. But what happens when those writes happen to arrive in order and you are doing a value modification? Don’t you still need to rely on some kind of value versioning or optimistic locking? Wouldn’t this make the use of a distributed lock unnecessary?
(譯文: 我理解當兩個客戶端同時得到鎖的時候fencing token是如何防止亂序的。可是若是兩個寫操做剛好按序到達了,並且它們在對同一個值進行修改,那會發生什麼呢?難道不會仍然是依賴某種數據版本號或者樂觀鎖的機制?這不會讓分佈式鎖變得沒有必要了嗎?)
一位叫Terr_的Hacker News用戶答:
I believe the 「first」 write fails, because the token being passed in is no longer 「the lastest」, which indicates their lock was already released or expired.
(譯文: 我認爲「第一個」寫請求會失敗,由於它傳入的token再也不是「最新的」了,這意味着鎖已經釋放或者過時了。)
Terr_的回答到底對不對呢?這很差說,取決於資源服務器對於fencing token進行檢查的實現細節。讓咱們來簡單分析一下。
爲了簡單起見,咱們假設有一臺(先不考慮分佈式的狀況)經過RPC進行遠程訪問文件服務器,它沒法提供對於文件的互斥訪問(不然咱們就不須要分佈式鎖了)。如今咱們按照Martin給出的說法,加入fencing token的檢查邏輯。因爲Martin沒有描述具體細節,咱們猜想至少有兩種可能。
第一種可能,咱們修改了文件服務器的代碼,讓它能多接受一個fencing token的參數,並在進行全部處理以前加入了一個簡單的判斷邏輯,保證只有當前接收到的fencing token大於以前的值才容許進行後邊的訪問。而一旦經過了這個判斷,後面的處理不變。
如今想象reza_n描述的場景,客戶端1和客戶端2都發生了GC pause,兩個fencing token都延遲了,它們幾乎同時到達了文件服務器,並且保持了順序。那麼,咱們新加入的判斷邏輯,應該對兩個請求都會放過,而放過以後它們幾乎同時在操做文件,仍是衝突了。既然Martin宣稱fencing token能保證分佈式鎖的正確性,那麼上面這種可能的猜想也許是咱們理解錯了。
固然,還有第二種可能,就是咱們對文件服務器確實作了比較大的改動,讓這裏判斷token的邏輯和隨後對文件的處理放在一個原子操做裏了。這可能更接近antirez的理解。這樣的話,前面reza_n描述的場景中,兩個寫操做都應該成功。
不少人(也包括Martin在內)都認爲,若是你想構建一個更安全的分佈式鎖,那麼應該使用ZooKeeper,而不是Redis。那麼,爲了對比的目的,讓咱們先暫時脫離開本文的題目,討論一下基於ZooKeeper的分佈式鎖能提供絕對的安全嗎?它須要fencing token機制的保護嗎?
咱們不得不提一下分佈式專家Flavio Junqueira所寫的一篇blog,題目叫「Note on fencing and distributed locks」,地址以下:
Flavio Junqueira是ZooKeeper的做者之一,他的這篇blog就寫在Martin和antirez發生爭論的那幾天。他在文中給出了一個基於ZooKeeper構建分佈式鎖的描述(固然這不是惟一的方式):
/lock
。那麼第一個客戶端就建立成功了,至關於拿到了鎖;而其它的客戶端會建立失敗(znode已存在),獲取鎖失敗。看起來這個鎖至關完美,沒有Redlock過時時間的問題,並且能在須要的時候讓鎖自動釋放。但仔細考察的話,並不盡然。
ZooKeeper是怎麼檢測出某個客戶端已經崩潰了呢?實際上,每一個客戶端都與ZooKeeper的某臺服務器維護着一個Session,這個Session依賴按期的心跳(heartbeat)來維持。若是ZooKeeper長時間收不到客戶端的心跳(這個時間稱爲Sesion的過時時間),那麼它就認爲Session過時了,經過這個Session所建立的全部的ephemeral類型的znode節點都會被自動刪除。
設想以下的執行序列:
/lock
,得到了鎖。/lock
被自動刪除。/lock
,從而得到了鎖。最後,客戶端1和客戶端2都認爲本身持有了鎖,衝突了。這與以前Martin在文章中描述的因爲GC pause致使的分佈式鎖失效的狀況相似。
看起來,用ZooKeeper實現的分佈式鎖也不必定就是安全的。該有的問題它仍是有。可是,ZooKeeper做爲一個專門爲分佈式應用提供方案的框架,它提供了一些很是好的特性,是Redis之類的方案所沒有的。像前面提到的ephemeral類型的znode自動刪除的功能就是一個例子。
還有一個頗有用的特性是ZooKeeper的watch機制。這個機制能夠這樣來使用,好比當客戶端試圖建立/lock
的時候,發現它已經存在了,這時候建立失敗,但客戶端不必定就此對外宣告獲取鎖失敗。客戶端能夠進入一種等待狀態,等待當/lock
節點被刪除的時候,ZooKeeper經過watch機制通知它,這樣它就能夠繼續完成建立操做(獲取鎖)。這可讓分佈式鎖在客戶端用起來就像一個本地的鎖同樣:加鎖失敗就阻塞住,直到獲取到鎖爲止。這樣的特性Redlock就沒法實現。
小結一下,基於ZooKeeper的鎖和基於Redis的鎖相比在實現特性上有兩個不一樣:
順便提一下,如上所述的基於ZooKeeper的分佈式鎖的實現,並非最優的。它會引起「herd effect」(羊羣效應),下降獲取鎖的性能。一個更好的實現參見下面連接:
咱們從新回到Flavio Junqueira對於fencing token的分析。Flavio Junqueira指出,fencing token機制本質上是要求客戶端在每次訪問一個共享資源的時候,在執行任何操做以前,先對資源進行某種形式的「標記」(mark)操做,這個「標記」能保證持有舊的鎖的客戶端請求(若是延遲到達了)沒法操做資源。這種標記操做能夠是不少形式,fencing token是其中比較典型的一個。
隨後Flavio Junqueira提到用遞增的epoch number(至關於Martin的fencing token)來保護共享資源。而對於分佈式的資源,爲了方便討論,假設分佈式資源是一個小型的多備份的數據存儲(a small replicated data store),執行寫操做的時候須要向全部節點上寫數據。最簡單的作標記的方式,就是在對資源進行任何操做以前,先把epoch number標記到各個資源節點上去。這樣,各個節點就保證了舊的(也就是小的)epoch number沒法操做數據。
固然,這裏再展開討論下去可能就涉及到了這個數據存儲服務的實現細節了。好比在實際系統中,可能爲了容錯,只要上面講的標記和寫入操做在多數節點上完成就算成功完成了(Flavio Junqueira並無展開去講)。在這裏咱們能看到的,最重要的,是這種標記操做如何起做用的方式。這有點相似於Paxos協議(Paxos協議要求每一個proposal對應一個遞增的數字,執行accept請求以前先執行prepare請求)。antirez提出的random token的方式顯然不符合Flavio Junqueira對於「標記」操做的定義,由於它沒法區分新的token和舊的token。只有遞增的數字才能確保最終收斂到最新的操做結果上。
在這個分佈式數據存儲服務(共享資源)的例子中,客戶端在標記完成以後執行寫入操做的時候,存儲服務的節點須要判斷epoch number是否是最新,而後肯定能不能執行寫入操做。若是按照上一節咱們的分析思路,這裏的epoch判斷和接下來的寫入操做,是否是在一個原子操做裏呢?根據Flavio Junqueira的相關描述,咱們相信,應該是原子的。那麼既然資源自己能夠提供原子互斥操做了,那麼分佈式鎖還有存在的意義嗎?應該說有。客戶端能夠利用分佈式鎖有效地避免衝突,等待寫入機會,這對於包含多個節點的分佈式資源尤爲有用(固然,是出於效率的緣由)。
提到分佈式鎖,就不能不提Google的Chubby。
Chubby是Google內部使用的分佈式鎖服務,有點相似於ZooKeeper,但也存在不少差別。Chubby對外公開的資料,主要是一篇論文,叫作「The Chubby lock service for loosely-coupled distributed systems」,下載地址以下:
另外,YouTube上有一個的講Chubby的talk,也很不錯,播放地址:
Chubby天然也考慮到了延遲形成的鎖失效的問題。論文裏有一段描述以下:
a process holding a lock L may issue a request R, but then fail. Another process may ac- quire L and perform some action before R arrives at its destination. If R later arrives, it may be acted on without the protection of L, and potentially on inconsistent data.
(譯文: 一個進程持有鎖L,發起了請求R,可是請求失敗了。另外一個進程得到了鎖L並在請求R到達目的方以前執行了一些動做。若是後來請求R到達了,它就有可能在沒有鎖L保護的狀況下進行操做,帶來數據不一致的潛在風險。)
這跟Martin的分析大同小異。
Chubby給出的用於解決(緩解)這一問題的機制稱爲sequencer,相似於fencing token機制。鎖的持有者能夠隨時請求一個sequencer,這是一個字節串,它由三部分組成:
客戶端拿到sequencer以後,在操做資源的時候把它傳給資源服務器。而後,資源服務器負責對sequencer的有效性進行檢查。檢查能夠有兩種方式:
固然,若是因爲兼容的緣由,資源服務自己不容易修改,那麼Chubby還提供了一種機制:
可見,爲了應對鎖失效問題,Chubby提供的三種處理方式:CheckSequencer()檢查、與上次最新的sequencer對比、lock-delay,它們對於安全性的保證是從強到弱的。並且,這些處理方式自己都沒有保證提供絕對的正確性(correctness)。可是,Chubby確實提供了單調遞增的lock generation number,這就容許資源服務器在須要的時候,利用它提供更強的安全性保障。
在Martin與antirez的這場爭論中,衝突最爲嚴重的就是對於系統時鐘的假設是否是合理的問題。Martin認爲系統時鐘不免會發生跳躍(這與分佈式算法的異步模型相符),而antirez認爲在實際中系統時鐘能夠保證不發生大的跳躍。
Martin對於這一分歧發表了以下見解(原話):
So, fundamentally, this discussion boils down to whether it is reasonable to make timing assumptions for ensuring safety properties. I say no, Salvatore says yes — but that’s ok. Engineering discussions rarely have one right answer.
(譯文: 從根本上來講,這場討論最後歸結到了一個問題上:爲了確保安全性而作出的記時假設究竟是否合理。我認爲不合理,而antirez認爲合理 —— 可是這也不要緊。工程問題的討論不多隻有一個正確答案。)
那麼,在實際系統中,時鐘究竟是否可信呢?對此,Julia Evans專門寫了一篇文章,「TIL: clock skew exists」,總結了不少跟時鐘偏移有關的實際資料,並進行了分析。這篇文章地址:
Julia Evans在文章最後得出的結論是:
clock skew is real (時鐘偏移在現實中是存在的)
咱們前面提到過,當各方的爭論在激烈進行的時候,Martin幾乎始終置身事外。可是Martin在這件事過去以後,把這個事件的先後通過總結成了一個很長的故事線。若是你想最全面地瞭解這個事件發生的先後通過,那麼建議去讀讀Martin的這個總結:
在這個故事總結的最後,Martin寫下了不少感性的評論:
For me, this is the most important point: I don’t care who is right or wrong in this debate — I care about learning from others’ work, so that we can avoid repeating old mistakes, and make things better in future. So much great work has already been done for us: by standing on the shoulders of giants, we can build better software.
……
By all means, test ideas by arguing them and checking whether they stand up to scrutiny by others. That’s part of the learning process. But the goal should be to learn, not to convince others that you are right. Sometimes that just means to stop and think for a while.(譯文:
對我來講最重要的一點在於:我並不在意在這場辯論中誰對誰錯 —— 我只關心從其餘人的工做中學到的東西,以便咱們可以避免重蹈覆轍,並讓將來更加美好。前人已經爲咱們創造出了許多偉大的成果:站在巨人的肩膀上,咱們得以構建更棒的軟件。
……
對於任何想法,務必要詳加檢驗,經過論證以及檢查它們是否經得住別人的詳細審查。那是學習過程的一部分。但目標應該是爲了得到知識,而不該該是爲了說服別人相信你本身是對的。有時候,那隻不過意味着停下來,好好地想想。)
關於分佈式鎖的這場爭論,咱們已經完整地作了回顧和分析。
按照鎖的兩種用途,若是僅是爲了效率(efficiency),那麼你能夠本身選擇你喜歡的一種分佈式鎖的實現。固然,你須要清楚地知道它在安全性上有哪些不足,以及它會帶來什麼後果。而若是你是爲了正確性(correctness),那麼請慎之又慎。在本文的討論中,咱們在分佈式鎖的正確性上走得最遠的地方,要數對於ZooKeeper分佈式鎖、單調遞增的epoch number以及對分佈式資源進行標記的分析了。請仔細審查相關的論證。
Martin爲咱們留下了很多疑問,尤爲是他提出的fencing token機制。他在blog中提到,會在他的新書《Designing Data-Intensive Applications》的第8章和第9章再詳加論述。目前,這本書尚在預售當中。我感受,這會是一本值得一讀的書,它不一樣於爲了出名或賺錢而出版的那種短平快的書籍。能夠看出做者在這本書上投入了巨大的精力。
最後,我相信,這個討論還遠沒有結束。分佈式鎖(Distributed Locks)和相應的fencing方案,能夠做爲一個長期的課題,隨着咱們對分佈式系統的認識逐漸增長,能夠再來慢慢地思考它。思考它更深層的本質,以及它在理論上的證實。
(完)
感謝:
由衷地感謝幾位朋友花了寶貴的時間對本文草稿所作的review:CacheCloud的做者付磊,快手的李偉博,阿里的李波。固然,文中若是還有錯漏,由我本人負責^-^。
其它精選文章: