java面試題核心篇(二)

LNhome發表於2018-03-28

快取使用

18、Redis 有哪些型別

string型別:
一個key對應一個value
set mykey "wangzai"             ##設定key,第二次賦值會直接覆蓋之前的
setnx mykey "wangzai"           ## 如果mykey存在,則不改變,如果不存在,則建立賦值   
get mykey                       ##獲取key的值
setex key1 10 1                 ##給key1設定過期時間為10s,值為1
mset key1 value1 key2 value2    ##設定多個key
mget key1 key2                  ##獲取多個key的值
list型別
list是一個連結串列結構,主要功能是push、pop以及獲取一個範圍的所有值等。使用list結構,可以輕鬆實現最新訊息排行,另一個應用是訊息佇列,可以利用list的push操作,將任務存在list中,然後工作執行緒再用pop操作將任務取出進行執行。(先進後出)
lpush list1 "wangzai"                   ##在列表中加入一個元素    
lrange list1 0 -1                       ##檢視list1裡面的所有元素
lpop list1                              ##取出list1最新的元素
linsert list1 before "wangzai" "doubi"  ##在值為"wangzai"的前面插入一個元素為"doubi"
lset list1 3 "hehe"                     ##把第五個元素修改為"hehe"
lindex list1 0                          ##檢視第一個元素
llen list1                              ##檢視列表中有多少元素


set型別
set是集合,對集合操作有新增刪除元素,有對多個集合求交併差等操作。在微博應用中,可以將一個使用者關注的所有人放在一個集合裡,將所有粉絲放在一個集合裡,因為redis為集合提供了求交集、並集、差集等操作,就可以方便的實現如共同關注、共同喜好等功能。

sadd set1 a b c d                      ## 建立集合set1並設定值
smembers set1                          ## 檢視集合set1的值
srem set1 a b                          ## 刪除set1的值
spop set1                              ## 隨機取出一個元素並刪除
sinter set1 set2                       ## 交集
sinterstore set1 set2 set3             ## 將交集儲存到set3 
sunion set1 set2                       ## 並集
sunionstore set1 set2 set3             ## 把並集儲存到set3  
sdiff set1 set2                        ## 差集
sdiffstore set1 set2 set3              ## 把差集儲存到set3
sismember set1 c                       ## 判斷一個元素是否屬於一個集合
srandmember set1                       ## 隨機取出一個元素,但不刪除
sorted set型別
sorted set是有序集合,比set多了一個權重引數score,使得集合元素能夠按score進行有序排列。例如儲存一個班級同學的成績,其集合value可以是同學的學號,而score可以是其考試的得分,這樣在資料插入集合的時候就進行了排序。
zadd zset1 1 a                  ## 增加一個集合zset1,score為1,member為a
zrange zset1 0 -1               ## 按score升序輸出member
zrange zset1 0 -1 withscores    ## 帶上分值
zrem zset1 a                    ## 刪除指定元素
zrank zset1 a                   ## 返回元素的索引值,索引從0開始
zrevrange zset1 0 -1            ## score降序輸出member
zcard zset1                     ## 返回集合中所有元素的個數
zcount zset1 1 10               ## 返回分值範圍1-10的元素個數
zrangebyscore zset1 1 10        ## 返回分值範圍1-10的元素
zremrangebyscore zset1 1 10     ## 刪除分值範圍1-10的元素
hash型別
把一些結構化的資訊打包成hashmap,在客戶端序列化後儲存為一個字串的值(一般為json格式),比如使用者姓名、年齡、性別等
hset hash1 name wangzai                  ## 建立hash (hset name key value)
hget hash1 name                          ## 獲取field值  HGET name key
hgetall hash1                            ## 獲取hash1中所有的key和value
hmset hash2 name wangzai age 26 job it   ## 批量建立鍵值對
hmget hash2 name age job                 ## 批量獲取field值
hdel hash2 job                           ## 刪除指定field
hkeys hash2                              ## 列印所有的key
hvals hash2                              ## 列印所有的value
hlen hash2                               ## 檢視hash2有幾個field

19、Redis 內部結構

