Redis面試題(2020最新版)


概述
什么是 Redis
Redis(Remote Dictionary Server) 是一個使用 C 語言編寫的,開源的(BSD 許可)高性
能非關系型(NoSQL)的鍵值對數據庫。
Redis 可以存儲鍵和五種不同類型的值之間的映射。鍵的類型只能為字符串,值支持五種
數據類型:字符串、列表、集合、散列表、有序集合。
與傳統數據庫不同的是 Redis 的數據是存在內存中的,所以讀寫速度非常快,因此 redis
被廣泛應用於緩存方向,每秒可以處理超過 10 萬次讀寫操作,是已知性能最快的
Key-Value DB。另外,Redis 也經常用來做分布式鎖。除此之外,Redis 支持事務 、持久
化、LUA 腳本、LRU 驅動事件、多種集群方案。
Redis 有哪些優缺點
優點
讀寫性能優異, Redis 能讀的速度是 110000 次/s,寫的速度是 81000 次/s。
支持數據持久化,支持 AOF 和 RDB 兩種持久化方式。
支持事務,Redis 的所有操作都是原子性的,同時 Redis 還支持對幾個操作合並后的原子性
執行。
數據結構豐富,除了支持 string 類型的 value 外還支持 hash、set、zset、list 等數據結構。支持主從復制,主機會自動將數據同步到從機,可以進行讀寫分離。
缺點
數據庫容量受到物理內存的限制,不能用作海量數據的高性能讀寫,因此 Redis 適合的場
景主要局限在較小數據量的高性能操作和運算上。
Redis 不具備自動容錯和恢復功能,主機從機的宕機都會導致前端部分讀寫請求失敗,需
要等待機器重啟或者手動切換前端的 IP 才能恢復。
主機宕機,宕機前有部分數據未能及時同步到從機,切換 IP 后還會引入數據不一致的問題,
降低了系統的可用性。
Redis 較難支持在線擴容,在集群容量達到上限時在線擴容會變得很復雜。為避免這一問
題,運維人員在系統上線時必須確保有足夠的空間,這對資源造成了很大的浪費。
為什么要用 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 相比其他緩存,有一個非常大的優勢,就是支持多種數據類型。
數據類型說明 string 字符串,最簡單的 k-v 存儲 hashhash 格式,value 為 field 和 value,
適合 ID-Detail 這樣的場景。list 簡單的 list,順序列表,支持首位或者末尾插入數據 set
無序 list,查找速度快,適合交集、並集、差集處理 sorted set 有序的 set其實,通過上面的數據類型的特性,基本就能想到合適的應用場景了。
string——適合最簡單的 k-v 存儲,類似於 memcached 的存儲結構,短信驗證碼,配置
信息等,就用這種類型來存儲。
hash——一般 key 為 ID 或者唯一標示,value 對應的就是詳情了。如商品詳情,個人信息
詳情,新聞詳情等。
list——因為 list 是有序的,比較適合存儲一些有序且數據相對固定的數據。如省市區表、
字典表等。因為 list 是有序的,適合根據寫入的時間來排序,如:最新的***,消息隊列等。
set——可以簡單的理解為 ID-List 的模式,如微博中一個人有哪些好友,set 最牛的地方在
於,可以對兩個 set 提供交集、並集、差集操作。例如:查找兩個人共同的好友等。
Sorted Set——是 set 的增強版本,增加了一個 score 參數,自動會根據 score 的值進行
排序。比較適合類似於 top 10 等不根據插入的時間來排序的數據。
如上所述,雖然 Redis 不像關系數據庫那么復雜的數據結構,但是,也能適合很多場景,
比一般的緩存數據結構要多。了解每種數據結構適合的業務場景,不僅有利於提升開發效率,
也能有效利用 Redis 的性能。
持久化什么是 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 中策略可供選擇),我們還可
以根據具體的業務需求進行自定義的緩存淘汰,常見的策略有兩種:
定時去清理過期的緩存;
當有用戶請求過來時,再判斷這個請求所用到的緩存是否過期,過期的話就去底層系統得到
新數據並更新緩存。
兩者各有優劣,第一種的缺點是維護大量緩存的 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 可以保證腳本內的命令一次性、按順序地執行,
其同時也不提供事務運行錯誤的回滾,執行過程中如果部分命令運行錯誤,剩下的命令還是
會繼續運行完
基於中間標記變量,通過另外的標記變量來標識事務是否執行完成,讀取數據時先讀取該標記變量判斷是否事務執行完成。但這樣會需要額外寫代碼實現,比較繁瑣
集群方案
哨兵模式
哨兵的介紹
sentinel,中文名是哨兵。哨兵是 redis 集群機構中非常重要的一個組件,主要有以下功能:
集群監控:負責監控 redis master 和 slave 進程是否正常工作。
消息通知:如果某個 redis 實例有故障,那么哨兵負責發送消息作為報警通知給管理員。
故障轉移:如果 master node 掛掉了,會自動轉移到 slave node 上。
配置中心:如果故障轉移發生了,通知 client 客戶端新的 master 地址。
哨兵用於實現 redis 集群的高可用,本身也是分布式的,作為一個哨兵集群去運行,互相
協同工作。
故障轉移時,判斷一個 master node 是否宕機了,需要大部分的哨兵都同意才行,涉及到
了分布式選舉的問題。
即使部分哨兵節點掛掉了,哨兵集群還是能正常工作的,因為如果一個作為高可用機制重要
組成部分的故障轉移系統本身是單點的,那就很坑爹了。
哨兵的核心知識
哨兵至少需要 3 個實例,來保證自己的健壯性。哨兵 + redis 主從的部署架構,是不保證數據零丟失的,只能保證 redis 集群的高可用性。
對於哨兵 + redis 主從這種復雜的部署架構,盡量在測試環境和生產環境,都進行充足的
測試和演練。
官方 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 協議,用於節點間進行高效的數據交換,占用更少的網絡帶寬和處理時間。
節點間的內部通信機制
基本通信原理
集群元數據的維護有兩種方式:集中式、Gossip 協議。redis cluster 節點間采用 gossip
協議進行通信。
分布式尋址算法
hash 算法(大量緩存重建)
一致性 hash 算法(自動緩存遷移)+ 虛擬節點(自動負載均衡)
redis cluster 的 hash slot 算法優點
無中心架構,支持動態擴容,對業務透明
具備 Sentinel 的監控和自動 Failover(故障轉移)能力
客戶端不需要連接集群所有節點,連接集群中任何一個可用節點即可
高性能,客戶端直連 redis 服務,免去了 proxy 代理的損耗
缺點
運維也很復雜,數據遷移需要人工干預
只能使用 0 號數據庫
不支持批量操作(pipeline 管道操作)
分布式邏輯和存儲模塊耦合等
基於客戶端分配
簡介
Redis Sharding 是 Redis Cluster 出來之前,業界普遍使用的多 Redis 實例集群方法。其
主要思想是采用哈希算法將 Redis 數據的 key 進行散列,通過 hash 函數,特定的 key 會映
射到特定的 Redis 節點上。Java redis 客戶端驅動 jedis,支持 Redis Sharding 功能,即
ShardedJedis 以及結合緩存池的 ShardedJedisPool
優點優勢在於非常簡單,服務端的 Redis 實例彼此獨立,相互無關聯,每個 Redis 實例像單服
務器一樣運行,非常容易線性擴展,系統的靈活性很強
缺點
由於 sharding 處理放到客戶端,規模進一步擴大時給運維帶來挑戰。
客戶端 sharding 不支持動態增刪節點。服務端 Redis 實例群拓撲結構有變化時,每個客戶
端都需要更新調整。連接不能共享,當應用規模增大時,資源浪費制約優化
基於代理服務器分片
簡介
客戶端發送請求到一個代理組件,代理解析客戶端的數據,並將請求轉發至正確的節點,最
后將結果回復給客戶端
特征
透明接入,業務程序不用關心后端 Redis 實例,切換成本低
Proxy 的邏輯和存儲的邏輯是隔離的
代理層多了一次轉發,性能有所損耗
業界開源方案Twtter 開源的 Twemproxy
豌豆莢開源的 Codis
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 的時候,它會發送一個 PSYNC 命令給 master node。
如 果 這 是 slave node 初 次 連 接 到 master node , 那 么 會 觸 發 一 次 full
resynchronization 全量復制。此時 master 會啟動一個后台線程,開始生成一份 RDB 快
照文件,同時還會將從客戶端 client 新收到的所有寫命令緩存在內存中。RDB 文件生成完畢后,
master 會將這個 RDB 發送給 slave,slave 會先寫入本地磁盤,然后再從本地磁盤加載
到內存中,
接着 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 節點存活就可以正常提供服務
緩存異常
緩存雪崩
緩存雪崩是指緩存同一時間大面積的失效,所以,后面的請求都會落到數據庫上,造成數據
庫短時間內承受大量請求而崩掉。
解決方案
緩存數據的過期時間設置隨機,防止同一時間大量數據過期現象發生。
一般並發量不是特別多的時候,使用最多的解決方案是加鎖排隊。
給每一個緩存數據增加相應的緩存標記,記錄緩存的是否失效,如果緩存標記失效,則更新
數據緩存。
緩存穿透
緩存穿透是指緩存和數據庫中都沒有的數據,導致所有的請求都落到數據庫上,造成數據庫
短時間內承受大量請求而崩掉。
解決方案
接口層增加校驗,如用戶鑒權校驗,id 做基礎校驗,id<=0 的直接攔截;
從緩存取不到的數據,在數據庫中也沒有取到,這時也可以將 key-value 對寫為 key-null,緩存有效時間可以設置短點,如 30 秒(設置太長會導致正常情況也沒法使用)。這樣可以
防止攻擊用戶反復用同一個 id 暴力攻擊
采用布隆過濾器,將所有可能存在的數據哈希到一個足夠大的 bitmap 中,一個一定不存
在的數據會被這個 bitmap 攔截掉,從而避免了對底層存儲系統的查詢壓力
附加
對於空間的利用到達了一種極致,那就是 Bitmap 和布隆過濾器(Bloom Filter)。
Bitmap: 典型的就是哈希表
缺點是,Bitmap 對於每個元素只能記錄 1bit 信息,如果還想完成額外的功能,恐怕只能靠
犧牲更多的空間、時間來完成了。
布隆過濾器(推薦)
就是引入了 k(k>1)k(k>1)個相互獨立的哈希函數,保證在給定的空間、誤判率下,完成元
素判重的過程。
它的優點是空間效率和查詢時間都遠遠超過一般的算法,缺點是有一定的誤識別率和刪除困
難。
Bloom-Filter 算法的核心思想就是利用多個不同的 Hash 函數來解決“沖突”。
Hash 存在一個沖突(碰撞)的問題,用同一個 Hash 得到的兩個 URL 的值有可能相同。為
了減少沖突,我們可以多引入幾個 Hash,如果通過其中的一個 Hash 值我們得出某元素不
在集合中,那么該元素肯定不在集合中。只有在所有的 Hash 函數告訴我們該元素在集合中
時,才能確定該元素存在於集合中。這便是 Bloom-Filter 的基本思想。Bloom-Filter 一般用於在大數據量的集合中判定某元素是否存在。
緩存擊穿
緩存擊穿是指緩存中沒有但數據庫中有的數據(一般是緩存時間到期),這時由於並發用戶
特別多,同時讀緩存沒讀到數據,又同時去數據庫去取數據,引起數據庫壓力瞬間增大,造
成過大壓力。和緩存雪崩不同的是,緩存擊穿指並發查同一條數據,緩存雪崩是不同數據都
過期了,很多數據都查不到從而查數據庫。
解決方案
設置熱點數據永遠不過期。
加互斥鎖,互斥鎖
緩存預熱
緩存預熱就是系統上線后,將相關的緩存數據直接加載到緩存系統。這樣就可以避免在用戶
請求的時候,先查詢數據庫,然后再將數據緩存的問題!用戶直接查詢事先被預熱的緩存數
據!
解決方案
直接寫個緩存刷新頁面,上線時手工操作一下;
數據量不大,可以在項目啟動的時候自動進行加載;定時刷新緩存;
緩存降級
當訪問量劇增、服務出現問題(如響應時間慢或不響應)或非核心服務影響到核心流程的性
能時,仍然需要保證服務還是可用的,即使是有損服務。系統可以根據一些關鍵數據進行自
動降級,也可以配置開關實現人工降級。
緩存降級的最終目的是保證核心服務可用,即使是有損的。而且有些服務是無法降級的(如
加入購物車、結算)。
在進行降級之前要對系統進行梳理,看看系統是不是可以丟卒保帥;從而梳理出哪些必須誓
死保護,哪些可降級;比如可以參考日志級別設置預案:
一般:比如有些服務偶爾因為網絡抖動或者服務正在上線而超時,可以自動降級;
警告:有些服務在一段時間內成功率有波動(如在 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,數據量非常大,並發量非常大的業務
(1) memcached 所有的值均是簡單的字符串,redis 作為其替代者,支持更為豐富的數據
類型
(2) redis 的速度比 memcached 快很多
(3) 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 算法


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM