大战熟女丰满人妻av-荡女精品导航-岛国aaaa级午夜福利片-岛国av动作片在线观看-岛国av无码免费无禁网站-岛国大片激情做爰视频

面試題首頁(yè) > Java分布式面試題

Java分布式面試題

001什么是CAP理論?

CAP原理指的是,在分布式系統(tǒng)中這三個(gè)要素最多只能同時(shí)實(shí)現(xiàn)兩點(diǎn),不可能三者兼顧。因此在進(jìn)行分布式架構(gòu)設(shè)計(jì)時(shí),必須做出取舍。而對(duì)于分布式數(shù)據(jù)系統(tǒng),分區(qū)容忍性是基本要求,否則就失去了價(jià)值。因此設(shè)計(jì)分布式數(shù)據(jù)系統(tǒng),就是在一致性和可用性之間取一個(gè)平衡。對(duì)于大多數(shù)Web應(yīng)用,其實(shí)并不需要強(qiáng)一致性,因此犧牲一致性而換取高可用性,是目前多數(shù)分布式數(shù)據(jù)庫(kù)產(chǎn)品的方向。 
一致性(Consistency):數(shù)據(jù)在多個(gè)副本之間是否能夠保持一致的特性。(當(dāng)一個(gè)系統(tǒng)在一致狀態(tài)下更新后,應(yīng)保持系統(tǒng)中所有數(shù)據(jù)仍處于一致的狀態(tài))。 
可用性(Availability):系統(tǒng)提供的服務(wù)必須一直處于可用狀態(tài),對(duì)每一個(gè)操作的請(qǐng)求必須在有限時(shí)間內(nèi)返回結(jié)果。 
分區(qū)容錯(cuò)性(Tolerance of network Partition):分布式系統(tǒng)在遇到網(wǎng)絡(luò)分區(qū)故障時(shí),仍然需要保證對(duì)外提供一致性和可用性的服務(wù),除非整個(gè)網(wǎng)絡(luò)都發(fā)生故障。

002CAP理論中為什么只能同時(shí)滿足兩個(gè)?

例如,服務(wù)器中原本存儲(chǔ)的value=0,當(dāng)客戶端A修改value=1時(shí),為了保證數(shù)據(jù)的一致性,要寫到3個(gè)服務(wù)器中,當(dāng)服務(wù)器C故障時(shí),數(shù)據(jù)無法寫入服務(wù)器C,則導(dǎo)致了此時(shí)服務(wù)器A、B和C的value是不一致的。這時(shí)候要保證分區(qū)容錯(cuò)性,即當(dāng)服務(wù)器C故障時(shí),仍然能保持良好的一致性和可用性服務(wù),則Consistency和Availability不能同時(shí)滿足。為什么呢? 如果滿足了一致性,則客戶端A的寫操作value=1不能成功,這時(shí)服務(wù)器中所有value=0。如果滿足可用性,即所有客戶端都可以提交操作并得到返回的結(jié)果,則此時(shí)允許客戶端A寫入服務(wù)器A和B,客戶端C將得到未修改之前的value=0結(jié)果。

003什么是BASE理論?

1)Basically Available(基本可用)分布式系統(tǒng)在出現(xiàn)不可預(yù)知故障的時(shí)候,允許損失部分可用性 
2)Soft state(軟狀態(tài))軟狀態(tài)也稱為弱狀態(tài),和硬狀態(tài)相對(duì),是指允許系統(tǒng)中的數(shù)據(jù)存在中間狀態(tài),并認(rèn)為該中間狀態(tài)的存在不會(huì)影響系統(tǒng)的整體可用性,即允許系統(tǒng)在不同節(jié)點(diǎn)的數(shù)據(jù)副本之間進(jìn)行數(shù)據(jù)同步的過程存在延時(shí)。 
2)Eventually consistent(最終一致性)最終一致性強(qiáng)調(diào)的是系統(tǒng)中所有的數(shù)據(jù)副本,在經(jīng)過一段時(shí)間的同步后,最終能夠達(dá)到一個(gè)一致的狀態(tài)。因此,最終一致性的本質(zhì)是需要系統(tǒng)保證最終數(shù)據(jù)能夠達(dá)到一致,而不需要實(shí)時(shí)保證系統(tǒng)數(shù)據(jù)的強(qiáng)一致性。

004CAP 與 ACID 關(guān)系?

ACID 是傳統(tǒng)數(shù)據(jù)庫(kù)常用的設(shè)計(jì)理念,追求強(qiáng)一致性模型。BASE 支持的是大型分布式系統(tǒng),提出通過犧牲強(qiáng)一致性獲得高可用性。 ACID 和 BASE 代表了兩種截然相反的設(shè)計(jì)哲學(xué),在分布式系統(tǒng)設(shè)計(jì)的場(chǎng)景中,系統(tǒng)組件對(duì)一致性要求是不同的,因此 ACID 和 BASE 又會(huì)結(jié)合使用。

