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

歡迎訪問 生活随笔!

生活随笔

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

数据库

Redis常见问题及其一些重点知识总结

發(fā)布時(shí)間:2023/11/30 数据库 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Redis常见问题及其一些重点知识总结 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1、什么是 Redis?簡述它的優(yōu)缺點(diǎn)?

Redis 的全稱是:Remote Dictionary.Server,本質(zhì)上是一個(gè) Key-Value 類型的內(nèi)存數(shù)據(jù)庫,很像

memcached,整個(gè)數(shù)據(jù)庫統(tǒng)統(tǒng)加載在內(nèi)存當(dāng)中進(jìn)行操作,定期通過異步操作把數(shù)據(jù)庫數(shù)據(jù) flush 到硬盤上進(jìn)行保存。

因?yàn)槭羌儍?nèi)存操作,Redis 的性能非常出色,每秒可以處理超過 10 萬次讀寫操作,是已知性能最快的Key-Value DB。

Redis 的出色之處不僅僅是性能,Redis 最大的魅力是支持保存多種數(shù)據(jù)結(jié)構(gòu),此外單個(gè) value 的最大限制是 1GB,不像 memcached 只能保存 1MB 的數(shù)據(jù),因此 Redis 可以用來實(shí)現(xiàn)很多有用的功能。

比方說用他的 List 來做 FIFO 雙向鏈表,實(shí)現(xiàn)一個(gè)輕量級的高性 能消息隊(duì)列服務(wù),用他的 Set 可以做高性能的 tag 系統(tǒng)等等。

另外 Redis 也可以對存入的 Key-Value 設(shè)置 expire 時(shí)間,因此也可以被當(dāng)作一 個(gè)功能加強(qiáng)版的memcached 來用。 Redis 的主要缺點(diǎn)是數(shù)據(jù)庫容量受到物理內(nèi)存的限制,不能用作海量數(shù)據(jù)的高性能讀寫,因此 Redis 適合的場景主要局限在較小數(shù)據(jù)量的高性能操作和運(yùn)算上。

2、Redis 與 memcached 相比有哪些優(yōu)勢?

1.memcached 所有的值均是簡單的字符串,redis 作為其替代者,支持更為豐富的數(shù)據(jù)類型

2.redis 的速度比 memcached 快很多 redis 的速度比 memcached 快很多

3.redis 可以持久化其數(shù)據(jù) redis 可以持久化其數(shù)據(jù)

3、Redis 支持哪幾種數(shù)據(jù)類型?

String、List、Set、Sorted Set、hashes

4、Redis 主要消耗什么物理資源?

內(nèi)存。

5、Redis 有哪幾種數(shù)據(jù)淘汰策略?

1.noeviction:返回錯(cuò)誤當(dāng)內(nèi)存限制達(dá)到,并且客戶端嘗試執(zhí)行會讓更多內(nèi)存被使用的命令。

2.allkeys-lru: 嘗試回收最少使用的鍵(LRU),使得新添加的數(shù)據(jù)有空間存放。

3.volatile-lru: 嘗試回收最少使用的鍵(LRU),但僅限于在過期集合的鍵,使得新添加的數(shù)據(jù)有空間存放。

4.allkeys-random: 回收隨機(jī)的鍵使得新添加的數(shù)據(jù)有空間存放。

5.volatile-random: 回收隨機(jī)的鍵使得新添加的數(shù)據(jù)有空間存放,但僅限于在過期集合的鍵。

6.volatile-ttl: 回收在過期集合的鍵,并且優(yōu)先回收存活時(shí)間(TTL)較短的鍵,使得新添加的數(shù)據(jù)有空間存放。

6、Redis 官方為什么不提供 Windows 版本?

因?yàn)槟壳?Linux 版本已經(jīng)相當(dāng)穩(wěn)定,而且用戶量很大,無需開發(fā) windows 版本,反而會帶來兼容性等問題。

7、一個(gè)字符串類型的值能存儲最大容量是多少?

512M

8、為什么 Redis 需要把所有數(shù)據(jù)放到內(nèi)存中?

Redis 為了達(dá)到最快的讀寫速度將數(shù)據(jù)都讀到內(nèi)存中,并通過異步的方式將數(shù)據(jù)寫入磁盤。

所以 redis 具有快速和數(shù)據(jù)持久化的特征,如果不將數(shù)據(jù)放在內(nèi)存中,磁盤 I/O 速度為嚴(yán)重影響 redis 的性能。

在內(nèi)存越來越便宜的今天,redis 將會越來越受歡迎, 如果設(shè)置了最大使用的內(nèi)存,則數(shù)據(jù)已有記錄數(shù)達(dá)到內(nèi)存限值后不能繼續(xù)插入新值。

9、Redis 集群方案應(yīng)該怎么做?都有哪些方案?

1.codis

2.目前用的最多的集群方案,基本和 twemproxy 一致的效果,但它支持在節(jié)點(diǎn)數(shù)量改變情況下,舊節(jié)點(diǎn)數(shù)據(jù)可恢復(fù)到新 hash 節(jié)點(diǎn)。

redis cluster3.0 自帶的集群,特點(diǎn)在于他的分布式算法不是一致性 hash,而是 hash 槽的概念,以及自身支持節(jié)點(diǎn)設(shè)置從節(jié)點(diǎn)。具體看官方文檔介紹。

3.在業(yè)務(wù)代碼層實(shí)現(xiàn),起幾個(gè)毫無關(guān)聯(lián)的 redis 實(shí)例,在代碼層,對 key 進(jìn)行 hash 計(jì)算,然后去對應(yīng)的redis 實(shí)例操作數(shù)據(jù)。這種方式對 hash 層代碼要求比較高,考慮部分包括,節(jié)點(diǎn)失效后的替代算法方案,數(shù)據(jù)震蕩后的自動腳本恢復(fù),實(shí)例的監(jiān)控,等等。

10、Redis 集群方案什么情況下會導(dǎo)致整個(gè)集群不可用?

有 A,B,C 三個(gè)節(jié)點(diǎn)的集群,在沒有復(fù)制模型的情況下,如果節(jié)點(diǎn) B 失敗了,那么整個(gè)集群就會以為缺少5501-11000 這個(gè)范圍的槽而不可用。

11、MySQL 里有 2000w 數(shù)據(jù),redis 中只存 20w 的數(shù)據(jù),如何保證 redis 中的數(shù)據(jù)都是熱點(diǎn)數(shù)據(jù)?

redis 內(nèi)存數(shù)據(jù)集大小上升到一定大小的時(shí)候,就會施行數(shù)據(jù)淘汰策略。

其實(shí)面試除了考察 Redis,不少公司都很重視高并發(fā)高可用的技術(shù),特別是一線互聯(lián)網(wǎng)公司,分布式、

12、Redis 有哪些適合的場景?

(1)會話緩存(Session Cache)

最常用的一種使用 Redis 的情景是會話緩存(sessioncache),用 Redis 緩存會話比其他存儲(如Memcached)的優(yōu)勢在于:Redis 提供持久化。當(dāng)維護(hù)一個(gè)不是嚴(yán)格要求一致性的緩存時(shí),如果用戶的購物車信息全部丟失,大部分人都會不高興的,現(xiàn)在,他們還會這樣嗎?

幸運(yùn)的是,隨著 Redis 這些年的改進(jìn),很容易找到怎么恰當(dāng)?shù)氖褂?Redis 來緩存會話的文檔。甚至廣為人知的商業(yè)平臺 Magento 也提供 Redis 的插件。

(2)全頁緩存(FPC)

除基本的會話 token 之外,Redis 還提供很簡便的 FPC 平臺。回到一致性問題,即使重啟了 Redis 實(shí)例,因?yàn)橛写疟P的持久化,用戶也不會看到頁面加載速度的下降,這是一個(gè)極大改進(jìn),類似 PHP 本地FPC。

再次以 Magento 為例,Magento 提供一個(gè)插件來使用 Redis 作為全頁緩存后端。

此外,對 WordPress 的用戶來說,Pantheon 有一個(gè)非常好的插件 wp-redis,這個(gè)插件能幫助你以最快速度加載你曾瀏覽過的頁面。

(3)隊(duì)列

Reids 在內(nèi)存存儲引擎領(lǐng)域的一大優(yōu)點(diǎn)是提供 list 和 set 操作,這使得 Redis 能作為一個(gè)很好的消息隊(duì)列平臺來使用。Redis 作為隊(duì)列使用的操作,就類似于本地程序語言(如 Python)對 list 的 push/pop操作。

如果你快速的在 Google 中搜索“Redis queues”,你馬上就能找到大量的開源項(xiàng)目,這些項(xiàng)目的目的就是利用 Redis 創(chuàng)建非常好的后端工具,以滿足各種隊(duì)列需求。例如,Celery 有一個(gè)后臺就是使用Redis 作為 broker,你可以從這里去查看。

(4)排行榜/計(jì)數(shù)器

Redis 在內(nèi)存中對數(shù)字進(jìn)行遞增或遞減的操作實(shí)現(xiàn)的非常好。集合(Set)和有序集合(SortedSet)也使得我們在執(zhí)行這些操作的時(shí)候變的非常簡單,Redis 只是正好提供了這兩種數(shù)據(jù)結(jié)構(gòu)。

所以,我們要從排序集合中獲取到排名最靠前的 10 個(gè)用戶–我們稱之為“user_scores”,我們只需要像下面一樣執(zhí)行即可:

當(dāng)然,這是假定你是根據(jù)你用戶的分?jǐn)?shù)做遞增的排序。如果你想返回用戶及用戶的分?jǐn)?shù),你需要這樣執(zhí)行:

ZRANGE user_scores 0 10 WITHSCORESAgora Games 就是一個(gè)很好的例子,用 Ruby 實(shí)現(xiàn)的,它的排行榜就是使用 Redis 來存儲數(shù)據(jù)的,你可以在這里看到。

(5)發(fā)布/訂閱

最后(但肯定不是最不重要的)是 Redis 的發(fā)布/訂閱功能。發(fā)布/訂閱的使用場景確實(shí)非常多。我已看見人們在社交網(wǎng)絡(luò)連接中使用,還可作為基于發(fā)布/訂閱的腳本觸發(fā)器,甚至用 Redis 的發(fā)布/訂閱功能來建立聊天系統(tǒng)!

13、Redis 支持的 Java 客戶端都有哪些?官方推薦用哪個(gè)?

Redisson、Jedis、lettuce 等等,官方推薦使用 Redisson。

14、Redis 和 Redisson 有什么關(guān)系?

Redisson 是一個(gè)高級的分布式協(xié)調(diào) Redis 客服端,能幫助用戶在分布式環(huán)境中輕松實(shí)現(xiàn)一些 Java 的對象 (Bloom filter, BitSet, Set, SetMultimap, ScoredSortedSet, SortedSet, Map, ConcurrentMap,List, ListMultimap, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock,ReadWriteLock, AtomicLong, CountDownLatch, Publish / Subscribe, HyperLogLog)。

15、Jedis 與 Redisson 對比有什么優(yōu)缺點(diǎn)?

Jedis 是 Redis 的 Java 實(shí)現(xiàn)的客戶端,其 API 提供了比較全面的 Redis 命令的支持;

Redisson 實(shí)現(xiàn)了分布式和可擴(kuò)展的 Java 數(shù)據(jù)結(jié)構(gòu),和 Jedis 相比,功能較為簡單,不支持字符串操作,不支持排序、事務(wù)、管道、分區(qū)等 Redis 特性。Redisson 的宗旨是促進(jìn)使用者對 Redis 的關(guān)注分離,從而讓使用者能夠?qū)⒕Ω械胤旁谔幚順I(yè)務(wù)邏輯上。

16、說說 Redis 哈希槽的概念?

Redis 集群沒有使用一致性 hash,而是引入了哈希槽的概念,Redis 集群有 16384 個(gè)哈希槽,每個(gè) key 通過 CRC16 校驗(yàn)后對 16384 取模來決定放置哪個(gè)槽,集群的每個(gè)節(jié)點(diǎn)負(fù)責(zé)一部分 hash 槽。

17、Redis 集群的主從復(fù)制模型是怎樣的?

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

18、Redis 集群會有寫操作丟失嗎?為什么?

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

19、Redis 集群之間是如何復(fù)制的?

異步復(fù)制

20、Redis 集群最大節(jié)點(diǎn)個(gè)數(shù)是多少?

16384 個(gè)

21、Redis 集群如何選擇數(shù)據(jù)庫?

Redis 集群目前無法做數(shù)據(jù)庫選擇,默認(rèn)在 0 數(shù)據(jù)庫。

22、Redis 中的管道有什么用?

一次請求/響應(yīng)服務(wù)器能實(shí)現(xiàn)處理新的請求即使舊的請求還未被響應(yīng),這樣就可以將多個(gè)命令發(fā)送到服務(wù)器,而不用等待回復(fù),最后在一個(gè)步驟中讀取該答復(fù)。

這就是管道(pipelining),是一種幾十年來廣泛使用的技術(shù)。例如許多 POP3 協(xié)議已經(jīng)實(shí)現(xiàn)支持這個(gè)功能,大大加快了從服務(wù)器下載新郵件的過程。

23、怎么理解 Redis 事務(wù)?

事務(wù)是一個(gè)單獨(dú)的隔離操作:事務(wù)中的所有命令都會序列化、按順序地執(zhí)行,事務(wù)在執(zhí)行的過程中,不會被其他客戶端發(fā)送來的命令請求所打斷。事務(wù)是一個(gè)原子操作:事務(wù)中的命令要么全部被執(zhí)行,要么全部都不執(zhí)行。

24、Redis 事務(wù)相關(guān)的命令有哪幾個(gè)?

  • MULTI
  • EXEC
  • DISCARD
  • WATCH
  • 25、Redis key 的過期時(shí)間和永久有效分別怎么設(shè)置?

    EXPIRE 和 PERSIST 命令

    26、Redis 如何做內(nèi)存優(yōu)化?

    盡可能使用散列表(hashes),散列表(是說散列表里面存儲的數(shù)少)使用的內(nèi)存非常小,所以你應(yīng)該盡可能的將你的數(shù)據(jù)模型抽象到一個(gè)散列表里面。

    比如你的 web 系統(tǒng)中有一個(gè)用戶對象,不要為這個(gè)用戶的名稱,姓氏,郵箱,密碼設(shè)置單獨(dú)的 key,而是應(yīng)該把這個(gè)用戶的所有信息存儲到一張散列表里面。

    27、Redis 回收進(jìn)程如何工作的?

    一個(gè)客戶端運(yùn)行了新的命令,添加了新的數(shù)據(jù)。Redi 檢查內(nèi)存使用情況,如果大于 maxmemory 的限制, 則根據(jù)設(shè)定好的策略進(jìn)行回收。一個(gè)新的命令被執(zhí)行,等等。

    所以我們不斷地穿越內(nèi)存限制的邊界,通過不斷達(dá)到邊界然后不斷地回收回到邊界以下。

    如果一個(gè)命令的結(jié)果導(dǎo)致大量內(nèi)存被使用(例如很大的集合的交集保存到一個(gè)新的鍵),不用多久內(nèi)存限制就會被這個(gè)內(nèi)存使用量超越。

    28.加鎖機(jī)制

    現(xiàn)在某個(gè)客戶端要加鎖。如果該客戶端面對的是一個(gè) redis cluster 集群,他首先會根據(jù) hash 節(jié)點(diǎn)選擇一臺機(jī)器。這里注意,僅僅只是選擇一臺機(jī)器!這點(diǎn)很關(guān)鍵!緊接著,就會發(fā)送一段 lua 腳本到 redis 上,那段 lua 腳本如下所示:

    為啥要用 lua 腳本呢?因?yàn)橐淮筵鐝?fù)雜的業(yè)務(wù)邏輯,可以通過封裝在 lua 腳本中發(fā)送給 redis,保證這段復(fù)雜業(yè)務(wù)邏輯執(zhí)行的原子性。

    那么,這段 lua 腳本是什么意思呢?這里 KEYS[1]代表的是你加鎖的那個(gè) key,比如說:RLock lock = redisson.getLock(“myLock”);這里你自己設(shè)置了加鎖的那個(gè)鎖 key 就是“myLock”。

    ARGV[1]代表的就是鎖 key 的默認(rèn)生存時(shí)間,默認(rèn) 30 秒。ARGV[2]代表的是加鎖的客戶端的 ID,類似于下面這樣:8743c9c0-0795-4907-87fd-6c719a6b4586:1給大家解釋一下,第一段 if 判斷語句,就是用“exists myLock”命令判斷一下,如果你要加鎖的那個(gè)鎖 key 不存在的話,你就進(jìn)行加鎖。如何加鎖呢?很簡單,用下面的命令:hset myLock8743c9c0-0795-4907-87fd-6c719a6b4586:1 1,通過這個(gè)命令設(shè)置一個(gè) hash 數(shù)據(jù)結(jié)構(gòu),這行命令執(zhí)行后,會出現(xiàn)一個(gè)類似下面的數(shù)據(jù)結(jié)構(gòu):

    上述就代表“8743c9c0-0795-4907-87fd-6c719a6b4586:1”這個(gè)客戶端對“myLock”這個(gè)鎖 key 完成了加鎖。接著會執(zhí)行“pexpire myLock 30000”命令,設(shè)置 myLock 這個(gè)鎖 key 的生存時(shí)間是 30 秒。好了,到此為止,ok,加鎖完成了。

    29.鎖互斥機(jī)制

    那么在這個(gè)時(shí)候,如果客戶端 2 來嘗試加鎖,執(zhí)行了同樣的一段 lua 腳本,會咋樣呢?很簡單,第一個(gè) if 判斷會執(zhí)行“exists myLock”,發(fā)現(xiàn) myLock 這個(gè)鎖 key 已經(jīng)存在了。接著第二個(gè) if 判斷,判斷一下,myLock 鎖 key 的 hash 數(shù)據(jù)結(jié)構(gòu)中,是否包含客戶端 2 的 ID,但是明顯不是的,因?yàn)槟抢锇氖强蛻舳?1 的 ID。

    所以,客戶端 2 會獲取到 pttl myLock 返回的一個(gè)數(shù)字,這個(gè)數(shù)字代表了 myLock 這個(gè)鎖 key的剩余生存時(shí)間。比如還剩 15000 毫秒的生存時(shí)間。此時(shí)客戶端 2 會進(jìn)入一個(gè) while 循環(huán),不停的嘗試加鎖。

    30.watch dog 自動延期機(jī)制

    客戶端 1 加鎖的鎖 key 默認(rèn)生存時(shí)間才 30 秒,如果超過了 30 秒,客戶端 1 還想一直持有這把鎖,怎么辦呢?

    簡單!只要客戶端 1 一旦加鎖成功,就會啟動一個(gè) watch dog 看門狗,他是一個(gè)后臺線程,會每隔 10 秒檢查一下,如果客戶端 1 還持有鎖 key,那么就會不斷的延長鎖 key 的生存時(shí)間。

    31.可重入加鎖機(jī)制

    那如果客戶端 1 都已經(jīng)持有了這把鎖了,結(jié)果可重入的加鎖會怎么樣呢?

    這時(shí)我們來分析一下上面那段 lua 腳本。第一個(gè) if 判斷肯定不成立,“exists myLock”會顯示鎖key 已經(jīng)存在了。第二個(gè) if 判斷會成立,因?yàn)?myLock 的 hash 數(shù)據(jù)結(jié)構(gòu)中包含的那個(gè) ID,就是客戶端 1 的那個(gè) ID,也就是“8743c9c0-0795-4907-87fd-6c719a6b4586:1”

    此時(shí)就會執(zhí)行可重入加鎖的邏輯,他會用:

    incrby myLock 8743c9c0-0795-4907-87fd-6c71a6b4586:1 1 ,通過這個(gè)命令,對客戶端 1的加鎖次數(shù),累加 1。此時(shí) myLock 數(shù)據(jù)結(jié)構(gòu)會發(fā)生改變

    myLock 的 hash 數(shù)據(jù)結(jié)構(gòu)中的那個(gè)客戶端 ID,就對應(yīng)著加鎖的次數(shù)

    32.釋放鎖機(jī)制

    如果執(zhí)行 lock.unlock(),就可以釋放分布式鎖,此時(shí)的業(yè)務(wù)邏輯也是非常簡單的。其實(shí)說白了,就是每次都對 myLock 數(shù)據(jù)結(jié)構(gòu)中的那個(gè)加鎖次數(shù)減 1。如果發(fā)現(xiàn)加鎖次數(shù)是 0 了,說明這個(gè)客戶端已經(jīng)不再持有鎖了,此時(shí)就會用:“del myLock”命令,從 redis 里刪除這個(gè) key。

    然后呢,另外的客戶端 2 就可以嘗試完成加鎖了。這就是所謂的分布式鎖的開源 Redisson 框架的實(shí)現(xiàn)機(jī)制。

    一般我們在生產(chǎn)系統(tǒng)中,可以用 Redisson 框架提供的這個(gè)類庫來基于 redis 進(jìn)行分布式鎖的加鎖與釋放鎖。

    33. Redis 分布式鎖的缺點(diǎn)

    其實(shí)上面那種方案最大的問題,就是如果你對某個(gè) redis master 實(shí)例,寫入了 myLock 這種鎖key 的 value,此時(shí)會異步復(fù)制給對應(yīng)的 master slave 實(shí)例。但是這個(gè)過程中一旦發(fā)生 redis master 宕機(jī),主備切換,redis slave 變?yōu)榱?redis master。

    接著就會導(dǎo)致,客戶端 2 來嘗試加鎖的時(shí)候,在新的 redis master 上完成了加鎖,而客戶端 1也以為自己成功加了鎖。此時(shí)就會導(dǎo)致多個(gè)客戶端對一個(gè)分布式鎖完成了加鎖。這時(shí)系統(tǒng)在業(yè)務(wù)語義上一定會出現(xiàn)問題,導(dǎo)致各種臟數(shù)據(jù)的產(chǎn)生。

    所以這個(gè)就是 redis cluster,或者是 redis master-slave 架構(gòu)的主從異步復(fù)制導(dǎo)致的 redis 分布式鎖的最大缺陷:在 redis master 實(shí)例宕機(jī)的時(shí)候,可能導(dǎo)致多個(gè)客戶端同時(shí)完成加鎖。

    34.使用過 Redis 分布式鎖么,它是怎么實(shí)現(xiàn)的?

    先拿 setnx 來爭搶鎖,搶到之后,再用 expire 給鎖加一個(gè)過期時(shí)間防止鎖忘記了釋放。

    如果在 setnx 之后執(zhí)行 expire 之前進(jìn)程意外 crash 或者要重啟維護(hù)了,那會怎么樣?

    set 指令有非常復(fù)雜的參數(shù),這個(gè)應(yīng)該是可以同時(shí)把 setnx 和 expire 合成一條指令來用的!

    35.使用過 Redis 做異步隊(duì)列么,你是怎么用的?有什么缺點(diǎn)?

    般使用 list 結(jié)構(gòu)作為隊(duì)列,rpush 生產(chǎn)消息,lpop 消費(fèi)消息。當(dāng) lpop 沒有消息的時(shí)候,要適當(dāng) sleep一會再重試。

    缺點(diǎn):

    在消費(fèi)者下線的情況下,生產(chǎn)的消息會丟失,得使用專業(yè)的消息隊(duì)列如 rabbitmq 等。

    能不能生產(chǎn)一次消費(fèi)多次呢?

    使用 pub/sub 主題訂閱者模式,可以實(shí)現(xiàn) 1:N 的消息隊(duì)列。

    36.什么是緩存穿透?如何避免?什么是緩存雪崩?何如避免?

    緩存穿透

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

    如何避免?

    1:對查詢結(jié)果為空的情況也進(jìn)行緩存,緩存時(shí)間設(shè)置短一點(diǎn),或者該 key 對應(yīng)的數(shù)據(jù) insert 了之后清理緩存。

    2:對一定不存在的 key 進(jìn)行過濾。可以把所有的可能存在的 key 放到一個(gè)大的 Bitmap 中,查詢時(shí)通過該 bitmap 過濾。

    緩存雪崩

    當(dāng)緩存服務(wù)器重啟或者大量緩存集中在某一個(gè)時(shí)間段失效,這樣在失效的時(shí)候,會給后端系統(tǒng)帶來很大壓力。導(dǎo)致系統(tǒng)崩潰。

    如何避免?

    1:在緩存失效后,通過加鎖或者隊(duì)列來控制讀數(shù)據(jù)庫寫緩存的線程數(shù)量。比如對某個(gè) key 只允許一個(gè)線程查詢數(shù)據(jù)和寫緩存,其他線程等待。

    2:做二級緩存,A1 為原始緩存,A2 為拷貝緩存,A1 失效時(shí),可以訪問 A2,A1 緩存失效時(shí)間設(shè)置為短期,A2 設(shè)置為長期

    3:不同的 key,設(shè)置不同的過期時(shí)間,讓緩存失效的時(shí)間點(diǎn)盡量均勻

    37.redis 和 memcached 什么區(qū)別?為什么高并發(fā)下有時(shí)單線程的 redis 比多線程的memcached 效率要高?

    區(qū)別:

    1.mc 可緩存圖片和視頻。rd 支持除 k/v 更多的數(shù)據(jù)結(jié)構(gòu);

    2.rd 可以使用虛擬內(nèi)存,rd 可持久化和 aof 災(zāi)難恢復(fù),rd 通過主從支持?jǐn)?shù)據(jù)備份;

    3.rd 可以做消息隊(duì)列。

    原因:

    mc 多線程模型引入了緩存一致性和鎖,加鎖帶來了性能損耗。

    redis 主從復(fù)制如何實(shí)現(xiàn)的?redis 的集群模式如何實(shí)現(xiàn)?redis 的 key 是如何尋址的?

    主從復(fù)制實(shí)現(xiàn):主節(jié)點(diǎn)將自己內(nèi)存中的數(shù)據(jù)做一份快照,將快照發(fā)給從節(jié)點(diǎn),從節(jié)點(diǎn)將數(shù)據(jù)恢復(fù)到內(nèi)存中。之后再每次增加新數(shù)據(jù)的時(shí)候,主節(jié)點(diǎn)以類似于 mysql 的二進(jìn)制日志方式將語句發(fā)送給從節(jié)點(diǎn),從節(jié)點(diǎn)拿到主節(jié)點(diǎn)發(fā)送過來的語句進(jìn)行重放。

    分片方式:

    -客戶端分片

    -基于代理的分片

    ● Twemproxy

    ● codis-路由查詢分片

    ● Redis-cluster(本身提供了自動將數(shù)據(jù)分散到 Redis Cluster 不同節(jié)點(diǎn)的能力,整個(gè)數(shù)據(jù)集合的某個(gè)數(shù)據(jù)子集存儲在哪個(gè)節(jié)點(diǎn)對于用戶來說是透明的)

    redis-cluster 分片原理:Cluster 中有一個(gè) 16384 長度的槽(虛擬槽),編號分別為 0-16383。

    每個(gè) Master 節(jié)點(diǎn)都會負(fù)責(zé)一部分的槽,當(dāng)有某個(gè) key 被映射到某個(gè) Master 負(fù)責(zé)的槽,那么這個(gè) Master 負(fù)責(zé)為這個(gè) key 提供服務(wù),至于哪個(gè) Master 節(jié)點(diǎn)負(fù)責(zé)哪個(gè)槽,可以由用戶指定,也可以在初始化的時(shí)候自動生成,只有 Master 才擁有槽的所有權(quán)。Master 節(jié)點(diǎn)維護(hù)著一個(gè) 16384/8 字節(jié)的位序列,Master 節(jié)點(diǎn)用 bit 來標(biāo)識對于某個(gè)槽自己是否擁有。比如對于編號為 1 的槽,Master 只要判斷序列的第二位(索引從 0 開始)是不是為 1 即可。

    這種結(jié)構(gòu)很容易添加或者刪除節(jié)點(diǎn)。比如如果我想新添加個(gè)節(jié)點(diǎn) D, 我需要從節(jié)點(diǎn) A、B、C 中得部分槽到 D 上。

    38 使用 redis 如何設(shè)計(jì)分布式鎖?說一下實(shí)現(xiàn)思路?使用 zk 可以嗎?如何實(shí)現(xiàn)?這兩種有什么區(qū)別?

    redis:

    1.線程 A setnx(上鎖的對象,超時(shí)時(shí)的時(shí)間戳 t1),如果返回 true,獲得鎖。

    2.線程 B 用 get 獲取 t1,與當(dāng)前時(shí)間戳比較,判斷是是否超時(shí),沒超時(shí) false,若超時(shí)執(zhí)行第 3 步;

    3.計(jì)算新的超時(shí)時(shí)間 t2,使用 getset 命令返回 t3(該值可能其他線程已經(jīng)修改過),如果

    t1==t3,獲得鎖,如果 t1!=t3 說明鎖被其他線程獲取了。

    4.獲取鎖后,處理完業(yè)務(wù)邏輯,再去判斷鎖是否超時(shí),如果沒超時(shí)刪除鎖,如果已超時(shí),不用處理(防止刪除其他線程的鎖)。

    zk:

    1.客戶端對某個(gè)方法加鎖時(shí),在 zk 上的與該方法對應(yīng)的指定節(jié)點(diǎn)的目錄下,生成一個(gè)唯一的瞬時(shí)有序節(jié)點(diǎn) node1;

    2.客戶端獲取該路徑下所有已經(jīng)創(chuàng)建的子節(jié)點(diǎn),如果發(fā)現(xiàn)自己創(chuàng)建的 node1 的序號是最小的,就認(rèn)為這個(gè)客戶端獲得了鎖。

    3.如果發(fā)現(xiàn) node1 不是最小的,則監(jiān)聽比自己創(chuàng)建節(jié)點(diǎn)序號小的最大的節(jié)點(diǎn),進(jìn)入等待。

    4.獲取鎖后,處理完邏輯,刪除自己創(chuàng)建的 node1 即可。

    區(qū)別:zk 性能差一些,開銷大,實(shí)現(xiàn)簡單。

    39 知道 redis 的持久化嗎?底層如何實(shí)現(xiàn)的?有什么優(yōu)點(diǎn)缺點(diǎn)?

    RDB(Redis DataBase:在不同的時(shí)間點(diǎn)將 redis 的數(shù)據(jù)生成的快照同步到磁盤等介質(zhì)上):內(nèi)存到硬盤的快照,定期更新。缺點(diǎn):耗時(shí),耗性能(fork+io 操作),易丟失數(shù)據(jù)。

    AOF(Append Only File:將 redis 所執(zhí)行過的所有指令都記錄下來,在下次 redis 重啟時(shí),只需要執(zhí)行指令就可以了):

    寫日志。缺點(diǎn):體積大,恢復(fù)速度慢。bgsave 做鏡像全量持久化,aof 做增量持久化。因?yàn)?bgsave 會消耗比較長的時(shí)間,不夠?qū)崟r(shí),在停機(jī)的時(shí)候會導(dǎo)致大量的數(shù)據(jù)丟失,需要 aof 來配合,在 redis 實(shí)例重啟時(shí),優(yōu)先使用 aof 來恢復(fù)內(nèi)存的狀態(tài),如果沒有 aof 日志,就會使用 rdb 文件來恢復(fù)。Redis 會定期做aof 重寫,壓縮 aof 文件日志大小。Redis4.0 之后有了混合持久化的功能,將 bgsave 的全量和 aof 的增量做了融合處理,這樣既保證了恢復(fù)的效率又兼顧了數(shù)據(jù)的安全性。bgsave 的原理,fork 和 cow, fork 是指 redis 通過創(chuàng)建子進(jìn)程來進(jìn)行 bgsave 操作,cow 指的是 copy onwrite,子進(jìn)程創(chuàng)建后,父子進(jìn)程共享數(shù)據(jù)段,父進(jìn)程繼續(xù)提供讀寫服務(wù),寫臟的頁面數(shù)據(jù)會逐漸和子進(jìn)程分離開來。

    40 redis 過期策略都有哪些?LRU 算法知道嗎?寫一下 java 代碼實(shí)現(xiàn)?

    過期策略:

    定時(shí)過期(一 key 一定時(shí)器),惰性過期:只有使用 key 時(shí)才判斷 key 是否已過期,過期則清除。定期過期:前兩者折中。

    LRU:new LinkedHashMap<K, V>(capacity, DEFAULT_LOAD_FACTORY, true);//第三個(gè)參數(shù)置為 true,代表 linkedlist 按訪問順序排序,可作為 LRU 緩存;設(shè)為 false 代表按插入順序排序,可作為 FIFO 緩存

    LRU 算法實(shí)現(xiàn):

    1.通過雙向鏈表來實(shí)現(xiàn),新數(shù)據(jù)插入到鏈表頭部;

    2.每當(dāng)緩存命中(即緩存數(shù)據(jù)被訪問),則將數(shù)據(jù)移到鏈表頭部;

    3.當(dāng)鏈表滿的時(shí)候,將鏈表尾部的數(shù)據(jù)丟棄。

    LinkedHashMap:HashMap 和雙向鏈表合二為一即是 LinkedHashMap。HashMap 是無序的,LinkedHashMap 通過維護(hù)一個(gè)額外的雙向鏈表保證了迭代順序。該迭代順序可以是插入順序(默認(rèn)),也可以是訪問順序。

    41 緩存穿透、緩存擊穿、緩存雪崩解決方案?

    緩存穿透:

    指查詢一個(gè)一定不存在的數(shù)據(jù),如果從存儲層查不到數(shù)據(jù)則不寫入緩存,這將導(dǎo)致這個(gè)不存在的數(shù)據(jù)每次請求都要到 DB 去查詢,可能導(dǎo)致 DB 掛掉。

    解決方案:

    1.查詢返回的數(shù)據(jù)為空,仍把這個(gè)空結(jié)果進(jìn)行緩存,但過期時(shí)間會比較短;

    2.布隆過濾器:將所有可能存在的數(shù)據(jù)哈希到一個(gè)足夠大的 bitmap 中,一個(gè)一定不存在的數(shù)據(jù)會被這個(gè) bitmap 攔截掉,從而避免了對 DB 的查詢。

    緩存擊穿:

    對于設(shè)置了過期時(shí)間的 key,緩存在某個(gè)時(shí)間點(diǎn)過期的時(shí)候,恰好這時(shí)間點(diǎn)對這個(gè) Key 有大量的并發(fā)請求過來,這些請求發(fā)現(xiàn)緩存過期一般都會從后端 DB 加載數(shù)據(jù)并回設(shè)到緩存,這個(gè)時(shí)候大并發(fā)的請求可能會瞬間把 DB 壓垮。

    解決方案:

    1.使用互斥鎖:當(dāng)緩存失效時(shí),不立即去 load db,先使用如 Redis 的 setnx 去設(shè)置一個(gè)互斥鎖,當(dāng)操作成功返回時(shí)再進(jìn)行 load db 的操作并回設(shè)緩存,否則重試 get 緩存的方法。

    2.永遠(yuǎn)不過期:物理不過期,但邏輯過期(后臺異步線程去刷新)。

    緩存雪崩:設(shè)置緩存時(shí)采用了相同的過期時(shí)間,導(dǎo)致緩存在某一時(shí)刻同時(shí)失效,請求全部轉(zhuǎn)發(fā)到 DB,DB 瞬時(shí)壓力過重雪崩。與緩存擊穿的區(qū)別:雪崩是很多 key,擊穿是某一個(gè)key 緩存。

    解決方案:將緩存失效時(shí)間分散開,比如可以在原有的失效時(shí)間基礎(chǔ)上增加一個(gè)隨機(jī)值,比如 1-5 分鐘隨機(jī),這樣每一個(gè)緩存的過期時(shí)間的重復(fù)率就會降低,就很難引發(fā)集體失效的事件。

    42 在選擇緩存時(shí),什么時(shí)候選擇 redis,什么時(shí)候選擇 memcached?

    選擇 redis 的情況:

    1、復(fù)雜數(shù)據(jù)結(jié)構(gòu),value 的數(shù)據(jù)是哈希,列表,集合,有序集合等這種情況下,會選擇redis, 因?yàn)?memcache 無法滿足這些數(shù)據(jù)結(jié)構(gòu),最典型的的使用場景是,用戶訂單列表,用戶消息,帖子評論等。

    2、需要進(jìn)行數(shù)據(jù)的持久化功能,但是注意,不要把 redis 當(dāng)成數(shù)據(jù)庫使用,如果 redis掛了,內(nèi)存能夠快速恢復(fù)熱數(shù)據(jù),不會將壓力瞬間壓在數(shù)據(jù)庫上,沒有 cache 預(yù)熱的過程。對于只讀和數(shù)據(jù)一致性要求不高的場景可以采用持久化存儲

    3、高可用,redis 支持集群,可以實(shí)現(xiàn)主動復(fù)制,讀寫分離,而對于 memcache 如果想要實(shí)現(xiàn)高可用,需要進(jìn)行二次開發(fā)。

    4、存儲的內(nèi)容比較大,memcache 存儲的 value 最大為 1M。

    選擇 memcache 的場景:

    1、純 KV,數(shù)據(jù)量非常大的業(yè)務(wù),使用 memcache 更合適,原因是:

    a)memcache 的內(nèi)存分配采用的是預(yù)分配內(nèi)存池的管理方式,能夠省去內(nèi)存分配的時(shí)間,redis 是臨時(shí)申請空間,可能導(dǎo)致碎片化。

    b)虛擬內(nèi)存使用,memcache 將所有的數(shù)據(jù)存儲在物理內(nèi)存里,redis 有自己的 vm 機(jī)制,理論上能夠存儲比物理內(nèi)存更多的數(shù)據(jù),當(dāng)數(shù)據(jù)超量時(shí),引發(fā) swap,把冷數(shù)據(jù)刷新到磁盤上,從這點(diǎn)上,數(shù)據(jù)量大時(shí),memcache 更快

    c)網(wǎng)絡(luò)模型,memcache 使用非阻塞的 IO 復(fù)用模型,redis 也是使用非阻塞的 IO 復(fù)用模型,但是 redis 還提供了一些非 KV 存儲之外的排序,聚合功能,復(fù)雜的 CPU 計(jì)算,會阻塞整個(gè) IO 調(diào)度,從這點(diǎn)上由于 redis 提供的功能較多,memcache 更快些

    d) 線程模型,memcache 使用多線程,主線程監(jiān)聽,worker 子線程接受請求,執(zhí)行讀寫,這個(gè)過程可能存在鎖沖突。redis 使用的單線程,雖然無鎖沖突,但是難以利用多核的特性提升吞吐量。

    緩存與數(shù)據(jù)庫不一致怎么辦

    假設(shè)采用的主存分離,讀寫分離的數(shù)據(jù)庫,

    如果一個(gè)線程 A 先刪除緩存數(shù)據(jù),然后將數(shù)據(jù)寫入到主庫當(dāng)中,這個(gè)時(shí)候,主庫和從庫同步?jīng)]有完成,線程 B 從緩存當(dāng)中讀取數(shù)據(jù)失敗,從從庫當(dāng)中讀取到舊數(shù)據(jù),然后更新至緩存,這個(gè)時(shí)候,緩存當(dāng)中的就是舊的數(shù)據(jù)。

    發(fā)生上述不一致的原因在于,主從庫數(shù)據(jù)不一致問題,加入了緩存之后,主從不一致的時(shí)間被拉長了

    處理思路:在從庫有數(shù)據(jù)更新之后,將緩存當(dāng)中的數(shù)據(jù)也同時(shí)進(jìn)行更新,即當(dāng)從庫發(fā)生了數(shù)據(jù)更新之后,向緩存發(fā)出刪除,淘汰這段時(shí)間寫入的舊數(shù)據(jù)。

    主從數(shù)據(jù)庫不一致如何解決場景描述,對于主從庫,讀寫分離,如果主從庫更新同步有時(shí)差,就會導(dǎo)致主從庫數(shù)據(jù)的不一致

    1、忽略這個(gè)數(shù)據(jù)不一致,在數(shù)據(jù)一致性要求不高的業(yè)務(wù)下,未必需要時(shí)時(shí)一致性

    2、強(qiáng)制讀主庫,使用一個(gè)高可用的主庫,數(shù)據(jù)庫讀寫都在主庫,添加一個(gè)緩存,提升數(shù)據(jù)讀取的性能。

    3、選擇性讀主庫,添加一個(gè)緩存,用來記錄必須讀主庫的數(shù)據(jù),將哪個(gè)庫,哪個(gè)表,哪個(gè)主鍵,作為緩存的 key,設(shè)置緩存失效的時(shí)間為主從庫同步的時(shí)間,如果緩存當(dāng)中有這個(gè)數(shù)據(jù),直接讀取主庫,如果緩存當(dāng)中沒有這個(gè)主鍵,就到對應(yīng)的從庫中讀取。

    43 Redis 常見的性能問題和解決方案

    1、master 最好不要做持久化工作,如 RDB 內(nèi)存快照和 AOF 日志文件

    2、如果數(shù)據(jù)比較重要,某個(gè) slave 開啟 AOF 備份,策略設(shè)置成每秒同步一次

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

    4、盡量避免在壓力大得主庫上增加從庫

    5、主從復(fù)制不要采用網(wǎng)狀結(jié)構(gòu),盡量是線性結(jié)構(gòu),Master<–Slave1<----Slave2 …

    44 Redis 的數(shù)據(jù)淘汰策略有哪些

    voltile-lru 從已經(jīng)設(shè)置過期時(shí)間的數(shù)據(jù)集中挑選最近最少使用的數(shù)據(jù)淘汰

    voltile-ttl 從已經(jīng)設(shè)置過期時(shí)間的數(shù)據(jù)庫集當(dāng)中挑選將要過期的數(shù)據(jù)

    voltile-random 從已經(jīng)設(shè)置過期時(shí)間的數(shù)據(jù)集任意選擇淘汰數(shù)據(jù)

    allkeys-lru 從數(shù)據(jù)集中挑選最近最少使用的數(shù)據(jù)淘汰

    allkeys-random 從數(shù)據(jù)集中任意選擇淘汰的數(shù)據(jù)

    no-eviction 禁止驅(qū)逐數(shù)據(jù)

    45Redis 當(dāng)中有哪些數(shù)據(jù)結(jié)構(gòu)

    字符串 String、字典 Hash、列表 List、集合 Set、有序集合 SortedSet。如果是高級用戶,那么還會有,如果你是 Redis 中高級用戶,還需要加上下面幾種數(shù)據(jù)結(jié)構(gòu) HyperLogLog、Geo、Pub/Sub。

    假如 Redis 里面有 1 億個(gè) key,其中有 10w 個(gè) key 是以某個(gè)固定的已知的前綴開頭的,如果將它們?nèi)空页鰜?#xff1f;

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

    對方接著追問:如果這個(gè) redis 正在給線上的業(yè)務(wù)提供服務(wù),那使用 keys 指令會有什么問題?

    這個(gè)時(shí)候你要回答 redis 關(guān)鍵的一個(gè)特性:redis 的單線程的。keys 指令會導(dǎo)致線程阻塞一段時(shí)間,線上服務(wù)會停頓,直到指令執(zhí)行完畢,服務(wù)才能恢復(fù)。這個(gè)時(shí)候可以使用 scan 指令,scan 指令可以無阻塞的提取出指定模式的 key 列表,但是會有一定的重復(fù)概率,在客戶端做一次去重就可以了,但是整體所花費(fèi)的時(shí)間會比直接用 keys 指令長。

    46 使用 Redis 做過異步隊(duì)列嗎,是如何實(shí)現(xiàn)的

    使用 list 類型保存數(shù)據(jù)信息,rpush 生產(chǎn)消息,lpop 消費(fèi)消息,當(dāng) lpop 沒有消息時(shí),可以 sleep 一段時(shí)間,然后再檢查有沒有信息,如果不想 sleep 的話,可以使用 blpop, 在沒有信息的時(shí)候,會一直阻塞,直到信息的到來。redis 可以通過 pub/sub 主題訂閱模式實(shí)現(xiàn)一個(gè)生產(chǎn)者,多個(gè)消費(fèi)者,當(dāng)然也存在一定的缺點(diǎn),當(dāng)消費(fèi)者下線時(shí),生產(chǎn)的消息會丟失。

    47 Redis 如何實(shí)現(xiàn)延時(shí)隊(duì)列

    使用 sortedset,使用時(shí)間戳做 score, 消息內(nèi)容作為 key,調(diào)用 zadd 來生產(chǎn)消息,消費(fèi)者使用 zrangbyscore 獲取 n 秒之前的數(shù)據(jù)做輪詢處理。

    總結(jié)

    以上是生活随笔為你收集整理的Redis常见问题及其一些重点知识总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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