Java中单体应用锁的局限性&分布式锁
互聯(lián)網(wǎng)系統(tǒng)架構(gòu)的演進(jìn)
在互聯(lián)網(wǎng)系統(tǒng)發(fā)展之初,系統(tǒng)比較簡單,消耗資源小,用戶訪問量也比較少,我們只部署一個(gè)Tomcat應(yīng)用就可以滿足需求。系統(tǒng)架構(gòu)圖如下:
一個(gè)Tomcat可以看作是一個(gè)JVM進(jìn)程,當(dāng)大量的請求并發(fā)到達(dá)系統(tǒng)時(shí),所有的請求都落在這唯一的一個(gè)Tomcat上,如果某些請求方法是需要加鎖的,比如:秒殺扣減庫存,是可以滿足需求的,這和我們前面章節(jié)所講的內(nèi)容是一樣的。但是隨著訪問量的增加,導(dǎo)致一個(gè)Tomcat難以支撐,這時(shí)我們就要集群部署Tomcat,使用多個(gè)Tomcat共同支撐整個(gè)系統(tǒng)。系統(tǒng)架構(gòu)圖如下:
上圖中,我們部署了兩個(gè)Tomcat,共同支撐系統(tǒng)。當(dāng)一個(gè)請求到達(dá)系統(tǒng)時(shí),首先會經(jīng)過Nginx,Nginx主要是做負(fù)載轉(zhuǎn)發(fā)的,它會根據(jù)自己配置的負(fù)載均衡策略將請求轉(zhuǎn)發(fā)到其中的一個(gè)Tomcat中。當(dāng)大量的請求并發(fā)訪問時(shí),兩個(gè)Tomcat共同承擔(dān)所有的訪問量,這時(shí),我們同樣在秒殺扣減庫存的場景中,使用單體應(yīng)用鎖,還能夠滿足要求嗎?
單體應(yīng)用鎖的局限性
如上圖所示,在整個(gè)系統(tǒng)架構(gòu)中,存在兩個(gè)Tomcat,每個(gè)Tomcat是 -個(gè)JVM。在進(jìn)行秒殺業(yè)務(wù)的時(shí)候,由于大家都在搶購秒殺商品,大量的請求同時(shí)到達(dá)系統(tǒng),通過Nginx分 發(fā)到兩個(gè)Tomcat上。我們通過一個(gè)極端的案例場景, 可以更好地理解單體應(yīng)用鎖的局限性。假如,秒殺商品的數(shù)量只有1個(gè),這時(shí),這些大量的請求當(dāng)中,只有一個(gè)請求可以成功的搶到這個(gè)商品,這就需要在扣減庫存的方法.上加鎖,扣減庫存的動作只能一個(gè)一個(gè)去執(zhí)行,而不能同時(shí)去執(zhí)行如果同時(shí)執(zhí)行,這1個(gè)商品可能同時(shí)被多個(gè)人搶到,從而產(chǎn)生超賣現(xiàn)象。加鎖之后,扣減庫存的動作一個(gè)一個(gè)去執(zhí)行,凡是將庫存扣減為負(fù)數(shù)的,都拋出異常,提示該用戶沒有搶到商品。通過加鎖看似解決了秒殺的問題,但是事實(shí),上真的是這樣嗎?
我們看到系統(tǒng)中存在兩個(gè)Tomcat,我們加的鎖是JDK提供的鎖,這種鎖只能在一個(gè)JVM下起作用,也就是在一個(gè)Tomcat內(nèi)是沒有問題的。當(dāng)存在兩個(gè)或兩個(gè)以上的Tomcat時(shí),大量的并發(fā)請求分散到不同的Tomcat_上,在每一一個(gè)Tomcat中都可以防止并發(fā)的產(chǎn)生,但是在多個(gè)Tomcat之間,每個(gè)Tomcat中獲得鎖的這個(gè)請求,又產(chǎn)生了并發(fā)從而產(chǎn)生超賣現(xiàn)象。這也就是單體應(yīng)用鎖的局限性,它只能在一個(gè)JVM內(nèi)加鎖,而不能從這個(gè)應(yīng)用層面去加鎖。
那么這個(gè)問題如何解決呢?這就需要使用分布式鎖了,在整個(gè)應(yīng)用層面去加鎖。什么是分布式鎖呢?我們怎么去使用分布式鎖呢?
什么是分布式鎖
在說分布式鎖之前,我們看一看單體應(yīng)用鎖的特點(diǎn),單體應(yīng)用鎖是在一個(gè)JVM進(jìn)程內(nèi)有效,無法跨JVM、跨進(jìn)程。那么分布式鎖的定義就出來了,分布式鎖就是可以跨越多個(gè)JVM、跨越多個(gè)進(jìn)程的鎖,這種鎖就叫做分布式鎖。
分布式鎖的設(shè)計(jì)思路
在上圖中,由于Tomcat是由Java啟動的,所以每個(gè)Tomcat可以看成一個(gè)JVM,JVM內(nèi)部的鎖是無法跨越多個(gè)進(jìn)程的。所以,我們要實(shí)現(xiàn)分布式鎖,我們只能在這些JVM之外去尋找,通過其他的組件來實(shí)現(xiàn)分布式鎖。系統(tǒng)的架構(gòu)如圖所示:
兩個(gè)Tomcat通過第三方的組件實(shí)現(xiàn)跨JVM、跨進(jìn)程的分布式鎖。這就是分布式鎖的解決思路,找到所有JVM可以共同訪問的第三方組件,通過第三方組件實(shí)現(xiàn)分布式鎖。
目前存在的分布式的方案
分布式鎖都是通過第三方組件來實(shí)現(xiàn)的,目前比較流行的分布式鎖的解決方案有:
- 數(shù)據(jù)庫,通過數(shù)據(jù)庫可以實(shí)現(xiàn)分布式鎖,但是在高并發(fā)的情況下對數(shù)據(jù)庫壓力較大,所以很少使用。
- Redis,借助Redis也可以實(shí)現(xiàn)分布式鎖,而且Redis的Java客戶端種類很多,使用的方法也不盡相同。
- Zookeeper,Zookeeper也可以實(shí)現(xiàn)分布式鎖,同樣Zookeeper 也存在多個(gè)Java客戶端,使用方法也不相同。
本人最近搭建了程序員專屬的編程資料個(gè)人網(wǎng)站:程序員波特,主要記錄Java相關(guān)技術(shù)系列教程,面試題的收集和整理等,讓上班摸魚的你,不再無聊。
總結(jié)
以上是生活随笔為你收集整理的Java中单体应用锁的局限性&分布式锁的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Blazor入门100天 : 身份验证和
- 下一篇: 背会了常见的几个线程池用法,结果被问翻了