005什么是接口冪等?

接口的冪等性實(shí)際上就是接口可重復(fù)調(diào)用,在調(diào)用方多次調(diào)用的情況下,接口最終得到的結(jié)果是一致的。有些接口可以天然的實(shí)現(xiàn)冪等性,比如查詢接口,對(duì)于查詢來說,你查詢一次和兩次,對(duì)于系統(tǒng)來說,沒有任何影響,查出的結(jié)果也是一樣。除了查詢功能具有天然的冪等性之外,增加、更新、刪除都要保證冪等性。

006如何來保證冪等性呢?

1)全局唯一ID:全局唯一ID就是根據(jù)業(yè)務(wù)的操作和內(nèi)容生成一個(gè)全局ID,在執(zhí)行操作前先根據(jù)這個(gè)全局唯一ID是否存在,來判斷這個(gè)操作是否已經(jīng)執(zhí)行。如果不存在則把全局ID,存儲(chǔ)到存儲(chǔ)系統(tǒng)中,比如數(shù)據(jù)庫(kù)、redis等。如果存在則表示該方法已經(jīng)執(zhí)行。 從工程的角度來說,使用全局ID做冪等可以作為一個(gè)業(yè)務(wù)的基礎(chǔ)的微服務(wù)存在,在很多的微服務(wù)中都會(huì)用到這樣的服務(wù),在每個(gè)微服務(wù)中都完成這樣的功能,會(huì)存在工作量重復(fù)。另外打造一個(gè)高可靠的冪等服務(wù)還需要考慮很多問題,比如一臺(tái)機(jī)器雖然把全局ID先寫入了存儲(chǔ),但是在寫入之后掛了,這就需要引入全局ID的超時(shí)機(jī)制。 使用全局唯一ID是一個(gè)通用方案,可以支持插入、更新、刪除業(yè)務(wù)操作。但是這個(gè)方案看起來很美但是實(shí)現(xiàn)起來比較麻煩,下面的方案適用于特定的場(chǎng)景,但是實(shí)現(xiàn)起來比較簡(jiǎn)單。 
2)去重表:這種方法適用于在業(yè)務(wù)中有唯一標(biāo)的插入場(chǎng)景中,比如在以上的支付場(chǎng)景中,如果一個(gè)訂單只會(huì)支付一次,所以訂單ID可以作為唯一標(biāo)識(shí)。這時(shí),我們就可以建一張去重表,并且把唯一標(biāo)識(shí)作為唯一索引,在我們實(shí)現(xiàn)時(shí),把創(chuàng)建支付單據(jù)和寫入去去重表,放在一個(gè)事務(wù)中,如果重復(fù)創(chuàng)建,數(shù)據(jù)庫(kù)會(huì)拋出唯一約束異常,操作就會(huì)回滾。 
3)插入或更新:這種方法插入并且有唯一索引的情況,比如我們要關(guān)聯(lián)商品品類,其中商品的ID和品類的ID可以構(gòu)成唯一索引,并且在數(shù)據(jù)表中也增加了唯一索引。這時(shí)就可以使用InsertOrUpdate操作。在mysql數(shù)據(jù)庫(kù)中如下: 

insert into goods_category (goods_id,category_id,create_time,update_time)?
? ? ? ?values(#{goodsId},#{categoryId},now(),now())?
? ? ? ?on DUPLICATE KEY UPDATE
? ? ? ?update_time=now()

4)多版本控制:這種方法適合在更新的場(chǎng)景中,比如我們要更新商品的名字,這時(shí)我們就可以在更新的接口中增加一個(gè)版本號(hào),來做冪等 

boolean updateGoodsName(int id,String newName,int version);

在實(shí)現(xiàn)時(shí)可以如下 

update goods set name=#{newName},version=#{version} where id=#{id} and version<${version}

5)狀態(tài)機(jī)控制:這種方法適合在有狀態(tài)機(jī)流轉(zhuǎn)的情況下,比如就會(huì)訂單的創(chuàng)建和付款,訂單的付款肯定是在之前,這時(shí)我們可以通過在設(shè)計(jì)狀態(tài)字段時(shí),使用int類型,并且通過值類型的大小來做冪等。比如訂單的創(chuàng)建為0,付款成功為100,付款失敗為99 。
在做狀態(tài)機(jī)更新時(shí),我們就這可以這樣控制 

update `order` set status=#{status} where id=#{id} and status<#{status}

007什么是分布式事務(wù)?

分布式事務(wù)是指事務(wù)的參與者、支持事務(wù)的服務(wù)器、資源服務(wù)器以及事務(wù)管理器分別位于不同的分布式系統(tǒng)的不同節(jié)點(diǎn)之上。一個(gè)大的操作由 N 多的小的操作共同完成。而這些小的操作又分布在不同的服務(wù)上。針對(duì)于這些操作,要么全部成功執(zhí)行,要么全部不執(zhí)行。

