Java面试——Redis系列总结
文章目錄:
1.什么是Redis?
2.為什么要用 Redis / 為什么要用緩存?
3.Redis為什么這么快?
4.Redis都有哪些數(shù)據(jù)類(lèi)型?
5.什么是Redis持久化?Redis 的持久化有哪些實(shí)現(xiàn)方式?
6.什么是Redis事務(wù)?
7.談?wù)勀銓?duì)Redis集群方案——哨兵模式 的理解
8.Redis主從復(fù)制的原理是什么?
9.Redis如何實(shí)現(xiàn)分布式鎖?
10.Redis中的緩存穿透、緩存擊穿、緩存雪崩是什么?
1.什么是Redis?
Redis(Remote Dictionary Server) 是一個(gè)使用 C 語(yǔ)言編寫(xiě)的,開(kāi)源的(BSD許可)高性能非關(guān)系型(NoSQL)的鍵值對(duì)數(shù)據(jù)庫(kù)。
Redis 可以存儲(chǔ)鍵和五種不同類(lèi)型的值之間的映射。鍵的類(lèi)型只能為字符串,值支持五種數(shù)據(jù)類(lèi)型:字符串、列表、散列表、集合、有序集合。
與傳統(tǒng)數(shù)據(jù)庫(kù)不同的是 Redis 的數(shù)據(jù)是存在內(nèi)存中的,所以讀寫(xiě)速度非常快,因此 redis 被廣泛應(yīng)用于緩存方向,每秒可以處理超過(guò) 10萬(wàn)次讀寫(xiě)操作,是已知性能最快的Key-Value DB。另外,Redis 也經(jīng)常用來(lái)做分布式鎖。除此之外,Redis 支持事務(wù) 、持久化、LUA腳本、LRU驅(qū)動(dòng)事件、多種集群方案。
2.為什么要用 Redis / 為什么要用緩存?
主要從“高性能”和“高并發(fā)”這兩點(diǎn)來(lái)看待這個(gè)問(wèn)題。
高性能
假如用戶(hù)第一次訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)中的某些數(shù)據(jù)。這個(gè)過(guò)程會(huì)比較慢,因?yàn)槭菑挠脖P(pán)上讀取的。再將該用戶(hù)訪(fǎng)問(wèn)的數(shù)據(jù)存在緩存中,這樣下一次再訪(fǎng)問(wèn)這些數(shù)據(jù)的時(shí)候就可以直接從緩存中獲取了。操作緩存就是直接操作內(nèi)存,所以速度相當(dāng)快。如果數(shù)據(jù)庫(kù)中的對(duì)應(yīng)數(shù)據(jù)改變的之后,同步改變緩存中相應(yīng)的數(shù)據(jù)即可!
高并發(fā)
直接操作緩存能夠承受的請(qǐng)求是遠(yuǎn)遠(yuǎn)大于直接訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)的,所以我們可以考慮把數(shù)據(jù)庫(kù)中的部分?jǐn)?shù)據(jù)轉(zhuǎn)移到緩存中去,這樣用戶(hù)的一部分請(qǐng)求會(huì)直接到緩存這里而不用經(jīng)過(guò)數(shù)據(jù)庫(kù)。
3.Redis為什么這么快?
4.Redis都有哪些數(shù)據(jù)類(lèi)型?
Redis主要有5種數(shù)據(jù)類(lèi)型,包括String,List,Hash,Set,ZSet。
| String | 字符串、整數(shù)或者浮點(diǎn)數(shù) | 對(duì)整個(gè)字符串或者字符串的其中一部分執(zhí)行操作對(duì)整數(shù)和浮點(diǎn)數(shù)執(zhí)行自增或者自減操作 | 做簡(jiǎn)單的鍵值對(duì)緩存 |
| List | 列表 | 從兩端壓入或者彈出元素對(duì)單個(gè)或者多個(gè)元素進(jìn)行修剪,只保留一個(gè)范圍內(nèi)的元素 | 存儲(chǔ)一些列表型的數(shù)據(jù)結(jié)構(gòu),類(lèi)似粉絲列表、文章的評(píng)論列表之類(lèi)的數(shù)據(jù) |
| Hash | 包含鍵值對(duì)的無(wú)序散列表 | 添加、獲取、移除單個(gè)鍵值對(duì)獲取所有鍵值對(duì) 檢查某個(gè)鍵是否存在 | 結(jié)構(gòu)化的數(shù)據(jù),比如一個(gè)對(duì)象 |
| Set | 無(wú)序集合 | 添加、獲取、移除單個(gè)元素檢查一個(gè)元素是否存在于集合中 計(jì)算交集、并集、差集從集合里面隨機(jī)獲取元素 | 交集、并集、差集的操作,比如交集,可以把兩個(gè)人的粉絲列表整一個(gè)交集 |
| ZSet | 有序集合 | 添加、獲取、刪除元素根據(jù)分值范圍或者成員來(lái)獲取元素 計(jì)算一個(gè)鍵的排名 | 去重但可以排序,如獲取排名前幾名的用戶(hù) |
- String應(yīng)用場(chǎng)景:
? 商品編號(hào)、訂單號(hào)采用incr命令生成;
? 是否喜歡的文章(點(diǎn)贊數(shù)incr)
- Hash應(yīng)用場(chǎng)景:
? 購(gòu)物車(chē)(新增商品hset、增加商品數(shù)量hincrby
? 商品總數(shù)hlen、全部選中hgetall)
- List應(yīng)用場(chǎng)景:
? 微信訂閱公眾號(hào)(訂閱lpush、查看訂閱號(hào)文章lrange)
- Set應(yīng)用場(chǎng)景:
? 抽獎(jiǎng)活動(dòng)(參與sadd、顯示參與人數(shù)scard、
? 隨機(jī)抽取srandmember、spop)
? 文章點(diǎn)贊(新增點(diǎn)贊sadd、取消點(diǎn)贊srem、
? 展現(xiàn)所有點(diǎn)贊用戶(hù)smember、點(diǎn)贊數(shù)統(tǒng)計(jì)scard)
? 社交平臺(tái)(兩個(gè)人的共同關(guān)注sinter、
? QQ可能認(rèn)識(shí)的人求差集sdiff)
- Zset應(yīng)用場(chǎng)景:
? 根據(jù)商品銷(xiāo)售對(duì)商品進(jìn)行排序(zadd、zincrby、zrange)
? 抖音熱搜排行榜
5.什么是Redis持久化?Redis 的持久化有哪些實(shí)現(xiàn)方式?
持久化就是把內(nèi)存的數(shù)據(jù)寫(xiě)到磁盤(pán)中去,防止服務(wù)宕機(jī)了內(nèi)存數(shù)據(jù)丟失。
Redis 提供兩種持久化機(jī)制 RDB(默認(rèn)) 和 AOF 機(jī)制:
RDB持久化:是Redis DataBase縮寫(xiě),快照
**RDB是Redis默認(rèn)的持久化方式。在指定的時(shí)間間隔內(nèi)將內(nèi)存中的數(shù)據(jù)集快照寫(xiě)入磁盤(pán), 也就是行話(huà)講的Snapshot快照,它恢復(fù)時(shí)是將快照文件直接讀到內(nèi)存里,對(duì)應(yīng)產(chǎn)生的數(shù)據(jù)文件為dump.rdb。**通過(guò)配置文件中的save參數(shù)來(lái)定義快照的周期。
如何觸發(fā)RDB快照;保持策略。
配置文件中默認(rèn)的快照配置,這三行save代碼的意思是:
在3600秒(一個(gè)小時(shí))內(nèi),如果有1個(gè)數(shù)據(jù)發(fā)生改變,則進(jìn)行持久化。
在30秒內(nèi),如果有10個(gè)數(shù)據(jù)發(fā)生改變,則進(jìn)行持久化。(原先是 save 300 100),我為了后面測(cè)試RDB,這里進(jìn)行了修改。
在60秒內(nèi),如果有10000個(gè)數(shù)據(jù)發(fā)生改變,則進(jìn)行持久化。
工作流程
優(yōu)點(diǎn)
缺點(diǎn)
AOF持久化:Append Only File縮寫(xiě)
將Redis執(zhí)行的每條寫(xiě)命令記錄到單獨(dú)的aof日志文件中,當(dāng)重啟Redis服務(wù)時(shí),會(huì)從持久化的日志文件中恢復(fù)數(shù)據(jù)。
當(dāng)兩種方式同時(shí)開(kāi)啟時(shí),數(shù)據(jù)恢復(fù)時(shí),Redis會(huì)優(yōu)先選擇AOF恢復(fù)。
配置
# 表示是否開(kāi)啟AOF持久化(默認(rèn)no,關(guān)閉)appendonly yes工作流程
優(yōu)點(diǎn)
缺點(diǎn)
6.什么是Redis事務(wù)?
事務(wù)是邏輯上的一組操作,要么都執(zhí)行,要么都不執(zhí)行。Redis 事務(wù)不是嚴(yán)格意義上的事務(wù),只是用于幫助用戶(hù)在一個(gè)步驟中執(zhí)行多個(gè)命令。單個(gè) Redis 命令的執(zhí)行是原子性的,但 Redis 沒(méi)有在事務(wù)上增加任何維持原子性的機(jī)制,所以 Redis 事務(wù)的執(zhí)行并不是原子性的。
Redis 事務(wù)可以理解為一個(gè)打包的批量執(zhí)行腳本,redis 事務(wù)不保證原子性,且沒(méi)有回滾,中間某條命令執(zhí)行失敗,前面已執(zhí)行的命令不回滾,后續(xù)的指令繼續(xù)執(zhí)行。
Redis 事務(wù)可以一次執(zhí)行多個(gè)命令, 并且?guī)в幸韵氯齻€(gè)重要的保證:
- 批量操作在發(fā)送 EXEC 命令前被放入隊(duì)列緩存。
- 收到 EXEC 命令后進(jìn)入事務(wù)執(zhí)行,事務(wù)中任意命令執(zhí)行失敗,前面已執(zhí)行的命令不回滾,后續(xù)的命令繼續(xù)執(zhí)行。
- 事務(wù)在執(zhí)行的過(guò)程中,不會(huì)被其他客戶(hù)端發(fā)送來(lái)的命令請(qǐng)求所打斷。
Redis事務(wù)的三個(gè)階段
Redis事務(wù)的相關(guān)命令:
| WATCH | WATCH 命令是一個(gè)樂(lè)觀(guān)鎖,可以為 Redis 事務(wù)提供 check-and-set (CAS)行為。可以監(jiān)控一個(gè)或多個(gè)鍵,一旦其中有一個(gè)鍵被修改(或刪除),之后的事務(wù)就不會(huì)執(zhí)行,監(jiān)控一直持續(xù)到EXEC命令。 |
| UNWATCH | UNWATCH命令可以取消watch對(duì)所有key的監(jiān)控。 |
| MULTI | MULTI命令用于開(kāi)啟一個(gè)事務(wù),它總是返回OK。MULTI執(zhí)行之后,客戶(hù)端可以繼續(xù)向服務(wù)器發(fā)送任意多條命令,這些命令不會(huì)立即被執(zhí)行,而是被放到一個(gè)隊(duì)列中,當(dāng)EXEC命令被調(diào)用時(shí),所有隊(duì)列中的命令才會(huì)被執(zhí)行。 |
| EXEC | EXEC:執(zhí)行所有事務(wù)塊內(nèi)的命令。返回事務(wù)塊內(nèi)所有命令的返回值,按命令執(zhí)行的先后順序排列。當(dāng)操作被打斷時(shí),返回空值 nil 。 |
| DISCARD | 通過(guò)調(diào)用DISCARD,客戶(hù)端可以清空事務(wù)隊(duì)列,并放棄執(zhí)行事務(wù), 并且客戶(hù)端會(huì)從事務(wù)狀態(tài)中退出。 |
7.談?wù)勀銓?duì)Redis集群方案——哨兵模式 的理解
哨兵的介紹
sentinel,中文名是哨兵。哨兵是 redis 集群機(jī)構(gòu)中非常重要的一個(gè)組件,主要有以下功能:
- 集群監(jiān)控:負(fù)責(zé)監(jiān)控 redis master 和 slave 進(jìn)程是否正常工作。
- 消息通知:如果某個(gè) redis 實(shí)例有故障,那么哨兵負(fù)責(zé)發(fā)送消息作為報(bào)警通知給管理員。
- 故障轉(zhuǎn)移:如果 master node 掛掉了,會(huì)自動(dòng)轉(zhuǎn)移到 slave node 上。
- 配置中心:如果故障轉(zhuǎn)移發(fā)生了,通知 client 客戶(hù)端新的 master 地址。
哨兵用于實(shí)現(xiàn) redis 集群的高可用,本身也是分布式的,作為一個(gè)哨兵集群去運(yùn)行,互相協(xié)同工作。
8.Redis主從復(fù)制的原理是什么?
9.Redis如何實(shí)現(xiàn)分布式鎖?
Redis為單進(jìn)程單線(xiàn)程模式,采用隊(duì)列模式將并發(fā)訪(fǎng)問(wèn)變成串行訪(fǎng)問(wèn),且多客戶(hù)端對(duì)Redis的連接并不存在競(jìng)爭(zhēng)關(guān)系,Redis中可以使用SETNX命令實(shí)現(xiàn)分布式鎖。
SETNX 是『SET if Not eXists』(如果不存在,則 SET)的簡(jiǎn)寫(xiě)。
當(dāng)且僅當(dāng) key 不存在,將 key 的值設(shè)為 value。若給定的 key 已經(jīng)存在,則 SETNX 不做任何動(dòng)作
返回值:設(shè)置成功,返回 1 。設(shè)置失敗,返回 0 。
使用SETNX完成同步鎖的流程及事項(xiàng)如下:
-
使用SETNX命令獲取鎖,若返回0(key已存在,鎖已存在)則獲取失敗,若返回1則獲取成功
-
為了防止獲取鎖后程序出現(xiàn)異常,導(dǎo)致其他線(xiàn)程/進(jìn)程調(diào)用SETNX命令總是返回0而進(jìn)入死鎖狀態(tài),需要為該key設(shè)置一個(gè)合理的過(guò)期時(shí)間
-
釋放鎖,使用DEL命令將鎖數(shù)據(jù)刪除
10.Redis中的緩存穿透、緩存擊穿、緩存雪崩是什么?
緩存穿透:
當(dāng)我們?cè)L問(wèn)某個(gè)key時(shí),這個(gè)key對(duì)應(yīng)的數(shù)據(jù)在數(shù)據(jù)源并不存在,每次針對(duì)這個(gè)key的請(qǐng)求從緩存中都獲取不到,那么這些請(qǐng)求都會(huì)壓到數(shù)據(jù)源(DB),從而可能壓垮數(shù)據(jù)源。比如用一個(gè)不存在的用戶(hù)id獲取用戶(hù)信息,不論緩存還是數(shù)據(jù)庫(kù)都沒(méi)有,若黑客利用此漏洞進(jìn)行攻擊可能壓垮數(shù)據(jù)庫(kù)。
解決方案:
- 對(duì)空值緩存:如果一個(gè)查詢(xún)返回的數(shù)據(jù)為空(不管是數(shù)據(jù)是否不存在),我們?nèi)匀话堰@個(gè)空結(jié)果(null)進(jìn)行緩存,設(shè)置空結(jié)果的過(guò)期時(shí)間會(huì)很短,最長(zhǎng)不超過(guò)五分鐘。
- 設(shè)置可訪(fǎng)問(wèn)的名單(白名單):使用bitmaps類(lèi)型定義一個(gè)可以訪(fǎng)問(wèn)的名單,名單id作為bitmaps的偏移量,每次訪(fǎng)問(wèn)和bitmap里面的id進(jìn)行比較,如果訪(fǎng)問(wèn)id不在bitmaps里面,進(jìn)行攔截,不允許訪(fǎng)問(wèn)。
- 采用布隆過(guò)濾器:將所有可能存在的數(shù)據(jù)哈希到一個(gè)足夠大的bitmaps中,一個(gè)一定不存在的數(shù)據(jù)會(huì)被 這個(gè)bitmaps攔截掉,從而避免了對(duì)底層存儲(chǔ)系統(tǒng)的查詢(xún)壓力。
緩存擊穿:
key對(duì)應(yīng)的數(shù)據(jù)存在,但在redis中過(guò)期,此時(shí)若有大量并發(fā)請(qǐng)求過(guò)來(lái),這些請(qǐng)求發(fā)現(xiàn)緩存過(guò)期一般都會(huì)從后端DB加載數(shù)據(jù)并回設(shè)到緩存,這個(gè)時(shí)候大并發(fā)的請(qǐng)求可能會(huì)瞬間把后端DB壓垮。
解決方案:
- 預(yù)先設(shè)置熱門(mén)數(shù)據(jù):在redis高峰訪(fǎng)問(wèn)之前,把一些熱門(mén)數(shù)據(jù)提前存入到redis里面,加大這些熱門(mén)數(shù)據(jù)key的存活時(shí)長(zhǎng),避免在高并發(fā)期間這些數(shù)據(jù)過(guò)期。
- 實(shí)時(shí)調(diào)整:現(xiàn)場(chǎng)監(jiān)控哪些數(shù)據(jù)熱門(mén),實(shí)時(shí)調(diào)整key的過(guò)期時(shí)長(zhǎng)。
- 使用鎖
緩存雪崩:
當(dāng)我們?cè)L問(wèn)多個(gè)key對(duì)應(yīng)的數(shù)據(jù)時(shí),這些key在redis中都過(guò)期(無(wú)法獲取)了,那么這些大量的高并發(fā)請(qǐng)求就會(huì)轉(zhuǎn)到后端DB中去查找訪(fǎng)問(wèn),進(jìn)而造成了數(shù)據(jù)庫(kù)的崩潰現(xiàn)象。緩存雪崩與緩存擊穿的區(qū)別在于:緩存雪崩是針對(duì)很多key而言的緩存,而緩存擊穿則是針對(duì)某一個(gè)key。
解決方案:
- 構(gòu)建多級(jí)緩存架構(gòu):nginx緩存 + redis緩存 +其他緩存(ehcache等)。
- 使用鎖或隊(duì)列:用加鎖或者隊(duì)列的方式保證不會(huì)有大量的線(xiàn)程對(duì)數(shù)據(jù)庫(kù)一次性進(jìn)行讀寫(xiě),從而避免失效時(shí)大量的并發(fā)請(qǐng)求落到底層存儲(chǔ)系統(tǒng)上。不適用高并發(fā)情況。
- 設(shè)置過(guò)期標(biāo)志更新緩存:記錄緩存數(shù)據(jù)是否過(guò)期(設(shè)置提前量),如果過(guò)期會(huì)觸發(fā)通知另外的線(xiàn)程在后臺(tái)去更新實(shí)際key的緩存。
- 將緩存失效時(shí)間分散開(kāi):比如我們可以在原有的失效時(shí)間基礎(chǔ)上增加一個(gè)隨機(jī)值,比如1-5分鐘隨機(jī),這樣每一個(gè)緩存的過(guò)期時(shí)間的重復(fù)率就會(huì)降低,就很難引發(fā)集體失效的事件。
總結(jié)
以上是生活随笔為你收集整理的Java面试——Redis系列总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 第四范式团队KDD Cup世界冠军方案详
- 下一篇: java美元兑换,(Java实现) 美元