7.面試總結分享之 —中間件

7.中間件

1.redis

1.購物車在redis中是怎麼存的?

我們的購物車,用的是redis 來實現的。 當加入購物車的時候 用戶id作爲redis 的key,產品集合作爲redis的value。商品存的是 ,商品id 商品名稱,和商品購買數量。

當加入商品到購物車的時候,首先判斷當前用戶id對應的的產品集合裏面是否含有當前產品,有則數量加一。沒有則新添加該商品。

2,說說Redis哈希槽的概念?

Redis集羣沒有使用一致性hash,而是引入了哈希槽的概念,Redis集羣有16384個哈希槽,每個key通過CRC16校驗後對16384取模來決定放置哪個槽,集羣的每個節點負責一部分hash槽。

3.怎麼測試Redis的連通性?

ping

4.redis相比memcached有哪些優勢?
  • memcached所有的值均是簡單的字符串,redis作爲其替代者,支持更爲豐富的數據類型
  • redis的速比memcached快很多
  • redis可以持久化其數據,也可以做數據備份
  • 單個value的最大限制是1GB,不像 memcached只能保存1MB的數據
5.使用過Redis分佈式鎖麼,它是怎麼實現的?

先拿setnx來爭搶鎖,搶到之後,再用expire給鎖加一個過期時間防止鎖忘記了釋放。

6.使用過Redis做異步隊列麼,你是怎麼用的?有什麼缺點?

一般使用list結構作爲隊列,rpush生產消息,lpop消費消息。當lpop沒有消息的時候,要適當sleep一會再重試。

缺點:在消費者下線的情況下,生產的消息會丟失,得使用專業的消息隊列如rabbitmq等。

7.什麼是緩存穿透?如何避免?什麼是緩存雪崩?何如避免?

緩存穿透
一般的緩存系統,都是按照key去緩存查詢,如果不存在對應的value,就應該去後端系統查找(比如DB)。一些惡意的請求會故意查詢不存在的key,請求量很大,就會對後端系統造成很大的壓力。這就叫做緩存穿透。

如何避免?

  1. 對查詢結果爲空的情況也進行緩存,緩存時間設置短一點,或者該key對應的數據insert了之後清理緩存。
  2. 對一定不存在的key進行過濾。可以把所有的可能存在的key放到一個大的Bitmap中,查詢時通過該bitmap過濾。

緩存雪崩
當緩存服務器重啓或者大量緩存集中在某一個時間段失效,這樣在失效的時候,會給後端系統帶來很大壓力。導致系統崩潰。

如何避免?

  1. 在緩存失效後,通過加鎖或者隊列來控制讀數據庫寫緩存的線程數量。比如對某個key只允許一個線程查詢數據和寫緩存,其他線程等待。
  2. 做二級緩存,A1爲原始緩存,A2爲拷貝緩存,A1失效時,可以訪問A2,A1緩存失效時間設置爲短期,A2設置爲長期
  3. 不同的key,設置不同的過期時間,讓緩存失效的時間點儘量均勻。(可以在設置緩存時間的時候再加上一個隨機的時間值,保證緩存的失效時間不過度集中)
8.redis 內存淘汰機制(MySQL裏有2000w數據,Redis中只存20w的數據,如何保證Redis中的數據都是熱點數據?)

redis 提供 6種數據淘汰策略:

  • volatile-lru:從已設置過期時間的數據集(server.db[i].expires)中挑選最近最少使用的數據淘汰
  • volatile-ttl:從已設置過期時間的數據集(server.db[i].expires)中挑選將要過期的數據淘汰
  • volatile-random:從已設置過期時間的數據集(server.db[i].expires)中任意選擇數據淘汰
  • allkeys-lru:當內存不足以容納新寫入數據時,在鍵空間中,移除最近最少使用的key(這個是最常用的)
  • allkeys-random:從數據集(server.db[i].dict)中任意選擇數據淘汰
  • no-eviction:禁止驅逐數據,也就是說當內存不足以容納新寫入數據時,新寫入操作會報錯。這個應該沒人使用吧!

4.0版本後增加以下兩種:

  • volatile-lfu:從已設置過期時間的數據集(server.db[i].expires)中挑選最不經常使用的數據淘汰
  • allkeys-lfu:當內存不足以容納新寫入數據時,在鍵空間中,移除最不經常使用的key
9.redis 事務

Redis 通過 MULTI、EXEC、WATCH 等命令來實現事務(transaction)功能。事務提供了一種將多個命令請求打包,然後一次性、按順序地執行多個命令的機制,並且在事務執行期間,服務器不會中斷事務而改去執行其他客戶端的命令請求,它會將事務中的所有命令都執行完畢,然後纔去處理其他客戶端的命令請求。