008分布式id生成方案有哪些?

1.UUID:時(shí)間戳+時(shí)鐘序列(計(jì)數(shù)器)+唯一的IEEE機(jī)器識(shí)別碼(比如網(wǎng)卡的MAC地址) 。
缺點(diǎn):對(duì)數(shù)據(jù)庫(kù)不友好,因?yàn)殡S機(jī)不連續(xù)。
2.數(shù)據(jù)庫(kù)自增:對(duì)于數(shù)據(jù)庫(kù)集群模型,要設(shè)置不同的數(shù)據(jù)庫(kù)起始值不同,但是步長(zhǎng)(自增幾)相同。 
3.Leaf-segment:(美團(tuán)大眾點(diǎn)評(píng)的)采用每次獲取一個(gè)ID區(qū)間的方式。比如一次和數(shù)據(jù)庫(kù)的交互,就請(qǐng)求到100個(gè)id,數(shù)據(jù)來了直接用。避免每次添加數(shù)據(jù)都請(qǐng)求一個(gè)id,增加了數(shù)據(jù)庫(kù)的壓力。 也是對(duì)數(shù)據(jù)庫(kù)自增策略的一個(gè)優(yōu)化。
4.雪花算法:其核心思想是:41位時(shí)間戳+10位機(jī)器id+12位序列號(hào)+符號(hào)位(0)。結(jié)果是一個(gè)長(zhǎng)度為64bit的long型的ID。  
優(yōu)點(diǎn):12位序列號(hào)是說每個(gè)節(jié)點(diǎn)在每毫秒可以產(chǎn)生4096 個(gè)ID,并且是遞增的。 這樣適合于Mysql的聚集索引,索引的連續(xù)性也好。 
缺點(diǎn):依賴于時(shí)間戳,時(shí)間戳是根據(jù)機(jī)器的時(shí)間得到的。比如linux中,如果人為的進(jìn)行時(shí)鐘回?fù)埽涂赡茉斐蒳d重復(fù)。

009分布式架構(gòu)下,Session 共享有什么方案?

● 使用jwt
● 使用cookie (有安全風(fēng)險(xiǎn))
● 服務(wù)器之間進(jìn)行session同步:保證每個(gè)服務(wù)器都有session信息,消耗比較大。
● ip綁定策略:比如使用Ngnix進(jìn)行源地址哈希法的負(fù)載均衡,讓每一個(gè)ip固定訪問一個(gè)服務(wù)器, 但是這種就失去分布式的作用。
● 使用redis存儲(chǔ):是業(yè)界最廣泛的。 可實(shí)現(xiàn)不同服務(wù),不同平臺(tái)(網(wǎng)頁(yè)/app),甚至不同語(yǔ)言的session共享。

010有哪些方案實(shí)現(xiàn)分布式鎖?

1)基于數(shù)據(jù)庫(kù)做分布式鎖--樂觀鎖(基于版本號(hào))和悲觀鎖(基于排它鎖) 
2)基于redis做分布式鎖:setnx(key,當(dāng)前時(shí)間+過期時(shí)間)和Redlock機(jī)制 
3)基于zookeeper做分布式鎖:臨時(shí)有序節(jié)點(diǎn)來實(shí)現(xiàn)的分布式鎖,Curator 
4)基于 Consul 做分布式鎖 

011MySQL如何做分布式鎖?

基于數(shù)據(jù)庫(kù)(MySQL)的分布式鎖方案,一般分為3類:基于表記錄、樂觀鎖和悲觀鎖。

012基于表記錄的數(shù)據(jù)庫(kù)鎖的原理。

該方法是最簡(jiǎn)單的,就是直接創(chuàng)建一張鎖表。當(dāng)我們想要獲得鎖的時(shí)候,就可以在該鎖表中增加一條記錄,想要釋放鎖的時(shí)候就刪除鎖表的這條記錄。
總結(jié):
1.這種鎖沒有失效時(shí)間,一旦釋放鎖操作失敗就會(huì)導(dǎo)致鎖記錄一直在數(shù)據(jù)庫(kù)中,其它線程無法獲得鎖。這個(gè)缺陷也很好解決,比如可以做一個(gè)定時(shí)任務(wù)去定時(shí)清理。
2.這種鎖的可靠性依賴于數(shù)據(jù)庫(kù)。建議設(shè)置備庫(kù),避免單點(diǎn),進(jìn)一步提高可靠性。
3.這種鎖是非阻塞的。因?yàn)椴迦霐?shù)據(jù)失敗之后會(huì)直接報(bào)錯(cuò),想要獲得鎖就需要再次操作。如果需要阻塞式的,可以弄個(gè)for循環(huán)、while循環(huán)之類的,直至INSERT成功再返回。
4.這種鎖是非可重入的。因?yàn)閿?shù)據(jù)庫(kù)中鎖表的一份記錄就是一把鎖,想要實(shí)現(xiàn)可重入鎖,可以在數(shù)據(jù)庫(kù)中添加一些字段,比如獲得鎖的主機(jī)信息、線程信息等,那么在再次獲得鎖的時(shí)候可以先查詢數(shù)據(jù),如果當(dāng)前的主機(jī)信息和線程信息等能被查到的話,可以直接把鎖分配給它。

