1. 程式人生 > 其它 >redis面試1-33

redis面試1-33

目錄

1.Redis你比較熟吧,說說它機制為什麼快?

1.它是純存記憶體操作;
2.核心是基於非阻塞的IO多路複用機制;
3.單執行緒的設計避免了多執行緒上下文切換的資源開銷;
4.簡單且解析效能高的序列化協議。

因為是純記憶體操作,Redis的效能非常出色,每秒可以處理超過 10萬次讀寫操作,是已知效能最快的Key-Value DB。

2.redis是單執行緒嗎?

	目前所說的Redis單執行緒,指的是"其網路IO和鍵值對讀寫是由一個執行緒完成的",也就是說,Redis中只有網路請求模組和資料操作模組是單執行緒的。
	而其他的如持久化儲存模組、叢集支撐模組等是多執行緒的。

3.為什麼redis需要把所有資料放到記憶體中?

1.Redis為了達到最快的讀寫速度將資料都讀到記憶體中,並通過非同步的方式將資料寫入磁碟。所以redis具有快速和資料持久化的特徵。
2.如果不將資料放在記憶體中,磁碟I/O速度為嚴重影響redis的效能。在記憶體越來越便宜的今天,redis將會越來越受歡迎。
3.如果設定了最大使用的記憶體,則資料已有記錄數達到記憶體限值後不能繼續插入新值。

4.Redis的回收策略有哪些?

(1)noeviction: 如果記憶體使用達到了maxmemory,client還要繼續寫入資料,那麼就直接報錯給客戶端
(2)allkeys-lru: 就是我們常說的LRU演算法,移除掉最近最少使用的那些keys對應的資料,ps最長用的策略
(3)volatile-lru: 也是採取LRU演算法,但是僅僅針對那些設定了指定存活時間(TTL)的key才會清理掉
(4)allkeys-random: 隨機選擇一些key來刪除掉
(5)volatile-random: 隨機選擇一些設定了TTL的key來刪除掉
(6)volatile-ttl: 移除掉部分keys,選擇那些TTL時間比較短的keys

5.MySQL裡有2000w資料, redis中只存20w的資料,如何保證 redis中都是熱點資料?

限定 Redis佔用的記憶體,Redis會根據自身資料淘汰策略,留下熱資料到記憶體。
所以,計算一下 50W 資料大約佔用的記憶體,然後設定一下Redis記憶體限制即可,並將淘汰策略為volatile-lru或者allkeys-lru。

6.使用Redis有哪些好處?

1.速度快,因為資料存在記憶體中,類似於HashMap,HashMap的優勢就是查詢和操作的時間複雜度都是O(1)
2.支援豐富資料型別,支援string,list,set,sorted set,hash
3.豐富的特性:可用於快取,訊息,按key設定過期時間,過期後將會自動刪除

7.redis相比memcached有哪些優勢?

1.memcached所有的值均是簡單的字串,redis作為其替代者,支援更為豐富的資料型別
2.redis的速度比memcached快很多
3.redis可以持久化其資料

8.Redis 常見的效能問題都有哪些?如何解決?

1).Master寫記憶體快照,save命令排程rdbSave函式,會阻塞主執行緒的工作,當快照比較大時對效能影響是非常大的,會間斷性暫停服務,所以:Master最好不要寫記憶體快照。
2).Master AOF持久化,如果不重寫AOF檔案,這個持久化方式對效能的影響是最小的,但是AOF檔案會不斷增大,AOF檔案過大會影響Master重啟的恢復速度。
Master最好不要做任何持久化工作,包括記憶體快照和AOF日誌檔案,特別是不要啟用記憶體快照做持久化,如果資料比較關鍵,某個Slave開啟AOF備份資料,策略為每秒同步一次。
3).Master呼叫BGREWRITEAOF重寫AOF檔案,AOF在重寫的時候會佔大量的CPU和記憶體資源,導致服務load過高,出現短暫服務暫停現象。
4). Redis主從複製的效能問題,為了主從複製的速度和連線的穩定性,Slave和Master最好在同一個區域網內

9.redis常見效能問題和解決方案

