redis知識整理
1、Redis是什麼?
簡單來說 redis 就是一個數據庫,不過與傳統資料庫不同的是 redis 的資料是存在記憶體中的,所以存寫速度非常快,因此 redis 被廣泛應用於快取方向。另外,redis 也經常用來做分散式鎖。redis 提供了多種資料型別來支援不同的業務場景。除此之外,redis 支援事務 、持久化、LUA指令碼、LRU驅動事件、多種叢集方案。
2、Redis 有哪些應用場景
1、熱點資料的快取:由於redis訪問速度塊、支援的資料型別比較豐富,所以redis很適合用來儲存熱點資料。
2、分散式鎖:多併發情況下,使用setnx和expire(原子性操作下)加鎖,以及當執行緒執行到一定時間還未結束使用守護執行緒,用來給快要過期的鎖“續航”。
3、做計數器:redis由於incrby命令可以實現原子性的遞增,所以可以運用於高併發的秒殺活動、分散式序列號的生成、具體業務還體現在比如限制一個手機號發多少條簡訊、一個介面一分鐘限制多少請求、一個介面一天限制呼叫多少次等等。
等。。
3、Redis 支援哪些資料型別?
String(字串)、List(列表)、Set(集合)、Zset(Sorted Set:有序集合)、以及Hash(雜湊)。
4、Redis 持久化有什麼用?
用於快速恢復資料。Redis為了內部資料的安全考慮,會把本身的資料以檔案的形式儲存在硬碟中一份,在重啟之後會自動把硬碟的資料恢復到記憶體(redis)裡面。
5、Redis 持久化之RDB和AOF
1、Redis 預設開啟RDB持久化方式,在指定的時間間隔內,執行指定次數的寫操作,則將記憶體中的資料寫入到磁碟中。
2、RDB 持久化適合大規模的資料恢復但它的資料一致性和完整性較差(映象全量持久化)。
3、Redis 需要手動開啟AOF持久化方式,預設是每秒將寫操作日誌追加到AOF檔案中(增量持久化)。
4、AOF 的資料完整性比RDB高,但記錄內容多了,會影響資料恢復的效率。
5、Redis 針對 AOF檔案大的問題,提供重寫的瘦身機制。
6、若只打算用Redis 做快取,可以關閉持久化。
7、若打算使用Redis 的持久化。建議RDB和AOF都開啟。其實RDB更適合做資料的備份,留一後手。AOF出問題了,還有RDB。
AOF的重寫機制:
AOF的工作原理是將寫操作追加到檔案中,檔案的冗餘內容會越來越多。所以聰明的 Redis 新增了重寫機制。當AOF檔案的大小超過所設定的閾值時,Redis就會對AOF檔案的內容壓縮。
重寫的原理:Redis 會fork出一條新程序,讀取記憶體中的資料,並重新寫到一個臨時檔案中,最後替換舊的aof檔案。
6、什麼是Redis跳躍表?
跳躍表:將有序連結串列改造為可以支援連結串列式“二分查詢”演算法,可以快速的進行插入、刪除、查詢。
跳躍表查詢節點的過程(以插入元素為例,刪除、查詢的過程是一樣的) 1、從head開始,根據forward指標(箭頭)向前查詢,如果前一個元素大於待查詢的元素或者遇到tail指標(紅色線情況),下移層次繼續查詢(紅色線頭節點為起始點);如果下一個元素不大於待查詢的元素,forward向前推進一個節點,繼續比較。 2、重複1步驟,直到遇到的前一個節點的值大於待查詢的值 最終總是能找到比待查詢節點的值大的前一個位置,在這個位置插入元素。 跳躍表插入資料時,層級為投硬幣的方式隨機生成level高度,然後找到前置節點進行插入(比如22,1層)。7、Redis 記憶體滿了怎麼辦?
1、通過配置檔案配置
通過在Redis安裝目錄下面的redis.conf配置檔案中新增以下配置設定記憶體大小
maxmemory 100mb
2、記憶體淘汰策略
記憶體淘汰策略相當於清除掉那些佔用記憶體並且使用不太頻繁的資料,淘汰掉這些不活躍資料來清理記憶體。
a)LRU剔除最近最少使用
volatile-lru:從全資料集(server.db[i].dict)中挑選最近最少使用的資料淘汰
allkeys-lru:從已設定過期時間的資料集(server.db[i].expires)中挑選最近最少使用的資料淘汰
b)LFU剔除最近使用頻率最低
volatile-lfu:從全資料集(server.db[i].dict)中挑選最近使用頻率最低的資料淘汰
allkeys-lfu:從已設定過期時間的資料集(server.db[i].expires)中挑選最近使用頻率最低的資料淘汰
c)Random隨機剔除
volatile-lfu:從全資料集(server.db[i].dict)中隨機資料淘汰
allkeys-lfu:從已設定過期時間的資料集(server.db[i].expires)中隨機資料淘汰
d)其他
noeviction:預設策略,不驅逐,不會繼續服務寫請求 (DEL 請求可以繼續服務),讀請求可以繼續進行。這樣可以保證不會丟失資料,但是會讓線上的業務不能持續進行。
volatile-ttl:在設定了過期時間的鍵空間中,具有更早過期時間的key優先移除。
8、Redis6.0之後支援多執行緒,開啟多執行緒後,是否會存線上程併發安全問題?
不會,Redis 的多執行緒部分只是用來處理網路資料的讀寫和協議解析,執行命令仍然是單執行緒順序執行。
9、Redis使用的I/O多路複用epoll
I/O多路複用:單個執行緒,通過記錄跟蹤每個I/O流(sock)的狀態,來同時管理多個I/O流 。select, poll, epoll 都是I/O多路複用的具體的實現。
三者區別:
1、底層資料結構
select:陣列,poll:連結串列,epoll:紅黑樹。
2、支援一個程序所能開啟的最大連線數
select 單個程序所能開啟的最大連線數有1024(x86)或2048(x64)。poll無上限。epoll 雖然連線數有上限,但是很大,1G記憶體的機器上可以開啟10萬左右的連線,2G記憶體的機器可以開啟20萬左右的連線。
3、FD劇增後帶來的IO效率問題
Epoll最大的優點就在於它只管你“活躍”的連線,而跟連線總數無關,因此在實際的網路環境中,Epoll的效率就會遠遠高於select和poll。
4、訊息傳遞方式
select/poll 核心需要將訊息傳遞到使用者空間,都需要核心拷貝動作。epoll通過核心和使用者空間共享一塊記憶體來實現的。
10、假如Redis裡面有1億個key,其中有10w個key是以某個固定的已知的字首開頭的,生產環境下,如何將它們全部找出來?
redis的命令是單執行緒的。keys指令會導致執行緒阻塞一段時間,線上服務會停頓,直到指令執行完畢,服務才能恢復。
這個時候可以使用scan指令,scan指令可以無阻塞的提取出指定模式的key列表,但是會有一定的重複概率,在客戶端做一次去重就可以了,但是整體所花費的時間會比直接用keys指令長。
11、什麼是快取穿透,快取雪崩,快取擊穿?如何解決或預防?
我一個QPS不到10的專案,天天問我快取穿透、快取擊穿、快取雪崩,我是真滴難T T。
a)快取穿透:
訪問一個快取和資料庫都不存在的 key,此時會直接打到資料庫上,並且查不到資料,沒法寫快取,所以下一次同樣會打到資料庫上。
此時,快取起不到作用,請求每次都會走到資料庫,流量大時資料庫可能會被打掛。此時快取就好像被“穿透”了一樣,起不到任何作用。
解決預防方案:
1、介面校驗。在正常業務流程中可能會存在少量訪問不存在 key 的情況,但是一般不會出現大量的情況,所以這種場景最大的可能性是遭受了非法攻擊。可以在最外層先做一層校驗:使用者鑑權、資料合法性校驗等,例如商品查詢中,商品的ID是正整數,則可以直接對非正整數直接過濾等等。
2、快取空值。當訪問快取和DB都沒有查詢到值時,可以將空值寫進快取,但是設定較短的過期時間,該時間需要根據產品業務特性來設定。
3、布隆過濾器
布隆過濾器應用場景:
- 在爬蟲時,對爬蟲網址進行過濾,已經存在布隆中的網址,不在爬取。
- 垃圾郵件過濾,對每個傳送郵件的地址進行判斷是否在布隆的黑名單中,若是在就判斷為垃圾郵件。
- 快取穿透。
布隆過濾器特性:
布隆過濾器可以用於檢索一個元素是否在一個集合中。它的優點是空間效率和查詢時間都遠遠超過一般的演算法,缺點是有一定的誤識別率和刪除困難。
原理:在一個足夠大的足夠大的 bitmap中,插入時與多個不同的hash函式生成多個雜湊值,將對應位置置1。查詢時如果發現所有hash函式對應位都是1說明存在,只要有一個為0則認為這個元素不存在。(hash衝突會導致一定的誤識別率)
b)快取雪崩:
快取雪崩:指在某一個時間段,快取集中過期失效。Redis宕機。
解決預防方案:
1、優化快取過期時間:設計快取時,讓過期時間儘量均勻,避免大量的 key 在同一時刻同時失效,造成快取雪崩。
2、叢集:可以把快取層設計成高可用的,即使個別節點、個別機器、甚至是機房宕掉,依然可以提供服務。利用sentinel或cluster實現。
3、構建多級快取架構:nginx快取 + redis快取 +其他快取(ehcache等)。
c)快取擊穿:
指一個熱點key被大併發量請求,熱點key突然失效時,大批量請求湧向資料庫,導致資料庫的壓力瞬間過大。
解決預防方案:
1、預先設定熱門資料
在Redis高峰訪問之前,把一些熱門資料提前存入Redis中,並且加大這些熱門資料key的時長。
2、互斥鎖:用分散式鎖控制訪問的執行緒,其他執行緒等待,等到搶到鎖的執行緒從資料庫中載入資料完畢。
3、本地快取:把快取資料取出時直接載入到本地快取(Ehcache、Guava Cache),這樣訪問熱key時就可以直接訪問呢自己快取了。
12、redis叢集三種方式
1、主從模式:可以一主多從,主從資料同步保證資料完整性,且可以實現寫主、讀從,效能有所提升,但主節點故障後寫受影響,沒有故障選舉功能,且無監控各主從執行狀態功能。
2、哨兵模式:哨兵(sentinel)監控各節點執行狀態,主節點發生故障後長(經歷主觀下線和客觀下線),可以通過再次選舉產生主節點,實現故障恢復,但若從節點掛了不能實現從節點的故障轉移;
選舉機制:
如果主節點被判定為客觀下線之後,就要選取一個哨兵節點來完成後面的故障轉移工作,選舉出一個leader的流程如下:
a)每個線上的哨兵節點都可以成為領導者,當它確認(比如哨兵3)主節點下線時,會向其它哨兵發is-master-down-by-addr
命令,徵求判斷並要求將自己設定為領導者,由領導者處理故障轉移;
b)當其它哨兵收到此命令時,可以同意或者拒絕它成為領導者;
c)如果哨兵3發現自己在選舉的票數大於等於num(sentinels)/2+1以及quorum數
時,將成為領導者,如果沒有超過,繼續選舉
3、cluster叢集:Redis Cluster 是一種伺服器 Sharding 技術(分片和路由都是在服務端實現),採用多主多從,每一個分割槽都是由一個 Redis 主機和多個從機組成,片區和片區之間是相互平行的。Redis Cluster 叢集採用了 P2P 的模式,完全去中心化。
工作原理:
- 叢集完全去中心化,採用多主多從;所有的 redis 節點彼此互聯(PING-PONG 機制),內部使用二進位制協議優化傳輸速度和頻寬。
- 客戶端與 Redis 節點直連,不需要中間代理層。客戶端不需要連線叢集所有節點,連線叢集中任何一個可用節點即可。
- 每一個 master 節點負責維護一部分槽,以及槽所對映的鍵值資料;叢集中每個節點都有全量的槽資訊,通過槽每個 node 都知道具體資料儲存到哪個 node 上。根據公式
HASH_SLOT=CRC16(key) mod 16384
,計算出對映到哪個分片上,然後Redis會去相應的節點進行存取操作。 - 為了保證高可用,redis-cluster叢集引入了主從模式,一個主節點對應一個或者多個從節點,當主節點宕機的時候,就會啟用從節點。
13、如何保證 Redis 快取與資料庫雙寫一致性
1、加分散式讀寫鎖(適合讀多寫少場景):通過加鎖保證併發讀寫,寫寫的時候按順序排好隊,讀讀不影響。(加讀寫鎖可能會導致系統變得沉重,系統變慢)
2、為快取設定超時時間(適合允許一段時間DB和快取不一致的場景):每隔一段時間自動重新整理快取。
3、使用Canal解決快取一致性問題:Mysql 資料庫更新操作後再 binlog 日誌中我們都能夠找到相應的操作,那麼我們可以訂閱 Mysql 資料庫的 binlog 日誌對快取進行操作。(用Canal需要額外增加Canal中介軟體,加重系統複雜度)。