013分布式中樂觀鎖的原理。

樂觀鎖大多數(shù)是基于數(shù)據(jù)版本(version)的記錄機(jī)制實(shí)現(xiàn)的。通過對(duì)數(shù)據(jù)庫(kù)表添加一個(gè) “version”字段來實(shí)現(xiàn)的。讀數(shù)據(jù)時(shí)會(huì)將此版本號(hào)一同讀出,之后更新數(shù)據(jù)時(shí)會(huì)對(duì)此版本號(hào)加1。在更新過程中,會(huì)對(duì)版本號(hào)進(jìn)行比較,如果是一致的,沒有發(fā)生改變,則會(huì)成功執(zhí)行更新操作;如果版本號(hào)不一致,則執(zhí)行不會(huì)更新。
當(dāng)然借助更新時(shí)間戳(updated_at)也可以實(shí)現(xiàn)樂觀鎖,和采用version字段的方式相似:更新操作執(zhí)行前先記錄當(dāng)前的更新時(shí)間,在提交更新時(shí),檢測(cè)當(dāng)前更新時(shí)間是否與更新開始時(shí)獲取的更新時(shí)間戳相等。

014樂觀鎖的優(yōu)點(diǎn)和缺點(diǎn)?

樂觀鎖的優(yōu)點(diǎn):由于在檢測(cè)數(shù)據(jù)沖突時(shí)并不依賴數(shù)據(jù)庫(kù)本身的鎖機(jī)制,不會(huì)影響請(qǐng)求的性能,當(dāng)產(chǎn)生并發(fā)且并發(fā)量較小的時(shí)候只有少部分請(qǐng)求會(huì)失敗。
樂觀鎖的缺點(diǎn):需要對(duì)表的設(shè)計(jì)增加額外的字段,增加了數(shù)據(jù)庫(kù)的冗余。另外,當(dāng)應(yīng)用并發(fā)量高的時(shí)候,version值在頻繁變化,會(huì)對(duì)數(shù)據(jù)庫(kù)產(chǎn)生很大的寫壓力。并且也會(huì)導(dǎo)致大量請(qǐng)求失敗,影響系統(tǒng)的可用性。所以數(shù)據(jù)庫(kù)樂觀鎖比較適合并發(fā)量不高,并且寫操作不頻繁的場(chǎng)景。

015悲觀鎖的實(shí)現(xiàn)原理。

悲觀鎖是數(shù)據(jù)庫(kù)中自帶的。在查詢語(yǔ)句后面增加FOR UPDATE,數(shù)據(jù)庫(kù)會(huì)在查詢過程中給數(shù)據(jù)庫(kù)表增加悲觀鎖,也稱排他鎖。悲觀鎖就會(huì)比較悲觀,總是假設(shè)最壞的情況,它認(rèn)為數(shù)據(jù)的更新在大多數(shù)情況下是會(huì)產(chǎn)生沖突的。
在使用悲觀鎖的同時(shí),我們需要注意一下鎖的級(jí)別。MySQL InnoDB在加鎖的時(shí)候,只有明確地指定主鍵(或索引)的才會(huì)執(zhí)行行鎖 (只鎖住被選取的數(shù)據(jù)),否則將會(huì)執(zhí)行表鎖(將整個(gè)數(shù)據(jù)表單給鎖住)。
在使用悲觀鎖時(shí),我們必須關(guān)閉MySQL數(shù)據(jù)庫(kù)的自動(dòng)提交屬性(參考下面的示例),因?yàn)镸ySQL默認(rèn)使用autocommit(自動(dòng)提交)模式。這樣在使用FOR UPDATE獲得鎖之后可以執(zhí)行相應(yīng)的業(yè)務(wù)邏輯,執(zhí)行完之后再使用COMMIT來釋放鎖。

016悲觀鎖的優(yōu)點(diǎn)和缺點(diǎn)?

悲觀鎖優(yōu)點(diǎn):可以嚴(yán)格保證數(shù)據(jù)訪問的安全。
悲觀鎖缺點(diǎn):即每次請(qǐng)求都會(huì)額外產(chǎn)生加鎖的開銷且未獲取到鎖的請(qǐng)求將會(huì)阻塞等待鎖的獲取,在高并發(fā)環(huán)境下,容易造成大量請(qǐng)求阻塞,影響系統(tǒng)可用性。另外,悲觀鎖使用不當(dāng)還可能產(chǎn)生死鎖的情況。