1.Master最好不要做任何持久化工作,如RDB記憶體快照和AOF日誌檔案
2.如果資料比較重要,某個Slave開啟AOF備份資料,策略設定為每秒同步一次
3.為了主從複製的速度和連線的穩定性,Master和Slave最好在同一個區域網內
4.儘量避免在壓力很大的主庫上增加從庫
5.主從複製不要用圖狀結構,用單向連結串列結構更為穩定,即:Master <- Slave1 <- Slave2 <- Slave3...
 這樣的結構方便解決單點故障問題,實現Slave對Master的替換。如果Master掛了,可以立刻啟用Slave1做Master,其他不變。

10.redis快取穿透,快取擊穿,快取雪崩問題?

# 快取穿透:
	-快取和資料庫都沒有資料,爬蟲,惡意攻擊
  -解決:
  	-1 介面層增加校驗,id小於0的直接處理掉
    -2 對應資料庫中也不存在的,也在快取中放一份,只不過value值是空
    -3 通過布隆過濾器實現,把所有使用者id都放到布隆過濾器中,來了一個請求,拿著id
    	去布隆過濾器看,沒有表示是惡意請求,直接返回

# 快取擊穿
	-快取沒有,資料庫有,快取擊穿是指快取中沒有但資料庫中有的資料(一般是快取時間到期),這時由於併發使用者特別多,同時讀快取沒讀到資料,又同時去資料庫去取資料,引起資料庫壓力瞬間增大,造成過大壓力
  -解決:
  	-設定熱點資料永遠不過期。

# 快取雪崩
	-快取雪崩是指快取中資料大批量到過期時間,而查詢資料量巨大,引起資料庫壓力過大甚至down機
  -解決方案:
    1 快取資料的過期時間設定隨機,防止同一時間大量資料過期現象發生。
    2 如果快取資料庫是分散式部署,將熱點資料均勻分佈在不同搞得快取資料庫中。
    3 設定熱點資料永遠不過期。

11.快取預熱

快取預熱:就是系統上線後,將相關的快取資料直接載入到快取系統。這樣就可以避免在使用者請求的時候,先查詢資料庫,然後再將資料快取的問題!使用者直接查詢事先被預熱的快取資料!

解決方案:
  1.直接寫個快取重新整理頁面,上線時手工操作一下;
  2.資料量不大,可以在專案啟動的時候自動進行載入;
  3.定時重新整理快取;

12.redis一個字串型別的值能儲存最大容量是多少?

512M

13.假如Redis裡面有1億個key,其中有10w個key是以某個固定的已知的字首開頭的,如果將它們全部找出來?

使用keys指令可以掃出指定模式的key列表。

對方接著追問:如果這個redis正在給線上的業務提供服務,那使用keys指令會有什麼問題?
這個時候你要回答redis關鍵的一個特性:redis的單執行緒的。keys指令會導致執行緒阻塞一段時間,線上服務會停頓,直到指令執行完畢,服務才能恢復。這個時候可以使用scan指令,scan指令可以無阻塞的提取出指定模式的key列表,但是會有一定的重複概率,在客戶端做一次去重就可以了,但是整體所花費的時間會比直接用keys指令長。

14.Redis回收程序如何工作的?

1.一個客戶端運行了新的命令,添加了新的資料。
2.Redis檢查記憶體使用情況,如果大於maxmemory的限制, 則根據設定好的策略進行回收。
3.一個新的命令被執行,等等。
4.所以我們不斷地穿越記憶體限制的邊界,通過不斷達到邊界然後不斷地回收回到邊界以下。

15.有幾種資料結構,底層分別是怎麼儲存的?

string:字串
Strings 資料結構是key-value型別,value其實不僅是String,也可以是數字
Hash:雜湊字典
Hash 資料結構是key-object型別
list:列表
list 就是雙鏈表
set:集合
set 是可以自動排重的,實際就是通過計算hash的方式來快速排重的
zset:有序集合
zset zset的內部使用HashMap和跳躍表(SkipList)來保證資料的儲存和有序,HashMap裡放的是成員到score的對映,而跳躍表裡存放的是所有的成員,排序依據是HashMap裡存的score,使用跳躍表的結構可以獲得比較高的查詢效率,並且在實現上比較簡單。

16.MySQL/redis有幾種高可用方案,你們用的是哪一種?

