Redis是一種開源的基于BSD許可的內(nèi)存數(shù)據(jù)庫,可用作數(shù)據(jù)庫、緩存、消息代理等,是NoSQL型數(shù)據(jù)庫
Redis的特點
Redis是基于內(nèi)存的,操作速度非???/span>
Redis是單進程單線程的,線程安全,采用IO多路復(fù)用機制
Redis支持豐富的數(shù)據(jù)類型,字符串(String)、哈希(Hash)、列表(List)、集合(Set)、有序集合(sorted set)等
Redis所有操作都是原子性的,要么全部成功,要么全部失敗
Redis為什么這么快?
redis速度非??欤蛇_到每秒十萬級的吞吐量,這基于以下幾點原因
redis是基于內(nèi)存實現(xiàn)的,內(nèi)存的讀寫速度要遠(yuǎn)高于硬盤的讀寫速度
redis主體是單線程的,沒有鎖的問題。說明:redis整體不是單線程的,處理請求時是單線程執(zhí)行
特殊的數(shù)據(jù)結(jié)構(gòu),redis中字符串用的是SDS動態(tài)字符串
SDS與C的字符串:
C中字符串未記錄字符串長度,查詢字符串長度時需要遍歷整個字符串,時間復(fù)雜度為O(n),并且在擴充和縮短字符串時,要注意緩沖區(qū)溢出和內(nèi)存泄漏問題
SDS字符串的len存儲了字符串長度信息,查詢字符串長度時間復(fù)雜度為O(1),在擴充字符串時會先檢查空間是否滿足需求空間,如果不滿足,則會先對SDS空間進行擴展,避免了緩沖區(qū)溢出
SDS字符串減少了內(nèi)存分配次數(shù),在擴充字符串時會執(zhí)行空間預(yù)分配(空間分配策略),在修改后字符串長度時,不僅分配了必須的空間,還會分配一定大小的free未使用空間(修改后長度小于1MB,則和字符串長度相等,反之,最大為1MB);在縮短字符串時,采用了惰性空間釋放,即修改字符串長度后,不會立即釋放空間,而是將空間分配到free未使用空間中,以便于下次使用
SDS字符串是二進制安全的,因為buf存儲的不是字符,存儲的是二進制數(shù)據(jù)
I/O多路復(fù)用
Redis服務(wù)器是一個事件驅(qū)動程序,包含了文件事件和時間事件。文件事件就是redis服務(wù)器和其他端進行通信時產(chǎn)生的相應(yīng)的文件;時間事件是redis內(nèi)部的一些在給定時間內(nèi)要進行的操作
文件事件處理器是單線程執(zhí)行的,但內(nèi)部實現(xiàn)了I/O多路復(fù)用,即內(nèi)部通過監(jiān)聽同時監(jiān)聽多個Socket連接,快速響應(yīng)連接請求,但在內(nèi)部I/O多路復(fù)用程序會將Socket放在一個有序的隊列中,通過文件事件分派器有序分配給事件處理器進行處理,一個Socket的事件執(zhí)行完畢后,才會執(zhí)行下一個Socket,即是單線程。但這里也要注意事件處理器里并不是單線程的
Redis數(shù)據(jù)的更新、過期可采用的策略是什么?
數(shù)據(jù)更新策略(redis緩存與DB數(shù)據(jù)保證一致性)
Cache-Aside pattern 緩存更新模式
在查詢時,首先去查詢緩存,如果命中了緩存,就取出返回數(shù)據(jù)。如果沒有命中緩存,則去數(shù)據(jù)庫進行查詢,并保存在redis緩存中,這樣保證了緩存的數(shù)據(jù)會進行更新;對數(shù)據(jù)進行更新的時候,先進行DB數(shù)據(jù)的更新,再刪除緩存,這樣避免了舊數(shù)據(jù)緩存一直存在(查詢時一直命中舊數(shù)據(jù)緩存)
定期刪除 優(yōu)點:節(jié)約了內(nèi)存 缺點:cpu壓力大
redis會間隔一段時間(默認(rèn)100ms)去隨機抽取一些設(shè)置了過期時間的緩存,檢查其是否過期。隨機抽取的原因是,如果按照一定數(shù)量去順序查詢時,后面的過期緩存可能長時間不能被清理,若每次都是全量的檢查時,數(shù)據(jù)量大,cpu壓力。
惰性刪除 優(yōu)點:cpu壓力小 缺點:內(nèi)存壓力大
redis不進行主動的刪除,當(dāng)查詢數(shù)據(jù)時,若該數(shù)據(jù)沒有過期,則返回數(shù)據(jù),反之,則刪除數(shù)據(jù),避免了cpu壓力大的情況,但是若過期數(shù)據(jù)長期未被查詢,則一直存留,增加了內(nèi)存的壓力
Redis的淘汰機制有哪些?
在數(shù)據(jù)過期策略中提到惰性刪除時,可能會有數(shù)據(jù)長時間未被刪除,再加上未過期數(shù)據(jù),那么就可能達到內(nèi)存限制的上限,此時需要進行數(shù)據(jù)淘汰
新寫入數(shù)據(jù)時報錯(默認(rèn)策略)
在鍵空間中,移除最近很少使用的key(LRU算法推薦)
Redis持久化有哪些方式?
RDB
快照形式,定時在redis需要做持久化時,redis會開啟子進程,將redis中的數(shù)據(jù)寫入dump.rdb文件中保存在硬盤
優(yōu)點:RDB存儲效率高,文件體積小,恢復(fù)時速度快于AOF
缺點:定時執(zhí)行,未保存數(shù)據(jù),redis就重啟了,不能保證數(shù)據(jù)完整性
AOF
默認(rèn)每秒鐘一次,將redis的修改命令全部保存在一個AOF文件中,每當(dāng)redis服務(wù)器做一次修改命令,都將該命令保存下來,從而達到持久化
優(yōu)點:數(shù)據(jù)足夠完整,即便丟失也僅丟失了一秒的數(shù)據(jù)
缺點:相對于RDB文件,恢復(fù)數(shù)據(jù)速度慢,文件體積大
從優(yōu)缺點中可以看出當(dāng)你的程序需要高度保證數(shù)據(jù)的完整性時還是采用AOF方式更加可靠
Redis緩存雪崩、穿透、擊穿的原因和解決方案有哪些?
緩存雪崩:
原因:存在緩存設(shè)置了過期時間且大量緩存在短時間段內(nèi)過期的情況
解決方案:
在可接受的范圍內(nèi),隨機設(shè)置過期時間
緩存穿透:
原因:
接口被攻擊,非常規(guī)查詢,如:查詢id<0,使得緩存無法命中
解決方案:
做一些通用的簡單校驗,例如:查詢時,若id<=0,則不進行查詢
緩存一條全空數(shù)據(jù),過期時間要盡可能小一點,效果可能不太理想
緩存擊穿:
原因:大量的請求命中相同一個key,在此key失效時,對應(yīng)的請求全部落到數(shù)據(jù)庫上
解決方案:
加鎖,排隊進行請求,若key不存在(不論是過期還是首次查詢無緩存),則進行一次DB查詢,然后將數(shù)據(jù)緩存進redis
閱讀原文:原文鏈接
該文章在 2025/8/15 12:08:56 編輯過