(參考https://www.cnblogs.com/chenpingzhao/archive/2017/06/10/6965164.html)

第一個層面,是從使用者的角度,string,list,hash,set,sorted set第二個層面,是從內部實現的角度,屬於更底層的實現,   ht(dict),raw,embstr,intset,sds,ziplist,quicklist,skiplist


20、Redis 使用場景

資料快取
對於熱點資料,快取以後可能讀取數十萬次,因此,對於熱點資料,快取的價值非常大。例如,分類欄目更新頻率不高,但是絕大多數的頁面都需要訪問這個資料,因此讀取頻率相當高,可以考慮基於 Redis 實現快取。
會話快取
使用 Redis 進行會話快取。例如,將 web session 存放在 Redis 中。
資料時效性
例如驗證碼只有60秒有效期,超過時間無法使用,或者基於 Oauth2 的 Token 只能在 5 分鐘內使用一次,超過時間也無法使用。
交集、並集和差集
在某些場景中,例如社交場景,通過交集、並集和差集運算,可以非常方便地實現共同好友,共同關注,共同偏好等社交關係。
排行榜/計數器
Redis在記憶體中對數字進行遞增或遞減的操作實現的非常好。
最新動態
按照時間順序排列的最新動態,也是一個很好的應用,可以使用 Sorted Set 型別的分數權重儲存 Unix 時間戳進行排序。

21、Redis 持久化機制

22、Redis 如何實現持久化

23、Redis 叢集方案與實現

24、Redis 為什麼是單執行緒的

單純的網路IO來說,量大到一定程度之後,多執行緒的確有優勢, 但並不是單純的多執行緒,而是每個執行緒自己有自己的epoll這樣的模型,也就是多執行緒和multiplexing混合。但是。還要考慮Redis操作的是記憶體中的資料結構。如果在多執行緒中操作,那就需要為這些物件加鎖。所以使用多執行緒可以提高效能,但是每個執行緒的效率嚴重下降了,而且程式的邏輯嚴重複雜化。Redis的資料結構並不全是簡單的Key-Value,還有list,hash等複雜的結構,這些結構有可能會進行很細粒度的操作,比如在很長的列表後面新增一個元素,在hash當中新增或者刪除一個物件,這些操作還可以合成MULTI/EXEC的組。這樣一個操作中可能就需要加非常多的鎖,導致的結果是同步開銷大大增加。Redis在權衡之後的選擇是用單執行緒,突出自己功能的靈活性。在單執行緒基礎上任何原子操作都可以幾乎無代價地實現,多麼複雜的資料結構都可以輕鬆運用,甚至可以使用Lua指令碼這樣的功能。對於多執行緒來說這需要高得多的代價。


25、快取中常見的問題及解決方案

快取一致性
當資料時效性要求很高時,需要保證快取中的資料與資料庫中的保持一致,而且需要保證快取節點和副本中的資料也保持同步(叢集同步)。解決快取的一致性比較依賴於快取的過期和更新策略。
快取併發
快取過期或者正在更新,同時有大量的併發請求該key。快取過期,大量請求落到資料庫,可能導致“雪崩”發生;如果快取更新,對某個key有大量的併發請求,此時請求獲得的可能是更新之前或者更新之後的,從而會導致“快取一致性”問題的發生。
解決策略:快取併發一般發生在查詢期間,而且問題出在快取更新時的高併發時刻,那麼就可以在這個時候對key加鎖(快取查詢加鎖,如果key不存在,然後查出資料寫入快取,然後解鎖)。
快取雪崩
在高併發情況下,快取更新或者過期導致快取命中失效,大量請求直接落到資料庫,致使其無法承受壓力,進而崩潰(快取併發的遞進和升級)。
解決策略:設定一個快取的過期時間時,可能有一些會設定1分鐘後或5分鐘後。當併發很高時,會出在某一個時間同時生成了很多的快取,並且過期時間都一樣,這個時候就可能引發一當過期時間到後,這些快取同時失效,請求全部轉發到 DB ,DB可能會壓力過重,這樣子,我們就可以將快取過期時間均勻地分佈在時間軸上,避免快取同時失效、更新的情況發生。還需要控制快取併發、擊穿現象的發生,查詢大key,想解決方案。
快取擊穿
該key被高併發訪問,快取訪問沒有命中,嘗試去從後端資料庫中獲取,從而導致了大量請求達到資料庫,而當該key對應的資料本身就是空的情況下,這就導致資料庫中併發的去執行了很多不必要的查詢操作,從而導致巨大沖擊和壓力。
解決策略:(1)通過設定過濾器(使用布隆過濾器),將所有可能存在的資料雜湊到一個足夠大的 bitmap 中,一個一定不存在的資料會被這個 bitmap 攔截掉,從而避免了對底層儲存系統的查詢壓力。(2)如果一個查詢返回的資料為空(可能由於資料不存在,也可能是系統故障),我們仍然把這個空結果進行快取,快取的值設定為一個指定值,同時設定它的過期時間很短,最長不超過五分鐘。(因為快取會佔用記憶體,長時間快取一個不存在的值比較耗資源。)在這五分鐘內,這個值可能由於寫入操作從而不再是一個不存在的值,這是就要更新快取,用真實值替代指定值。


總結:
“併發”和“雪崩”都是高併發時候快取不被命中直接訪問DB的例子,前者是因,或者是果,“併發”造成的影響還不夠惡劣,雪崩會導致資料庫直接崩潰。“併發”和“擊穿”可能會導致“雪崩”發生,避免發生“雪崩”,除了給出的解決方案,更要防止“併發”和“擊穿”的發生。


26、快取降級

服務降級的目的,是為了防止Redis服務故障,導致資料庫跟著一起發生雪崩問題。因此,對於不重要的快取資料,可以採取服務降級策略,例如一個比較常見的做法就是,Redis出現問題,不去資料庫查詢,而是直接返回預設值給使用者。


27、使用快取的合理性問題

(1)熱點資料,快取才有價值。
(2)頻繁修改的資料,看情況考慮使用快取。
(3)快取的不一致性,一般會對快取設定失效時間,一旦超過失效時間,就要從資料庫重新載入,因此應用要容忍一定時間的資料不一致。還有一種是在資料更新時立即更新快取,不過這也會更多系統開銷和事務一致性問題。
(4)快取更新機制,一般情況下,我們採取快取雙淘汰機制,在更新資料庫的時候淘汰快取。此外,設定超時時間,例如30分鐘。極限場景下,即使有髒資料入cache,這個髒資料也最多存在三十分鐘。
(5)快取可用性,快取是提高資料讀取效能的,快取資料丟失和快取不可用不會影響應用程式的處理。因此,一般的操作手段是,如果Redis出現異常,我們手動捕獲這個異常,記錄日誌,並且去資料庫查詢資料返回給使用者。
(6)快取服務降級,服務降級的目的,是為了防止Redis服務故障,導致資料庫跟著一起發生雪崩問題。因此,對於不重要的快取資料,可以採取服務降級策略,例如一個比較常見的做法就是,Redis出現問題,不去資料庫查詢,而是直接返回預設值給使用者。
(7)快取預熱,在新啟動的快取系統中,如果沒有任何資料,在重建快取資料過程中,系統的效能和資料庫複製都不太好,那麼最好的快取系統啟動時就把熱點資料載入好,例如對於快取資訊,在啟動快取載入資料庫中全部資料進行預熱。一般情況下,我們會開通一個同步資料的介面,進行快取預熱。

(8)快取穿透,如果因為不恰當的業務,或者惡意攻擊持續地發請求某些不存在的資料,由於快取沒有儲存該資料,所有的請求都會落到資料庫上,會對資料庫造成很大壓力,甚至奔潰。一個簡單的對策是將不存在的資料也快取起來。

訊息佇列

28、訊息佇列的使用場景

(1)資料驅動的任務依賴,task3需要使用task2的輸出作為輸入,task2需要使用task1的輸出作為輸入。MQ只用來傳遞上游任務執行完成的訊息,並不用於傳遞真正的輸入輸出資料。
(2)上游不關心執行結果,帖子釋出成功後,向MQ發一個訊息,哪個下游關注“帖子釋出成功”的訊息,主動去MQ訂閱。
(3)上游關注執行結果,但執行時間很長。
什麼時候不使用MQ?
上游實時關注執行結果
什麼時候使用MQ?
資料驅動的任務依賴,上游不關心多下游執行結果,非同步返回執行時間長。

相關文章