前言
大家好,這里是浩道linux,主要給大家分享linux、python、網(wǎng)絡通信相關的IT知識平臺。
今天浩道跟大家分享硬核干貨,關于redis總結,讓你一文掌握redis大體知識點!
1、什么是redis?
Redis 本質上是一個 Key-Value 類型的內存數(shù)據(jù)庫, 整個數(shù)據(jù)庫加載在內存當中進行操作, 定期通過異步操作把數(shù)據(jù)庫數(shù)據(jù) flush 到硬盤上進行保存。
因為是純內存操作, Redis 的性能非常出色, 每秒可以處理超過 10 萬次讀寫操作, 是已知性能最快的 Key-Value DB。
Redis 的出色之處不僅僅是性能, Redis 最大的魅力是支持保存多種數(shù)據(jù)結構, 此外單個value 的最大限制是 1GB, 不像 memcached 只能保存 1MB 的數(shù)據(jù), 因此 Redis 可以用來實現(xiàn)很多有用的功能,比方說用他的 List 來做 FIFO 雙向鏈表,實現(xiàn)一個輕量級的高性 能消息隊列服務, 用他的 Set 可以做高性能的 tag 系統(tǒng)等等。
另外 Redis 也可以對存入的Key-Value 設置 expire 時間, 因此也可以被當作一 個功能加強版的 memcached 來用。Redis 的主要缺點是數(shù)據(jù)庫容量受到物理內存的限制, 不能用作海量數(shù)據(jù)的高性能讀寫, 因此 Redis 適合的場景主要局限在較小數(shù)據(jù)量的高性能操作和運算上。
2、相比 memcached 有哪些優(yōu)勢?
redis支持更豐富的數(shù)據(jù)類型(支持更復雜的應用場景)
Redis不僅僅支持簡單的k/v類型的數(shù)據(jù),同時還提供list,set,zset,hash等數(shù)據(jù)結構的存儲。
memcache支持簡單的數(shù)據(jù)類型,String。Redis支持數(shù)據(jù)的持久化,可以將內存中的數(shù)據(jù)保持在磁盤中,重啟的時候可以再次加載進行使用,而Memecache把數(shù)據(jù)全部存在內存之中。
集群模式:
memcached沒有原生的集群模式,需要依靠客戶端來實現(xiàn)往集群中分片寫入數(shù)據(jù);
但是 redis 目前是原生支持 cluster 模式的.
Memcached是多線程,非阻塞IO復用的網(wǎng)絡模型;Redis使用單線程的多路 IO 復用模型。
3、Redis 的全稱是什么?
4、支持哪幾種數(shù)據(jù)類型?
String、 List、 Set、 Sorted Set、 hashes
5、Redis 有哪幾種數(shù)據(jù)淘汰策略?
noeviction:返回錯誤當內存限制達到并且客戶端嘗試執(zhí)行會讓更多內存被使用的命令(大部分的寫入指令, 但 DEL 和幾個例外)
allkeys-lru: 嘗試回收最少使用的鍵(LRU), 使得新添加的數(shù)據(jù)有空間存放。
volatile-lru: 嘗試回收最少使用的鍵(LRU), 但僅限于在過期集合的鍵,使得新添加的數(shù)據(jù)有空間存放。
allkeys-random: 回收隨機的鍵使得新添加的數(shù)據(jù)有空間存放。
volatile-random: 回收隨機的鍵使得新添加的數(shù)據(jù)有空間存放,但僅限于在過期集合的鍵。
volatile-ttl: 回收在過期集合的鍵, 并且優(yōu)先回收存活時間(TTL) 較短的鍵,使得新添加的數(shù)據(jù)有空間存放。
6、redis為什么采用跳表而不是紅黑樹
在做范圍查找的時候,平衡樹比skiplist操作要復雜。在平衡樹上,我們找到指定范圍的小值之后,還需要以中序遍歷的順序繼續(xù)尋找其它不超過大值的節(jié)點。如果不對平衡樹進行一定的改造,這里的中序遍歷并不容易實現(xiàn)。而在skiplist上進行范圍查找就非常簡單,只需要在找到小值之后,對第1層鏈表進行若干步的遍歷就可以實現(xiàn)。
平衡樹的插入和刪除操作可能引發(fā)子樹的調整,邏輯復雜,而skiplist的插入和刪除只需要修改相鄰節(jié)點的指針,操作簡單又快速。
從內存占用上來說,skiplist比平衡樹更靈活一些。一般來說,平衡樹每個節(jié)點包含2個指針(分別指向左右子樹),而skiplist每個節(jié)點包含的指針數(shù)目平均為1/(1-p),具體取決于參數(shù)p的大小。如果像Redis里的實現(xiàn)一樣,取p=1/4,那么平均每個節(jié)點包含1.33個指針,比平衡樹更有優(yōu)勢。
查找單個key,skiplist和平衡樹的時間復雜度都為O(log n),大體相當;而哈希表在保持較低的哈希值沖突概率的前提下,查找時間復雜度接近O(1),性能更高一些。所以我們平常使用的各種Map或dictionary結構,大都是基于哈希表實現(xiàn)的。
從算法實現(xiàn)難度上來比較,skiplist比平衡樹要簡單得多。
7、介紹一下HyperLogLog?
HyperLogLog 是一種概率數(shù)據(jù)結構,用來估算數(shù)據(jù)的基數(shù)。數(shù)據(jù)集可以是網(wǎng)站訪客的 IP 地址,E-mail 郵箱或者用戶 ID。
基數(shù)就是指一個集合中不同值的數(shù)目,比如 a, b, c, d 的基數(shù)就是 4,a, b, c, d, a 的基數(shù)還是 4。雖然 a 出現(xiàn)兩次,只會被計算一次。
使用 Redis 統(tǒng)計集合的基數(shù)一般有三種方法,分別是使用 Redis 的 HashMap,BitMap 和 HyperLogLog。前兩個數(shù)據(jù)結構在集合的數(shù)量級增長時,所消耗的內存會大大增加,但是 HyperLogLog 則不會。
Redis 的 HyperLogLog 通過犧牲準確率來減少內存空間的消耗,只需要12K內存,在標準誤差0.81%的前提下,能夠統(tǒng)計2^64個數(shù)據(jù)。所以 HyperLogLog 是否適合在比如統(tǒng)計日活月活此類的對精度要不不高的場景。
這是一個很驚人的結果,以如此小的內存來記錄如此大數(shù)量級的數(shù)據(jù)基數(shù)。
8、為什么 Redis 需要把所有數(shù)據(jù)放到內存中?
Redis 為了達到最快的讀寫速度將數(shù)據(jù)都讀到內存中, 并通過異步的方式將數(shù)據(jù)寫入磁盤。
所以 Redis 具有快速和數(shù)據(jù)持久化的特征。如果不將數(shù)據(jù)放在內存中, 磁盤 I/O 速度為嚴重影響 Redis 的性能。在內存越來越便宜的今天, Redis 將會越來越受歡迎。
9、Redis支持的數(shù)據(jù)類型?
String字符串:
格式: set key value
string類型是二進制安全的。意思是redis的string可以包含任何數(shù)據(jù)。比如jpg圖片或者序列化的對象 。
string類型是Redis最基本的數(shù)據(jù)類型,一個鍵最大能存儲512MB。
Hash(哈希)
格式: hmset name key1 value1 key2 value2
Redis hash 是一個鍵值(key=>value)對集合。
Redis hash是一個string類型的field和value的映射表,hash特別適合用于存儲對象。
List(列表)
Redis 列表是簡單的字符串列表,按照插入順序排序。你可以添加一個元素到列表的頭部(左邊)或者尾部(右邊)
格式: lpush name value
在 key 對應 list 的頭部添加字符串元素
格式: rpush name value
在 key 對應 list 的尾部添加字符串元素
格式: lrem name index
key 對應 list 中刪除 count 個和 value 相同的元素
格式: llen name
返回 key 對應 list 的長度
Set(集合)
格式: sadd name value
Redis的Set是string類型的無序集合。
集合是通過哈希表實現(xiàn)的,所以添加,刪除,查找的復雜度都是O(1)。
zset(sorted set:有序集合)
格式: zadd name score value
Redis zset 和 set 一樣也是string類型元素的集合,且不允許重復的成員。
不同的是每個元素都會關聯(lián)一個double類型的分數(shù)。redis正是通過分數(shù)來為集合中的成員進行從小到大的排序。
zset的成員是唯一的,但分數(shù)(score)卻可以重復。
10、sds相對c的改進?
獲取長度:c字符串并不記錄自身長度,所以獲取長度只能遍歷一遍字符串,redis直接讀取len即可。
緩沖區(qū)安全:c字符串容易造成緩沖區(qū)溢出,比如:程序員沒有分配足夠的空間就執(zhí)行拼接操作。而redis會先檢查sds的空間是否滿足所需要求,如果不滿足會自動擴充。
內存分配:由于c不記錄字符串長度,對于包含了n個字符的字符串,底層總是一個長度n+1的數(shù)組,每一次長度變化,總是要對這個數(shù)組進行一次內存重新分配的操作。因為內存分配涉及復雜算法并且可能需要執(zhí)行系統(tǒng)調用,所以它通常是比較耗時的操作。
11、redis鏈表源碼?有什么特性?
雙端、無環(huán)、帶長度記錄、
多態(tài):使用 void* 指針來保存節(jié)點值, 可以通過 dup 、 free 、 match 為節(jié)點值設置類型特定函數(shù), 可以保存不同類型的值。
12、字典是如何實現(xiàn)的?
其實字典這種數(shù)據(jù)結構也內置在很多高級語言中,但是c語言沒有,所以redis自己實現(xiàn)了。
應用也比較廣泛,比如redis的數(shù)據(jù)庫就是字典實現(xiàn)的。不僅如此,當一個哈希鍵包含的鍵值對比較多,或者都是很長的字符串,redis就會用字典作為哈希鍵的底層實現(xiàn)。
13、LRU?redis里的具體實現(xiàn)?
LRU全稱是Least Recently Used,即最近最久未使用的意思。
LRU算法的設計原則是:如果一個數(shù)據(jù)在最近一段時間沒有被訪問到,那么在將來它被訪問的可能性也很小。也就是說,當限定的空間已存滿數(shù)據(jù)時,應當把最久沒有被訪問到的數(shù)據(jù)淘汰。
redis原始的淘汰算法簡單實現(xiàn):當需要淘汰一個key時,隨機選擇3個key,淘汰其中間隔時間最長的key。**基本上,我們隨機選擇key,淘汰key效果很好。后來隨機3個key改成一個配置項"N隨機key"。但把默認值提高改成5個后效果大大提高??紤]到它的效果,你根本不用修改他。
14、redis的持久化?
RDB持久化可以手動執(zhí)行,也可以配置定期執(zhí)行,可以把某個時間的數(shù)據(jù)狀態(tài)保存到RDB文件中,反之,我們可以用RDB文件還原數(shù)據(jù)庫狀態(tài)。
AOF持久化是通過保存服務器執(zhí)行的命令來記錄狀態(tài)的。還原的時候再執(zhí)行一遍即可。
15、如何選擇合適的持久化方式?
一般來說, 如果想達到足以媲美 PostgreSQL 的數(shù)據(jù)安全性, 你應該同時使用兩種持久化功能。如果你非常關心你的數(shù)據(jù), 但仍然可以承受數(shù)分鐘以內的數(shù)據(jù)丟失, 那么你可以只使用 RDB 持久化。
有很多用戶都只使用 AOF 持久化, 但并不推薦這種方式:因為定時生成 RDB 快照(snapshot) 非常便于進行數(shù)據(jù)庫備份, 并且 RDB 恢復數(shù)據(jù)集的速度也要比 AOF 恢復的速度要快, 除此之外, 使用 RDB 還可以避免之前提到的 AOF 程序的 bug。
16、Redis 集群方案應該怎么做?都有哪些方案?
1.twemproxy, 大概概念是, 它類似于一個代理方式, 使用方法和普通 Redis 無任何區(qū)別,設 置 好它 下 屬 的多 個 Redis 實 例 后, 使 用 時在 本 需 要 連接 Redis 的 地 方改 為 連接twemproxy, 它會以一個代理的身份接收請求并使用一致性 hash 算法, 將請求轉接到具體 Redis, 將結果再返回 twemproxy。使用方式簡便(相對 Redis 只需修改連接端口), 對舊項目擴展的首選。問題:twemproxy 自身單端口實例的壓力, 使用一致性 hash 后, 對Redis 節(jié)點數(shù)量改變時候的計算值的改變, 數(shù)據(jù)無法自動移動到新的節(jié)點。
2.codis, 目前用的最多的集群方案, 基本和 twemproxy 一致的效果, 但它支持在 節(jié)點數(shù)量改變情況下, 舊節(jié)點數(shù)據(jù)可恢復到新 hash 節(jié)點。
3.Redis cluster3.0 自帶的集群, 特點在于他的分布式算法不是一致性 hash, 而是 hash槽的概念, 以及自身支持節(jié)點設置從節(jié)點。具體看官方文檔介紹。
4.在業(yè)務代碼層實現(xiàn), 起幾個毫無關聯(lián)的 Redis 實例, 在代碼層, 對 key 進行 hash 計算,然后去對應的 Redis 實例操作數(shù)據(jù)。這種方式對 hash 層代碼要求比較高, 考慮部分包括,節(jié)點失效后的替代算法方案, 數(shù)據(jù)震蕩后的自動腳本恢復, 實例的監(jiān)控, 等等。
17、MySQL 里有 2000w 數(shù)據(jù), Redis 中只存 20w 的數(shù)據(jù),如何保證 Redis 中的數(shù)據(jù)都是熱點數(shù)據(jù)?
Redis 內存數(shù)據(jù)集大小上升到一定大小的時候, 就會施行數(shù)據(jù)淘汰策略;
18、Redis 有哪些適合的場景?
1、會話緩存(Session Cache)
最常用的一種使用 Redis 的情景是會話緩存(session cache)。用 Redis 緩存會話比其他存儲(如 Memcached) 的優(yōu)勢在于:Redis 提供持久化。當維護一個不是嚴格要求一致性的緩存時, 如果用戶的購物車信息全部丟失, 大部分人都會不高興的, 現(xiàn)在, 他們還會這樣嗎?
幸運的是, 隨著 Redis 這些年的改進, 很容易找到怎么恰當?shù)氖褂?Redis 來緩存會話的文檔。甚至廣為人知的商業(yè)平臺 Magento 也提供 Redis 的插件。
2、全頁緩存(FPC)
除基本的會話 token 之外, Redis 還提供很簡便的 FPC 平臺?;氐揭恢滦詥栴}, 即使重啟了 Redis 實例, 因為有磁盤的持久化, 用戶也不會看到頁面加載速度的下降, 這是一個極大改進, 類似 PHP 本地 FPC。再次以 Magento 為例, Magento 提供一個插件來使用 Redis 作為全頁緩存后端。
此外, 對 WordPress 的用戶來說, Pantheon 有一個非常好的插件 wp-Redis, 這個插件能幫助你以最快速度加載你曾瀏覽過的頁面。
3、隊列
Reids 在內存存儲引擎領域的一大優(yōu)點是提供 list 和 set 操作,這使得 Redis 能作為一個很好的消息隊列平臺來使用。Redis 作為隊列使用的操作, 就類似于本地程序語言(如Python) 對 list 的 push/pop 操作。
如果你快速的在 Google 中搜索“Redis queues”, 你馬上就能找到大量的開源項目, 這些項目的目的就是利用 Redis 創(chuàng)建非常好的后端工具, 以滿足各種隊列需求。例如, Celery有一個后臺就是使用 Redis 作為 broker, 你可以從這里去查看。
4、排行榜/計數(shù)器
Redis在內存中對數(shù)字進行遞增或遞減的操作實現(xiàn)的非常好。集合(Set)和有序集合(SortedSet) 也使得我們在執(zhí)行這些操作的時候變的非常簡單, Redis 只是正好提供了這兩種數(shù)據(jù)結構。
所以, 我們要從排序集合中獲取到排名最靠前的 10 個用戶–我們稱之為“user_scores”, 我們只需要像下面一樣執(zhí)行即可:當然, 這是假定你是根據(jù)你用戶的分數(shù)做遞增的排序。如果你想返回用戶及用戶的分數(shù),。
你需要這樣執(zhí)行:ZRANGE user_scores 0 10 WITHSCORES Agora Games 就是一個很好的例子, 用 Ruby 實現(xiàn)的, 它的排行榜就是使用 Redis 來存儲數(shù)據(jù)的, 你可以在這里看到。
5、發(fā)布/訂閱
最后 是 Redis 的發(fā)布/訂閱功能。發(fā)布/訂閱的使用場景確實非常多。我已看見人們在社交網(wǎng)絡連接中使用, 還可作為基于發(fā)布/訂閱的腳本觸發(fā)器, 甚至用 Redis 的發(fā)布/訂閱功能來建立聊天系統(tǒng)。
19、說說 Redis 哈希槽的概念?
Redis 集群沒有使用一致性 hash,而是引入了哈希槽的概念, Redis 集群有 16384 個哈希槽,每個 key 通過 CRC16 校驗后對 16384 取模來決定放置哪個槽, 集群的每個節(jié)點負責一部分hash 槽
20、為什么Redis集群有16384個槽
1、如果槽位為65536,發(fā)送心跳信息的消息頭達8k,發(fā)送的心跳包過于龐大。
如上所述,在消息頭中,最占空間的是myslots[CLUSTER_SLOTS/8]。當槽位為65536時,這塊的大小是: 65536÷8÷1024=8kb 因為每秒鐘,redis節(jié)點需要發(fā)送一定數(shù)量的ping消息作為心跳包,如果槽位為65536,這個ping消息的消息頭太大了,浪費帶寬。
2、redis的集群主節(jié)點數(shù)量基本不可能超過1000個。
如上所述,集群節(jié)點越多,心跳包的消息體內攜帶的數(shù)據(jù)越多。如果節(jié)點過1000個,也會導致網(wǎng)絡擁堵。因此redis作者,不建議redis cluster節(jié)點數(shù)量超過1000個。那么,對于節(jié)點數(shù)在1000以內的redis cluster集群,16384個槽位夠用了。沒有必要拓展到65536個。
3、槽位越小,節(jié)點少的情況下,壓縮比高
Redis主節(jié)點的配置信息中,它所負責的哈希槽是通過一張bitmap的形式來保存的,在傳輸過程中,會對bitmap進行壓縮,但是如果bitmap的填充率slots / N很高的話(N表示節(jié)點數(shù)),bitmap的壓縮率就很低。如果節(jié)點數(shù)很少,而哈希槽數(shù)量很多的話,bitmap的壓縮率就很低。
21、Redis 集群會有寫操作丟失嗎?為什么?
Redis 并不能保證數(shù)據(jù)的強一致性, 這意味著在實際中集群在特定的條件下可能會丟失寫操作。
22、Redis 集群方案應該怎么做?都有哪些方案?
1.twemproxy,大概概念是,它類似于一個代理方式, 使用時在本需要連接 redis 的地方改為連接 twemproxy, 它會以一個代理的身份接收請求并使用一致性 hash 算法,將請求轉接到具體 redis,將結果再返回 twemproxy。
缺點:twemproxy 自身單端口實例的壓力,使用一致性 hash 后,對 redis 節(jié)點數(shù)量改變時候的計算值的改變,數(shù)據(jù)無法自動移動到新的節(jié)點。
2.codis,目前用的最多的集群方案,基本和 twemproxy 一致的效果,但它支持在 節(jié)點數(shù)量改變情況下,舊節(jié)點數(shù)據(jù)可恢復到新 hash 節(jié)點
3.redis cluster3.0 自帶的集群,特點在于他的分布式算法不是一致性 hash,而是 hash 槽的概念,以及自身支持節(jié)點設置從節(jié)點。具體看官方文檔介紹。
23、為什么要做 Redis 分區(qū)?
分區(qū)可以讓 Redis 管理更大的內存, Redis 將可以使用所有機器的內存。如果沒有分區(qū), 你最多只能使用一臺機器的內存。分區(qū)使 Redis 的計算能力通過簡單地增加計算機得到成倍提升,Redis 的網(wǎng)絡帶寬也會隨著計算機和網(wǎng)卡的增加而成倍增長。
24、Redis 分區(qū)有什么缺點?
涉及多個 key 的操作通常不會被支持。例如你不能對兩個集合求交集, 因為他們可能被存儲到不同的 Redis 實例(實際上這種情況也有辦法, 但是不能直接使用交集指令)。
同時操作多個 key,則不能使用 Redis 事務.分區(qū)使用的粒度是key,不能使用一個非常長的排序key存儲一個數(shù)據(jù)集(The partitioning granularity is the key, so it is not possible to shard a dataset with a single huge key like a very big sorted set) .
當使用分區(qū)的時候, 數(shù)據(jù)處理會非常復雜, 例如為了備份你必須從不同的 Redis 實例和主機同時收集 RDB / AOF 文件。
分區(qū)時動態(tài)擴容或縮容可能非常復雜。Redis 集群在運行時增加或者刪除 Redis 節(jié)點, 能做到最大程度對用戶透明地數(shù)據(jù)再平衡,但其他一些客戶端分區(qū)或者代理分區(qū)方法則不支持這種特性。然而, 有一種預分片的技術也可以較好的解決這個問題。
25、Redis 與其他 key-value 存儲有什么不同?
Redis 有著更為復雜的數(shù)據(jù)結構并且提供對他們的原子性操作,這是一個不同于其他數(shù)據(jù)庫的進化路徑。Redis 的數(shù)據(jù)類型都是基于基本數(shù)據(jù)結構的同時對程序員透明, 無需進行額外的抽象。
Redis 運行在內存中但是可以持久化到磁盤,所以在對不同數(shù)據(jù)集進行高速讀寫時需要權衡內存, 應為數(shù)據(jù)量不能大于硬件內存。在內存數(shù)據(jù)庫方面的另一個優(yōu)點是, 相比在磁盤上相同的復雜的數(shù)據(jù)結構, 在內存中操作起來非常簡單, 這樣 Redis 可以做很多內部復雜性很強的事情。同時, 在磁盤格式方面他們是緊湊的以追加的方式產生的, 因為他們并不需要進行隨機訪問。
26、Redis 的內存用完了會發(fā)生什么?
如果達到設置的上限, Redis 的寫命令會返回錯誤信息(但是讀命令還可以正常返回。) 或者你可以將 Redis 當緩存來使用配置淘汰機制,當 Redis 達到內存上限時會沖刷掉舊的內容。
27、Redis 是單線程的, 如何提高多核 CPU 的利用率?
可以在同一個服務器部署多個 Redis 的實例, 并把他們當作不同的服務器來使用, 在某些時候, 無論如何一個服務器是不夠的,所以, 如果你想使用多個 CPU, 你可以考慮一下分片(shard)。
28、一個 Redis 實例最多能存放多少的 keys?List、 Set、Sorted Set 他們最多能存放多少元素?
理論上 Redis 可以處理多達 232 的 keys, 并且在實際中進行了測試, 每個實例至少存放了 2億 5 千萬的 keys。我們正在測試一些較大的值。
任何 list、 set、 和 sorted set 都可以放 232 個元素。
換句話說, Redis 的存儲極限是系統(tǒng)中的可用內存值。
29、修改配置不重啟 Redis 會實時生效嗎?
針對運行實例, 有許多配置選項可以通過 CONFIG SET 命令進行修改, 而無需執(zhí)行任何形式的重啟。從 Redis 2.2 開始, 可以從 AOF 切換到 RDB 的快照持久性或其他方式而不需要重啟 Redis。檢索 ‘CONFIG GET *’ 命令獲取更多信息。
但偶爾重新啟動是必須的, 如為升級 Redis 程序到新的版本, 或者當你需要修改某些目前CONFIG 命令還不支持的配置參數(shù)的時候。
30、哨兵
Redis sentinel 是一個分布式系統(tǒng)中監(jiān)控 redis 主從服務器,并在主服務器下線時自動進行故障轉移。其中三個特性:
監(jiān)控(Monitoring):Sentinel 會不斷地檢查你的主服務器和從服務器是否運作正常。
提醒(Notification):被監(jiān)控的某個 Redis 服務器出現(xiàn)問題時, Sentinel 可以通過 API 向管理員或者其他應用程序發(fā)送通知。
自動故障遷移(Automatic failover):當一個主服務器不能正常工作時, Sentinel 會開始一次自動故障遷移操作。
特點:
保證高可用
監(jiān)控各個節(jié)點
自動故障遷移
缺點:
主從模式,切換需要時間丟數(shù)據(jù),沒有解決 master 寫的壓力
31、緩存穿透
一般的緩存系統(tǒng),都是按照key去緩存查詢,如果不存在對應的value,就去后端系統(tǒng)查找(比如DB)。
一些惡意的請求會故意查詢不存在的key,請求量很大,就會對后端系統(tǒng)造成很大的壓力。這就叫做緩存穿透。
如何避免?
對查詢結果為空的情況也進行緩存,這樣,再次訪問時,緩存層會直接返回空值。緩存時間設置短一點,或者該key對應的數(shù)據(jù)insert了之后清理緩存。
對一定不存在的key進行過濾。具體請看布隆過濾器。
32、緩存擊穿
是針對緩存中沒有但數(shù)據(jù)庫有的數(shù)據(jù)。
場景是,當Key失效后,假如瞬間突然涌入大量的請求,來請求同一個Key,這些請求不會命中Redis,都會請求到DB,導致數(shù)據(jù)庫壓力過大,甚至扛不住,掛掉。
解決辦法
設置熱點Key,自動檢測熱點Key,將熱點Key的過期時間加大或者設置為永不過期,或者設置為邏輯上永不過期
加互斥鎖。當發(fā)現(xiàn)沒有命中Redis,去查數(shù)據(jù)庫的時候,在執(zhí)行更新緩存的操作上加鎖,當一個線程訪問時,其它線程等待,這個線程訪問過后,緩存中的數(shù)據(jù)會被重建,這樣其他線程就可以從緩存中取值。
33、緩存雪崩
是指大量Key同時失效,對這些Key的請求又會打到DB上,同樣會導致數(shù)據(jù)庫壓力過大甚至掛掉。
解決辦法
讓Key的失效時間分散開,可以在統(tǒng)一的失效時間上再加一個隨機值,或者使用更高級的算法分散失效時間。
構建多個redis實例,個別節(jié)點掛了還有別的可以用。
多級緩存:比如增加本地緩存,減小redis壓力。
對存儲層增加限流措施,當請求超出限制,提供降級服務(一般就是返回錯誤即可)
34、單線程的 redis 為什么這么快
純內存操作
單線程操作,避免了頻繁的上下文切換
采用了非阻塞I/O多路復用機制
35、redis采用的刪除策略
redis采用的是定期刪除+惰性刪除策略。
36、為什么不用定時刪除策略?
定時刪除,用一個定時器來負責監(jiān)視key,過期則自動刪除。雖然內存及時釋放,但是十分消耗CPU資源。在大并發(fā)請求下,CPU要將時間應用在處理請求,而不是刪除key,因此沒有采用這一策略。
37、定期刪除+惰性刪除是如何工作的呢?
定期刪除,redis默認每個100ms檢查,是否有過期的key,有過期key則刪除。需要說明的是,redis不是每個100ms將所有的key檢查一次,而是隨機抽取進行檢查(如果每隔100ms,全部key進行檢查,redis豈不是卡死)。因此,如果只采用定期刪除策略,會導致很多key到時間沒有刪除。
于是,惰性刪除派上用場。也就是說在你獲取某個key的時候,redis會檢查一下,這個key如果設置了過期時間那么是否過期了?如果過期了此時就會刪除。
38、為什么Redis的操作是原子性的,怎么保證原子性的?
對于Redis而言,命令的原子性指的是:一個操作的不可以再分,操作要么執(zhí)行,要么不執(zhí)行。
Redis的操作之所以是原子性的,是因為Redis是單線程的。
Redis本身提供的所有API都是原子操作,Redis中的事務其實是要保證批量操作的原子性。
多個命令在并發(fā)中也是原子性的嗎?
不一定, 將get和set改成單命令操作,incr 。使用Redis的事務,或者使用Redis+Lua==的方式實現(xiàn)。
39、消息隊列
不要使用redis去做消息隊列,這不是redis的設計目標。但實在太多人使用redis去做去消息隊列,redis的作者看不下去。
審核編輯:湯梓紅
-
數(shù)據(jù)庫
+關注
關注
7文章
3799瀏覽量
64396 -
Memcached
+關注
關注
0文章
13瀏覽量
7022 -
Redis
+關注
關注
0文章
375瀏覽量
10878
原文標題:【建議收藏】一文爆肝Redis總結!
文章出處:【微信號:浩道linux,微信公眾號:浩道linux】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
相關推薦
評論