一、什麼是分布式鎖
分布式鎖是控制分布式系統之間同步訪問共享資源的一種機制。在單節點應用中,我們需要對一個共享資源進行多線程訪問時,使用普通的鎖就能夠保證同步循序訪問資源,不存在線程安全問題。當你掌握了流量密碼後,業務突飛猛進,應用部署需要擴容,進行集群部署。此時,普通的鎖已經控制不了集群各節點線程對共享資源的訪問,為解決此問題,分布式鎖誕生。
二、分布式鎖特性與應用場景
- CAP理論的理解CAP是分布式領域⾮常重要的⼀個理論,很多分布式中間件在實現時都需要遵守這個理論,其中:C表示⼀緻性(Consistency):指的的是分布式系統中的數據的⼀緻性。A表示可⽤性(Availability):表示分布式系統是否正常可⽤。P表示分區容錯性(Partition tolerance):表示分布式系統出現⽹絡問題時的容錯性。CAP理論是指,在分布式系統中不能同時保證C和A,也就是說在分布式系統中要麼保證CP,要麼保證AP,也就是⼀緻性和可⽤性隻能取其⼀,如果想要數據的⼀緻性,那麼就需要損失系統的可⽤性,如果需要系統⾼可⽤,那麼就要損失系統的數據⼀緻性,特指強⼀緻性。CAP理論太過嚴格,在實際⽣産環境中更多的是使⽤BASE理論,BASE理論是指分布式系統不需要保證數據的強⼀緻,隻要做到最終⼀緻,也不需要保證⼀直可⽤,保證基本可⽤即可。
- 分布式鎖應具備的能力1、在分布式系統環境下,一個資源在同一時刻隻能被一台機器的一個線程使用;2、高可用的獲取鎖與釋放鎖;3、高性能的獲取鎖與釋放鎖4、具備可重入特性;5、具備鎖失效機制,防止死鎖;6、具備非阻塞鎖特性,即沒有獲取到鎖将直接返回獲取鎖失敗。
- 高頻業務場景1、扣減庫存2、訂單支付3、退貨退款這些業務場景是一定不能出問題的,特别是高并發,大流量的環境下,一但出問題,就需要對海量異常數據進行恢複,這是我們不希望發生的。
- 分布式鎖實現方式1、基于數據庫實現分布式鎖2、基于Redis緩存實現分布式鎖3、基于Zookeeper實現分布式鎖
三、分布式鎖你用對了嗎?
使用了分布式鎖,為什麼你的訂單還是有重複支付的記錄産生?
先來說故事,小Q已做開發好幾年,近期負責一個新項目的訂單支付接口開發。在小Q看來,支付API已有,畢竟也有幾年工作經驗,輕車熟路,知道訂單支付要加分布式鎖,信心滿滿,揮一揮手幹完一個訂單支付接口。系統測試階段,支付功能正常,沒啥BUG。系統上線後,訂單支付功能運行良好。突然有一天,客服接到客戶反饋"你們這是什麼破系統,竟敢重複扣我的血汗錢"。小Q接到項目經理通知後,驚呆了,心想"難道是架構師提供的分布式鎖組件有bug?"。
然而并不像小Q想的那樣,原因竟是小Q自己的分布式鎖使用不當造成的。原來架構師為了防止死鎖,提供了一個可以設置鎖超時自動釋放的加鎖方法。而小Q在加鎖時也考慮到了死鎖的情況,給加鎖方法設置了一個10秒的超時釋放時間。正常情況下,一個同步支付的請求處理時間不超過2秒,小Q考慮10秒總該夠了吧,于是自信地設置了10秒。
小Q在業務處理異常考慮得較少,在支付處理中,支付後需要調用外部服務推送數據,推送數據接口由于異常15秒後報了ReadTimeout。而小Q加鎖的代碼中正包含調用外部服務推送數據方法。業務要求如果推送數據失敗不能影響正常支付,所以小Q用了try..catch,記錄失敗日志以便後續系統定時任務重新推送。所以推送數據超時後也正常寫入了支付數據。
由于用戶支付操作等了很久,在12秒的時候又重新發起了一次支付,此時,由于第一次支付的鎖釋放時間(10秒)已到,鎖自動釋放。第二次支付請求,在12秒又獲得鎖,第二次支付也正常完成流程處理。産生了2筆都是支付完成的支付記錄。

支付時序圖
圖中主要有幾個問題:
- 分布式鎖失效時間設置不當為了防止死鎖,可以合理使用使用失效機制。既然要設置失效時間,那麼重點應該關注時間的長度。時間多少取決于鎖從開始到結束整個過程中包圍的業務代碼處理的總時長。即:本地接口處理時間 外部接口處理時間。注意要考慮外部接口調用超時情況(一般會設置超時熔斷)。所以鎖的失效時間長度應該大于鎖範圍内的業務處理總耗時。
- 業務流程編排不合理調用第三方支付正常響應後寫入支付數據,此時支付業務已完成,可以提交事務。推送數據可以try...catch,說明數據強一緻性要求不高,不需要包含在Transaction中。對于可以着延時的數據處理,推薦使用消息中間件處理,隻要保證數據的最終一緻性即可。
- 事務作用範圍不合理Transaction的使用,大家都明白要麼都成功,要麼都失敗。但是還要提前考慮什麼需要都成功,為你使用事務正确提供決策條件。另外要注意"要麼都失敗"的理解:不是不用管了,使用Transaction,最重要的是失敗後怎麼保證業務數據不丢失。在測試環境中,數據丢了可以重新造。生産環境中,數據丢了客戶要給你投訴,你還得費盡精力恢複補數據,你還得背負生産責任,所以數據的最終一緻性是必須的,這也是系統健壯穩定的一個評判标準。
- 異常處理考慮不周做設計、開發、測試最容易忽略的就是異常,測試環境系統運行穩如狗,一到生産就趴窩。不同的環境,數據容量、網絡架構、硬件配置、軟件配置、訪問流量、網絡訪問策略等等因素,都可以給我們參考,從而做出良好的設計,開發出健壯穩定的系統。
, 更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!