概述
什麼是Redis?
- Redis 是一個使用 C 語言寫成的,開源的高性能key-value非關系緩存資料庫。它支援存儲的value類型相對更多,包括string(字元串)、list(連結清單)、set(集合)、zset(sorted set --有序集合)和hash(哈希類型)。Redis的資料都基于緩存的,是以很快,每秒可以處理超過 10萬次讀寫操作,是已知性能最快的Key-Value DB。Redis也可以實作資料寫入磁盤中,保證了資料的安全不丢失,而且Redis的操作是原子性的。
Redis有哪些優缺點?
- 優點
- 讀寫性能優異, Redis能讀的速度是110000次/s,寫的速度是81000次/s。
- 支援資料持久化,支援AOF和RDB兩種持久化方式。
- 支援事務,Redis的所有操作都是原子性的,同時Redis還支援對幾個操作合并後的原子性執行。
- 資料結構豐富,除了支援string類型的value外還支援hash、set、zset、list等資料結構。
- 支援主從複制,主機會自動将資料同步到從機,可以進行讀寫分離。
- 缺點
- 資料庫容量受到實體記憶體的限制,不能用作海量資料的高性能讀寫,是以Redis适合的場景主要局限在較小資料量的高性能操作和運算上。
- Redis 不具備自動容錯和恢複功能,主機從機的當機都會導緻前端部分讀寫請求失敗,需要等待機器重新開機或者手動切換前端的IP才能恢複。
- 主機當機,當機前有部分資料未能及時同步到從機,切換IP後還會引入資料不一緻的問題,降低了系統的可用性。
- Redis 較難支援線上擴容,在叢集容量達到上限時線上擴容會變得很複雜。為避免這一問題,運維人員在系統上線時必須確定有足夠的空間,這對資源造成了很大的浪費。
使用redis有哪些好處?
- (1) 速度快,因為資料存在記憶體中,類似于HashMap,HashMap的優勢就是查找和操作的時間複雜度都很低
- (2)支援豐富資料類型,支援string,list,set,sorted set,hash
- (3) 支援事務,操作都是原子性,所謂的原子性就是對資料的更改要麼全部執行,要麼全部不執行
- (4) 豐富的特性:可用于緩存,消息,按key設定過期時間,過期後将會自動删除
為什麼要用 Redis / 為什麼要用緩存
主要從“高性能”和“高并發”這兩點來看待這個問題。
- 高性能:
- 假如使用者第一次通路資料庫中的某些資料。這個過程會比較慢,因為是從硬碟上讀取的。将該使用者通路的資料存在數緩存中,這樣下一次再通路這些資料的時候就可以直接從緩存中擷取了。操作緩存就是直接操作記憶體,是以速度相當快。如果資料庫中的對應資料改變的之後,同步改變緩存中相應的資料即可!
- 高并發:
- 直接操作緩存能夠承受的請求是遠遠大于直接通路資料庫的,是以我們可以考慮把資料庫中的部分資料轉移到緩存中去,這樣使用者的一部分請求會直接到緩存這裡而不用經過資料庫。
為什麼要用 Redis 而不用 map/guava 做緩存?
- 緩存分為本地緩存和分布式緩存。以 Java 為例,使用自帶的 map 或者 guava 實作的是本地緩存,最主要的特點是輕量以及快速,生命周期随着 jvm 的銷毀而結束,并且在多執行個體的情況下,每個執行個體都需要各自儲存一份緩存,緩存不具有一緻性。
- 使用 redis 或 memcached 之類的稱為分布式緩存,在多執行個體的情況下,各執行個體共用一份緩存資料,緩存具有一緻性。缺點是需要保持 redis 或 memcached服務的高可用,整個程式架構上較為複雜。
Redis為什麼這麼快
- 1、完全基于記憶體,絕大部分請求是純粹的記憶體操作,非常快速。資料存在記憶體中,類似于 HashMap,HashMap 的優勢就是查找和操作的時間複雜度都是O(1);
- 2、資料結構簡單,對資料操作也簡單,Redis 中的資料結構是專門進行設計的;
- 3、采用單線程,避免了不必要的上下文切換和競争條件,也不存在多程序或者多線程導緻的切換而消耗 CPU,不用去考慮各種鎖的問題,不存在加鎖釋放鎖操作,沒有因為可能出現死鎖而導緻的性能消耗;
- 4、使用多路 I/O 複用模型,非阻塞 IO;
- 5、使用底層模型不同,它們之間底層實作方式以及與用戶端之間通信的應用協定不一樣,Redis 直接自己建構了 VM 機制 ,因為一般的系統調用系統函數的話,會浪費一定的時間去移動和請求;
Redis有哪些資料類型
- Redis主要有5種資料類型,包括String,List,Set,Zset,Hash,滿足大部分的使用要求
資料類型 | 可以存儲的值 | 操作 | 應用場景 |
---|---|---|---|
String | 字元串、整數或者浮點數 | 對整個字元串或者字元串的其中一部分執行操作 對整數和浮點數執行自增或者自減操作 | 做簡單的鍵值對緩存 |
List | 清單 | 從兩端壓入或者彈出元素 對單個或者多個元素進行修剪, 隻保留一個範圍内的元素 | 存儲一些清單型的資料結構,類似粉絲清單、文章的評論清單之類的資料 |
Set | 無序集合 | 添加、擷取、移除單個元素 檢查一個元素是否存在于集合中 計算交集、并集、差集 從集合裡面随機擷取元素 | 交集、并集、差集的操作,比如交集,可以把兩個人的粉絲清單整一個交集 |
Hash | 包含鍵值對的無序散清單 | 添加、擷取、移除單個鍵值對 擷取所有鍵值對 檢查某個鍵是否存在 | 結構化的資料,比如一個對象 |
ZSet | 有序集合 | 添加、擷取、删除元素 根據分值範圍或者成員來擷取元素 計算一個鍵的排名 | 去重但可以排序,如擷取排名前幾名的使用者 |
Redis的應用場景
- 計數器
可以對 String 進行自增自減運算,進而實作計數器功能。Redis 這種記憶體型資料庫的讀寫性能非常高,很适合存儲頻繁讀寫的計數量。
- 緩存
将熱點資料放到記憶體中,設定記憶體的最大使用量以及淘汰政策來保證緩存的命中率。
- 會話緩存
可以使用 Redis 來統一存儲多台應用伺服器的會話資訊。當應用伺服器不再存儲使用者的會話資訊,也就不再具有狀态,一個使用者可以請求任意一個應用伺服器,進而更容易實作高可用性以及可伸縮性。
- 全頁緩存(FPC)
除基本的會話token之外,Redis還提供很簡便的FPC平台。以Magento為例,Magento提供一個插件來使用Redis作為全頁緩存後端。此外,對WordPress的使用者來說,Pantheon有一個非常好的插件 wp-redis,這個插件能幫助你以最快速度加載你曾浏覽過的頁面。
- 查找表
例如 DNS 記錄就很适合使用 Redis 進行存儲。查找表和緩存類似,也是利用了 Redis 快速的查找特性。但是查找表的内容不能失效,而緩存的内容可以失效,因為緩存不作為可靠的資料來源。
- 消息隊列(釋出/訂閱功能)
List 是一個雙向連結清單,可以通過 lpush 和 rpop 寫入和讀取消息。不過最好使用 Kafka、RabbitMQ 等消息中間件。
- 分布式鎖實作
在分布式場景下,無法使用單機環境下的鎖來對多個節點上的程序進行同步。可以使用 Redis 自帶的 SETNX 指令實作分布式鎖,除此之外,還可以使用官方提供的 RedLock 分布式鎖實作。
- 其它
Set 可以實作交集、并集等操作,進而實作共同好友等功能。ZSet 可以實作有序性操作,進而實作排行榜等功能。
持久化
- 什麼是Redis持久化? 持久化就是把記憶體的資料寫到磁盤中去,防止服務當機了記憶體資料丢失。
Redis 的持久化機制是什麼?各自的優缺點?
- Redis 提供兩種持久化機制 RDB(預設) 和 AOF 機制:
RDB:是Redis DataBase縮寫快照
- RDB是Redis預設的持久化方式。按照一定的時間将記憶體的資料以快照的形式儲存到硬碟中,對應産生的資料檔案為dump.rdb。通過配置檔案中的save參數來定義快照的周期。