1.基於主從複製;(我們使用)

2.基於Galera協議;

3.基於NDB引擎;

4.基於中介軟體/proxy;

5.基於共享儲存;

6.基於主機高可用;

17.redis叢集模式和哨兵模式

哨兵模式是redis高可用的實現方式之一
使用一個或者多個哨兵(Sentinel)例項組成的系統,對redis節點進行監控,在主節點出現故障的情況下,能將從節點中的一個升級為主節點,進行故障轉義,保證系統的可用性
選舉一個從節點升為主節點

18.哨兵們是怎麼感知整個系統中的所有節點(主節點/從節點/哨兵節點)的

哨兵(Sentinel)節點會每秒一次的頻率向建立了命令連線的例項傳送PING命令,如果在down-after-milliseconds毫秒內沒有做出有效響應包括(PONG/LOADING/MASTERDOWN)以外的響應,哨兵就會將該例項在本結構體中的狀態標記為SRI_S_DOWN主觀下線

19.redis資料冪等性是怎麼保證的

冪等性:多次發起同一個請求, 必須保證操作只能執行一次

1.token機制,防止頁面重複提交
2.唯一索引,防止新增髒資料
3.悲觀鎖,獲取資料的時候加鎖(鎖表或鎖行)
4.樂觀鎖,基於版本號version實現, 在更新資料那一刻校驗資料
5.分散式鎖, redis(jedis、redisson)或zookeeper實現
6.狀態機,狀態變更, 更新資料時判斷狀態

20.redis分散式鎖怎麼使用

在redis放一把鎖,使用完立即解鎖

// 加鎖
func Lock(key string) bool {
	// ex:設定預設過期時間10秒,防止死鎖
	ex:=10*time.Second
	mutex.Lock()
	defer mutex.Unlock()
	bool,err := rdb.SetNX(key, `{"lock":1}`, ex).Result()
	if err != nil {
		return bool
	}
	return bool
}

// 解鎖
func UnLock(key string) int64 {
	nums, err := rdb.Del(key).Result()
	if err != nil {
		log.Println(err.Error())
		return 0
	}
	return nums
}

21.redis分散式鎖實現原理?

在分析分散式鎖的三種實現方式之前,先了解一下分散式鎖應該具備哪些條件:

在分散式系統環境下,一個方法在同一時間只能被一個機器的一個執行緒執行;
高可用的獲取鎖與釋放鎖;
高效能的獲取鎖與釋放鎖;
具備可重入特性;
具備鎖失效機制,防止死鎖;
具備非阻塞鎖特性,即沒有獲取到鎖將直接返回獲取鎖失敗。
分散式的CAP理論告訴我們“任何一個分散式系統都無法同時滿足一致性(Consistency)、可用性(Availability)和分割槽容錯性(Partition tolerance),最多隻能同時滿足兩項。”所以,很多系統在設計之初就要對這三者做出取捨。在網際網路領域的絕大多數的場景中,都需要犧牲強一致性來換取系統的高可用性,系統往往只需要保證“最終一致性”,只要這個最終時間是在使用者可以接受的範圍內即可。

通常分散式鎖以單獨的服務方式實現,目前比較常用的分散式鎖實現有三種:

基於資料庫實現分散式鎖。
基於快取(redis,memcached,tair)實現分散式鎖。
基於mq,kafka佇列實現分散式鎖。
儘管有這三種方案,但是不同的業務也要根據自己的情況進行選型,他們之間沒有最好只有更適合!

22.redis熱key發現及解決?

所謂熱key問題就是,突然有幾十萬的請求去訪問redis上的某個特定key。那麼,這樣會造成流量過於集中,達到物理網絡卡上限,從而導致這臺redis的伺服器宕機。
那接下來這個key的請求,就會直接懟到你的資料庫上,導致你的服務不可用。

方法一:redis Monitor命令,該命令可以實時抓取出redis伺服器接收到的命令。然後統計出熱key
方法二:憑藉業務經驗,進行預估哪些是熱key
	其實這個方法還是挺有可行性的。比如某商品在做秒殺,那這個商品的key就可以判斷出是熱key。缺點很明顯,並非所有業務都能預估出哪些key是熱key。

解決熱key:
1.二級快取(本地快取)
2.讀寫分離,備份熱key,分散壓力

23.分佈多臺redis的話,如果某一臺快取過期了,流量過大該怎麼辦?

1.設定熱點key永不過期
2.立即重新新增到快取
3.有訪問快取時間延長

24.redis持久化方式有哪些?有什麼區別?

兩種持久化方式:RDB,AOF
一:RDB持久化-(備份檔案)
  SAVE或者BGSAVE來生成RDB檔案,它的作用是將某個時間點上的資料庫狀態儲存到RDB檔案中
	save命令會阻塞redis,期間不能接受任何命令
	bgsave命令會新開一個子程序,然後由子程序生成RDB檔案,不會阻塞redis

RDB優點:
	1.Redis資料庫將只包含一個檔案,這對於檔案備份而言是非常完美的
  2.對於災難恢復而言,RDB是非常不錯的選擇。因為我們可以非常輕鬆的將一個單獨的檔案壓縮後再轉移到其它儲存介質上。
  3.效能最大化。對於Redis的服務程序而言,在開始持久化時,它唯一需要做的只是fork出子程序,之後再由子程序完成這些持久化的工作,這樣就可以極大的避免服務程序執行IO操作了。
  4.相比於AOF機制,如果資料集很大,RDB的啟動效率會更高。

RDB缺點:
  1.在持久化之前出現宕機,此前沒有來得及寫入磁碟的資料都將丟失
  2.由於RDB是通過fork子程序來協助完成資料持久化工作的,因此,如果當資料集較大時,可能會導致整個伺服器停止服務幾百毫秒,甚至是1秒鐘。

RDB配置檔案:
  save 900 1  # 超過900秒有1個鍵值對操作,會自動呼叫save完成資料持久化
  save 300 10  # 超過300秒有10個鍵值對操作,會自動呼叫save完成資料持久化
  save 60 10000  # 超過60秒有10000個鍵值對操作,會自動呼叫save完成資料持久化

二:AOF持久化-(備份操作記錄的命令,查詢不會記錄)
AOF優點:
  1.該機制可以帶來更高的資料安全性,即資料永續性。
  2.AOF包含一個格式清晰、易於理解的日誌檔案用於記錄所有的修改操作。事實上,我們也可以通過該檔案完成資料的重建。
  3.更好的保證資料的安全

AOF缺點:
  1.對於相同數量的資料集而言,AOF檔案通常要大於RDB檔案
  2.RDB 在恢復大資料集時的速度比 AOF 的恢復速度要快。RDB相當於資料複製的操作,AOF資料重建
  3.根據同步策略的不同,AOF在執行效率上往往會慢於RDB。總之,每秒同步策略的效率是比較高的,同步禁用策略的效率和RDB一樣高效

AOF配置檔案:
在Redis的配置檔案中存在三種同步方式,它們分別是:

appendfsync always     #每次有資料修改發生時都會寫入AOF檔案。
appendfsync everysec  #每秒鐘同步一次,該策略為AOF的預設策略。
appendfsync no          #從不同步。高效但是資料不會被持久化。


總結:二者選擇的標準,就是看系統是願意犧牲一些效能,換取更高的快取一致性(aof),還是願意寫操作頻繁的時候,不啟用備份來換取更高的效能,待手動執行save的時候,再做備份(rdb)。rdb這個就更有些 eventually consistent的意思了。

25.redis叢集的原理嗎?

主從+哨兵
故障轉移

26.限流是怎麼做的?有幾種策略?

1.協程池:限制gorouting數量,redis分散式鎖100。拿到鎖-1,釋放鎖+1
2.redis漏斗桶:限流100,redis裡面放key=100,進來一個請求-1,請求結束+1。小於0時,丟棄
3.訊號量:channel管道,緩衝區,訊號量實現

上面3種缺點:可以被惡意攻擊,佔用資源。
解決方法:使用者需要登陸,把token,存起來。訪問計數,如果訪問異常加入黑名單(redis給一個假資料)

27.Redis叢集跟MySQL的一致性?

