java常見疑難面試題及答案(阿里、螞蟻、百度、美團)(二)

11.redis持久化,RDB和AOF有什麼區別

RDB持久化(效率優先):指定的時間間隔內fork一個子進程,先將數據集寫入臨時文件,寫入成功後,再替換之前的文件,用二進制壓縮存儲。

優勢:

1)數據都存儲在一個文件中,便於災難恢復。

2)不會對性能造成太大的影響,持久化是通過fork出子進程完成的,可以極大的避免服務進程執行IO操作。

3)當數據集較大時,啟動效率高於AOF。

劣勢:

1)定時持久化前宕機的話,沒有保存的數據會全部丟失

2)由於是fork子進程來協助完成數據集持久化工作,當數據集較大時,可能會導致整個服務器停止服務。


AOF持久化(一致性優先):以日誌的形式記錄服務器所處理的每一個寫、刪除操作,保留詳細的操作記錄(格式清晰、易於理解)

優勢:

1)數據安全性高,寫入操作採用的是append模式,出現宕機現象,也不會破壞日誌文件中已經存在的記錄。

2)如果日誌過大,Redis可以自動啟用rewrite機制(以append模式將修改數據寫入到老的磁盤文件中,同時會創建一個新的文件用於記錄此期間有哪些修改命令被執行)。

3)可以根據日誌文件完成數據重建:

劣勢:

1)因為需要記錄每條操作,文件會比RDB大,災難恢復速度也會被較慢。

2)AOF運行效率會比RDB稍慢。

12.Redis部署模式有哪些?

主從模式:設置一個主節點,N個從節點,寫主讀從。必須保證主節點不會宕機,一旦主節點宕機,其它節點不會競爭成為主節點,Redis將喪失寫的能力


哨兵模式:比主從模式多了一個競選機制,主節點宕機,所有的從節點會競選出新的主節點。(依賴於在系統中啟動一個sentinel進程)sentinel進程會監聽主從之間是否正常工作,實例出了問題時會通過API通知。主節點出問題後,sentinel會在所有的從節點中競選出一個節點,並將其作為新的主節點。它還能夠向使用者提供當前主節點的地址,故障轉移後使用者不用做任何修改就可以知道當前主節點地址。


cluster(集群)模式:自動分割數據到不同的節點上(集群有16384個哈希槽,每個key完成CRC16校驗後對16384取模來決定放置哈希槽),主從複製模型,每個節點都會有N-1個複製品,整個集群的部分節點失敗或者不可達的情況下能夠繼續處理命令。但是因為是集群使用了異步複製,所以不能保證數據的強一致性。

13.nosql是否瞭解?項目實際運用?

nosql泛指非關係型的數據庫。

1)高性能,高可用性和可伸縮性

3)存儲格式為鍵 - 值對存儲(redis)、列式存儲(HBase)、文檔存儲(MongDB)、圖形數據庫(Neo4j)

4)最終一致性,並非遵循ACID(原子、一致、隔離、持久)

數據庫選型

1)數據量少,併發少建議選擇關係型數據庫

2)流量大系統後臺建議關係型數據庫

3)批量數據處理、離線計算、即時查詢、監控,建議選列式存儲

4)事務性系統建議選擇關係型數據庫

5)數據量很大或者未來會變得很大,且表結構不明確,且字段在不斷增加,建議使用文檔存儲

6)關係性強、記錄大量基於事件的數據、推薦引擎推薦使用圖形數據庫

14.tomcat集群怎麼保證同步?

增量複製:只同步會話增量,集群中一個節點發生改變後,在一個請求被響應之前會同步到其餘全部節點。但是因為備份的網絡流量會隨著節點數的增加而急速增加,無法構建較大規模集群。