- 優點:
1、隻有一個檔案 dump.rdb,友善持久化。
2、容災性好,一個檔案可以儲存到安全的磁盤。
3、性能最大化,fork 子程序來完成寫操作,讓主程序繼續處理指令,是以是 IO 最大化。使用單獨子程序來進行持久化,主程序不會進行任何 IO 操作,保證了 redis 的高性能
4.相對于資料集大時,比 AOF 的啟動效率更高。
- 缺點:
1、資料安全性低。RDB 是間隔一段時間進行持久化,如果持久化之間 redis 發生故障,會發生資料丢失。是以這種方式更适合資料要求不嚴謹的時候)
2、AOF(Append-only file)持久化方式: 是指所有的指令行記錄以 redis 指令請 求協定的格式完全持久化存儲)儲存為 aof 檔案。
AOF:持久化:
- AOF持久化(即Append Only File持久化),則是将Redis執行的每次寫指令記錄到單獨的日志檔案中,當重新開機Redis會重新将持久化的日志中檔案恢複資料。
- 當兩種方式同時開啟時,資料恢複Redis會優先選擇AOF恢複
1、資料安全,aof 持久化可以配置 appendfsync 屬性,有 always,每進行一次 指令操作就記錄到 aof 檔案中一次。
2、通過 append 模式寫檔案,即使中途伺服器當機,可以通過 redis-check-aof 工具解決資料一緻性問題。
3、AOF 機制的 rewrite 模式。AOF 檔案沒被 rewrite 之前(檔案過大時會對指令 進行合并重寫),可以删除其中的某些指令(比如誤操作的 flushall))
1、AOF 檔案比 RDB 檔案大,且恢複速度慢。
2、資料集大的時候,比 rdb 啟動效率低。
- 倆種持久化的優缺點是什麼?
- AOF檔案比RDB更新頻率高,優先使用AOF還原資料。
- AOF比RDB更安全也更大
- RDB性能比AOF好
- 如果兩個都配了優先加載AOF
如何選擇合适的持久化方式
- 一般來說, 如果想達到足以媲美PostgreSQL的資料安全性,你應該同時使用兩種持久化功能。在這種情況下,當 Redis 重新開機的時候會優先載入AOF檔案來恢複原始的資料,因為在通常情況下AOF檔案儲存的資料集要比RDB檔案儲存的資料集要完整。
- 如果你非常關心你的資料, 但仍然可以承受數分鐘以内的資料丢失,那麼你可以隻使用RDB持久化。
- 有很多使用者都隻使用AOF持久化,但并不推薦這種方式,因為定時生成RDB快照(snapshot)非常便于進行資料庫備份, 并且 RDB 恢複資料集的速度也要比AOF恢複的速度要快,除此之外,使用RDB還可以避免AOF程式的bug。
- 如果你隻希望你的資料在伺服器運作的時候存在,你也可以不使用任何持久化方式。
Redis持久化資料和緩存怎麼做擴容?
- 如果Redis被當做緩存使用,使用一緻性哈希實作動态擴容縮容。
- 如果Redis被當做一個持久化存儲使用,必須使用固定的keys-to-nodes映射關系,節點的數量一旦确定不能變化。否則的話(即Redis節點需要動态變化的情況),必須使用可以在運作時進行資料再平衡的一套系統,而目前隻有Redis叢集可以做到這樣。
Redis的過期鍵的删除政策
我們都知道,Redis是key-value資料庫,我們可以設定Redis中緩存的key的過期時間。Redis的過期政策就是指當Redis中緩存的key過期了,Redis如何處理。
- 過期政策通常有以下三種:
- 定時過期:每個設定過期時間的key都需要建立一個定時器,到過期時間就會立即清除。該政策可以立即清除過期的資料,對記憶體很友好;但是會占用大量的CPU資源去處理過期的資料,進而影響緩存的響應時間和吞吐量。
- 惰性過期:隻有當通路一個key時,才會判斷該key是否已過期,過期則清除。該政策可以最大化地節省CPU資源,卻對記憶體非常不友好。極端情況可能出現大量的過期key沒有再次被通路,進而不會被清除,占用大量記憶體。
- 定期過期:每隔一定的時間,會掃描一定數量的資料庫的expires字典中一定數量的key,并清除其中已過期的key。該政策是前兩者的一個折中方案。通過調整定時掃描的時間間隔和每次掃描的限定耗時,可以在不同情況下使得CPU和記憶體資源達到最優的平衡效果。 (expires字典會儲存所有設定了過期時間的key的過期時間資料,其中,key是指向鍵空間中的某個鍵的指針,value是該鍵的毫秒精度的UNIX時間戳表示的過期時間。鍵空間是指該Redis叢集中儲存的所有鍵。)
Redis中同時使用了惰性過期和定期過期兩種過期政策。
Redis key的過期時間和永久有效分别怎麼設定?
- expire和persist指令。
我們知道通過expire來設定key 的過期時間,那麼對過期的資料怎麼處理呢?
- 除了緩存伺服器自帶的緩存失效政策之外(Redis預設的有6中政策可供選擇),我們還可以根據具體的業務需求進行自定義的緩存淘汰,常見的政策有兩種:
- 1、定時去清理過期的緩存;
- 2、當有使用者請求過來時,再判斷這個請求所用到的緩存是否過期,過期的話就去底層系統得到新資料并更新緩存。
兩者各有優劣,第一種的缺點是維護大量緩存的key是比較麻煩的,第二種的缺點就是每次使用者請求過來都要判斷緩存失效,邏輯相對比較複雜!具體用哪種方案,大家可以根據自己的應用場景來權衡。
MySQL裡有2000w資料,redis中隻存20w的資料,如何保證redis中的資料都是熱點資料
- redis記憶體資料集大小上升到一定大小的時候,就會施行資料淘汰政策。
Redis的記憶體淘汰政策有哪些
Redis的記憶體淘汰政策是指在Redis的用于緩存的記憶體不足時,怎麼處理需要新寫入且需要申請額外空間的資料。
- 全局的鍵空間選擇性移除
- noeviction:當記憶體不足以容納新寫入資料時,新寫入操作會報錯。
- allkeys-lru:當記憶體不足以容納新寫入資料時,在鍵空間中,移除最近最少使用的key。(這個是最常用的)
- allkeys-random:當記憶體不足以容納新寫入資料時,在鍵空間中,随機移除某個key。
- 設定過期時間的鍵空間選擇性移除
- volatile-lru:當記憶體不足以容納新寫入資料時,在設定了過期時間的鍵空間中,移除最近最少使用的key。
- volatile-random:當記憶體不足以容納新寫入資料時,在設定了過期時間的鍵空間中,随機移除某個key。
- volatile-ttl:當記憶體不足以容納新寫入資料時,在設定了過期時間的鍵空間中,有更早過期時間的key優先移除。
- 總結
Redis的記憶體淘汰政策的選取并不會影響過期的key的處理。記憶體淘汰政策用于處理記憶體不足時的需要申請額外空間的資料;過期政策用于處理過期的緩存資料。
Redis主要消耗什麼實體資源?
- 記憶體。
Redis的記憶體用完了會發生什麼?
- 如果達到設定的上限,Redis的寫指令會傳回錯誤資訊(但是讀指令還可以正常傳回。)或者你可以配置記憶體淘汰機制,當Redis達到記憶體上限時會沖刷掉舊的内容。
Redis如何做記憶體優化?
- 可以好好利用Hash,list,sorted set,set等集合類型資料,因為通常情況下很多小的Key-Value可以用更緊湊的方式存放到一起。盡可能使用散清單(hashes),散清單(是說散清單裡面存儲的數少)使用的記憶體非常小,是以你應該盡可能的将你的資料模型抽象到一個散清單裡面。比如你的web系統中有一個使用者對象,不要為這個使用者的名稱,姓氏,郵箱,密碼設定單獨的key,而是應該把這個使用者的所有資訊存儲到一張散清單裡面
線程模型
Redis線程模型
Redis基于Reactor模式開發了網絡事件處理器,這個處理器被稱為檔案事件處理器(file event handler)。它的組成結構為4部分:多個套接字、IO多路複用程式、檔案事件分派器、事件處理器。因為檔案事件分派器隊列的消費是單線程的,是以Redis才叫單線程模型。
- 檔案事件處理器使用 I/O 多路複用(multiplexing)程式來同時監聽多個套接字, 并根據套接字目前執行的任務來為套接字關聯不同的事件處理器。
- 當被監聽的套接字準備好執行連接配接應答(accept)、讀取(read)、寫入(write)、關閉(close)等操作時, 與操作相對應的檔案事件就會産生, 這時檔案事件處理器就會調用套接字之前關聯好的事件處理器來處理這些事件。
雖然檔案事件處理器以單線程方式運作, 但通過使用 I/O 多路複用程式來監聽多個套接字, 檔案事件處理器既實作了高性能的網絡通信模型, 又可以很好地與 redis 伺服器中其他同樣以單線程方式運作的子產品進行對接, 這保持了 Redis 内部單線程設計的簡單性。
事務
什麼是事務?
- 事務是一個單獨的隔離操作:事務中的所有指令都會序列化、按順序地執行。事務在執行的過程中,不會被其他用戶端發送來的指令請求所打斷。
- 事務是一個原子操作:事務中的指令要麼全部被執行,要麼全部都不執行。
Redis事務的概念
- Redis 事務的本質是通過MULTI、EXEC、WATCH等一組指令的集合。事務支援一次執行多個指令,一個事務中所有指令都會被序列化。在事務執行過程,會按照順序串行化執行隊列中的指令,其他用戶端送出的指令請求不會插入到事務執行指令序列中。
- 總結說:redis事務就是一次性、順序性、排他性的執行一個隊列中的一系列指令。
Redis事務的三個階段
- 事務開始 MULTI
- 指令入隊
- 事務執行 EXEC
事務執行過程中,如果服務端收到有EXEC、DISCARD、WATCH、MULTI之外的請求,将會把請求放入隊列中排隊
Redis事務相關指令
Redis事務功能是通過MULTI、EXEC、DISCARD和WATCH 四個原語實作的
Redis會将一個事務中的所有指令序列化,然後按順序執行。
- redis 不支援復原,“Redis 在事務失敗時不進行復原,而是繼續執行餘下的指令”, 是以 Redis 的内部可以保持簡單且快速。
- 如果在一個事務中的指令出現錯誤,那麼所有的指令都不會執行;
- 如果在一個事務中出現運作錯誤,那麼正确的指令會被執行。
- WATCH 指令是一個樂觀鎖,可以為 Redis 事務提供 check-and-set (CAS)行為。 可以監控一個或多個鍵,一旦其中有一個鍵被修改(或删除),之後的事務就不會執行,監控一直持續到EXEC指令。
- MULTI指令用于開啟一個事務,它總是傳回OK。 MULTI執行之後,用戶端可以繼續向伺服器發送任意多條指令,這些指令不會立即被執行,而是被放到一個隊列中,當EXEC指令被調用時,所有隊列中的指令才會被執行。
- EXEC:執行所有事務塊内的指令。傳回事務塊内所有指令的傳回值,按指令執行的先後順序排列。 當操作被打斷時,傳回空值 nil 。
- 通過調用DISCARD,用戶端可以清空事務隊列,并放棄執行事務, 并且用戶端會從事務狀态中退出。
- UNWATCH指令可以取消watch對所有key的監控。
事務管理(ACID)概述
-
原子性(Atomicity)
原子性是指事務是一個不可分割的工作機關,事務中的操作要麼都發生,要麼都不發生。
-
一緻性(Consistency)
事務前後資料的完整性必須保持一緻。
-
隔離性(Isolation)
多個事務并發執行時,一個事務的執行不應影響其他事務的執行
-
持久性(Durability)
持久性是指一個事務一旦被送出,它對資料庫中資料的改變就是永久性的,接下來即使資料庫發生故障也不應該對其有任何影響
Redis的事務總是具有ACID中的一緻性和隔離性,其他特性是不支援的。當伺服器運作在_AOF_持久化模式下,并且appendfsync選項的值為always時,事務也具有耐久性。
Redis事務支援隔離性嗎
- Redis 是單程序程式,并且它保證在執行事務時,不會對事務進行中斷,事務可以運作直到執行完所有事務隊列中的指令為止。是以,Redis 的事務是總是帶有隔離性的。
Redis事務保證原子性嗎,支援復原嗎
- Redis中,單條指令是原子性執行的,但事務不保證原子性,且沒有復原。事務中任意指令執行失敗,其餘的指令仍會被執行。
Redis事務其他實作
-
基于Lua腳本,Redis可以保證腳本内的指令一次性、按順序地執行,
其同時也不提供事務運作錯誤的復原,執行過程中如果部分指令運作錯誤,剩下的指令還是會繼續運作完
- 基于中間标記變量,通過另外的标記變量來辨別事務是否執行完成,讀取資料時先讀取該标記變量判斷是否事務執行完成。但這樣會需要額外寫代碼實作,比較繁瑣
叢集方案
1、哨兵模式
哨兵的介紹
sentinel,中文名是哨兵。哨兵是 redis 叢集機構中非常重要的一個元件,主要有以下功能:
- 叢集監控:負責監控 redis master 和 slave 程序是否正常工作。
- 消息通知:如果某個 redis 執行個體有故障,那麼哨兵負責發送消息作為報警通知給管理者。
- 故障轉移:如果 master node 挂掉了,會自動轉移到 slave node 上。
- 配置中心:如果故障轉移發生了,通知 client 用戶端新的 master 位址。
哨兵用于實作 redis 叢集的高可用,本身也是分布式的,作為一個哨兵叢集去運作,互相協同工作。
- 故障轉移時,判斷一個 master node 是否當機了,需要大部分的哨兵都同意才行,涉及到了分布式選舉的問題。
- 即使部分哨兵節點挂掉了,哨兵叢集還是能正常工作的,因為如果一個作為高可用機制重要組成部分的故障轉移系統本身是單點的,那就很坑爹了。
哨兵的核心知識
- 哨兵至少需要 3 個執行個體,來保證自己的健壯性。
- 哨兵 + redis 主從的部署架構,是不保證資料零丢失的,隻能保證 redis 叢集的高可用性。
- 對于哨兵 + redis 主從這種複雜的部署架構,盡量在測試環境和生産環境,都進行充足的測試和演練。
2、官方Redis Cluster 方案(服務端路由查詢)
- redis 叢集模式的工作原理能說一下麼?在叢集模式下,redis 的 key 是如何尋址的?分布式尋址都有哪些算法?了解一緻性 hash 算法嗎?
簡介
- Redis Cluster是一種服務端Sharding技術,3.0版本開始正式提供。Redis Cluster并沒有使用一緻性hash,而是采用slot(槽)的概念,一共分成16384個槽。将請求發送到任意節點,接收到請求的節點會将查詢請求發送到正确的節點上執行
方案說明
- 通過哈希的方式,将資料分片,每個節點均分存儲一定哈希槽(哈希值)區間的資料,預設配置設定了16384 個槽位
- 每份資料分片會存儲在多個互為主從的多節點上
- 資料寫入先寫主節點,再同步到從節點(支援配置為阻塞同步)
- 同一分片多個節點間的資料不保持一緻性
- 讀取資料時,當用戶端操作的key沒有配置設定在該節點上時,redis會傳回轉向指令,指向正确的節點
- 擴容時時需要需要把舊節點的資料遷移一部分到新節點
- 在 redis cluster 架構下,每個 redis 要放開兩個端口号,比如一個是 6379,另外一個就是 加1w 的端口号,比如 16379。
- 16379 端口号是用來進行節點間通信的,也就是 cluster bus 的東西,cluster bus 的通信,用來進行故障檢測、配置更新、故障轉移授權。cluster bus 用了另外一種二進制的協定,
協定,用于節點間進行高效的資料交換,占用更少的網絡帶寬和處理時間。gossip
- 16379 端口号是用來進行節點間通信的,也就是 cluster bus 的東西,cluster bus 的通信,用來進行故障檢測、配置更新、故障轉移授權。cluster bus 用了另外一種二進制的協定,
節點間的内部通信機制
- 基本通信原理
- 叢集中繼資料的維護有兩種方式:集中式、Gossip 協定。redis cluster 節點間采用 gossip 協定進行通信。
分布式尋址算法
- hash 算法(大量緩存重建)
- 一緻性 hash 算法(自動緩存遷移)+ 虛拟節點(自動負載均衡)
- redis cluster 的 hash slot 算法
- 無中心架構,支援動态擴容,對業務透明
- 具備Sentinel的監控和自動Failover(故障轉移)能力
- 用戶端不需要連接配接叢集所有節點,連接配接叢集中任何一個可用節點即可
- 高性能,用戶端直連redis服務,免去了proxy代理的損耗
- 運維也很複雜,資料遷移需要人工幹預
- 隻能使用0号資料庫
- 不支援批量操作(pipeline管道操作)
- 分布式邏輯和存儲子產品耦合等
3、基于用戶端配置設定
- Redis Sharding是Redis Cluster出來之前,業界普遍使用的多Redis執行個體叢集方法。其主要思想是采用雜湊演算法将Redis資料的key進行散列,通過hash函數,特定的key會映射到特定的Redis節點上。Java redis用戶端驅動jedis,支援Redis Sharding功能,即ShardedJedis以及結合緩存池的ShardedJedisPool
- 優勢在于非常簡單,服務端的Redis執行個體彼此獨立,互相無關聯,每個Redis執行個體像單伺服器一樣運作,非常容易線性擴充,系統的靈活性很強
- 由于sharding處理放到用戶端,規模進一步擴大時給運維帶來挑戰。
- 用戶端sharding不支援動态增删節點。服務端Redis執行個體群拓撲結構有變化時,每個用戶端都需要更新調整。連接配接不能共享,當應用規模增大時,資源浪費制約優化
4、基于代理伺服器分片
- 用戶端發送請求到一個代理元件,代了解析用戶端的資料,并将請求轉發至正确的節點,最後将結果回複給用戶端
特征
- 透明接入,業務程式不用關心後端Redis執行個體,切換成本低
- Proxy 的邏輯和存儲的邏輯是隔離的
- 代理層多了一次轉發,性能有所損耗
業界開源方案
- Twtter開源的Twemproxy
- 豌豆莢開源的Codis
5、Redis 主從架構
- 單機的 redis,能夠承載的 QPS 大概就在上萬到幾萬不等。對于緩存來說,一般都是用來支撐讀高并發的。是以架構做成主從(master-slave)架構,一主多從,主負責寫,并且将資料複制到其它的 slave 節點,從節點負責讀。所有的讀請求全部走從節點。這樣也可以很輕松實作水準擴容,支撐讀高并發。
redis replication -> 主從架構 -> 讀寫分離 -> 水準擴容支撐讀高并發
redis replication 的核心機制
- redis 采用異步方式複制資料到 slave 節點,不過 redis2.8 開始,slave node 會周期性地确認自己每次複制的資料量;
- 一個 master node 是可以配置多個 slave node 的;
- slave node 也可以連接配接其他的 slave node;
- slave node 做複制的時候,不會 block master node 的正常工作;
- slave node 在做複制的時候,也不會 block 對自己的查詢操作,它會用舊的資料集來提供服務;但是複制完成的時候,需要删除舊資料集,加載新資料集,這個時候就會暫停對外服務了;
- slave node 主要用來進行橫向擴容,做讀寫分離,擴容的 slave node 可以提高讀的吞吐量。
注意:
- 如果采用了主從架構,那麼建議必須開啟 master node 的持久化,不建議用 slave node 作為 master node 的資料熱備,因為那樣的話,如果你關掉 master 的持久化,可能在 master 當機重新開機的時候資料是空的,然後可能一經過複制, slave node 的資料也丢了。
- 另外,master 的各種備份方案,也需要做。萬一本地的所有檔案丢失了,從備份中挑選一份 rdb 去恢複 master,這樣才能確定啟動的時候,是有資料的,即使采用了後續講解的高可用機制,slave node 可以自動接管 master node,但也可能 sentinel 還沒檢測到 master failure,master node 就自動重新開機了,還是可能導緻上面所有的 slave node 資料被清空。
redis 主從複制的核心原理
- 當啟動一個 slave node 的時候,它會發送一個
指令給 master node。PSYNC
- 如果這是 slave node 初次連接配接到 master node,那麼會觸發一次
全量複制。此時 master 會啟動一個背景線程,開始生成一份full resynchronization
快照檔案,RDB
- 同時還會将從用戶端 client 新收到的所有寫指令緩存在記憶體中。
檔案生成完畢後, master 會将這個RDB
發送給 slave,slave 會先寫入本地磁盤,然後再從本地磁盤加載到記憶體中,RDB
- 接着 master 會将記憶體中緩存的寫指令發送到 slave,slave 也會同步這些資料。
- slave node 如果跟 master node 有網絡故障,斷開了連接配接,會自動重連,連接配接之後 master node 僅會複制給 slave 部分缺少的資料。
過程原理
- 當從庫和主庫建立MS關系後,會向主資料庫發送SYNC指令
- 主庫接收到SYNC指令後會開始在背景儲存快照(RDB持久化過程),并将期間接收到的寫指令緩存起來
- 當快照完成後,主Redis會将快照檔案和所有緩存的寫指令發送給從Redis
- 從Redis接收到後,會載入快照檔案并且執行收到的緩存的指令
- 之後,主Redis每當接收到寫指令時就會将指令發送從Redis,進而保證資料的一緻
- 所有的slave節點資料的複制和同步都由master節點來處理,會照成master節點壓力太大,使用主從從結構來解決
Redis叢集的主從複制模型是怎樣的?
- 為了使在部分節點失敗或者大部分節點無法通信的情況下叢集仍然可用,是以叢集使用了主從複制模型,每個節點都會有N-1個複制品
生産環境中的 redis 是怎麼部署的?
- redis cluster,10 台機器,5 台機器部署了 redis 主執行個體,另外 5 台機器部署了 redis 的從執行個體,每個主執行個體挂了一個從執行個體,5 個節點對外提供讀寫服務,每個節點的讀寫高峰qps可能可以達到每秒 5 萬,5 台機器最多是 25 萬讀寫請求/s。
- 機器是什麼配置?32G 記憶體+ 8 核 CPU + 1T 磁盤,但是配置設定給 redis 程序的是10g記憶體,一般線上生産環境,redis 的記憶體盡量不要超過 10g,超過 10g 可能會有問題。
- 5 台機器對外提供讀寫,一共有 50g 記憶體。
- 因為每個主執行個體都挂了一個從執行個體,是以是高可用的,任何一個主執行個體當機,都會自動故障遷移,redis 從執行個體會自動變成主執行個體繼續提供讀寫服務。
- 你往記憶體裡寫的是什麼資料?每條資料的大小是多少?商品資料,每條資料是 10kb。100 條資料是 1mb,10 萬條資料是 1g。常駐記憶體的是 200 萬條商品資料,占用記憶體是 20g,僅僅不到總記憶體的 50%。目前高峰期每秒就是 3500 左右的請求量。
其實大型的公司,會有基礎架構的 team 負責緩存叢集的運維。
說說Redis哈希槽的概念?
- Redis叢集沒有使用一緻性hash,而是引入了哈希槽的概念,Redis叢集有16384個哈希槽,每個key通過CRC16校驗後對16384取模來決定放置哪個槽,叢集的每個節點負責一部分hash槽。
Redis叢集會有寫操作丢失嗎?為什麼?
- Redis并不能保證資料的強一緻性,這意味這在實際中叢集在特定的條件下可能會丢失寫操作。
Redis叢集之間是如何複制的?
- 異步複制
Redis叢集最大節點個數是多少?
- 16384個
Redis叢集如何選擇資料庫?
- Redis叢集目前無法做資料庫選擇,預設在0資料庫。
分區
Redis是單線程的,如何提高多核CPU的使用率?
- 可以在同一個伺服器部署多個Redis的執行個體,并把他們當作不同的伺服器來使用,在某些時候,無論如何一個伺服器是不夠的, 是以,如果你想使用多個CPU,你可以考慮一下分片(shard)。
為什麼要做Redis分區?
- 分區可以讓Redis管理更大的記憶體,Redis将可以使用所有機器的記憶體。如果沒有分區,你最多隻能使用一台機器的記憶體。分區使Redis的計算能力通過簡單地增加計算機得到成倍提升,Redis的網絡帶寬也會随着計算機和網卡的增加而成倍增長。
你知道有哪些Redis分區實作方案?
- 用戶端分區就是在用戶端就已經決定資料會被存儲到哪個redis節點或者從哪個redis節點讀取。大多數用戶端已經實作了用戶端分區。
- 代理分區 意味着用戶端将請求發送給代理,然後代理決定去哪個節點寫資料或者讀資料。代理根據分區規則決定請求哪些Redis執行個體,然後根據Redis的響應結果傳回給用戶端。redis和memcached的一種代理實作就是Twemproxy
- 查詢路由(Query routing) 的意思是用戶端随機地請求任意一個redis執行個體,然後由Redis将請求轉發給正确的Redis節點。Redis Cluster實作了一種混合形式的查詢路由,但并不是直接将請求從一個redis節點轉發到另一個redis節點,而是在用戶端的幫助下直接redirected到正确的redis節點。
Redis分區有什麼缺點?
- 涉及多個key的操作通常不會被支援。例如你不能對兩個集合求交集,因為他們可能被存儲到不同的Redis執行個體(實際上這種情況也有辦法,但是不能直接使用交集指令)。
- 同時操作多個key,則不能使用Redis事務.
- 分區使用的粒度是key,不能使用一個非常長的排序key存儲一個資料集(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)
- 當使用分區的時候,資料處理會非常複雜,例如為了備份你必須從不同的Redis執行個體和主機同時收集RDB / AOF檔案。
- 分區時動态擴容或縮容可能非常複雜。Redis叢集在運作時增加或者删除Redis節點,能做到最大程度對使用者透明地資料再平衡,但其他一些用戶端分區或者代理分區方法則不支援這種特性。然而,有一種預分片的技術也可以較好的解決這個問題。
分布式問題
Redis實作分布式鎖
- Redis為單程序單線程模式,采用隊列模式将并發通路變成串行通路,且多用戶端對Redis的連接配接并不存在競争關系Redis中可以使用setNx指令實作分布式鎖。
- 當且僅當 key 不存在,将 key 的值設為 value。 若給定的 key 已經存在,則 setNx不做任何動作
- SETNX 是『SET if Not eXists』(如果不存在,則 SET)的簡寫。
- 傳回值:設定成功,傳回 1 。設定失敗,傳回 0 。
- 使用setNx完成同步鎖的流程及事項如下:
- 使用SETNX指令擷取鎖,若傳回0(key已存在,鎖已存在)則擷取失敗,反之擷取成功
- 為了防止擷取鎖後程式出現異常,導緻其他線程/程序調用setNx指令總是傳回0而進入死鎖狀态,需要為該key設定一個“合理”的過期時間釋放鎖,使用DEL指令将鎖資料删除
如何解決 Redis 的并發競争 Key 問題
- 所謂 Redis 的并發競争 Key 的問題也就是多個系統同時對一個 key 進行操作,但是最後執行的順序和我們期望的順序不同,這樣也就導緻了結果的不同!
- 推薦一種方案:分布式鎖(zookeeper 和 redis 都可以實作分布式鎖)。(如果不存在 Redis 的并發競争 Key 問題,不要使用分布式鎖,這樣會影響性能)
- 基于zookeeper臨時有序節點可以實作的分布式鎖。大緻思想為:每個用戶端對某個方法加鎖時,在zookeeper上的與該方法對應的指定節點的目錄下,生成一個唯一的瞬時有序節點。 判斷是否擷取鎖的方式很簡單,隻需要判斷有序節點中序号最小的一個。 當釋放鎖的時候,隻需将這個瞬時節點删除即可。同時,其可以避免服務當機導緻的鎖無法釋放,而産生的死鎖問題。完成業務流程後,删除對應的子節點釋放鎖。
在實踐中,當然是從以可靠性為主。是以首推Zookeeper。
分布式Redis是前期做還是後期規模上來了再做好?為什麼?
- 既然Redis是如此的輕量(單執行個體隻使用1M記憶體),為防止以後的擴容,最好的辦法就是一開始就啟動較多執行個體。即便你隻有一台伺服器,你也可以一開始就讓Redis以分布式的方式運作,使用分區,在同一台伺服器上啟動多個執行個體。
- 一開始就多設定幾個Redis執行個體,例如32或者64個執行個體,對大多數使用者來說這操作起來可能比較麻煩,但是從長久來看做這點犧牲是值得的。
- 這樣的話,當你的資料不斷增長,需要更多的Redis伺服器時,你需要做的就是僅僅将Redis執行個體從一台服務遷移到另外一台伺服器而已(而不用考慮重新分區的問題)。一旦你添加了另一台伺服器,你需要将你一半的Redis執行個體從第一台機器遷移到第二台機器。
什麼是 RedLock
- Redis 官方站提出了一種權威的基于 Redis 實作分布式鎖的方式名叫
Redlock
,此種方式比原先的單節點的方法更安全。它可以保證以下特性:
- 安全特性:互斥通路,即永遠隻有一個 client 能拿到鎖
- 避免死鎖:最終 client 都可能拿到鎖,不會出現死鎖的情況,即使原本鎖住某資源的 client crash 了或者出現了網絡分區
- 容錯性:隻要大部分 Redis 節點存活就可以正常提供服務
緩存異常
什麼是redis穿透?
- 就是使用者請求透過redis去請求mysql伺服器,導緻mysql壓力過載。但一個web服務裡,極容易出現瓶頸的就是mysql,是以才讓redis去分擔mysql 的壓力,是以這種問題是萬萬要避免的
- 解決方法:
- 從緩存取不到的資料,在資料庫中也沒有取到,這時也可以将key-value對寫為key-null,緩存有效時間可以設定短點,如30秒(設定太長會導緻正常情況也沒法使用)。這樣可以防止攻擊使用者反複用同一個id暴力攻擊
- 接口層增加校驗,如使用者鑒權校驗,id做基礎校驗,id<=0的直接攔截;
- 采用布隆過濾器,将所有可能存在的資料哈希到一個足夠大的 bitmap 中,一個一定不存在的資料會被這個 bitmap 攔截掉,進而避免了對底層存儲系統的查詢壓力
什麼是redis雪崩?
- 就是redis服務由于負載過大而當機,導緻mysql的負載過大也當機,最終整個系統癱瘓
-
- redis叢集,将原來一個人幹的工作,分發給多個人幹
- 緩存預熱(關閉外網通路,先開啟mysql,通過預熱腳本将熱點資料寫入緩存中,啟動緩存。開啟外網服務)
- 資料不要設定相同的生存時間,不然過期時,redis壓力會大
- 高并發下,由于一個key失效,而導緻多個線程去mysql查同一業務資料并存到redis(并發下,存了多份資料),而一段時間後,多份資料同時失效。導緻壓力驟增
-
- 分級緩存(緩存兩份資料,第二份資料生存時間長一點作為備份,第一份資料用于被請求命中,如果第二份資料被命中說明第一份資料已經過期,要去mysql請求資料重新緩存兩份資料)
- 計劃任務(假如資料生存時間為30分鐘,計劃任務就20分鐘執行一次更新緩存資料)
緩存預熱
- 緩存預熱就是系統上線後,将相關的緩存資料直接加載到緩存系統。這樣就可以避免在使用者請求的時候,先查詢資料庫,然後再将資料緩存的問題!使用者直接查詢事先被預熱的緩存資料!
- 解決方案
- 直接寫個緩存重新整理頁面,上線時手工操作一下;
- 資料量不大,可以在項目啟動的時候自動進行加載;
- 定時重新整理緩存;
緩存降級
- 當通路量劇增、服務出現問題(如響應時間慢或不響應)或非核心服務影響到核心流程的性能時,仍然需要保證服務還是可用的,即使是有損服務。系統可以根據一些關鍵資料進行自動降級,也可以配置開關實作人工降級。
- 緩存降級的最終目的是保證核心服務可用,即使是有損的。而且有些服務是無法降級的(如加入購物車、結算)。
- 在進行降級之前要對系統進行梳理,看看系統是不是可以丢卒保帥;進而梳理出哪些必須誓死保護,哪些可降級;比如可以參考日志級别設定預案:
- 一般:比如有些服務偶爾因為網絡抖動或者服務正在上線而逾時,可以自動降級;
- 警告:有些服務在一段時間内成功率有波動(如在95~100%之間),可以自動降級或人工降級,并發送告警;
- 錯誤:比如可用率低于90%,或者資料庫連接配接池被打爆了,或者通路量突然猛增到系統能承受的最大閥值,此時可以根據情況自動降級或者人工降級;
- 嚴重錯誤:比如因為特殊原因資料錯誤了,此時需要緊急人工降級。
- 服務降級的目的,是為了防止Redis服務故障,導緻資料庫跟着一起發生雪崩問題。是以,對于不重要的緩存資料,可以采取服務降級政策,例如一個比較常見的做法就是,Redis出現問題,不去資料庫查詢,而是直接傳回預設值給使用者。
熱點資料和冷資料
- 熱點資料,緩存才有價值
- 對于冷資料而言,大部分資料可能還沒有再次通路到就已經被擠出記憶體,不僅占用記憶體,而且價值不大。頻繁修改的資料,看情況考慮使用緩存
- 對于熱點資料,比如我們的某IM産品,生日祝福子產品,當天的壽星清單,緩存以後可能讀取數十萬次。再舉個例子,某導航産品,我們将導航資訊,緩存以後可能讀取數百萬次。
- 資料更新前至少讀取兩次,緩存才有意義。這個是最基本的政策,如果緩存還沒有起作用就失效了,那就沒有太大價值了。
- 那存不存在,修改頻率很高,但是又不得不考慮緩存的場景呢?有!比如,這個讀取接口對資料庫的壓力很大,但是又是熱點資料,這個時候就需要考慮通過緩存手段,減少資料庫的壓力,比如我們的某助手産品的,點贊數,收藏數,分享數等是非常典型的熱點資料,但是又不斷變化,此時就需要将資料同步儲存到Redis緩存,減少資料庫壓力。
緩存熱點key
- 緩存中的一個Key(比如一個促銷商品),在某個時間點過期的時候,恰好在這個時間點對這個Key有大量的并發請求過來,這些請求發現緩存過期一般都會從後端DB加載資料并回設到緩存,這個時候大并發的請求可能會瞬間把後端DB壓垮。
- 對緩存查詢加鎖,如果KEY不存在,就加鎖,然後查DB入緩存,然後解鎖;其他程序如果發現有鎖就等待,然後等解鎖後傳回資料或者進入DB查詢
常用工具
Redis支援的Java用戶端都有哪些?官方推薦用哪個?
- Redisson、Jedis、lettuce等等,官方推薦使用Redisson。
Redis和Redisson有什麼關系?
- Redisson是一個進階的分布式協調Redis客服端,能幫助使用者在分布式環境中輕松實作一些Java的對象 (Bloom filter, BitSet, Set, SetMultimap, ScoredSortedSet, SortedSet, Map, ConcurrentMap, List, ListMultimap, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, ReadWriteLock, AtomicLong, CountDownLatch, Publish / Subscribe, HyperLogLog)。
Jedis與Redisson對比有什麼優缺點?
- Jedis是Redis的Java實作的用戶端,其API提供了比較全面的Redis指令的支援;Redisson實作了分布式和可擴充的Java資料結構,和Jedis相比,功能較為簡單,不支援字元串操作,不支援排序、事務、管道、分區等Redis特性。Redisson的宗旨是促進使用者對Redis的關注分離,進而讓使用者能夠将精力更集中地放在處理業務邏輯上。
其他問題
Redis與Memcached的差別
- 兩者都是非關系型記憶體鍵值資料庫,現在公司一般都是用 Redis 來實作緩存,而且 Redis 自身也越來越強大了!Redis 與 Memcached 主要有以下不同:
對比參數 Redis Memcached 類型 1. 支援記憶體 2. 非關系型資料庫 1. 支援記憶體 2. 鍵值對形式 3. 緩存形式 資料存儲類型 1. String 2. List 3. Set 4. Hash 5. Sort Set 【俗稱ZSet】 1. 文本型 2. 二進制類型 查詢【操作】類型 1. 批量操作 2. 事務支援 3. 每個類型不同的CRUD 1.常用的CRUD 2. 少量的其他指令 附加功能 1. 釋出/訂閱模式 2. 主從分區 3. 序列化支援 4. 腳本支援【Lua腳本】 1. 多線程服務支援 網絡IO模型 1. 單線程的多路 IO 複用模型 1. 多線程,非阻塞IO模式 事件庫 自封轉簡易事件庫AeEvent 貴族血統的LibEvent事件庫 持久化支援 1. RDB 2. AOF 不支援 叢集模式 原生支援 cluster 模式,可以實作主從複制,讀寫分離 沒有原生的叢集模式,需要依靠用戶端來實作往叢集中分片寫入資料 記憶體管理機制 在 Redis 中,并不是所有資料都一直存儲在記憶體中,可以将一些很久沒用的 value 交換到磁盤 Memcached 的資料則會一直在記憶體中,Memcached 将記憶體分割成特定長度的塊來存儲資料,以完全解決記憶體碎片的問題。但是這種方式會使得記憶體的使用率不高,例如塊的大小為 128 bytes,隻存儲 100 bytes 的資料,那麼剩下的 28 bytes 就浪費掉了。 适用場景 複雜資料結構,有持久化,高可用需求,value存儲内容較大 純key-value,資料量非常大,并發量非常大的業務
- memcached所有的值均是簡單的字元串,redis作為其替代者,支援更為豐富的資料類型
- redis的速度比memcached快很多
- redis可以持久化其資料
如何保證緩存與資料庫雙寫時的資料一緻性?
- 你隻要用緩存,就可能會涉及到緩存與資料庫雙存儲雙寫,你隻要是雙寫,就一定會有資料一緻性的問題,那麼你如何解決一緻性問題?
- 一般來說,就是如果你的系統不是嚴格要求緩存+資料庫必須一緻性的話,緩存可以稍微的跟資料庫偶爾有不一緻的情況,最好不要做這個方案,讀請求和寫請求串行化,串到一個記憶體隊列裡去,這樣就可以保證一定不會出現不一緻的情況
- 串行化之後,就會導緻系統的吞吐量會大幅度的降低,用比正常情況下多幾倍的機器去支撐線上的一個請求。
- 還有一種方式就是可能會暫時産生不一緻的情況,但是發生的幾率特别小,就是先更新資料庫,然後再删除緩存。
問題場景 | 描述 | 解決 |
---|---|---|
先寫緩存,再寫資料庫,緩存寫成功,資料庫寫失敗 | 緩存寫成功,但寫資料庫失敗或者響應延遲,則下次讀取(并發讀)緩存時,就出現髒讀 | 這個寫緩存的方式,本身就是錯誤的,需要改為先寫資料庫,把舊緩存置為失效;讀取資料的時候,如果緩存不存在,則讀取資料庫再寫緩存 |
先寫資料庫,再寫緩存,資料庫寫成功,緩存寫失敗 | 寫資料庫成功,但寫緩存失敗,則下次讀取(并發讀)緩存時,則讀不到資料 | 緩存使用時,假如讀緩存失敗,先讀資料庫,再回寫緩存的方式實作 |
需要緩存異步重新整理 | 指資料庫操作和寫緩存不在一個操作步驟中,比如在分布式場景下,無法做到同時寫緩存或需要異步重新整理(補救措施)時候 | 确定哪些資料适合此類場景,根據經驗值确定合理的資料不一緻時間,使用者資料重新整理的時間間隔 |
Redis常見性能問題和解決方案?
- Master最好不要做任何持久化工作,包括記憶體快照和AOF日志檔案,特别是不要啟用記憶體快照做持久化。
- 如果資料比較關鍵,某個Slave開啟AOF備份資料,政策為每秒同步一次。
- 為了主從複制的速度和連接配接的穩定性,Slave和Master最好在同一個區域網路内。
- 盡量避免在壓力較大的主庫上增加從庫
- Master調用BGREWRITEAOF重寫AOF檔案,AOF在重寫的時候會占大量的CPU和記憶體資源,導緻服務load過高,出現短暫服務暫停現象。
- 為了Master的穩定性,主從複制不要用圖狀結構,用單向連結清單結構更穩定,即主從關系為:Master<–Slave1<–Slave2<–Slave3…,這樣的結構也友善解決單點故障問題,實作Slave對Master的替換,也即,如果Master挂了,可以立馬啟用Slave1做Master,其他不變。
Redis官方為什麼不提供Windows版本?
- 因為目前Linux版本已經相當穩定,而且使用者量很大,無需開發windows版本,反而會帶來相容性等問題。
一個字元串類型的值能存儲最大容量是多少?
- 512M
Redis如何做大量資料插入?
- Redis2.6開始redis-cli支援一種新的被稱之為pipe mode的新模式用于執行大量資料插入工作。
假如Redis裡面有1億個key,其中有10w個key是以某個固定的已知的字首開頭的,如果将它們全部找出來?
- 使用keys指令可以掃出指定模式的key清單。
-
對方接着追問:如果這個redis正在給線上的業務提供服務,那使用keys指令會有什麼問題?
這個時候你要回答redis關鍵的一個特性:redis的單線程的。keys指令會導緻線程阻塞一段時間,線上服務會停頓,直到指令執行完畢,服務才能恢複。這個時候可以使用scan指令,scan指令可以無阻塞的提取出指定模式的key清單,但是會有一定的重複機率,在用戶端做一次去重就可以了,但是整體所花費的時間會比直接用keys指令長。
使用Redis做過異步隊列嗎,是如何實作的
- 使用list類型儲存資料資訊,rpush生産消息,lpop消費消息,當lpop沒有消息時,可以sleep一段時間,然後再檢查有沒有資訊,如果不想sleep的話,可以使用blpop, 在沒有資訊的時候,會一直阻塞,直到資訊的到來。redis可以通過pub/sub主題訂閱模式實作一個生産者,多個消費者,當然也存在一定的缺點,當消費者下線時,生産的消息會丢失。
Redis如何實作延時隊列
- 使用sortedset,使用時間戳做score, 消息内容作為key,調用zadd來生産消息,消費者使用zrangbyscore擷取n秒之前的資料做輪詢處理。
Redis回收程序如何工作的?
- 一個用戶端運作了新的指令,添加了新的資料。
- Redis檢查記憶體使用情況,如果大于maxmemory的限制, 則根據設定好的政策進行回收。
- 一個新的指令被執行,等等。
- 是以我們不斷地穿越記憶體限制的邊界,通過不斷達到邊界然後不斷地回收回到邊界以下。
如果一個指令的結果導緻大量記憶體被使用(例如很大的集合的交集儲存到一個新的鍵),不用多久記憶體限制就會被這個記憶體使用量超越。
Redis回收使用的是什麼算法?
- LRU算法
參考部落格:
[1]
Redis面試題(總結最全面的面試題)