日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

10000字超全Redis面试题,再也不怕被问住了!

發(fā)布時(shí)間:2025/3/12 数据库 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 10000字超全Redis面试题,再也不怕被问住了! 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Redis 在當(dāng)今的計(jì)算機(jī)行業(yè),可以說是使用的最為廣泛的內(nèi)存數(shù)據(jù)庫,幾乎所有的后端技術(shù)面試都會(huì)涉及到 Redis 相關(guān)的知識(shí),正所謂知己知彼,百戰(zhàn)百勝。小白今天精心整理的超全的 Redis 面試題,希望可以幫助到在路上的你們~

什么是 Redis

Redis 是完全開源免費(fèi)的,遵守 BSD 協(xié)議,是一個(gè)高性能的 key-value 數(shù)據(jù)庫

是一個(gè)使用 C 語言開發(fā)的數(shù)據(jù)庫,不過與傳統(tǒng)數(shù)據(jù)庫不同的是 Redis 的數(shù)據(jù)是存在內(nèi)存中的,它是內(nèi)存數(shù)據(jù)庫,所以讀寫速度非常快,因此 Redis 被廣泛應(yīng)用于緩存方向

Redis 除了做緩存之外,也經(jīng)常用來做分布式鎖,甚至是消息隊(duì)列

Redis 還支持事務(wù) 、持久化、Lua 腳本、多種集群方案等,可以使用眾多復(fù)雜的業(yè)務(wù)場(chǎng)景

常見的分布式緩存技術(shù)

緩存使用的比較多的主要是 Memcached 和 Redis。不過現(xiàn)在使用 Memcached 做緩存的比較少

Memcached 是分布式緩存最開始興起的時(shí)候比較常用的方案,后來隨著 Redis 的發(fā)展,Redis 逐漸成為了人們的首選

分布式緩存主要解決的是單機(jī)緩存的容量受服務(wù)器限制并且無法保存通用信息的問題。因?yàn)楸镜鼐彺嬷辉诋?dāng)前服務(wù)里有效,比如如果你部署了兩個(gè)相同的服務(wù),他們兩者之間的緩存數(shù)據(jù)是無法共享的

Memcached 與 Redis 的異同