在傳統的關係式數據庫中,常常用 ACID 性質來檢驗事務功能的可靠性和安全性。在 Redis 中,事務總是具有原子性(Atomicity)、一致性(Consistency)和隔離性(Isolation),並且當 Redis 運行在某種特定的持久化模式下時,事務也具有持久性(Durability)。

10.Memcache與Redis的區別都有哪些?
  • 存儲方式 Memecache把數據全部存在內存之中,斷電後會掛掉,數據不能超過內存大小。Redis有部份存在硬盤上,這樣能保證數據的持久性。
  • 數據支持類型 Memcache對數據類型支持相對簡單。Redis有複雜的數據類型。
  • 使用底層模型不同 它們之間底層實現方式 以及與客戶端之間通信的應用協議不一樣。Redis直接自己構建了VM 機制 ,因爲一般的系統調用系統函數的話,會浪費一定的時間去移動和請求。
11.redis的併發競爭問題如何解決?

Redis爲單進程單線程模式,採用隊列模式將併發訪問變爲串行訪問。Redis本身沒有鎖的概念,Redis對於多個客戶端連接並不存在競爭,但是在Jedis客戶端對Redis進行併發訪問時會發生連接超時、數據轉換錯誤、阻塞、客戶端關閉連接等問題,這些問題均是由於客戶端連接混亂造成。

對此有2種解決方法:

  1. 客戶端角度,爲保證每個客戶端間正常有序與Redis進行通信,對連接進行池化,同時對客戶端讀寫Redis操作採用內部鎖synchronized。
  2. 服務器角度,利用setnx實現鎖。
12.redis集羣中一致性hash的使用

redis集羣中存儲的文件,加入數量很大的時候,由於我們定義的規則是隨機的,所以我們的數據有可能存儲在任何一組Redis中查詢數據時就需要遍歷每一個集羣中的結點去尋找對應的數據。顯然,查詢數據過程中對redis集羣進行遍歷並不是我們想要的,所以我們會想到按某一個字段值進行Hash值、取模。
使用hash的redis集羣

在這裏插入圖片描述

從上圖中,我們需要查詢的是圖product.png,由於我們有6臺主服務器,所以計算的公式爲:hash(product.png) % 6 = 5, 我們就可以定位到是5號主從,這們就省去了遍歷所有服務器的時間,從而大大提升了性能。

使用Hash時遇到的問題

在上述hash取模的過程中,我們雖然不需要對所有Redis服務器進行遍歷而提升了性能。但是,使用Hash算法緩存時會出現一些問題,Redis服務器變動時,所有緩存的位置都會發生改變。
比如,現在我們的Redis緩存服務器增加到了8臺,我們計算的公式從hash(product.png) % 6 = 5變成了hash(product.png) % 8 = ? 結果肯定不是原來的5了。

再者,6臺的服務器集羣中,當某個主從羣出現故障時,無法進行緩存,那我們需要把故障機器移除,所以取模數又會從6變成了5。我們計算的公式也會變化。由於上面hash算法是使用取模來進行緩存的,爲了規避上述情況,Hash一致性算法就誕生了

一致性Hash算法原理

一致性Hash算法也是使用取模的方法,不過,上述的取模方法是對服務器的數量進行取模,而一致性的Hash算法是對2的32方取模。即,一致性Hash算法將整個Hash空間組織成一個虛擬的圓環,Hash函數的值空間爲0 ~ 2^32 - 1(一個32位無符號整型),整個哈希環如下:

在這裏插入圖片描述

一致性Hash算法的容錯性和可擴展性

現在,假設我們的Node C宕機了,我們從圖中可以看到,A、B不會受到影響,只有Object C對象被重新定位到Node A。所以我們發現,在一致性Hash算法中,如果一臺服務器不可用,受影響的數據僅僅是此服務器到其環空間前一臺服務器之間的數據(這裏爲Node C到Node B之間的數據),其他不會受到影響

數據傾斜問題

爲了解決數據傾斜問題,一致性Hash算法引入了虛擬節點機制,即對每一個服務器節點計算多個哈希,每個計算結果位置都放置一個此服務節點,稱爲虛擬節點。

在這裏插入圖片描述

2.kafka

3.MQ

4.zookeeper

1.dubbo和zookeeper

Duboo是一個分佈式框架,zookeeper是duboo生產者暴露服務的註冊中心。起一個調度和協調功能,當然註冊中心也可以用redis 或者duboo自帶的Multicast 來註冊。

5.dubbo