綁定:每個會話只有一個備份,利用負載均衡的源地址Hash算法實現,整個會話期間,用戶所有的請求都來自一一個節點。(宕機會導致節點上的數據全部丟失

15.如何解決超賣問題?

當商品庫存接近0時,如果多個買家同時付款購買此寶貝,會出現超賣缺貨的現象。

sql適合流量少的情況,秒殺的情況下,數據庫扛不住:

排他鎖

<code>update goods set num = num - 1 WHERE id = 1001 and num > 0;/<code>
java常見疑難面試題及答案(阿里、螞蟻、百度、美團)(二)

樂觀鎖

<code>select version from goods where id = 1001;
update goods set num = num - 1, version = version + 1 WHERE id = 1001 AND num > 0 AND version = 1;/<code>
java常見疑難面試題及答案(阿里、螞蟻、百度、美團)(二)

為什麼通過新增字段version控制,而不是利用原有num字段?

存在ABA問題:A線程獲取num為3,B線程獲取num也為3,B線程先將num-1=2,處理失敗又將庫存數恢復成3,A線程在進行更新操作時num=3,但是操作期間num已經有了變化。

悲觀鎖

select * from goods where id = 1001 for update;

update goods set num = num - 1, version = version + 1 WHERE id= 1001;

redis:

鎖 將商品數量放入緩存中,使用鎖來處理其併發情況。當接到買家提交訂單的情況下,先加鎖,然後將商品數量遞減,解鎖後進行其他處理。如果處理失敗加鎖後將數據遞增1再解鎖。當商品數量遞減到0時,表示商品秒殺完畢,拒絕其他用戶的請求。

隊列 Redis 隊列中加入商品數量相等的元素,請求進入從隊列上 pop 出一個元素,獲得就代表成功。

異步:

將購買請求放入消息隊列之中,異步處理結果。

16.分佈式id生成方式

1)數據庫自增

優勢:

實現簡單、自增方便排序

劣勢:

分庫分表、數據遷移的時候會出現問題,且難以擴展

2)uuid

優勢:

實現簡單、擁有唯一性,分庫分表和數據遷移無影響

劣勢:

沒有排序,無法保證趨勢遞增,長度較長,存儲、查詢效率較低,作為id性能差

3)Redis的原子操作 INCR

優勢:

性能好,遞增保證排序

劣勢:

需要引入redis,增加複雜度

4)snowflake算法(百度uid-generator和美團ecp-uid都是基於snowflake實現的)

使用41bit作為毫秒數,10bit作為機器的ID(5個bit是數據中心,5個bit的機器ID),12bit作為毫秒內的流水號(意味著每個節點在每毫秒可以產生 4096 個 ID),最後還有一個符號位,永遠是0

優勢:

性能好、單機遞增

劣勢:

要求系統時間只能增不能減,無法應對時間回退(修改機器時間)問題(官方scala代碼會對比時間,如果發生回退回拋InvalidSystemClock異常)

17.int的範圍?

-2^31-2^31-1

18.java常用數據結構

List、Set、Map

19.ConcurrentHashMap

線程安全且高效的HashMap實現,數組+鏈表(鏈表節點數超過指定閾值8的話,也是會轉換成紅黑樹

Java 5 之後,引用了內部的 Segment ( ReentrantLock ) 分段鎖,操作同段 map 的時候,進行鎖的競爭和等待。

jdk8重新使用synchronized+cas

1)多個分段鎖浪費內存空間,而且影響gc效率

2)同時map 在放入時競爭同一個鎖的概率非常小,分段鎖反而會造成更新等操作的長時間等待

20.ConcurrentHashMap擴容

1)如果新增節點之後,所在鏈表的元素個數達到了閾值 8,則會調用treeifyBin方法把鏈表轉換成紅黑樹。

2)如果數組長度n小於閾值MIN_TREEIFY_CAPACITY(默認是64),則會調用tryPresize方法把數組長度擴大到原來的兩倍,並觸發transfer方法,重新調整節點的位置。

3)新增節點之後,當數組元素個數達到閾值時,會觸發transfer方法。

transfer方法:

1)新建一個長度為2n的數組。

2)線程獲取一個擴容子任務,設置當前處理子任務的下界並更新當前處理節點所在的索引位置。(每遷移一個元素,元素會被設置為ForwardingNode,方便遷移過程中get)

3)對子任務中的每個節點,擴容線程從後向前依次判斷該節點是否已經轉移,如果沒有轉移,則對該節點進行加鎖,並且把節點對應的鏈表或紅黑樹遷移到新數組中。

4)如果線程處理的節點索引已經到達子任務的下界,則子任務執行結束,並嘗試去領取新的子任務,若領取不到再判斷當前線程是否是最後一個擴容線程,若是則最後掃描一遍數組,執行清理工作,否則直接退出。


分享到:


相關文章: