平頂山車禍最新新聞事件百度seo什么意思
1.分布式鎖
jdk的鎖: 1、顯示鎖:Lock 2、隱式鎖:synchronized
使用jdk鎖保證線程的安全性要求:要求多個線程必須運行在同一個jvm中
但現(xiàn)在的系統(tǒng)基本都是分布式部署的,一個應用會被部署到多臺服務器上,synchronized只能控制當前服務器自身的線程安全,并不能跨服務器控制并發(fā)安全。
所以在分布式環(huán)境下要解決線程安全問題就需要使用分布式鎖
思想:需要在我們分布式應用的外面使用一個第三方組件(可以是數(shù)據(jù)庫、Redis、Zookeeper等)進行全局鎖的監(jiān)控,由這個組件決定什么時候加鎖,什么時候釋放鎖
原理:在獲取鎖的時候插入數(shù)據(jù),如何數(shù)據(jù)可以存儲成功那么就獲取獲取到了鎖,如果數(shù)據(jù)插入不成功那么就說明獲取鎖失敗了。在進行鎖釋放的時候只需要將數(shù)據(jù)刪除掉。
1.🌟redis分布式鎖實現(xiàn)業(yè)務流程:
-
首先我們項目中是基于原生redis實現(xiàn)分布式的就會涉及到一些redis原生命令
-
前置操作一定是緩存無數(shù)據(jù),布隆判斷之后可能有數(shù)據(jù),才會在此處添動加商品自身分布式鎖
-
使用set nx ex命令設置一個有效期為指定時間的鎖,我記得當時是根據(jù)多次壓測結(jié)果取的值
-
這樣會有一個問題,萬一在給定時間內(nèi)未完成查詢操作此時我們是通過后端代碼自定義守護線程方式位鎖進行自動續(xù)期
-
上面的操作如果都沒有問題,表示上鎖成功.回源查詢數(shù)據(jù)庫寫入緩存,整個分布式鎖的實現(xiàn)會涉及到鎖的獲取、判斷、刪除,需要保證這三個操作原子性,我們借助于lu腳本實現(xiàn)這個一般也不需要記用的時候,通過文檔查閱即可
1.基礎實現(xiàn)
基于setnx命令的特性,我們就可以實現(xiàn)一個最簡單的分布式鎖了。我們通過向Redis發(fā)送 setnx 命令,然后判斷Redis返回的結(jié)果是否為1,結(jié)果是1就表示setnx成功了,那本次就獲得鎖了,可以繼續(xù)執(zhí)行業(yè)務邏輯;如果結(jié)果是0,則表示setnx失敗了,那本次就沒有獲取到鎖,可以通過循環(huán)的方式一直嘗試獲取鎖,直至其他客戶端釋放了鎖(delete掉key)后,就可以正常執(zhí)行setnx命令獲取到鎖。流程如下:
2.lua原子性操作
針對上述Redis原始命令無法滿足部分業(yè)務原子性操作的問題,Redis提供了Lua腳本的支持。
釋放鎖時:
Lua腳本是一種輕量小巧的腳本語言,它支持原子性操作,Redis將整個Lua腳本作為一個整體執(zhí)行,中間不會被其他請求插入,因此Redis執(zhí)行Lua腳本是一個原子操作。在上面的流程中,我們把get key value、判斷value是否屬于當前線程、刪除鎖這三步寫到Lua腳本中,使它們變成一個整體交個Redis執(zhí)行,改造后流程如下:
解決了釋放鎖時取值、判斷值、刪除鎖等多個步驟無法保證原子操作的問題了
加鎖時:
在使用set key value ex seconds nx命令加鎖時,并不能做到重入鎖的效果,也就是當一個線程獲取到鎖后,在沒有釋放這把鎖之前,當前線程自己也無法再獲得這把鎖,這顯然會影響系統(tǒng)的性能。使用Lua腳本就可以解決這個問題,我們可以在Lua腳本中先判斷鎖(key)是否存在,如果存在則再判斷持有這把鎖的線程是否是當前線程,如果不是則加鎖失敗,否則當前線程再次持有這把鎖,并把鎖的重入次數(shù)+1。在釋放鎖時,也是先判斷持有鎖的線程是否是當前線程,如果是則將鎖的重入次數(shù)-1,直至重入次數(shù)減至0,即可刪除該鎖(key)。
2.🌟Aop-分布式鎖(首頁三級分類、詳情頁)
分布式鎖實現(xiàn)、A0P在項目中的使用場景
本身咱們在不使用緩存和分布式鎖的情況下,也可以實現(xiàn)詳情頁或者首頁三級分類信息的展示,使用了緩存和分布式鎖,只是對核心功能的一個增強,按照00P思想,會直接侵入代碼不易維護,所以需要將這種從上到下的關系優(yōu)化為從左到右的增強,即AOP思想AOP是spring提供的一個面向切面編程思想,其底層原理是動態(tài)代理,項目中是這樣做的
-
自定了一個注解@MyCache包含redis使用的key的前綴、過期時間、分布式鎖key值等信息
-
自定義一個切面類,就是一個被@Aspect注解修飾的一個普通類而己,在類中定義一個通知,其實就是方法名around在這個方法上需要加@Around注解表示,我們用的是spring5通知類型中的環(huán)繞通知,通過該注解的一個屬性annotation對自定義注解進行增強
-
鑒于環(huán)繞通知的使用方法是固定的,所以在定義環(huán)繞通知的時候,需要注意方法返回值必須是Object類型,方法形參必須是ProceedingJoinPoint的,為了能夠手動調(diào)用目標方法,另外還需要注意,環(huán)繞通知方法必須手動拋出異常信息
-
這樣就完成了項目中對于A0P封裝和使用,在需要用到緩存和分布式鎖的場景,我們只需要將注解添加到使用的位置即可
3 如何提高分布式鎖性能
1 優(yōu)化分布式鎖性能的關鍵因素
要提升分布式鎖的性能,首先需要了解影響性能的關鍵因素。以下是一些影響分布式鎖性能的關鍵因素:
-
鎖的粒度:鎖的粒度越小,性能通常越高。粒度較大的鎖可能會導致鎖爭用,從而降低性能。
-
鎖的持有時間:鎖的持有時間越短,性能越高。長時間持有鎖會限制其他節(jié)點的訪問。
-
鎖的實現(xiàn)方式:不同的分布式鎖實現(xiàn)方式性能差異較大。使用緩存的速度比較快。
-
網(wǎng)絡延遲:分布式鎖通常需要跨越網(wǎng)絡進行通信,網(wǎng)絡延遲會影響性能。
-
鎖的競爭情況:如果鎖的競爭情況較少,性能通常較好。高度競爭的鎖會導致性能下降。
2 優(yōu)化技巧和最佳實踐
1. 選擇合適的分布式鎖實現(xiàn)
選擇合適的分布式鎖實現(xiàn)是性能優(yōu)化的關鍵。不同的實現(xiàn)方式有不同的性能特點。例如,基于
Redis的分布式鎖通常性能較高,因為Redis是一個高性能的內(nèi)存數(shù)據(jù)庫,而基于ZooKeeper的鎖可
能性能較低,因為它需要跨越網(wǎng)絡進行通信。因此,根據(jù)需求選擇合適的實現(xiàn)方式非常重要。
2. 減小鎖的粒度
將鎖的粒度盡量減小可以提高性能。例如,如果系統(tǒng)中有多個共享資源,可以為每個資源使用單獨
的鎖,而不是一個全局鎖。這樣可以減小鎖的競爭情況,提高吞
吐量。
3. 限制鎖的持有時間
盡量減小鎖的持有時間可以提高性能。在獲取鎖后,盡快完成需要鎖保護的操作,然后釋放鎖,讓
其他節(jié)點有機會訪問共享資源。
4. 使用非阻塞鎖
非阻塞鎖通常性能更高,因為它們不會阻塞線程或進程,而是會立即返回鎖的狀態(tài)。常見的非阻塞
鎖包括樂觀鎖和基于CAS(比較并交換)的鎖。
5. 考慮鎖的超時和重試機制
在獲取鎖時,考慮設置鎖的超時時間和重試機制,以避免出現(xiàn)死鎖情況。如果獲取鎖失敗,可以等
待一段時間后重試,或者使用指數(shù)退避策略。
6. 考慮分布式事務
在某些場景下,使用分布式事務可以代替分布式鎖,從而提高性能。分布式事務通常比分布式鎖更
高效,但需要謹慎設計,以確保數(shù)據(jù)一致性。