017基于 ZooKeeper 的分布式鎖實(shí)現(xiàn)原理是什么?

ZooKeeper是一個(gè)分布式的,開放源碼的分布式應(yīng)用程序協(xié)調(diào)服務(wù),Zookeeper在本質(zhì)上就像一個(gè)文件管理系統(tǒng)。其用類似文件路徑的方式管理來監(jiān)聽多個(gè)節(jié)點(diǎn)(Znode),同時(shí)判斷當(dāng)前每個(gè)節(jié)點(diǎn)上機(jī)器的狀態(tài)(是否宕機(jī)、是否斷開連接等),從而達(dá)到分布式協(xié)同的操作。
ZooKeeper 可以根據(jù)有序節(jié)點(diǎn)+watch實(shí)現(xiàn),實(shí)現(xiàn)思路,如:為每個(gè)線程生成一個(gè)有序的臨時(shí)節(jié)點(diǎn),為確保有序性,在排序一次全部節(jié)點(diǎn),獲取全部節(jié)點(diǎn),每個(gè)線程判斷自己是否最小,如果是的話,獲得鎖,執(zhí)行操作,操作完刪除自身節(jié)點(diǎn)。如果不是第一個(gè)的節(jié)點(diǎn)則監(jiān)聽它的前一個(gè)節(jié)點(diǎn),當(dāng)它的前一個(gè)節(jié)點(diǎn)被刪除時(shí),則它會(huì)獲得鎖,以此類推。

018ZooKeeper和Reids做分布式鎖的區(qū)別?

1. Redis分布式鎖需要不斷去嘗試獲取鎖,比較消耗性能。而ZooKeeper分布式鎖,獲取不到鎖會(huì)注冊(cè)個(gè)監(jiān)聽器,不需要不斷主動(dòng)嘗試獲取鎖因此性能開銷較小;
2. 如果是Redis獲取鎖的那個(gè)客戶端bug了或者掛了,那么只能等待超時(shí)時(shí)間之后才能釋放鎖;而ZooKeeper的話,因?yàn)閯?chuàng)建的是臨時(shí)znode,只要客戶端掛了,znode就沒了,此時(shí)就自動(dòng)釋放鎖;

019Redis分布式鎖之SETNX + EXPIRE

SETNX 是SET IF NOT EXISTS的簡(jiǎn)寫.日常命令格式是SETNX key value,如果 key不存在,則SETNX成功返回1,如果這個(gè)key已經(jīng)存在了,則返回0。
偽代碼實(shí)現(xiàn)如下:假設(shè)某電商網(wǎng)站的某商品做秒殺活動(dòng),key可以設(shè)置為key_resource_id,value設(shè)置任意值

if(jedis.setnx(key_resource_id,lock_value) == 1){ //加鎖 ? ??
? ? expire(key_resource_id,100);//設(shè)置過期時(shí)間 ? ??
? ? try { ? ? ? ??
? ? ? ? do something ?//業(yè)務(wù)請(qǐng)求 ? ??
? ? }catch(){ ??
? ? }finally { ? ? ? ?
? ? ? ? jedis.del(key_resource_id); //釋放鎖 ? ??
? ? }
}

缺點(diǎn):setnx和expire兩個(gè)命令分開了,不是原子操作。如果執(zhí)行完setnx加鎖,正要執(zhí)行expire設(shè)置過期時(shí)間時(shí),進(jìn)程crash或者要重啟維護(hù)了,那么這個(gè)鎖就永遠(yuǎn)釋放不了,別的線程永遠(yuǎn)獲取不到鎖啦。

020Redis分布式鎖之SETNX + (系統(tǒng)時(shí)間+過期時(shí)間)

為了解決發(fā)生異常鎖得不到釋放的場(chǎng)景,可以把過期時(shí)間放到setnx的value值里面。如果加鎖失敗,再拿出value值校驗(yàn)一下即可。加鎖代碼如下:

long expires = System.currentTimeMillis() + expireTime; //系統(tǒng)時(shí)間+設(shè)置的過期時(shí)間
String expiresStr = String.valueOf(expires);
// 如果當(dāng)前鎖不存在,返回加鎖成功
if (jedis.setnx(key_resource_id, expiresStr) == 1) {
        return true;
} 
// 如果鎖已經(jīng)存在,獲取鎖的過期時(shí)間
String currentValueStr = jedis.get(key_resource_id);

// 如果獲取到的過期時(shí)間,小于系統(tǒng)當(dāng)前時(shí)間,表示已經(jīng)過期
if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) {
     // 鎖已過期,獲取上一個(gè)鎖的過期時(shí)間,并設(shè)置現(xiàn)在鎖的過期時(shí)間(不了解redis的getSet命令的小伙伴,可以去官網(wǎng)看下哈)
    String oldValueStr = jedis.getSet(key_resource_id, expiresStr);
    if (oldValueStr != null && oldValueStr.equals(currentValueStr)) {
         // 考慮多線程并發(fā)的情況,只有一個(gè)線程的設(shè)置值和當(dāng)前值相同,它才可以加鎖
         return true;
    }
}     
//其他情況,均返回加鎖失敗
return false;
}

缺點(diǎn):
1.過期時(shí)間是客戶端自己生成的(System.currentTimeMillis()是當(dāng)前系統(tǒng)的時(shí)間),必須要求分布式環(huán)境下,每個(gè)客戶端的時(shí)間必須同步。
2.如果鎖過期的時(shí)候,并發(fā)多個(gè)客戶端同時(shí)請(qǐng)求過來,都執(zhí)行jedis.getSet(),最終只能有一個(gè)客戶端加鎖成功,因此某個(gè)客戶端加的鎖可能被別的客戶端所覆蓋。
3.該鎖沒有保存持有者的唯一標(biāo)識(shí),可能被別的客戶端釋放/解鎖。

021Redis分布式鎖之SET擴(kuò)展命令。

SET key value[EX seconds][PX milliseconds][NX|XX]
● EX seconds :設(shè)定key的過期時(shí)間,時(shí)間單位是秒。
● PX milliseconds: 設(shè)定key的過期時(shí)間,單位為毫秒。
● NX :表示key不存在的時(shí)候,才能set成功,也即保證只有第一個(gè)客戶端請(qǐng)求才能獲得鎖,而其他客戶端請(qǐng)求只能等其釋放鎖,才能獲取。
● XX: 僅當(dāng)key存在時(shí)設(shè)置值;

if(jedis.set(key_resource_id,lock_value,"NX","EX",100s)==1){//加鎖  
    try{ 
        dosomething  
        //業(yè)務(wù)處理     
    }catch(){   
    }finally {        
        jedis.del(key_resource_id); //釋放鎖     
    } 
}

缺點(diǎn):
問題一:鎖過期釋放了,業(yè)務(wù)還沒執(zhí)行完。假設(shè)線程a獲取鎖成功,一直在執(zhí)行臨界區(qū)的代碼。但是100s過去后,它還沒執(zhí)行完。但是,這時(shí)候鎖已經(jīng)過期了,此時(shí)線程b又請(qǐng)求過來。顯然線程b就可以獲得鎖成功,也開始執(zhí)行臨界區(qū)的代碼。那么問題就來了,臨界區(qū)的業(yè)務(wù)代碼都不是嚴(yán)格串行執(zhí)行的啦。
問題二:鎖被別的線程誤刪。假設(shè)線程a執(zhí)行完后,去釋放鎖。但是它不知道當(dāng)前的鎖可能是線程b持有的(線程a去釋放鎖時(shí),有可能過期時(shí)間已經(jīng)到了,此時(shí)線程b進(jìn)來占有了鎖)。那線程a就把線程b的鎖釋放掉了,但是線程b臨界區(qū)業(yè)務(wù)代碼可能都還沒執(zhí)行完呢。

022Redis分布式鎖之SET EX PX NX + 校驗(yàn)唯一隨機(jī)值,再刪除。

既然鎖可能被別的線程誤刪,那我們給value值設(shè)置一個(gè)標(biāo)記當(dāng)前線程唯一的隨機(jī)數(shù),在刪除的時(shí)候,校驗(yàn)一下:

if(jedis.set(key_resource_id,uni_request_id,"NX","EX",100s)==1){ 
    //加鎖     
    try {         
        do something  //業(yè)務(wù)處理     
    }catch(){   
    }finally {        
        //判斷是不是當(dāng)前線程加的鎖,是才釋放        
        if (uni_request_id.equals(jedis.get(key_resource_id))) {         
            jedis.del(lockKey); //釋放鎖         
        }     
    } 
}

023Redis分布式鎖之Redisson框架

方案四中還是可能存在鎖過期釋放,業(yè)務(wù)沒執(zhí)行完的問題。開源框架Redisson解決了這個(gè)問題。先來看下Redisson底層原理圖:

只要線程一加鎖成功,就會(huì)啟動(dòng)一個(gè)watch dog看門狗,它是一個(gè)后臺(tái)線程,會(huì)每隔10秒檢查一下,如果線程1還持有鎖,那么就會(huì)不斷的延長(zhǎng)鎖key的生存時(shí)間。因此Redisson解決了鎖過期釋放,業(yè)務(wù)沒執(zhí)行完問題。

024Redis多機(jī)版分布式鎖之Redlock+Redisson

前面五種方案都是基于單機(jī)版的,其實(shí)Redis一般都是集群部署的。為了解決這個(gè)問題,Redis作者 antirez提出一種高級(jí)的分布式鎖算法:Redlock。

025什么是分布式的XA協(xié)議?

XA協(xié)議是一個(gè)基于數(shù)據(jù)庫(kù)的分布式事務(wù)協(xié)議,其分為兩部分:事務(wù)管理器和本地資源管理器。事務(wù)管理器作為一個(gè)全局的調(diào)度者,負(fù)責(zé)對(duì)各個(gè)本地資源管理器統(tǒng)一號(hào)令提交或者回滾。二階提交協(xié)議(2PC)和三階提交協(xié)議(3PC)就是根據(jù)此協(xié)議衍生出來而來。主流的諸如Oracle、MySQL等數(shù)據(jù)庫(kù)均已實(shí)現(xiàn)了XA接口。 XA接口是雙向的系統(tǒng)接口,在事務(wù)管理器(Transaction Manager)以及一個(gè)或多個(gè)資源管理器(Resource Manager)之間形成通信橋梁。也就是說,在基于XA的一個(gè)事務(wù)中,我們可以針對(duì)多個(gè)資源進(jìn)行事務(wù)管理,例如一個(gè)系統(tǒng)訪問多個(gè)數(shù)據(jù)庫(kù),或即訪問數(shù)據(jù)庫(kù)、又訪問像消息中間件這樣的資源。這樣我們就能夠?qū)崿F(xiàn)在多個(gè)數(shù)據(jù)庫(kù)和消息中間件直接實(shí)現(xiàn)全部提交、或全部取消的事務(wù)。XA規(guī)范不是java的規(guī)范,而是一種通用的規(guī)范。

026什么是2PC?

兩段提交顧名思義就是要進(jìn)行兩個(gè)階段的提交:
第一階段,準(zhǔn)備階段(投票階段);
第二階段,提交階段(執(zhí)行階段);

027兩段提交(2PC)的缺點(diǎn)?

二階段提交看似能夠提供原子性的操作,但它存在著嚴(yán)重的缺陷: 
1)網(wǎng)絡(luò)抖動(dòng)導(dǎo)致的數(shù)據(jù)不一致:第二階段中協(xié)調(diào)者向參與者發(fā)送commit命令之后,一旦此時(shí)發(fā)生網(wǎng)絡(luò)抖動(dòng),導(dǎo)致一部分參與者接收到了commit請(qǐng)求并執(zhí)行,可其他未接到commit請(qǐng)求的參與者無法執(zhí)行事務(wù)提交。進(jìn)而導(dǎo)致整個(gè)分布式系統(tǒng)出現(xiàn)了數(shù)據(jù)不一致。 
2)超時(shí)導(dǎo)致的同步阻塞問題:2PC中的所有的參與者節(jié)點(diǎn)都為事務(wù)阻塞型,當(dāng)某一個(gè)參與者節(jié)點(diǎn)出現(xiàn)通信超時(shí),其余參與者都會(huì)被動(dòng)阻塞占用資源不能釋放。 3)單點(diǎn)故障的風(fēng)險(xiǎn):由于嚴(yán)重的依賴協(xié)調(diào)者,一旦協(xié)調(diào)者發(fā)生故障,而此時(shí)參與者還都處于鎖定資源的狀態(tài),無法完成事務(wù)commit操作。雖然協(xié)調(diào)者出現(xiàn)故障后,會(huì)重新選舉一個(gè)協(xié)調(diào)者,可無法解決因前一個(gè)協(xié)調(diào)者宕機(jī)導(dǎo)致的參與者處于阻塞狀態(tài)的問題。 

028什么是3PC?

三段提交(3PC)是對(duì)兩段提交(2PC)的一種升級(jí)優(yōu)化,3PC在2PC的第一階段和第二階段中插入一個(gè)準(zhǔn)備階段。保證了在最后提交階段之前,各參與者節(jié)點(diǎn)的狀態(tài)都一致。同時(shí)在協(xié)調(diào)者和參與者中都引入超時(shí)機(jī)制,當(dāng)參與者各種原因未收到協(xié)調(diào)者的commit請(qǐng)求后,會(huì)對(duì)本地事務(wù)進(jìn)行commit,不會(huì)一直阻塞等待,解決了2PC的單點(diǎn)故障問題,但3PC還是沒能從根本上解決數(shù)據(jù)一致性的問題。