原則:一般不更新快取,寫的操作操作資料庫。因為如果更新快取就會出現快取不一致的情況,很難維護	
  讀取快取步驟一般沒有什麼問題,但是一旦涉及到資料更新:資料庫和快取更新,就容易出現快取和資料庫之間的資料一致性問題。不管是先寫資料庫,在刪除快取;還是先刪除快取,再寫庫,都有可能出現數據不一致的情況。舉個例子:

1.如果刪除了快取redis,還沒有來記得寫庫mysql,另一個執行緒就來讀取,發現快取為空,則去資料庫中讀取資料寫入快取,此時快取為髒資料。

2.如果先寫庫,在刪除快取前,寫庫的執行緒宕機了,沒有刪除掉快取,則也會出現資料不一致的情況。

因為寫和讀是併發的,沒法保證順序,就會出現快取和資料庫的資料不一致的問題。如何解決?

方案一:
	設定快取過期時間,是保證最終一致性的解決方案,只要達到快取過期時間,則後面的讀請求自然會從資料庫中讀取新值然後回填快取。(看資料實時性,精確性)

方案二:先寫入資料庫,再刪除快取,刪除後只要有請求再次加入快取(寫入時,還沒有刪除快取,其他併發來還是獲取的老快取髒資料,看資料實時性,精確性)

方案三:先刪除快取,再寫入資料庫。同時併發訪問redis沒有資料時,等待0.05秒(等待寫入最新資料到mysql,防止讀取到髒資料),再訪問mysql,再次寫入最新快取。(比較精確和實時,但是需要等待0.05秒)

網路上懶載入,利用訊息佇列等個人覺得程式碼複雜化了。主要還是要看業務等實時性要求高不高

28.Redis掛了跟MySQL的一致性?

redis只放需要加入快取的資料,這些資料如果要更新直接更新mysql資料庫,而不會更新快取。刪除快取,或者讓快取過期。這樣redis掛了跟一致性沒關係,只會影響其他的業務,或者快取擊穿導致mysql宕機

29.分散式鎖如果master掛了,然後鎖沒有同步到其他機器,這時別的執行緒也拿到鎖了,怎麼辦?

Redis做分散式並非絕對安全,最保底的方式就是保證業務冪等
多主多從,多主不可能同時掛

30.如果鎖即將過期,但業務沒處理完,該怎麼處理?

可以參考Redission的看門狗設計,就是定時對即將失效的鎖續期

31.專案有用到布隆過濾器嗎,如果用的話要多大記憶體?

  沒用到,說不上來,但也別這麼直接,可以適當延伸一下,比如說經過綜合考慮,專案場景在這方面不需要做那麼複雜的功能,或者是運維層面做了大量的異常請求攔截之類的,別讓面試官覺得你這方面沒什麼思考。

  上一家公司使用過,業務場景:
    輿情繫統的產品需要一批抖音達人資料做分析,介面是買的。
		啟個定時任務,每天把產品給我的一批達人使用者id的發文,評論點贊等存起來。布隆過濾器過濾已經在庫裡面的作品,及評論。防止大量的重複入庫,給資料庫造成壓力。

32.分表為什麼要停服這種操作,如果不停服可以怎麼做?

停服:是指停止服務,暫停新的資料寫入。停服拆分表
如果不停服:
第一階段首先編寫代理層,代理層通過動態開關決定訪問舊錶還是新表,此時流量還是全部訪問舊錶;
第二階段開啟雙寫,增量資料不僅在舊錶新增和修改,也在新表新增和修改,日誌或者臨時表記錄寫入新表ID起始值,舊錶中小於這個值的資料就是存量資料;
第三階段進行存量資料同步,通過指令碼將存量資料分頁寫入新表;
第四階段停讀舊錶改讀新表,此時新表已經承載了所有讀寫業務,但是不要立刻停寫舊錶,需要保持雙寫一段時間。
第五階段當讀寫新表一段時間之後,沒有發生業務問題則可以停寫舊錶;

33.redis分散式,如何減少同步延遲

1.為了主從複製的速度和連線的穩定性,Master和Slave最好在同一個區域網內
2.不要讓master壓力太大,持久化工作放在slave節點
3.想要穩定,及效能高。就不要用圖妝結構繫結slave,用單鏈表結構。即:Master <- Slave1 <- Slave2 <- Slave3...
4.儘量避免在壓力很大的主庫上增加從庫
選擇了IT,必定終身學習