您好,登錄后才能下訂單哦!
Java 原生 API 雖然有并發(fā)鎖,但并沒(méi)有提供分布式鎖的能力,所以針對(duì)分布式場(chǎng)景中的鎖需要解決的方案。
分布式鎖的解決方案大致有以下幾種:
1. 創(chuàng)建表
CREATE TABLE `methodLock` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵', `method_name` varchar(64) NOT NULL DEFAULT '' COMMENT '鎖定的方法名', `desc` varchar(1024) NOT NULL DEFAULT '備注信息', `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '保存數(shù)據(jù)時(shí)間,自動(dòng)生成', PRIMARY KEY (`id`), UNIQUE KEY `uidx_method_name` (`method_name `) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='鎖定中的方法';
2. 獲取鎖
想要鎖住某個(gè)方法時(shí),執(zhí)行以下 SQL:
insert into methodLock(method_name,desc) values (‘method_name’,‘desc’)
因?yàn)槲覀儗?duì)
method_name
做了唯一性約束,這里如果有多個(gè)請(qǐng)求同時(shí)提交到數(shù)據(jù)庫(kù)的話(huà),數(shù)據(jù)庫(kù)會(huì)保證只有一個(gè)操作可以成功,那么我們就可以認(rèn)為操作成功的那個(gè)線(xiàn)程獲得了該方法的鎖,可以執(zhí)行方法體內(nèi)容。
成功插入則獲取鎖。
3. 釋放鎖
當(dāng)方法執(zhí)行完畢之后,想要釋放鎖的話(huà),需要執(zhí)行以下 Sql:
delete from methodLock where method_name ='method_name'
相比于用數(shù)據(jù)庫(kù)來(lái)實(shí)現(xiàn)分布式鎖,基于緩存實(shí)現(xiàn)的分布式鎖的性能會(huì)更好一些。目前有很多成熟的分布式產(chǎn)品,包括 Redis、memcache、Tair 等。這里以 Redis 舉例。
單點(diǎn)實(shí)現(xiàn)步驟:
可以考慮使用 redisson 的解決方案。
這也是 ZooKeeper 客戶(hù)端 curator 的分布式鎖實(shí)現(xiàn)。
ZooKeeper 版本的分布式鎖問(wèn)題相對(duì)比較來(lái)說(shuō)少。
總體上來(lái)說(shuō) ZooKeeper 實(shí)現(xiàn)分布式鎖更加的簡(jiǎn)單,可靠性更高。但 ZooKeeper 因?yàn)樾枰l繁的創(chuàng)建和刪除節(jié)點(diǎn),性能上不如 Redis 方式。
在分布式場(chǎng)景下,一個(gè)用戶(hù)的 Session 如果只存儲(chǔ)在一個(gè)服務(wù)器上,那么當(dāng)負(fù)載均衡器把用戶(hù)的下一個(gè)請(qǐng)求轉(zhuǎn)發(fā)到另一個(gè)服務(wù)器上,該服務(wù)器沒(méi)有用戶(hù)的 Session,就可能導(dǎo)致用戶(hù)需要重新進(jìn)行登錄等操作。
分布式 Session 的幾種實(shí)現(xiàn)策略:
需要配置負(fù)載均衡器,使得一個(gè)用戶(hù)的所有請(qǐng)求都路由到一個(gè)服務(wù)器節(jié)點(diǎn)上,這樣就可以把用戶(hù)的 Session 存放在該服務(wù)器節(jié)點(diǎn)中。
缺點(diǎn):當(dāng)服務(wù)器節(jié)點(diǎn)宕機(jī)時(shí),將丟失該服務(wù)器節(jié)點(diǎn)上的所有 Session。
在服務(wù)器節(jié)點(diǎn)之間進(jìn)行 Session 同步操作,這樣的話(huà)用戶(hù)可以訪問(wèn)任何一個(gè)服務(wù)器節(jié)點(diǎn)。
缺點(diǎn):占用過(guò)多內(nèi)存;同步過(guò)程占用網(wǎng)絡(luò)帶寬以及服務(wù)器處理器時(shí)間。
使用一個(gè)單獨(dú)的服務(wù)器存儲(chǔ) Session 數(shù)據(jù),可以存在 MySQL 數(shù)據(jù)庫(kù)上,也可以存在 Redis 或者 Memcached 這種內(nèi)存型數(shù)據(jù)庫(kù)。
缺點(diǎn):需要去實(shí)現(xiàn)存取 Session 的代碼。
通常有兩種解決方案:
使用緩存的好處:
根據(jù)業(yè)務(wù)場(chǎng)景,通常緩存有以下幾種使用方式
緩存分類(lèi):
輪詢(xún)算法把每個(gè)請(qǐng)求輪流發(fā)送到每個(gè)服務(wù)器上。下圖中,一共有 6 個(gè)客戶(hù)端產(chǎn)生了 6 個(gè)請(qǐng)求,這 6 個(gè)請(qǐng)求按 (1, 2, 3, 4, 5, 6) 的順序發(fā)送。最后,(1, 3, 5) 的請(qǐng)求會(huì)被發(fā)送到服務(wù)器 1,(2, 4, 6) 的請(qǐng)求會(huì)被發(fā)送到服務(wù)器 2。
該算法比較適合每個(gè)服務(wù)器的性能差不多的場(chǎng)景,如果有性能存在差異的情況下,那么性能較差的服務(wù)器可能無(wú)法承擔(dān)過(guò)大的負(fù)載(下圖的 Server 2)。
加權(quán)輪詢(xún)是在輪詢(xún)的基礎(chǔ)上,根據(jù)服務(wù)器的性能差異,為服務(wù)器賦予一定的權(quán)值。例如下圖中,服務(wù)器 1 被賦予的權(quán)值為 5,服務(wù)器 2 被賦予的權(quán)值為 1,那么 (1, 2, 3, 4, 5) 請(qǐng)求會(huì)被發(fā)送到服務(wù)器 1,(6) 請(qǐng)求會(huì)被發(fā)送到服務(wù)器 2。
由于每個(gè)請(qǐng)求的連接時(shí)間不一樣,使用輪詢(xún)或者加權(quán)輪詢(xún)算法的話(huà),可能會(huì)讓一臺(tái)服務(wù)器當(dāng)前連接數(shù)過(guò)大,而另一臺(tái)服務(wù)器的連接過(guò)小,造成負(fù)載不均衡。例如下圖中,(1, 3, 5) 請(qǐng)求會(huì)被發(fā)送到服務(wù)器 1,但是 (1, 3) 很快就斷開(kāi)連接,此時(shí)只有 (5) 請(qǐng)求連接服務(wù)器 1;(2, 4, 6) 請(qǐng)求被發(fā)送到服務(wù)器 2,只有 (2) 的連接斷開(kāi)。該系統(tǒng)繼續(xù)運(yùn)行時(shí),服務(wù)器 2 會(huì)承擔(dān)過(guò)大的負(fù)載。
最少連接算法就是將請(qǐng)求發(fā)送給當(dāng)前最少連接數(shù)的服務(wù)器上。例如下圖中,服務(wù)器 1 當(dāng)前連接數(shù)最小,那么新到來(lái)的請(qǐng)求 6 就會(huì)被發(fā)送到服務(wù)器 1 上。
在最少連接的基礎(chǔ)上,根據(jù)服務(wù)器的性能為每臺(tái)服務(wù)器分配權(quán)重,再根據(jù)權(quán)重計(jì)算出每臺(tái)服務(wù)器能處理的連接數(shù)。
把請(qǐng)求隨機(jī)發(fā)送到服務(wù)器上。和輪詢(xún)算法類(lèi)似,該算法比較適合服務(wù)器性能差不多的場(chǎng)景。
源地址哈希通過(guò)對(duì)客戶(hù)端 IP 哈希計(jì)算得到的一個(gè)數(shù)值,用該數(shù)值對(duì)服務(wù)器數(shù)量進(jìn)行取模運(yùn)算,取模結(jié)果便是目標(biāo)服務(wù)器的序號(hào)。
HTTP 重定向負(fù)載均衡服務(wù)器收到 HTTP 請(qǐng)求之后會(huì)返回服務(wù)器的地址,并將該地址寫(xiě)入 HTTP 重定向響應(yīng)中返回給瀏覽器,瀏覽器收到后需要再次發(fā)送請(qǐng)求。
缺點(diǎn):
使用 DNS 作為負(fù)載均衡器,根據(jù)負(fù)載情況返回不同服務(wù)器的 IP 地址。大型網(wǎng)站基本使用了這種方式做為第一級(jí)負(fù)載均衡手段,然后在內(nèi)部使用其它方式做第二級(jí)負(fù)載均衡。
缺點(diǎn):
使用 LVS(Linux Virtual Server)這種鏈路層負(fù)載均衡器,根據(jù)負(fù)載情況修改請(qǐng)求的 MAC 地址。
在網(wǎng)絡(luò)層修改請(qǐng)求的目的 IP 地址。
正向代理與反向代理的區(qū)別:
PAC 服務(wù)器是用來(lái)判斷一個(gè)請(qǐng)求是否要經(jīng)過(guò)代理。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。