3PC的三個(gè)階段分別是CanCommit、PreCommit、DoCommit: CanCommit:協(xié)調(diào)者向所有參與者發(fā)送CanCommit命令,詢問是否可以執(zhí)行事務(wù)提交操作。如果全部響應(yīng)YES則進(jìn)入下一個(gè)階段。 PreCommit:協(xié)調(diào)者向所有參與者發(fā)送PreCommit命令,詢問是否可以進(jìn)行事務(wù)的預(yù)提交操作,參與者接收到PreCommit請(qǐng)求后,如參與者成功的執(zhí)行了事務(wù)操作,則返回Yes響應(yīng),進(jìn)入最終commit階段。一旦參與者中有向協(xié)調(diào)者發(fā)送了No響應(yīng),或因網(wǎng)絡(luò)造成超時(shí),協(xié)調(diào)者沒有接到參與者的響應(yīng),協(xié)調(diào)者向所有參與者發(fā)送abort請(qǐng)求,參與者接受abort命令執(zhí)行事務(wù)的中斷。 DoCommit:在前兩個(gè)階段中所有參與者的響應(yīng)反饋均是YES后,協(xié)調(diào)者向參與者發(fā)送DoCommit命令正式提交事務(wù),如協(xié)調(diào)者沒有接收到參與者發(fā)送的ACK響應(yīng),會(huì)向所有參與者發(fā)送abort請(qǐng)求命令,執(zhí)行事務(wù)的中斷。

029什么是TCC?

TCC(Try-Confirm-Cancel)又被稱補(bǔ)償事務(wù),TCC與2PC的思想很相似,事務(wù)處理流程也很相似,但2PC是應(yīng)用于在DB層面,TCC則可以理解為在應(yīng)用層面的2PC,是需要我們編寫業(yè)務(wù)邏輯來實(shí)現(xiàn)。 TCC它的核心思想是:"針對(duì)每個(gè)操作都要注冊(cè)一個(gè)與其對(duì)應(yīng)的確認(rèn)(Try)和補(bǔ)償(Cancel)"。 還拿下單扣庫(kù)存解釋下它的三個(gè)操作: 
Try階段:下單時(shí)通過Try操作去扣除庫(kù)存預(yù)留資源。 
Confirm階段:確認(rèn)執(zhí)行業(yè)務(wù)操作,在只預(yù)留的資源基礎(chǔ)上,發(fā)起購(gòu)買請(qǐng)求。 
Cancel階段:只要涉及到的相關(guān)業(yè)務(wù)中,有一個(gè)業(yè)務(wù)方預(yù)留資源未成功,則取消所有業(yè)務(wù)資源的預(yù)留請(qǐng)求。

030TCC 事務(wù)機(jī)制相比于 2PC,解決了其幾個(gè)缺點(diǎn)?

1)解決了協(xié)調(diào)者單點(diǎn),由主業(yè)務(wù)方發(fā)起并完成這個(gè)業(yè)務(wù)活動(dòng)。業(yè)務(wù)活動(dòng)管理器也變成多點(diǎn),引入集群。
2)同步阻塞:引入超時(shí),超時(shí)后進(jìn)行補(bǔ)償,并且不會(huì)鎖定整個(gè)資源,將資源轉(zhuǎn)換為業(yè)務(wù)邏輯形式,粒度變小。
3)數(shù)據(jù)一致性,有了補(bǔ)償機(jī)制之后,由業(yè)務(wù)活動(dòng)管理器控制一致性。
總之,TCC 就是通過代碼人為實(shí)現(xiàn)了兩階段提交,不同的業(yè)務(wù)場(chǎng)景所寫的代碼都不一樣,并且很大程度的增加了業(yè)務(wù)代碼的復(fù)雜度。因此,這種模式并不能很好地被復(fù)用。

031TCC的缺點(diǎn)?

應(yīng)用侵入性強(qiáng):TCC由于基于在業(yè)務(wù)層面,至使每個(gè)操作都需要有try、confirm、cancel三個(gè)接口。
開發(fā)難度大:代碼開發(fā)量很大,要保證數(shù)據(jù)一致性confirm和cancel接口還必須實(shí)現(xiàn)冪等性。

目錄

返回頂部
主站蜘蛛池模板: 米奇精品一区二区三区在线观看 | 日本精品视频一视频高清 | 青青久久国产成人免费网站 | 成人综合久久精品色婷婷 | 亚洲xoxo | 欧美三级午夜理伦三级小说 | 成人香蕉| 日本不卡不码高清免费观看 | 国内色视频 | 久久日本经典片免费看 | 欧美在线观看视频网站 | 久久在线播放 | 亚洲天堂不卡 | 日本一级在线观看视频播放 | 日韩久久精品视频 | 国产高清不卡一区二区三区 | 久久一| 亚洲综合一 | 国产成人做受免费视频 | 在线观看日本人免费视频色 | 奇米在线免费视频 | 美女啪啪免费网站 | 亚洲一级片免费 | 狠狠操天天操夜夜操 | 国产欧美曰韩一区二区三区 | 精品欧美一区二区三区 | 精品乱人伦一区二区 | 波多野结衣视频一区二区 | 综合精品视频 | 国产香蕉一区二区在线网站 | 国产伦精品一区二区免费 | 亚洲五月综合网色九月色 | 亚洲国产激情 | 成人免费视频在线 | 五月天久久综合 | 欧美成人h精品网站 | www.日日日| 男女超爽视频免费播放在线观看 | 国产精品久久久久久久久夜色 | 日本sese | 国产成人毛片精品不卡在线 |