使用場景
1.數(shù)據(jù)高并發(fā)的讀寫
2.海量數(shù)據(jù)的讀寫
3.對擴(kuò)展性要求高的數(shù)據(jù)配合關(guān)系型數(shù)據(jù)庫做高速緩存緩存高頻次訪問的數(shù)據(jù)久脯,降低數(shù)據(jù)庫io分布式架構(gòu)默伍,做session共享可以持久化特定數(shù)據(jù)蹂安。利用zset類型可以存儲(chǔ)排行榜利用list的自然時(shí)間排序存儲(chǔ)最新n個(gè)數(shù)據(jù)
Redis快的主要原因是:
1.完全基于內(nèi)存
2.數(shù)據(jù)結(jié)構(gòu)簡單章鲤,對數(shù)據(jù)操作也簡單
3.使用多路 I/O 復(fù)用模型
單進(jìn)程單線程好處
1.代碼更清晰挠蛉,處理邏輯更簡單
2.不用去考慮各種鎖的問題辐益,不存在加鎖釋放鎖操作断傲,沒有因?yàn)榭赡艹霈F(xiàn)死鎖而導(dǎo)致的性能消耗
3.不存在多進(jìn)程或者多線程導(dǎo)致的切換而消耗CPU
Redis6.0的新特性
1.多線程IO
Redis 6引入多線程IO,但多線程部分只是用來處理網(wǎng)絡(luò)數(shù)據(jù)的讀寫和協(xié)議解析智政,執(zhí)行命令仍然是單線程认罩。之所以這么設(shè)計(jì)是不想因?yàn)槎嗑€程而變得復(fù)雜,需要去控制 key续捂、lua垦垂、事務(wù),LPUSH/LPOP等等的并發(fā)問題牙瓢。
2.重新設(shè)計(jì)了客戶端緩存功能實(shí)現(xiàn)了Client-side-caching(客戶端緩存)功能劫拗。放棄了caching slot,而只使用key names一罩。Redis server-assisted client side caching
3.RESP3協(xié)議
RESP(Redis Serialization Protocol)是 Redis 服務(wù)端與客戶端之間通信的協(xié)議杨幼。Redis 5 使用的是 RESP2,而 Redis 6 開始在兼容 RESP2 的基礎(chǔ)上聂渊,開始支持 RESP3差购。
推出RESP3的目的:一是因?yàn)橄M転榭蛻舳颂峁└嗟恼Z義化響應(yīng),以開發(fā)使用舊協(xié)議難以實(shí)現(xiàn)的功能汉嗽;另一個(gè)原因是實(shí)現(xiàn) Client-side-caching(客戶端緩存)功能欲逃。
4.支持SSL
連接支持SSL,更加安全饼暑。
5.ACL權(quán)限控制
1).支持對客戶端的權(quán)限控制稳析,實(shí)現(xiàn)對不同的key授予不同的操作權(quán)限。
2).有一個(gè)新的ACL日志命令弓叛,允許查看所有違反ACL的客戶機(jī)彰居、訪問不應(yīng)該訪問的命令、訪問不應(yīng)該訪問的密鑰撰筷,或者驗(yàn)證嘗試失敗陈惰。這對于調(diào)試ACL問題非常有用。
6.提升了RDB日志加載速度根據(jù)文件的實(shí)際組成(較大或較小的值)毕籽,可以預(yù)期20/30%的改進(jìn)抬闯。當(dāng)有很多客戶機(jī)連接時(shí)井辆,信息也更快了,這是一個(gè)老問題溶握,現(xiàn)在終于解決了杯缺。
7.發(fā)布官方的Redis集群代理模塊RedisCluster proxy。在 Redis 集群中睡榆,客戶端會(huì)非常分散萍肆,現(xiàn)在為此引入了一個(gè)集群代理,可以為客戶端抽象 Redis 群集肉微,使其像正在與單個(gè)實(shí)例進(jìn)行對話一樣匾鸥。同時(shí)在簡單且客戶端僅使用簡單命令和功能時(shí)執(zhí)行多路復(fù)用。
8.提供了眾多的新模塊(modules)API
怎么保證緩存和數(shù)據(jù)庫數(shù)據(jù)的一致性碉纳?
Redis持久化有幾種方式勿负?
Redis提供兩種持久化機(jī)制 RDB 和 AOF 機(jī)制:
1.snapshotting(快照),這個(gè)是redis默認(rèn)持久化的方式劳曹∨洌快照是redis默認(rèn)的持久化的方式,這種方式在規(guī)定的時(shí)間將內(nèi)存中數(shù)據(jù)以快照的方式寫入到二進(jìn)制文件中(所有數(shù)據(jù)完全備份)铁孵,默認(rèn)的文件名是:dump.rdb锭硼;可以通過配置設(shè)置自動(dòng)持久化的方式,我們可以修改redis.conf文件蜕劝,來配置redis在n秒如果超過m個(gè)key被修改檀头,則自動(dòng)做快照操作。
2.Append-only file岖沛,簡稱aof的方式由于快照的方式有一定的間隔時(shí)間暑始,所以如果redis在間隔時(shí)間內(nèi)意外down掉后,就會(huì)丟失最后一次快照后的所有數(shù)據(jù)婴削。
aof比快照方式有更好的持久化性廊镜,是由于在使用aof時(shí),redis會(huì)將每一個(gè)收到的命令通過write函數(shù)追加到文件中唉俗,當(dāng)redis重啟后嗤朴,會(huì)通過重新執(zhí)行aof文件中的內(nèi)容,來在內(nèi)存中重建整個(gè)數(shù)據(jù)庫的內(nèi)容虫溜。
redis過期鍵的刪除策略
(1)定時(shí)刪除:在設(shè)置鍵的過期時(shí)間的同時(shí)雹姊,創(chuàng)建一個(gè)定時(shí)器 timer). 讓定時(shí)器在鍵的過期時(shí)間來臨時(shí),立即執(zhí)行對鍵的刪除操作衡楞。
(2)惰性刪除:放任鍵過期不管容为,但是每次從鍵空間中獲取鍵時(shí),都檢查取得的鍵是否過期,如果過期的話坎背,就刪除該鍵;如果沒有過期,就返回該鍵寄雀。
(3)定期刪除:每隔一段時(shí)間程序就對數(shù)據(jù)庫進(jìn)行一次檢查得滤,刪除里面的過期鍵。至于要?jiǎng)h除多少過期鍵盒犹,以及要檢查多少個(gè)數(shù)據(jù)庫懂更,則由算法決定。
Redis的回收策略(淘汰策略)
volatile-lru:從已設(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:從數(shù)據(jù)集(server.db[i].dict)中挑選最近最少使用的數(shù)據(jù)淘汰
allkeys-random:從數(shù)據(jù)集(server.db[i].dict)中任意選擇數(shù)據(jù)淘汰no-enviction(驅(qū)逐):禁止驅(qū)逐數(shù)據(jù)注意這里的 6 種機(jī)制急膀,volatile 和 allkeys 規(guī)定了是對已設(shè)置過期時(shí)間的數(shù)據(jù)集淘汰數(shù)據(jù)還是從全部數(shù)據(jù)集淘汰數(shù)據(jù)沮协,后面的 lru、ttl 以及 random 是三種不同的淘汰策略卓嫂,再加上一種 no-enviction 永不回收的策略慷暂。
使用策略規(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的同步機(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哈希槽
Redis集群沒有使用一致性 hash,而是引入了哈希槽的概念豁翎,Redis 集群有16384 個(gè)哈希槽,每個(gè) key 通過 CRC16 校驗(yàn)后對16384 取模來決定放置哪個(gè)槽隅忿,集群的每個(gè)節(jié)點(diǎn)負(fù)責(zé)一部分 hash 槽心剥。
Redis事務(wù)相關(guān)的命令
MULTI、EXEC背桐、DISCARD优烧、WATCH
MySQL里有 2000w 數(shù)據(jù),redis 中只存 20w 的數(shù)據(jù)链峭,如何保證 redis 中的數(shù)據(jù)都是熱點(diǎn)數(shù)據(jù)畦娄?
Redis內(nèi)存數(shù)據(jù)集大小上升到一定大小的時(shí)候,就會(huì)施行數(shù)據(jù)淘汰策略。相關(guān)知識(shí):Redis 提供 6 種數(shù)據(jù)淘汰策略:
volatile-lru:從已設(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:從數(shù)據(jù)集(server.db[i].dict)中挑選最近最少使用的數(shù)據(jù)淘汰
allkeys-random:從數(shù)據(jù)集(server.db[i].dict)中任意選擇數(shù)據(jù)淘汰
no-enviction(驅(qū)逐):禁止驅(qū)逐數(shù)據(jù)
使用過 Redis 做異步隊(duì)列么熙卡,你是怎么用的
一般使用 list 結(jié)構(gòu)作為隊(duì)列杖刷,rpush 生產(chǎn)消息,lpop 消費(fèi)消息驳癌。當(dāng) lpop 沒有消息的時(shí)候滑燃,要適當(dāng) sleep 一會(huì)再重試。如果對方追問可不可以不用 sleep 呢颓鲜?list 還有個(gè)指令叫 blpop表窘,在沒有消息的時(shí)候,它會(huì)阻塞住直到消息到來甜滨。如果對方追問能不能生產(chǎn)一次消費(fèi)多次呢乐严?使用 pub/sub 主題訂閱者模式,可以實(shí)現(xiàn)1:N 的消息隊(duì)列衣摩。如果對方追問 pub/sub 有什么缺點(diǎn)昂验?在消費(fèi)者下線的情況下,生產(chǎn)的消息會(huì)丟失昭娩,得使用專業(yè)的消息隊(duì)列如 RabbitMQ等凛篙。如果對方追問 redis 如何實(shí)現(xiàn)延時(shí)隊(duì)列?使用 sortedset栏渺,拿時(shí)間戳作為score呛梆,消息內(nèi)容作為 key 調(diào)用 zadd 來生產(chǎn)消息,消費(fèi)者用 zrangebyscore 指令獲取 N 秒之前的數(shù)據(jù)輪詢進(jìn)行處理磕诊。
如何解決 Redis 的并發(fā)競爭 Key 問題
所謂 Redis 的并發(fā)競爭 Key 的問題也就是多個(gè)系統(tǒng)同時(shí)對一個(gè) key 進(jìn)行操作填物,但是最后執(zhí)行的順序和我們期望的順序不同,這樣也就導(dǎo)致了結(jié)果的不同霎终!
推薦一種方案:分布式鎖(zookeeper 和 redis 都可以實(shí)現(xiàn)分布式鎖)滞磺。(如果不存在 Redis 的并發(fā)競爭 Key 問題,不要使用分布式鎖莱褒,這樣會(huì)影響性能)
基于zookeeper臨時(shí)有序節(jié)點(diǎn)可以實(shí)現(xiàn)的分布式鎖击困。大致思想為:每個(gè)客戶端對某個(gè)方法加鎖時(shí),在zookeeper上的與該方法對應(yīng)的指定節(jié)點(diǎn)的目錄下广凸,生成一個(gè)唯一的瞬時(shí)有序節(jié)點(diǎn)阅茶。 判斷是否獲取鎖的方式很簡單,只需要判斷有序節(jié)點(diǎn)中序號(hào)最小的一個(gè)谅海。當(dāng)釋放鎖的時(shí)候脸哀,只需將這個(gè)瞬時(shí)節(jié)點(diǎn)刪除即可。同時(shí)扭吁,其可以避免服務(wù)宕機(jī)導(dǎo)致的鎖無法釋放撞蜂,而產(chǎn)生的死鎖問題盲镶。完成業(yè)務(wù)流程后,刪除對應(yīng)的子節(jié)點(diǎn)釋放鎖蝌诡。
在實(shí)踐中溉贿,當(dāng)然是從以可靠性為主。所以首推Zookeeper送漠。
redis緩存穿透的概念以及解決
緩存穿透:key對應(yīng)的數(shù)據(jù)在數(shù)據(jù)源并不存在顽照,每次針對此key的請求從緩存獲取不到,請求都會(huì)到數(shù)據(jù)源闽寡,從而可能壓垮數(shù)據(jù)源。比如用一個(gè)不存在的用戶id獲取用戶信息尼酿,不論緩存還是數(shù)據(jù)庫都沒有爷狈,若黑客利用此漏洞進(jìn)行攻擊可能壓垮數(shù)據(jù)庫。
解決方案:
1.布隆過濾器
原理就是一個(gè)對一個(gè)key進(jìn)行k個(gè)hash算法獲取k個(gè)值裳擎,在比特?cái)?shù)組中將這k個(gè)值散列后設(shè)定為1涎永,然后查的時(shí)候如果特定的這幾個(gè)位置都為1,那么布隆過濾器判斷該key存在鹿响。
布隆過濾器可能會(huì)誤判羡微,如果它說不存在那肯定不存在,如果它說存在惶我,那數(shù)據(jù)有可能實(shí)際不存在
2.緩存層緩存空值
將數(shù)據(jù)庫中的空值也緩存到緩存層中妈倔,這樣查詢該空值就不會(huì)再訪問DB,而是直接在緩存層訪問就行绸贡。
但是這樣有個(gè)弊端就是緩存太多空值占用了更多的空間盯蝴,可以通過給緩存層空值設(shè)立一個(gè)較短的過期時(shí)間來解決,例如60s听怕。
redis緩存擊穿的概念以及解決
緩存擊穿:key對應(yīng)的數(shù)據(jù)存在捧挺,但在redis中過期,此時(shí)若有大量并發(fā)請求過來尿瞭,這些請求發(fā)現(xiàn)緩存過期一般都會(huì)從后端DB加載數(shù)據(jù)并回設(shè)到緩存闽烙,這個(gè)時(shí)候大并發(fā)的請求可能會(huì)瞬間把后端DB壓垮。
解決方案:
使用mutex声搁。簡單地來說黑竞,就是在緩存失效的時(shí)候(判斷拿出來的值為空),不是立即去load db酥艳,而是先使用緩存工具的某些帶成功操作返回值的操作(比如Redis的SETNX或者M(jìn)emcache的ADD)去set一個(gè)mutex key摊溶,當(dāng)操作返回成功時(shí),再進(jìn)行l(wèi)oad db的操作并回設(shè)緩存充石;否則莫换,就重試整個(gè)get緩存的方法
redis緩存雪崩的概念以及解決
緩存雪崩:緩存中大批量的數(shù)據(jù)都到了過期時(shí)間霞玄,從而導(dǎo)致查詢數(shù)據(jù)量巨大,引起數(shù)據(jù)庫壓力過大甚至down機(jī)拉岁。和緩存擊穿不同坷剧,緩存擊穿是指某一條數(shù)據(jù)到了過期時(shí)間,大量的并發(fā)請求都來查詢這一條數(shù)據(jù)喊暖,緩存雪崩是不同數(shù)據(jù)都過期了惫企,很多數(shù)據(jù)都查不到從而查數(shù)據(jù)庫
解決方案:
1、設(shè)置熱點(diǎn)數(shù)據(jù)永不過期
2陵叽、緩存數(shù)據(jù)的過期時(shí)間設(shè)置隨機(jī)狞尔,可以在原有的過期時(shí)間上加上一個(gè)隨機(jī)值,比如1-3min巩掺,防止同一時(shí)間大量緩存數(shù)據(jù)集體失效偏序,導(dǎo)致數(shù)據(jù)庫壓力過大。
3胖替、如果是分布式部署緩存數(shù)據(jù)庫研儒,可將熱點(diǎn)數(shù)據(jù)分別存放到不同的緩存數(shù)據(jù)庫中,避免某一點(diǎn)由于壓力過大而down掉独令。