redis面試題(持續更新)
大量的數據請求可能造成數據庫的宕機(如秒殺,熱點數據,),Redis是使用內存存貯,每秒的運行次數可以達到10w+,可以減少數據庫的壓力。
String、Hash、List、Set、SortedSet。
要設置隨機的過期時間,否則造成雪崩。
使用set語法,加入jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
也可以用setnx然后在使用expire設置過期時間,但是如果在setnx后服務掛掉了,就會造成死鎖。
使用keys指令。
keys指令會導致線程阻塞一段時間,線上服務會停頓,直到指令執行完畢,服務才能恢復。
使用rpush生產消息,lpop消費消息。當lpop沒有消息的時候,要適當sleep一會再重試。
list還有個指令叫blpop,在沒有消息的時候,它會阻塞住直到消息到來。
使用pub/sub主題訂閱者模式,可以實現 1:N 的消息隊列。
在消費者下線的情況下,生產的消息會丟失,得使用專業的消息隊列如RocketMQ等。
使用zset score放入要延時的時間 ,然后使用rangebyscore輪詢獲取。
使用pub/sub。
redisTemplate.convertAndSend(“testkafka”, data); 放入隊列。
請參考上文。
Redis 高可用,主從+哨兵,Redis cluster,避免全盤崩潰。
本地 ehcache 緩存 + Hystrix 限流+降級,避免** MySQL** -。
Redis 持久化 RDB+AOF,一旦重啟,自動從磁盤上加載數據,快速恢復緩存數據。
請參考上文。
Redis Cluster:主要為擴展分片 當內存不足使用Cluster擴展。
Redis Sentinal:高可用,當主機死掉后選舉從機為主機。
首先進行RDB全局持久化存放于內存,然后將RDB文件發送給從機,同時,在接下來使用AOF逐步同步。
redis管道,可以將多次請求放于pipeline,然后一起讀取出來,這樣可以增加redis吞吐量。
本地緩存就是在進程的內存中進行緩存,比如我們的 JVM 堆中,可以用 LRUMap 來實現,也可以使用 Ehcache 這樣的工具來實現。本地緩存是內存訪問,沒有遠程交互開銷,性能最好,但是受限于單機容量,一般緩存較小且無法擴展。
分布式緩存一般都具有良好的水平擴展能力,對較大數據量的場景也能應付自如。缺點就是需要進行遠程請求,性能不如本地緩存。
為了平衡這種情況,實際業務中一般采用多級緩存,本地緩存只保存訪問頻率最高的部分熱點數據,其他的熱點數據放在分布式緩存中。
不管是本地緩存還是分布式緩存,為了保證較高性能,都是使用內存來保存數據,由于成本和內存限制,當存儲的數據超過緩存容量時,需要對緩存的數據進行剔除。
一般的剔除策略有 FIFO 淘汰最早數據、LRU 剔除最近最少使用、和 LFU 剔除最近使用頻率最低的數據幾種策略。
noeviction:返回錯誤當內存限制達到并且客戶端嘗試執行會讓更多內存被使用的命令(大部分的寫入指令,但DEL和幾個例外)
allkeys-lru: 嘗試回收最少使用的鍵(LRU),使得新添加的數據有空間存放。
volatile-lru: 嘗試回收最少使用的鍵(LRU),但僅限于在過期集合的鍵,使得新添加的數據有空間存放。
allkeys-random: 回收隨機的鍵使得新添加的數據有空間存放。
volatile-random: 回收隨機的鍵使得新添加的數據有空間存放,但僅限于在過期集合的鍵。
volatile-ttl: 回收在過期集合的鍵,并且優先回收存活時間(TTL)較短的鍵,使得新添加的數據有空間存放。
如果沒有鍵滿足回收的前提條件的話,策略volatile-lru, volatile-random以及volatile-ttl就和noeviction 差不多了。
使用Redis cluster,主從同步讀寫分離,類似Mysql的主從同步,Redis cluster 支撐 N 個 Redis master node,每個master node都可以掛載多個 slave node。
你啟動一臺slave 的時候,他會發送一個psync命令給master ,如果是這個slave第一次連接到master,他會觸發一個全量復制。master就會啟動一個線程,生成RDB快照,還會把新的寫請求都緩存在內存中,RDB文件生成后,master會將這個RDB發送給slave的,slave拿到之后做的第一件事情就是寫進本地的磁盤,然后加載進內存,然后master會把內存里面緩存的那些新命名都發給slave。
是有定期刪除+惰性刪除兩種。
定期好理解,默認100ms就隨機抽一些設置了過期時間的key,去檢查是否過期,過期了就刪了。
惰性策略:請求時判斷是否過去。
假如Redis里面所有的key都有過期時間,都掃描一遍?那太恐怖了,而且我們線上基本上也都是會設置一定的過期時間的。全掃描跟你去查數據庫不帶where條件不走索引全表掃描一樣,100ms一次,Redis累都累死了。
好問題,惰性刪除,見名知意,惰性嘛,我不主動刪,我懶,我等你來查詢了我看看你過期沒,過期就刪了還不給你返回,沒過期該怎么樣就怎么樣。
傳輸過程中有什么網絡問題啥的,會自動重連的,并且連接之后會把缺少的數據補上的。
如果第一個請求網絡延遲了 可能覆蓋之后的請求,造成數據不一致
1 使用分布式鎖
2 輸入時加入時間戳 通過時間戳判斷
在不要求效率的情況下,可以放入隊列中。 但是會引起阻塞。
讀緩存 ,緩存沒有讀db,保存到緩存
更新 先更新數據庫在刪除緩存
緩存來源不一定是一個操作,而且如果多次操作db,同時多次操作db同時多次更新緩存會造成很多冷數據。
Redis 內部使用文件事件處理器 file event handler,這個文件事件處理器是單線程的,所以 Redis 才叫做單線程的模型。它采用 IO 多路復用機制同時監聽多個 Socket,根據 Socket 上的事件來選擇對應的事件處理器進行處理。
文件事件處理器的結構包含 4 個部分:
多個 Socket
IO 多路復用程序
文件事件分派器
事件處理器(連接應答處理器、命令請求處理器、命令回復處理器)
多個 Socket 可能會并發產生不同的操作,每個操作對應不同的文件事件,但是 IO 多路復用程序會監聽多個 Socket,會將 Socket 產生的事件放入隊列中排隊,事件分派器每次從隊列中取出一個事件,把該事件交給對應的事件處理器進行處理。
第二個問題是數據不一致的問題,可以說只要使用緩存,就要考慮如何面對這個問題。緩存不一致產生的原因一般是主動更新失敗,例如更新 DB 后,更新 Redis 因為網絡原因請求超時;或者是異步更新失敗導致。
解決的辦法是,如果服務對耗時不是特別敏感可以增加重試;如果服務對耗時敏感可以通過異步補償任務來處理失敗的更新,或者短期的數據不一致不會影響業務,那么只要下次更新時可以成功,能保證最終一致性就可以。
比如 Redis 是單線程處理請求,應盡量避免耗時較高的單個請求任務,防止相互影響;Redis 服務應避免和其他 CPU 密集型的進程部署在同一機器;或者禁用 Swap 內存交換,防止 Redis 的緩存數據交換到硬盤上,影響性能。
Redis
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。