按照自己的理解寫口水子話,有錯(cuò)請(qǐng)指正。
場(chǎng)景一
現(xiàn)在數(shù)據(jù)庫(kù)的一張表有一條數(shù)據(jù),里面有個(gè)字段istrue=true,假設(shè)用來(lái)判斷是否給作者1個(gè)億(=true就給)?,F(xiàn)在有倆個(gè)公司(為服務(wù)器)。他們從數(shù)據(jù)庫(kù)拿出這條數(shù)據(jù),然后根據(jù)istrue來(lái)判斷給我一個(gè)億。給我錢后,把istrue設(shè)置為false,以后拿出來(lái)再判斷的時(shí)候就不會(huì)給錢了。但是現(xiàn)在一個(gè)公司去請(qǐng)求這條數(shù)據(jù),發(fā)現(xiàn)為true,就準(zhǔn)備給我錢,此時(shí)另一家公司也去拿到了這條數(shù)據(jù),因?yàn)槲液颓耙患夜具€在交易數(shù)錢,還沒(méi)有成功所以不會(huì)修改數(shù)據(jù)庫(kù)這條數(shù)據(jù)的狀態(tài),導(dǎo)致后面來(lái)的這家公司拿到的istrue也是等于true.所以這家公司也需要給我一個(gè)億,這樣我就拿到了2個(gè)億,公司就不干了啊,所以需要一個(gè)鎖。
場(chǎng)景二
現(xiàn)在為了防止上面的情況,倆個(gè)公司決定加一個(gè)鎖,但是這個(gè)鎖必須要有一些特性。第一原子性:簡(jiǎn)單理解就是如果倆個(gè)公司一起加鎖,必須保證只能有一個(gè)公司加鎖成功,不然倆個(gè)公司都成功了,他們都以為自己是拿到鎖的那個(gè)人,最后還是要給我2個(gè)億。第二過(guò)期時(shí)間:本來(lái)的邏輯是得到鎖的公司,再把錢給了我,把數(shù)據(jù)庫(kù)的istrue的狀態(tài)修改了,然后釋放鎖,但是不正常的邏輯就是這家公司上鎖了,但是中途掛了,發(fā)現(xiàn)拿不出1個(gè)億跑路了,帶著鎖的鑰匙跑路了,另一家公司本來(lái)有1個(gè)億,但是沒(méi)鑰匙,一直卡在外面,我就拿不到一分錢,所以我就不干了啊。所以必須給這個(gè)鎖加一個(gè)過(guò)期時(shí)間,你半小時(shí)還沒(méi)給我轉(zhuǎn)賬打錢,我就把這個(gè)鎖撬了,讓他失效。這時(shí)候,神器出現(xiàn)了,Redis.它具有原子性:?jiǎn)我坏木€程,內(nèi)部串行執(zhí)行,加鎖的時(shí)候還可以設(shè)置過(guò)期時(shí)間。有人會(huì)問(wèn)了:萬(wàn)一我加鎖成功,但是設(shè)置過(guò)期時(shí)間的時(shí)候掛了怎么辦,還不是最后拿不到錢。不用擔(dān)心,Redis的命令setnx幫助我們解決,它加鎖設(shè)置過(guò)期時(shí)間一起的具有原子性,要不都成功,要不都失敗。不會(huì)有第三種情況。
場(chǎng)景三
上面有了神器,但是我們知道Redis一般是集群(保證Redis的高可用,提高Redis的讀寫性能),怎么理解呢?假設(shè)現(xiàn)在是3臺(tái)redis組成的集群。
然后現(xiàn)在來(lái)個(gè)一個(gè)請(qǐng)求(帶著一個(gè)key為“簡(jiǎn)書”),需要redis集群你把這個(gè)“簡(jiǎn)書”資源給我鎖上,然后Redis按照請(qǐng)求的要求給你鎖上,并存在了3臺(tái)redis中的一臺(tái)?,F(xiàn)在來(lái)了另外一個(gè)請(qǐng)求,它也帶著(一個(gè)key為“簡(jiǎn)書”),它也要求Redis集群給我鎖上,可是會(huì)出現(xiàn)一個(gè)問(wèn)題,就是Redis在判斷這個(gè)名為“簡(jiǎn)書”的資源是否有加鎖的時(shí)候,它剛好沒(méi)去存了key的那臺(tái)機(jī)器上判斷,就導(dǎo)致了誤判。這時(shí)候前面的加鎖就毫無(wú)意義了呀。所以我們就需要相同的key值必須命中同一臺(tái)redis,(前提是這臺(tái)Redis沒(méi)有掛掉)。所以就有了Hash一致性算法這個(gè)算法我們另外寫學(xué)習(xí),假設(shè)現(xiàn)在我們有了這個(gè)功能了,相同的key會(huì)命中同一臺(tái)機(jī)器。這樣我們就解決了Redis是集群的問(wèn)題。
場(chǎng)景四
上面的場(chǎng)景已經(jīng)差不多了,但是還有毛病,人人都是掛掉的時(shí)候,機(jī)器也不例外啊,現(xiàn)在同樣來(lái)了一個(gè)請(qǐng)求(帶著一個(gè)key為“簡(jiǎn)書”),Redis加了這個(gè)鎖,然后告訴這個(gè)請(qǐng)求方,我加鎖成功了,你可以打錢了,請(qǐng)求方收到后就準(zhǔn)備給我打錢了,但是很不巧,Redis剛好成功告訴可以打錢了,然后就掛掉了。現(xiàn)在來(lái)個(gè)另一家公司的另外一個(gè)請(qǐng)求(帶著一個(gè)key為“簡(jiǎn)書”),本來(lái)是命中那個(gè)掛掉的機(jī)器,但是它掛了,所以,為了高可用,Redis集群肯定有應(yīng)急方案的(也就是一致性Hash算法的容錯(cuò)性和可擴(kuò)展性),暫時(shí)后面學(xué)習(xí),Redis就會(huì)把這個(gè)key存在另外的機(jī)器上,這就導(dǎo)致了原本加鎖的意義也沒(méi)有了,最后還是給我打了2個(gè)億。這時(shí)候不要慌,這種情況redis作者給我們考慮了,提出了RedLock紅鎖的算法,在redisson中也對(duì)紅鎖進(jìn)行了實(shí)現(xiàn)。會(huì)用redisson就行
redisson使用手冊(cè):[點(diǎn)我跳轉(zhuǎn)下載]https://cloud.189.cn/t/VveuuiAJBf2y (訪問(wèn)碼:uq2t)
redlock算法大概是這樣的:
客戶端需要進(jìn)行的操作:
1、獲取當(dāng)前時(shí)間(單位是毫秒)。
2、輪流用相同的key和隨機(jī)值在N個(gè)節(jié)點(diǎn)上請(qǐng)求鎖,在這一步里,客戶端在每個(gè)master上請(qǐng)求鎖時(shí),會(huì)有一個(gè)和總的鎖釋放時(shí)間相比小的多的超時(shí)時(shí)間。比如如果鎖自動(dòng)釋放時(shí)間是10秒鐘,那每個(gè)節(jié)點(diǎn)鎖請(qǐng)求的超時(shí)時(shí)間可能是5-50毫秒的范圍,這個(gè)可以防止一個(gè)客戶端在某個(gè)宕掉的master節(jié)點(diǎn)上阻塞過(guò)長(zhǎng)時(shí)間,如果一個(gè)master節(jié)點(diǎn)不可用了,我們應(yīng)該盡快嘗試下一個(gè)master節(jié)點(diǎn)。
3、客戶端計(jì)算第二步中獲取鎖所花的時(shí)間,只有當(dāng)客戶端在大多數(shù)master節(jié)點(diǎn)上成功獲取了鎖(在這里是3個(gè)),而且總共消耗的時(shí)間不超過(guò)鎖釋放時(shí)間,這個(gè)鎖就認(rèn)為是獲取成功了。
4、如果鎖獲取成功了,那現(xiàn)在鎖自動(dòng)釋放時(shí)間就是最初的鎖釋放時(shí)間減去之前獲取鎖所消耗的時(shí)間。
5、如果鎖獲取失敗了,不管是因?yàn)楂@取成功的鎖不超過(guò)一半(N/2+1)還是因?yàn)榭傁臅r(shí)間超過(guò)了鎖釋放時(shí)間,客戶端都會(huì)到每個(gè)master節(jié)點(diǎn)上釋放鎖,即便是那些他認(rèn)為沒(méi)有獲取成功的鎖。