共同點(diǎn)

  • 都是基于內(nèi)存的數(shù)據(jù)庫,一般都用來當(dāng)作緩存使用

  • 都有過期策略

  • 兩者的性能都非常高

  • 異同點(diǎn)

  • Redis 支持更豐富的數(shù)據(jù)類型,Memcached 只支持最簡(jiǎn)單的 k/v 數(shù)據(jù)類型,所有的值均是簡(jiǎn)單的字符串

  • Redis 支持?jǐn)?shù)據(jù)的持久化,而 Memecache 把數(shù)據(jù)全部存在內(nèi)存之中,重啟之后數(shù)據(jù)丟失

  • Redis 有災(zāi)難恢復(fù)機(jī)制,因?yàn)榭梢园丫彺嬷械臄?shù)據(jù)持久化到磁盤上

  • Redis 在服務(wù)器內(nèi)存使用完之后,可以將不用的數(shù)據(jù)放到磁盤上。但 Memcached 在服務(wù)器內(nèi)存使用完之后,就會(huì)直接報(bào)異常

  • Memcached 沒有原生的集群模式,需要依靠客戶端來實(shí)現(xiàn)往集群中分片寫入數(shù)據(jù);但 Redis目前是原生支持 cluster 模式的

  • Memcached 是多線程,非阻塞 IO 復(fù)用的網(wǎng)絡(luò)模型;Redis 使用單線程的多路 IO 復(fù)用模型

  • Redis 支持發(fā)布訂閱模型、Lua 腳本、事務(wù)等功能,而 Memcached 不支持。并且,Redis 支持更多的編程語言

  • Memcached 過期數(shù)據(jù)的刪除策略只用了惰性刪除,而 Redis 同時(shí)使用了惰性刪除與定期刪除

  • Redis 的數(shù)據(jù)類型

    Redis 支持五種數(shù)據(jù)類型:string(字符串),hash(哈希),list(列表),set(集合)及 zsetsorted set:有序集合)

    實(shí)際中我們最為常用的還是 string 類型,不過還有幾種高級(jí)數(shù)據(jù)類型我們也需要了解掌握:BloomFilter,RedisSearch,Redis-ML,還有更高級(jí)的數(shù)據(jù)類型,BloomFilter,RedisSearch,Redis-ML 如果使用過,那么在面試官眼里都是加分項(xiàng)!

    緩存數(shù)據(jù)的處理流程

    緩存的簡(jiǎn)單處理流程如下:

  • 如果用戶請(qǐng)求的數(shù)據(jù)命中緩存,就直接返回

  • 緩存中不存在的話,查看數(shù)據(jù)庫中是否存在

  • 如果數(shù)據(jù)庫中存在,則更新緩存中的數(shù)據(jù)

  • 如果數(shù)據(jù)庫中不存在,則返回空數(shù)據(jù)

  • 上圖就是一個(gè)最為簡(jiǎn)易的緩存流程圖,從圖中我們也可以看出在使用緩存時(shí)的一系列注意事項(xiàng),比如當(dāng)緩存失效時(shí),如何更好的保護(hù)數(shù)據(jù)庫,如何保證數(shù)據(jù)庫與緩存數(shù)據(jù)一致等

    Redis 運(yùn)行模式(單進(jìn)程還是單線程)

    Redis 是單線程,利用隊(duì)列技術(shù)將并發(fā)訪問變?yōu)榇性L問,消除了傳統(tǒng)數(shù)據(jù)庫串行控制的開銷問題

    一個(gè)字符串能存儲(chǔ)的最大容量

    512 M

    為什么要使用緩存

    高性能

    將高頻訪問的數(shù)據(jù)放進(jìn)緩存,保證高頻操作可以快速響應(yīng),提高系統(tǒng)響應(yīng)速度和用戶體驗(yàn)

    高并發(fā)

    一般像 MySQL 這類數(shù)據(jù)庫的 QPS 大概都在 1w 左右(4 核 8g) ,但是使用 Redis 緩存之后很容易達(dá)到 10w+,甚至最高能達(dá)到 30w+(redis 集群的話會(huì)更高)

    QPS(Query Per Second):服務(wù)器每秒可以執(zhí)行的查詢次數(shù)

    所以增加緩存可以大大提高系統(tǒng)的并發(fā)能力

    具體說說 Redis 可以做什么

    緩存

    緩存機(jī)制幾乎在所有的大型網(wǎng)站都有使用,合理地使用緩存不僅可以加 快數(shù)據(jù)的訪問速度,而且能夠有效地降低后端數(shù)據(jù)源的壓力。Redis提供了鍵值過期時(shí)間設(shè)置,并且也提供了靈活控制最大內(nèi)存和內(nèi)存溢出后的淘汰策略。可以這么說,一個(gè)合理的緩存設(shè)計(jì)能夠很好的為一個(gè)網(wǎng)站的穩(wěn)定保駕護(hù)航

    排行榜系統(tǒng)

    排行榜系統(tǒng)幾乎存在于所有的網(wǎng)站,例如按照熱度排名的排行榜,按照 發(fā)布時(shí)間的排行榜,按照各種復(fù)雜維度計(jì)算出的排行榜,Redis提供了列表和有序集合數(shù)據(jù)結(jié)構(gòu),合理地使用這些數(shù)據(jù)結(jié)構(gòu)可以很方便地構(gòu)建各種排行榜系統(tǒng)

    計(jì)數(shù)器應(yīng)用

    計(jì)數(shù)器在網(wǎng)站中的作用至關(guān)重要,例如視頻網(wǎng)站有播放數(shù)、電商網(wǎng)站有 瀏覽數(shù),為了保證數(shù)據(jù)的實(shí)時(shí)性,每一次播放和瀏覽都要做加1的操作,如果并發(fā)量很大對(duì)于傳統(tǒng)關(guān)系型數(shù)據(jù)的性能是一種挑戰(zhàn)。Redis天然支持計(jì)數(shù)功能而且計(jì)數(shù)的性能也非常好,可以說是計(jì)數(shù)器系統(tǒng)的重要選擇

    社交網(wǎng)絡(luò)

    贊/踩、粉絲、共同好友/喜好、推送、下拉刷新等是社交網(wǎng)站的必備功能,由于社交網(wǎng)站訪問量通常比較大,而且傳統(tǒng)的關(guān)系型數(shù)據(jù)不太適合保存這種類型的數(shù)據(jù),Redis 提供的數(shù)據(jù)結(jié)構(gòu)可以相對(duì)比較容易地實(shí)現(xiàn)這些功能

    消息隊(duì)列系統(tǒng)

    消息隊(duì)列系統(tǒng)可以說是一個(gè)大型網(wǎng)站的必備基礎(chǔ)組件,因?yàn)槠渚哂袠I(yè)務(wù) 解耦、非實(shí)時(shí)業(yè)務(wù)削峰等特性。Redis 提供了發(fā)布訂閱功能和阻塞隊(duì)列的功能,雖然和專業(yè)的消息隊(duì)列比還不夠足夠強(qiáng)大,但是對(duì)于一般的消息隊(duì)列功能基本可以滿足

    哪些是 Redis 不可以(不擅長(zhǎng))做的

    我們可以站在數(shù)據(jù)規(guī)模和數(shù)據(jù)冷熱的角度來進(jìn)行分析

    站在數(shù)據(jù)規(guī)模的角度看,數(shù)據(jù)可以分為大規(guī)模數(shù)據(jù)和小規(guī)模數(shù)據(jù),我們 知道 Redis 的數(shù)據(jù)是存放在內(nèi)存中的,雖然現(xiàn)在內(nèi)存已經(jīng)足夠便宜,但是如果數(shù)據(jù)量非常大,例如每天有幾億的用戶行為數(shù)據(jù),使用 Redis 來存儲(chǔ)的話,基本上是個(gè)無底洞,經(jīng)濟(jì)成本相當(dāng)?shù)母?/p>

    站在數(shù)據(jù)冷熱的角度看,數(shù)據(jù)分為熱數(shù)據(jù)和冷數(shù)據(jù),熱數(shù)據(jù)通常是指需 要頻繁操作的數(shù)據(jù),反之為冷數(shù)據(jù),例如對(duì)于視頻網(wǎng)站來說,視頻基本信息基本上在各個(gè)業(yè)務(wù)線都是經(jīng)常要操作的數(shù)據(jù),而用戶的觀看記錄不一定是經(jīng)常需要訪問的數(shù)據(jù),這里暫且不討論兩者數(shù)據(jù)規(guī)模的差異,單純站在數(shù)據(jù)冷熱的角度上看,視頻信息屬于熱數(shù)據(jù),用戶觀看記錄屬于冷數(shù)據(jù)。如果將這些冷數(shù)據(jù)放在 Redis 中,基本上是對(duì)于內(nèi)存的一種浪費(fèi),但是對(duì)于一些熱數(shù)據(jù)可以放在 Redis 中加速讀寫,也可以減輕后端存儲(chǔ)的負(fù)載,可以說是事半功倍

    Redis 常見數(shù)據(jù)結(jié)構(gòu)與使用場(chǎng)景

    String

    String 數(shù)據(jù)結(jié)構(gòu)是簡(jiǎn)單的 key-value 類型,也是我們平時(shí)使用的最多的數(shù)據(jù)類型

    常用命令:set,get,strlen,exists,decr,incr,setex 等等

    應(yīng)用場(chǎng)景:一般常用在需要計(jì)數(shù)的場(chǎng)景,比如用戶的訪問次數(shù)、熱點(diǎn)文章的點(diǎn)贊轉(zhuǎn)發(fā)數(shù)量等等

    基本操作

    127.0.0.1:6379> set key value # 設(shè)置 key-value 類型的值 OK 127.0.0.1:6379> get key # 根據(jù) key 獲得對(duì)應(yīng)的 value "value" 127.0.0.1:6379> exists key # 判斷某個(gè) key 是否存在 (integer) 1 127.0.0.1:6379> strlen key # 返回 key 所儲(chǔ)存的字符串值的長(zhǎng)度 (integer) 5 127.0.0.1:6379> del key # 刪除某個(gè) key 對(duì)應(yīng)的值 (integer) 1 127.0.0.1:6379> get key (nil)Copy to clipboardErrorCopied

    批量設(shè)置

    127.0.0.1:6379> mset key1 value1 key2 value2 # 批量設(shè)置 key-value 類型的值 OK 127.0.0.1:6379> mget key1 key2 # 批量獲取多個(gè) key 對(duì)應(yīng)的 value 1) "value1" 2) "value2"Copy to clipboardErrorCopied

    計(jì)數(shù)器設(shè)置

    127.0.0.1:6379> set number 1 OK 127.0.0.1:6379> incr number # 將 key 中儲(chǔ)存的數(shù)字值增一 (integer) 2 127.0.0.1:6379> get number "2" 127.0.0.1:6379> decr number # 將 key 中儲(chǔ)存的數(shù)字值減一 (integer) 1 127.0.0.1:6379> get number "1"Copy to clipboardErrorCopied

    過期設(shè)置

    127.0.0.1:6379> expire key 60 # 數(shù)據(jù)在 60s 后過期 (integer) 1 127.0.0.1:6379> setex key 60 value # 數(shù)據(jù)在 60s 后過期 (setex:[set] + [ex]pire) OK 127.0.0.1:6379> ttl key # 查看數(shù)據(jù)還有多久過期 (integer) 56Copy to clipboardErrorCopied

    list

    list 即是鏈表,鏈表是一種非常常見的數(shù)據(jù)結(jié)構(gòu),特點(diǎn)是易于數(shù)據(jù)元素的插入和刪除并且可以靈活調(diào)整鏈表長(zhǎng)度,但是鏈表的隨機(jī)訪問困難

    常用命令:rpush,lpop,lpush,rpop,lrange,llen 等

    應(yīng)用場(chǎng)景:發(fā)布與訂閱或者說消息隊(duì)列、慢查詢等

    隊(duì)列和棧的實(shí)現(xiàn)

    通過 rpush/lpop 實(shí)現(xiàn)隊(duì)列

    127.0.0.1:6379> rpush myList value1 # 向 list 的頭部(右邊)添加元素 (integer) 1 127.0.0.1:6379> rpush myList value2 value3 # 向 list 的頭部(最右邊)添加多個(gè)元素 (integer) 3 127.0.0.1:6379> lpop myList # 將 list 的尾部(最左邊)元素取出 "value1" 127.0.0.1:6379> lrange myList 0 1 # 查看對(duì)應(yīng)下標(biāo)的 list 列表, 0 為 start,1為 end 1) "value2" 2) "value3" 127.0.0.1:6379> lrange myList 0 -1 # 查看列表中的所有元素,-1表示倒數(shù)第一 1) "value2" 2) "value3"Copy to clipboardErrorCopied

    通過 rpush/rpop 實(shí)現(xiàn)棧

    127.0.0.1:6379> rpush myList2 value1 value2 value3 (integer) 3 127.0.0.1:6379> rpop myList2 # 將 list的頭部(最右邊)元素取出 "value3"Copy to clipboardErrorCopied

    hash

    hash 類似于 JDK1.8 前的 HashMap,內(nèi)部實(shí)現(xiàn)也差不多(數(shù)組 + 鏈表),不過 Redis 的 hash 做了更多優(yōu)化。另外 hash 是一個(gè) string 類型的 field 和 value 的映射表,特別適合用于存 儲(chǔ)對(duì)象,比如我們可以用 hash 數(shù)據(jù)結(jié)構(gòu)來存儲(chǔ)用戶信息,商品信息等等

    常用命令:hset,hmset,hexists,hget,hgetall,hkeys,hvals 等

    應(yīng)用場(chǎng)景:系統(tǒng)中對(duì)象數(shù)據(jù)的存儲(chǔ)

    127.0.0.1:6379> hmset userInfoKey name "guide" description "dev" age "24" OK 127.0.0.1:6379> hexists userInfoKey name # 查看 key 對(duì)應(yīng)的 value 中指定的字段是否存在 (integer) 1 127.0.0.1:6379> hget userInfoKey name # 獲取存儲(chǔ)在哈希表中指定字段的值 "guide" 127.0.0.1:6379> hget userInfoKey age "24" 127.0.0.1:6379> hgetall userInfoKey # 獲取在哈希表中指定 key 的所有字段和值 1) "name" 2) "guide" 3) "description" 4) "dev" 5) "age" 6) "24" 127.0.0.1:6379> hkeys userInfoKey # 獲取 key 列表 1) "name" 2) "description" 3) "age" 127.0.0.1:6379> hvals userInfoKey # 獲取 value 列表 1) "guide" 2) "dev" 3) "24" 127.0.0.1:6379> hset userInfoKey name "GuideGeGe" # 修改某個(gè)字段對(duì)應(yīng)的值 127.0.0.1:6379> hget userInfoKey name "GuideGeGe"Copy to clipboardErrorCopied

    set

    set 類似于 Java 中的 HashSet,Redis 中的 set 類型是一種無序集合,集合中的元素沒有先后順序。當(dāng)你需要存儲(chǔ)一個(gè)列表數(shù)據(jù),又不希望出現(xiàn)重復(fù)數(shù)據(jù)時(shí),set 是一個(gè)很好的選擇,并且 set 提供了判斷某個(gè)成員是否在一個(gè) set 集合內(nèi)的重要接口,這個(gè)也是 list 所不能提供的。可以基于 set 輕易實(shí)現(xiàn)交集、并集、差集的操作。如:可以將一個(gè)用戶所有的關(guān)注人存在一個(gè)集合中,將其所有粉絲存在一個(gè)集合。Redis 可以非常方便的實(shí)現(xiàn)如共同關(guān)注、共同粉絲、共同喜好等功能

    常用命令:sadd,spop,smembers,sismember,scard,sinterstore,sunion 等

    應(yīng)用場(chǎng)景:需要存放的數(shù)據(jù)不能重復(fù)以及需要獲取多個(gè)數(shù)據(jù)源交集和并集等場(chǎng)景

    127.0.0.1:6379> sadd mySet value1 value2 # 添加元素進(jìn)去 (integer) 2 127.0.0.1:6379> sadd mySet value1 # 不允許有重復(fù)元素 (integer) 0 127.0.0.1:6379> smembers mySet # 查看 set 中所有的元素 1) "value1" 2) "value2" 127.0.0.1:6379> scard mySet # 查看 set 的長(zhǎng)度 (integer) 2 127.0.0.1:6379> sismember mySet value1 # 檢查某個(gè)元素是否存在set 中,只能接收單個(gè)元素 (integer) 1 127.0.0.1:6379> sadd mySet2 value2 value3 (integer) 2 127.0.0.1:6379> sinterstore mySet3 mySet mySet2 # 獲取 mySet 和 mySet2 的交集并存放 在 mySet3 中 (integer) 1 127.0.0.1:6379> smembers mySet3 1) "value2"Copy to clipboardErrorCopied

    sorted set

    和 set 相比,sorted set 增加了一個(gè)權(quán)重參數(shù) score,使得集合中的元素能夠按 score 進(jìn)行有序排列,還可以通過 score 的范圍來獲取元素的列表

    常用命令:zadd,zcard,zscore,zrange,zrevrange,zrem 等

    應(yīng)用場(chǎng)景:需要對(duì)數(shù)據(jù)根據(jù)某個(gè)權(quán)重進(jìn)行排序的場(chǎng)景。比如在直播系統(tǒng)中,實(shí)時(shí)排行信息包含直播間在線用戶列表,各種禮物排行榜,彈幕消息等信息

    127.0.0.1:6379> zadd myZset 3.0 value1 # 添加元素到 sorted set 中 3.0 為權(quán)重 (integer) 1 127.0.0.1:6379> zadd myZset 2.0 value2 1.0 value3 # 一次添加多個(gè)元素 (integer) 2 127.0.0.1:6379> zcard myZset # 查看 sorted set 中的元素?cái)?shù)量 (integer) 3 127.0.0.1:6379> zscore myZset value1 # 查看某個(gè) value 的權(quán)重 "3" 127.0.0.1:6379> zrange myZset 0 -1 # 順序輸出某個(gè)范圍區(qū)間的元素,0 -1 表示輸出所有元素 1) "value3" 2) "value2" 3) "value1" 127.0.0.1:6379> zrange myZset 0 1 # 順序輸出某個(gè)范圍區(qū)間的元素,0 為 start 1 為 stop 1) "value3" 2) "value2" 127.0.0.1:6379> zrevrange myZset 0 1 # 逆序輸出某個(gè)范圍區(qū)間的元素,0 為 start 1 為 stop 1) "value1" 2) "value2"Copy to clipboardErrorCopied

    bitmap

    bitmap 存儲(chǔ)的是連續(xù)的二進(jìn)制數(shù)字(0 和 1),通過 bitmap, 只需要一個(gè) bit 位來表示某個(gè)元素對(duì)應(yīng)的值或者狀態(tài),key 就是對(duì)應(yīng)元素本身。我們知道 8 個(gè) bit 可以組成一個(gè) byte,所以 bitmap 本身會(huì)極大的節(jié)省儲(chǔ)存空間

    常用命令:setbit 、 getbit 、 bitcount 、 bitop

    應(yīng)用場(chǎng)景:適合需要保存狀態(tài)信息(比如是否簽到、是否登錄...)并需要進(jìn)一步對(duì)這些信息進(jìn)行分析的場(chǎng)景。比如用戶簽到情況、活躍用戶情況、用戶行為統(tǒng)計(jì)

    # SETBIT 會(huì)返回之前位的值(默認(rèn)是 0)這里會(huì)生成 7 個(gè)位 127.0.0.1:6379> setbit mykey 7 1 (integer) 0 127.0.0.1:6379> setbit mykey 7 0 (integer) 1 127.0.0.1:6379> getbit mykey 7 (integer) 0 127.0.0.1:6379> setbit mykey 6 1 (integer) 0 127.0.0.1:6379> setbit mykey 8 1 (integer) 0 # 通過 bitcount 統(tǒng)計(jì)被被設(shè)置為 1 的位的數(shù)量。 127.0.0.1:6379> bitcount mykey (integer) 2Copy to clipboardErrorCopied

    Redis 為什么不用多線程以及為什么 Redis6.0 之后又引入了多線程

    使用單線程的原因

  • 單線程編程更容易并且更容易維護(hù)

  • Redis 的性能瓶頸不在 CPU ,主要在內(nèi)存和網(wǎng)絡(luò)

  • 多線程就會(huì)存在死鎖、線程上下文切換等問題,甚至?xí)绊懶阅?/p>

  • Redis6.0 引入多線程主要是為了提高網(wǎng)絡(luò) IO 讀寫性能,因?yàn)檫@個(gè)是 Redis 中的一個(gè)性能瓶頸

    雖然 Redis6.0 引入了多線程,但是 Redis 的多線程只是在網(wǎng)絡(luò)數(shù)據(jù)的讀寫這類耗時(shí)操作上使用了,執(zhí)行命令仍然是單線程順序執(zhí)行

    設(shè)置緩存過期的作用

    因?yàn)閮?nèi)存是有限的,如果緩存中的所有數(shù)據(jù)都是一直保存的話,很快就會(huì) Out of memory 了

    Redis 中除了字符串類型有自己獨(dú)有設(shè)置過期時(shí)間的命令 setex 外,其他方法都需要依靠 expire 命令來設(shè)置過期時(shí)間 。另外 persist 命令可以移除一個(gè)鍵的過期時(shí)間

    還有一種情況需要設(shè)置過期時(shí)間,當(dāng)我們的業(yè)務(wù)場(chǎng)景就是需要某個(gè)數(shù)據(jù)只在某一時(shí)間段內(nèi)存在,比如我們的短信驗(yàn)證碼可能只在 1 分鐘內(nèi)有效,用戶登錄的 token 可能只在 1 天內(nèi)有效,此時(shí)設(shè)置過期時(shí)間就能比較好的處理,如果使用傳統(tǒng)的數(shù)據(jù)庫來處理的話,一般都是自己判斷過期,這樣更麻煩并且性能要差很多

    Redis 過期刪除策略

  • 定時(shí)刪除:在設(shè)置鍵的過期時(shí)間的同時(shí),創(chuàng)建一個(gè)定時(shí)器 time,讓定時(shí)器在鍵的過期時(shí)間來臨時(shí),立即執(zhí)行對(duì)鍵的刪除操作

  • 惰性刪除:放任鍵過期不管,但是每次從鍵空間中獲取鍵時(shí),都檢查取得的鍵是否過期,如果過期的話,就刪除該鍵;如果沒有過期,就返回該鍵

  • 定期刪除:每隔一段時(shí)間程序就對(duì)數(shù)據(jù)庫進(jìn)行一次檢查,刪除里面的過期鍵。至于要?jiǎng)h除多少過期鍵,以及要檢查多少個(gè)數(shù)據(jù)庫,則由算法決定

  • 更新策略對(duì)比

    Redis 內(nèi)存淘汰機(jī)制

    Redis 提供 6 種數(shù)據(jù)淘汰策略:

  • volatile-lru(least recently used):從已設(shè)置過期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中挑選最近最少使用的數(shù)據(jù)淘汰

  • volatile-ttl:從已設(shè)置過期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中挑選將要過期的數(shù)據(jù)淘汰

  • volatile-random:從已設(shè)置過期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中任意選擇數(shù)據(jù)淘汰

  • allkeys-lru(least recently used):當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí),在鍵空間中,移除最近最少使用的 key(這個(gè)是最常用的)

  • allkeys-random:從數(shù)據(jù)集(server.db[i].dict)中任意選擇數(shù)據(jù)淘汰

  • no-eviction:禁止驅(qū)逐數(shù)據(jù),也就是說當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí),新寫入操作會(huì)報(bào)錯(cuò)

  • 4.0 版本后增加以下兩種:

  • volatile-lfu(least frequently used):從已設(shè)置過期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中挑選最不經(jīng)常使用的數(shù)據(jù)淘汰

  • allkeys-lfu(least frequently used):當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí),在鍵空間中,移除最不經(jīng)常使用的 key

  • 使用策略的規(guī)則:

    (1)如果數(shù)據(jù)呈現(xiàn)冪律分布,也就是一部分?jǐn)?shù)據(jù)訪問頻率高,一部分?jǐn)?shù)據(jù)訪問頻率低,則使用 allkeys-lru

    (2)如果數(shù)據(jù)呈現(xiàn)平等分布,也就是所有的數(shù)據(jù)訪問頻率都相同,則使用 allkeys-random

    Redis 持久化

    Redis 的一種持久化方式叫快照(snapshotting,RDB),另一種方式是只追加文件(append-only file, AOF)

    快照(snapshotting)持久化(RDB)

    Redis 可以通過創(chuàng)建快照來獲得存儲(chǔ)在內(nèi)存里面的數(shù)據(jù)在某個(gè)時(shí)間點(diǎn)上的副本。Redis 創(chuàng)建快照之后,可以對(duì)快照進(jìn)行備份,可以將快照復(fù)制到其他服務(wù)器從而創(chuàng)建具有相同數(shù)據(jù)的服務(wù)器副本(Redis 主從結(jié)構(gòu),主要用來提高 Redis 性能),還可以將快照留在原地以便重啟服務(wù)器的時(shí)候使用

    AOF(append-only file)持久化

    與快照持久化相比,AOF 持久化的實(shí)時(shí)性更好,因此已成為主流的持久化方案,是指所有的命令行記錄以 Redis 命令請(qǐng)求協(xié)議的格式完全持久化存儲(chǔ))保存為 aof 文件

    默認(rèn)沒有開啟 AOF,可以通過如下命令開啟

    appendonly yesCopy to clipboardErrorCopied

    兩種持久化方案對(duì)比:

    Redis 常見的性能問題

  • Master 最好不要寫內(nèi)存快照,如果 Master 寫內(nèi)存快照,save 命令調(diào)度 rdbSave 函數(shù),會(huì)阻塞主線程的工作,當(dāng)快照比較大時(shí)對(duì)性能影響會(huì)非常大,會(huì)間斷性暫停服務(wù)

  • 如果數(shù)據(jù)比較重要,需要在某個(gè) Slave 開啟 AOF 備份數(shù)據(jù),策略設(shè)置為每秒同步一次

  • 為了主從復(fù)制的速度和連接的穩(wěn)定性,Master 和 Slave 最好在同一個(gè)局域網(wǎng)

  • 盡量避免在壓力很大的主庫上增加從庫

  • 主從復(fù)制不要用圖狀結(jié)構(gòu),用單向鏈表結(jié)構(gòu)更為穩(wěn)定,即:Master <- Slave1<- Slave2 <- Slave3…這樣的結(jié)構(gòu)方便解決單點(diǎn)故障問題,實(shí)現(xiàn) Slave 對(duì) Master 的替換。如果 Master 掛了,可以立刻啟用 Slave1 做 Master,其他不變

  • Redis 同步機(jī)制

    Redis 可以使用主從同步,從從同步。第一次同步時(shí),主節(jié)點(diǎn)做一次 bgsave,并同時(shí)將后續(xù)修改操作記錄到內(nèi)存 buffer,待完成后將 rdb 文件全量同步到復(fù)制節(jié)點(diǎn),復(fù)制節(jié)點(diǎn)接收完成后將 rdb 鏡像加載到內(nèi)存。加載完成后,再通知主節(jié)點(diǎn)將期間修改的操作記錄同步到復(fù)制節(jié)點(diǎn)進(jìn)行重放就完成了同步過程

    Redis 主從同步有新舊兩種方案,具體看下面圖示

    老方案:

    新方案:

    Pipeline 的好處

    可以將多次 IO 往返的時(shí)間縮減為一次,前提是 pipeline 執(zhí)行的指令之間沒有因果相關(guān)性。使用 redis-benchmark 進(jìn)行壓測(cè)的時(shí)候可以發(fā)現(xiàn)影響 Redis 的 QPS 峰值的一個(gè)重要因素是 pipeline 批次指令的數(shù)目

    緩存穿透

    緩存穿透說簡(jiǎn)單點(diǎn)就是大量請(qǐng)求的 key 根本不存在于緩存中,導(dǎo)致請(qǐng)求直接到了數(shù)據(jù)庫上,根本沒有經(jīng)過緩存這一層。比如某個(gè)攻擊者故意制造我們緩存中不存在的 key 發(fā)起大量請(qǐng)求,導(dǎo)致大量請(qǐng)求落到數(shù)據(jù)庫上,使得數(shù)據(jù)庫由于性能的原因崩潰,導(dǎo)致系統(tǒng)異常

    緩存穿透問題產(chǎn)生

    解決辦法:

  • 緩存無效 key

  • 如果緩存和數(shù)據(jù)庫都查不到某個(gè) key 的數(shù)據(jù)就寫一個(gè)到 Redis 中去并設(shè)置過期時(shí)間,可以解決請(qǐng)求的 key 變化不頻繁的情況,如果攻擊者的惡意攻擊,每次構(gòu)建不同的請(qǐng)求 key,會(huì)導(dǎo)致 Redis 中緩存大量無效的 key 。很明顯,這種方案并不能從根本上解決此問題

  • 使用布隆過濾器

  • 布隆過濾器是一個(gè)非常神奇的數(shù)據(jù)結(jié)構(gòu),通過它我們可以非常方便地判斷一個(gè)給定數(shù)據(jù)是否存在于海量數(shù)據(jù)中

    具體是這樣做的:把所有可能存在的請(qǐng)求的值都存放在布隆過濾器中,當(dāng)用戶請(qǐng)求過來,先判斷用戶發(fā)來的請(qǐng)求的值是否存在于布隆過濾器中。不存在的話,直接返回請(qǐng)求參數(shù)錯(cuò)誤信息給客戶端,存在的話才會(huì)走下面的流程

    緩存雪崩

    緩存雪崩描述的就是這樣一個(gè)簡(jiǎn)單的場(chǎng)景:緩存在同一時(shí)間大面積的失效,后面的請(qǐng)求都直接落到了數(shù)據(jù)庫上,造成數(shù)據(jù)庫短時(shí)間內(nèi)承受大量請(qǐng)求

    還有一種緩存雪崩的場(chǎng)景是:有一些被大量訪問數(shù)據(jù)(熱點(diǎn)緩存)在某一時(shí)刻大面積失效,導(dǎo)致對(duì)應(yīng)的請(qǐng)求直接落到了數(shù)據(jù)庫上

    以上兩種常見,就好比雪崩一樣,摧枯拉朽之勢(shì),數(shù)據(jù)庫的壓力可想而知,可能直接就被這么多請(qǐng)求弄宕機(jī)了

    解決辦法

    針對(duì) Redis 服務(wù)不可用的情況:

  • 采用 Redis 集群,避免單機(jī)出現(xiàn)問題整個(gè)緩存服務(wù)都沒辦法使用

  • 限流,避免同時(shí)處理大量的請(qǐng)求

  • 針對(duì)熱點(diǎn)緩存失效的情況:

  • 設(shè)置不同的失效時(shí)間比如隨機(jī)設(shè)置緩存的失效時(shí)間

  • 緩存永不失效

  • 緩存擊穿

    如果緩存中的某個(gè)熱點(diǎn)數(shù)據(jù)過期了,此時(shí)大量的請(qǐng)求訪問了該熱點(diǎn)數(shù)據(jù),就無法從緩存中讀取,直接訪問數(shù)據(jù)庫,數(shù)據(jù)庫很容易就被高并發(fā)的請(qǐng)求沖垮,這就是緩存擊穿的問題

    擊穿其實(shí)可以看做是雪崩的一個(gè)子集,解決方法一般有兩種,設(shè)置熱點(diǎn)數(shù)據(jù)永不過期和設(shè)置互斥鎖

    所謂的互斥鎖,就是保證同一時(shí)間只有一個(gè)業(yè)務(wù)線程更新緩存,對(duì)于沒有獲取互斥鎖的請(qǐng)求,要么等待鎖釋放后重新讀取緩存,要么就返回空值或者默認(rèn)值

    如何保證緩存和數(shù)據(jù)庫的數(shù)據(jù)一致性

    其實(shí)這是一個(gè)非常龐大且復(fù)雜的問題,根本不是一兩句話能夠說清楚的,如果要完全規(guī)避一致性問題,那么整個(gè)系統(tǒng)也會(huì)變得非常復(fù)雜

    一般來說可以進(jìn)行如下處理:更新 DB,然后刪除 cache

    當(dāng)然此時(shí)有可能遇到更新 DB 成功,但是刪除 cache 失敗的情況,處理辦法大致有兩種:

  • 緩存失效時(shí)間變短(不推薦,治標(biāo)不治本) :我們讓緩存數(shù)據(jù)的過期時(shí)間變短,這樣的話緩存就會(huì)從數(shù)據(jù)庫中加載數(shù)據(jù)。另外,這種解決辦法對(duì)于先操作緩存后操作數(shù)據(jù)庫的場(chǎng)景不適用

  • 增加 cache 更新重試機(jī)制(常用):如果 cache 服務(wù)當(dāng)前不可用導(dǎo)致緩存刪除失敗的話,我們就隔一段時(shí)間進(jìn)行重試,重試次數(shù)可以自己定。如果多次重試還是失敗的話,我們可以把當(dāng)前更新失敗的 key 存入隊(duì)列中,等緩存服務(wù)可用之后,再將緩存中對(duì)應(yīng)的 key 刪除即可

  • 簡(jiǎn)單介紹 Redis 事物

    Redis 事務(wù)可以一次執(zhí)行多個(gè)命令,并且?guī)в幸韵氯齻€(gè)重要的保證:

    • 批量操作在發(fā)送 EXEC 命令前被放入隊(duì)列緩存

    • 收到 EXEC 命令后進(jìn)入事務(wù)執(zhí)行,事務(wù)中任意命令執(zhí)行失敗,其余的命令依然被執(zhí)行

    • 在事務(wù)執(zhí)行過程,其他客戶端提交的命令請(qǐng)求不會(huì)插入到事務(wù)執(zhí)行命令序列中

    一個(gè)事務(wù)從開始到執(zhí)行會(huì)經(jīng)歷以下三個(gè)階段:

    • 開始事務(wù)

    • 命令入隊(duì)

    • 執(zhí)行事務(wù)

    命令:

    • DISCARD 取消事務(wù),放棄執(zhí)行事務(wù)塊內(nèi)的所有命令

    • EXEC 執(zhí)行所有事務(wù)塊內(nèi)的命令

    • MULTI 標(biāo)記一個(gè)事務(wù)塊的開始

    • UNWATCH 取消 WATCH 命令對(duì)所有 key 的監(jiān)視

    • WATCH key [key ...] 監(jiān)視一個(gè)(或多個(gè)) key ,如果在事務(wù)執(zhí)行之前這個(gè)(或這些) key 被其他命令所改動(dòng),那么事務(wù)將被打斷

    Redis 集群

    (1)Redis Sentinal 著眼于高可用,在 master 宕機(jī)時(shí)會(huì)自動(dòng)將 slave 提升為 master,繼續(xù)提供服務(wù)

    (2)Redis Cluster 著眼于擴(kuò)展性,在單個(gè) redis 內(nèi)存不足時(shí),使用 Cluster 進(jìn)行分片存儲(chǔ)

    集群之間是異步復(fù)制的,最大節(jié)點(diǎn)個(gè)數(shù)為16384個(gè),Redis 集群目前無法做數(shù)據(jù)庫選擇,默認(rèn)在 0 數(shù)據(jù)庫

    為了使在部分節(jié)點(diǎn)失敗或者大部分節(jié)點(diǎn)無法通信的情況下集群仍然可用,所以集群使用了主從復(fù)制模型,每個(gè)節(jié)點(diǎn)都會(huì)有 N-1 個(gè)復(fù)制品

    Redis 并不能保證數(shù)據(jù)的強(qiáng)一致性,這意味著在實(shí)際中集群在特定的條件下可能會(huì)丟失寫操作

    Redis 內(nèi)存優(yōu)化

    盡可能使用散列表(hashes),散列表(是說散列表里面存儲(chǔ)的數(shù)少)使用的內(nèi)存非常小,所以你應(yīng)該盡可能的將你的數(shù)據(jù)模型抽象到一個(gè)散列表里面。比如你的 web 系統(tǒng)中有一個(gè)用戶對(duì)象,不要為這個(gè)用戶的名稱,姓氏,郵箱,密碼設(shè)置單獨(dú)的 key,而是應(yīng)該把這個(gè)用戶的所有信息存儲(chǔ)到一張散列表里面

    一個(gè) Redis 實(shí)例最多能存放多少的 keys?各數(shù)據(jù)類型最多能存放多少元素

    理論上 Redis 可以處理多達(dá) 232 的 keys,并且在實(shí)際中進(jìn)行了測(cè)試,每個(gè)實(shí)例至少存放了 2 億 5 千萬的 keys。任何 list、set、和 sorted set 都可以放 232 個(gè)元素。換句話說,Redis 的存儲(chǔ)極限是系統(tǒng)中的可用內(nèi)存值

    如何保證 Redis 中的20W數(shù)據(jù)都是數(shù)據(jù)庫中200W數(shù)據(jù)的熱點(diǎn)數(shù)據(jù)

    正確設(shè)置內(nèi)存淘汰策略,當(dāng) Redis 內(nèi)存數(shù)據(jù)集大小上升到一定大小的時(shí)候,就會(huì)施行數(shù)據(jù)淘汰策略,從而剩下的數(shù)據(jù)就是熱點(diǎn)數(shù)據(jù)

    如何將10W個(gè)以某個(gè)固定前綴開頭的key全部找出

    使用 keys 指令可以掃出指定模式的 key 列表,但是,keys 指令會(huì)導(dǎo)致線程阻塞一段時(shí)間,此時(shí)整個(gè) Redis 系統(tǒng)不再能接受其他指令

    這個(gè)時(shí)候可以使用 scan 指令,scan 指令可以無阻塞的提取出指定模式的 key 列表,但是會(huì)有一定的重復(fù)概率,在客戶端做一次去重就可以了,但是整體所花費(fèi)的時(shí)間會(huì)比直接用 keys 指令長(zhǎng),但是安全性更高!

    如果有大量的 key 需要設(shè)置同一時(shí)間過期,一般需要注意什么

    如果大量的 key 過期時(shí)間設(shè)置的過于集中,到過期的那個(gè)時(shí)間點(diǎn),Redis 可能會(huì)出現(xiàn)短暫的卡頓現(xiàn)象。一般需要在時(shí)間上加一個(gè)隨機(jī)值,使得過期時(shí)間分散一些

    Redis 分布式鎖

    通過 SETNX 來爭(zhēng)搶鎖,再用 EXPIRE 給鎖加一個(gè)過期時(shí)間,當(dāng)然為了保證 SETNX 和 EXPIRE 原子性執(zhí)行,在 Redis 2.6.12 之后,Redis 擴(kuò)展了 SET 命令的參數(shù),用這一條命令就可以了:

    127.0.0.1:6379> SET lock 1 EX 10 NX OK

    好了,這就是今天的內(nèi)容,如果你覺得對(duì)你有所幫助,就點(diǎn)贊+在看支持一下吧~

    往期精彩回顧適合初學(xué)者入門人工智能的路線及資料下載中國(guó)大學(xué)慕課《機(jī)器學(xué)習(xí)》(黃海廣主講)機(jī)器學(xué)習(xí)及深度學(xué)習(xí)筆記等資料打印機(jī)器學(xué)習(xí)在線手冊(cè)深度學(xué)習(xí)筆記專輯《統(tǒng)計(jì)學(xué)習(xí)方法》的代碼復(fù)現(xiàn)專輯 AI基礎(chǔ)下載本站qq群955171419,加入微信群請(qǐng)掃碼:

    總結(jié)

    以上是生活随笔為你收集整理的10000字超全Redis面试题,再也不怕被问住了!的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。