天天看點

一天五道Java面試題----第十一天(分布式架構下,Session共享有什麼方案--------->分布式事務解決方案)

這裡是參考B站上的大佬做的面試題筆記。大家也可以去看視訊講解!!!

文章目錄

  • ​​1、分布式架構下,Session共享有什麼方案​​
  • ​​2、簡述你對RPC、RMI的了解​​
  • ​​3、分布式id生成方案​​
  • ​​4、分布式鎖解決方案​​
  • ​​5、分布式事務解決方案​​

1、分布式架構下,Session共享有什麼方案

1、采用無服務狀态,抛棄session

2、存入cookie(有安全風險)

3、伺服器之間進行session同步,這樣可以保證每個伺服器上都有全部的session資訊,不過當伺服器數量比較多的時候,同步是會有延遲甚至同步失敗;

4、IP綁定政策

使用Nginx(或其他複雜負載均衡硬體)中的IP綁定政策,同一個IP隻能在指定的同一個機器通路,但是這樣做失去了負載均衡的意義,當挂掉一台伺服器的時候,會影響一批使用者的使用,風險很大;

5、使用Redis存儲

把Session放到Redis中存儲,雖然架構上變得複雜,并且通路需要多通路一次Redis,但是這種方案帶來的好處也是很大的:

  • 實作了session共享
  • 可以水準擴充(增加Redis伺服器)
  • 伺服器重新開機Session不丢失(不過也要注意Session在Redis中的重新整理/失效機制);
  • 不僅可以跨伺服器Session共享,甚至可以跨平台(例如網頁端和APP端)

2、簡述你對RPC、RMI的了解

RPC:在本地調用遠端的函數,遠端過程調用,可以跨語言實作, httpClient

RMI:遠端方法調用,java中用于實作RPC的一種機制,RPC的java版本,是J2EE的網路調用機制,跨JVM調用對象的方法,面向對象的思維方式

直接或間接實作接口 java.rmi.Remove 成為存在于服務端的遠端對象,供用戶端通路并提供一頂的服務

遠端對象必須實作java.rmi.server.UniCastRemoteObject類,這樣才能保證用戶端通路獲得遠端對象時,該遠端對象将會把自身的一個拷貝以Socket的形式傳輸給用戶端。此時用戶端所獲得的這個拷貝稱為”存根“,而伺服器端本身已存在的遠端對象則稱之為”骨架“,其實此時的存根是用戶端的一個代理,用于伺服器端的通信,而骨架也可以認位是伺服器端的一個代理,用于接收用戶端的請求之後調用遠端方法來響應用戶端的請求。

3、分布式id生成方案

uuid

  • 1、目前日期和時間 時間戳
  • 時鐘序列。 計數器
  • 全局唯一的IEEE機器識别号,如果有網卡,從網卡MAC位址獲得,沒有網卡以其他方式獲得。

優點:代碼簡單,性能好(本地生成,沒有網絡消耗),保證唯一(相對而言,重複機率極低可以忽略)

缺點:

  • 每次生成的ID都是無序的,而且不是全數字,且無法保證趨勢遞增
  • UUID生成的是字元串,字元串存儲性能差,查詢效率慢,寫的時候由于不能産生順序的append操作,需要進行insert操作,導緻頻繁的頁分裂,這種操作在記錄占用空間比較大的情況下,性能下降比較大,還會增加讀取磁盤次數
  • UUID長度過長,不适用于存儲,耗費資料庫性能。
  • ID無一定業務含義,可讀性差。
  • 有資訊安全問題,有可能洩漏mac位址

資料庫自增序列

單機模式:

優點:

  • 實作簡單,依靠資料庫即可,成本小。
  • ID數字化,單調自增,滿足資料庫存儲和查詢性能。
  • 具有一定的業務可讀性。(結合業務code)

缺點:

  • 強依賴DB,存在單點問題,如果資料庫當機,則業務不可用。
  • DB生成ID性能有限,單點資料庫壓力大,無法抗高并發場景。
  • 資訊安全問題,比如暴露訂單量,url查詢改一下id查到别人的訂單

    資料庫高可用:多主模式做負載,基于序列的起始值和步長設定,不同的初始值,相同的步長,步長大于節點數。

優點:解決了ID生成的單點問題,同時平衡了負載。

缺點:

  • 系統擴容困難:系統定義好步長之後,增加機器之後調整步長困難。
  • 資料庫壓力大:每次擷取一個ID都必須讀寫一次資料庫。
  • 主從同步的時候,電商下單---->支付insert master db select 資料,因為資料同步延遲導緻查不到這個資料。加cache(不是最好的解決方式)資料要求比較嚴謹的話查master主庫

leaf-sagmnet

-采用每次擷取一個ID區間段的方式來解決,區間段用完之後再去資料庫擷取新的号段,這樣一來就可以大大減輕資料庫的壓力

核心字段:biz_tag, max_id ,step

biz_tag用來區分業務,max_id表示該biz_tag目前所被配置設定的ID号段的最大值,step表示每次配置設定的号段長度,原來每次擷取ID都需要通路資料庫,現在隻需要把Step設定的足夠合理如1000,那麼現在可以在1000個ID用完之後再去通路資料庫

優點:

  • 擴充靈活,性能強能撐起大部分業務場景。
  • ID号碼是趨勢遞增的,滿足資料庫存儲和查詢性能要求
  • 可用性高,即使ID生成伺服器不可用,也能夠使得業務在短時間内可用,為排查問題争取時間。

缺點:

  • 可能存在多個節點同時請求ID區間的情況,依賴DB

對buffer:将擷取一個号段的方式優化成擷取兩個号段,在一個号段用完之後不用立馬去更新号段,還有一個緩存号段備用,這樣能夠有效解決這種沖突問題,而且采用雙buffer的方式,在目前号段消耗了10%的時候就去檢查下一個号段有沒有準備好,如果沒有準備好就去更新下一個号段,目前号段用完了就切換到下一個已經緩存好的号段去使用,同時在下一個号段消耗到10%的時候,又去檢測下一個号段有沒有準備好,如此往複。

優點:

  • 基于JVM存儲雙buffer的号段,減少了資料庫查詢,減少了網絡依賴,效率更高。

缺點

segment号段長度是固定的,業務量大時可能會頻繁更新号段,因為原本配置設定的号段會一下用完,如果号段長度設定的過長,但凡緩存中有号段沒有消耗完,其他節點重新擷取的号段與之前相比可能跨度會很大,動态調整Step

基于redis、mongodb、zk等中間件生成

雪花算法:

生成一個64bit的整性數字

第一位符号位固定為0,41位時間戳,10位workid,12位序列号

位數可以有不同實作

優點

  • 每個毫秒值包含的ID值很大,不夠可以變動位數來增加,性能佳(依賴workId的實作)。
  • 時間戳值在高位,中間是固定的機器碼,自增的序列在低位,整個ID是趨勢遞增的。
  • 能夠根據業務場景資料庫節點布置靈活挑戰bit位劃分,靈活度高。

缺點

  • 強依賴于機器時鐘,如果時鐘回撥,會導緻重複的ID生成,是以一般基于此的算法發現時鐘回撥,都會抛異常處理,阻止ID生成,這可能導緻服務不可用。

4、分布式鎖解決方案

需要這個鎖獨立于每一個服務之外,而不是在服務裡面。

資料庫:利用主鍵沖突控制一次隻有一個線程能擷取鎖,非阻塞、不可重入、單點、失效時間

Zookeeper分布式鎖:

zk通過臨時節點,解決了死鎖的問題,一旦用戶端擷取到鎖之後突然挂掉(Session連接配接斷開),那麼這個臨時節點就會自動删除,其他用戶端自動擷取鎖。臨時順序節點解決驚群效應。

Redis分布式鎖:setNX,單線程處理網絡請求,不需要考慮并發安全性

所有服務節點設定相同的key,傳回為0,則鎖擷取失敗

setnx問題:

  • 1、早期版本沒有逾時參數,需要單獨設定,存在死鎖問題(中途當機)
  • 2、後期版本提供加鎖與設定原子性操作,但是存在任務逾時,鎖自動釋放,導緻并發問題,加鎖與釋放鎖不是同一線程問題。

删除鎖:判斷線程唯一标志,再删除

可重入性及鎖續期沒有 實作,通過redisson解決(類似AQS的實作,看門狗機制)

redlock:意思的機制都隻操作單節點、即使Redis通過sentinel保證高可用,如果這個master節點由于某些原因發生了主從切換,那麼就會出現鎖丢失的情況(redis同步設定可能資料丢失)。redlock從多個節點申請鎖,當一半以上節點擷取成功,鎖才算擷取成功,redission有相應的實作。

5、分布式事務解決方案

XA規範:分布式事務規範,定義了分布式事務模型

四個角色:事務管理器(協調者TM)、資料總管(參與者RM)、應用程式AP、通信資料總管CRM

全局事務:一個橫跨多個資料庫的事務,要麼全部送出、要麼全部復原

JTA事務時java對XA規範的實作,對應JDBC的單庫事務。

兩階段協定:

一天五道Java面試題----第十一天(分布式架構下,Session共享有什麼方案--------->分布式事務解決方案)

第一階段(prepare):每個參與者執行本地事務但不送出,進入ready狀态,并通知協調者已經準備就緒。

第二階段(commit)當協調者确認每個參與者都read後,通知參與者進行commit操作,如果有參與者fail,則發送rollback指令,各參與者做復原。

問題:

  • 單點故障:一旦事務管理器出現故障,整個系統不可用(參與者都會阻塞住)
  • 資料不一緻:在階段二,如果事務管理器隻發送了部分commit消息,此時網絡發生異常,那麼隻有部分參與者接收到commit資訊,也就是說隻有部分參與者送出了事務,使得系統資料不一緻。
  • 響應時間較長:參與者和協調者資源都被鎖住,送出或者復原之後才能釋放
  • 不确定性:當協調者管理器發送commit之後,并且此時隻有一個參與者收到了commit,那麼當該參與者與事務管理器同時當機之後,重新選舉的事務管理器無法确定該條消息是否送出成功。

三階段協定:主要是針對兩階段的優化,解決了2PC單點故障的問題,但是性能問題和不一緻問題仍然沒有根本解決

一天五道Java面試題----第十一天(分布式架構下,Session共享有什麼方案--------->分布式事務解決方案)

引入了逾時機制解決參與者阻塞的問題,逾時後本地送出,2pc隻有協調者有逾時機制

  • 第一階段:CanCommit階段,協調者詢問事務參與者,是否有能力完成此次事務。

    如果都傳回yes,則進入第二階段

    有一個傳回no或等待響應逾時,則中斷事務,并向所有參與者發送abort請求

  • 第二階段:precommit階段,此時協調者會向所有的參與者發送precommit請求,參與者收到後開始執行事務操作。參與者執行完事務操作後(此時屬于未送出事務的狀态),就會向協調者回報”Ack“表示我已經準備好送出了,并等待協調者的下一步指令。
  • 第三階段:DoCommit階段,在階段二中如果所有的參與者節點都傳回Ack,那麼協調者就會從”預送出狀态“轉變為”送出狀态“。然後向所有的參與者節點發送”doCommit"請求,參與者節點在收到送出請求後就會各自執行事務送出操作,并向協調者節點回報“Ack”消息,協調者收到所有參與者的Ack消息後完成事務。相反,如果有一個參與者節點未完成PreCommit的回報或者回報逾時,那麼協調者都會向所有的參與者節點發送abort請求,進而中斷事務。

TCC(補償事務):Try、Confirm、Cancel

  • 針對每個操作,都要注冊一個與其對應的确認和補償(撤銷)操作

    Try操作做業務檢查及資源預留,Confirm做業務确認,Cancel實作一個與Try相反的操作既復原操作。TM首先發起所有的分支事務的try操作,任何一個分支事務的try操作執行失敗,TM将會發起所有分支事務的Cancel操作,若try操作全部成功,TM将會發起所有分支事務的Confirm操作,其中Confirm/Cancel操作若執行失敗,TM會進行重試。

  • 發送prepare消息到消息中間件
  • 發送成功後,執行本地事務

    如果事務執行成功,則commit,消息中間件将消息下發至消費端(commit前,消息不會被消費)

    如果事務執行失敗,則復原,消息中間件将這條prepare消息删除

  • 消費端接收到消息進行消費,如果消費失敗,則不斷重試