Redis
1 什麼是Redis?
Redis本質上是一個Key-Value型別的記憶體資料庫,很像memcached,整個資料庫統統載入在記憶體當中進行操作,定期透過非同步操作把資料庫資料flush到硬碟上進行儲存。因為是純記憶體操作,Redis的效能非常出色,每秒可以處理超過 10萬次讀寫操作,是已知效能最快的Key-Value DB。 Redis的出色之處不僅僅是效能,Redis最大的魅力是支援儲存多種資料結構,此外單個value的最大限制是1GB,不像 memcached只能儲存1MB的資料,因此Redis可以用來實現很多有用的功能,比方說用他的List來做FIFO雙向連結串列,實現一個輕量級的高性 能訊息佇列服務,用他的Set可以做高效能的tag系統等等。另外Redis也可以對存入的Key-Value設定expire時間,因此也可以被當作一 個功能加強版的memcached來用。 Redis的主要缺點是資料庫容量受到物理記憶體的限制,不能用作海量資料的高效能讀寫,因此Redis適合的場景主要侷限在較小資料量的高效能操作和運算上。
2 Redis的全稱是什麼?
Remote Dictionary Server
3 redis有哪些資料型別?
string字串list可以重複的集合set不可以重複的集合hash類似於Map<String,String>zset(sorted set)帶分數的set
4 一個字串型別的智慧儲存最大容量是多少?
512M
5 怎麼理解Redis事務?
Redis無法做到像關係型資料庫事務那樣嚴格的ACID屬性,特別是Redis官網明確指出了Redis為什麼不支援回滾。
為了內部結構簡單、執行效率更高,Redis捨棄了事務控制過程中的回滾支援。一個佇列中的多個命令除非是在加入佇列時發現錯誤會做到整個事務都不執行,否則所有命令都會執行,哪怕是佇列中有的命令執行失敗——顯然Redis並沒有在這裡對佇列中的多條命令進行回滾處理。Redis認為這些錯誤都應該在開發過程中被發現,而不是產品上線之後。
配合WATCH命令之後Redis的事務可以實現樂觀鎖效果:一個佇列中的命令在執行時如果檢測到碰撞,則放棄自己的操作。
6 Redis事務相關的命令有哪幾個?
MULTI、EXEC、DISCARD、WATCH
7 Redis key的過期時間和永久有效分別怎麼設定?
EXPIRE和PERSIST命令。
8 Redis持久化資料和快取怎麼做擴容?
如果Redis被當做快取使用,使用一致性雜湊實現動態擴容縮容。
如果Redis被當做一個持久化儲存使用,必須使用固定的keys-to-nodes對映關係,節點的數量一旦確定不能變化。否則的話(即Redis節點需要動態變化的情況),必須使用可以在執行時進行資料再平衡的一套系統,而當前只有Redis叢集可以做到這樣。4、Redis主要消耗什麼物理資源?
記憶體。
9 為什麼Redis需要把所有資料放到記憶體中?
Redis為了達到最快的讀寫速度將資料都讀到記憶體中,並透過非同步的方式將資料寫入磁碟。所以redis具有快速和資料持久化的特徵。如果不將資料放在記憶體中,磁碟I/O速度會嚴重影響redis的效能。在記憶體越來越便宜的今天,redis將會越來越受歡迎。 如果設定了最大使用的記憶體,則資料已有記錄數達到記憶體限值後不能繼續插入新值。
10 Redis如何做記憶體最佳化?
儘可能使用散列表(hashes),散列表(是說散列表裡面儲存的數少)使用的記憶體非常小,所以你應該儘可能的將你的資料模型抽象到一個散列表裡面。比如你的web系統中有一個使用者物件,不要為這個使用者的名稱,姓氏,郵箱,密碼設定單獨的key,而是應該把這個使用者的所有資訊儲存到一張散列表裡面.
11 快取穿透
快取系統定義:
按照KEY去查詢VALUE,當KEY對應的VALUE一定不存在的時候並對KEY併發請求量很大的時候,就會對後端造成很大的壓力。(查詢一個必然不存在的資料。比如文章表,查詢一個不存在的id,每次都會訪問DB,如果有人惡意破壞,很可能直接對DB造成影響。)
由於快取不命中,每次都要查詢持久層。從而失去快取的意義。
解決方法:
(1)快取層緩 存空值。
快取太多空值,佔用更多空間。(最佳化:給個空值過 期時間)
(2)將資料庫中所有的查詢條件,放布隆過濾器中。當一個查詢請求來臨的時候,先經過布隆過濾器進行查,如果請求存在這個條件中,那麼繼續執行,如果不在,直接丟棄。
備註 :
比如資料庫中有10000個條件,那麼布隆過濾器的容量size設定的要稍微比10000大一些,比如12000.
對於誤判率的設定,根據實際專案,以及硬體設施來具體定。但一定不能設定為0,並且誤判率設定的越小,雜湊函式跟陣列長度都會更多跟更長,那麼對硬體,記憶體中間的要求就會相應 的高
private st atic BloomFilter<Inte ger> bloomFi lt er = BloomFilter.create(Funnels.integerFue l(), s ize, 000 01) ;
有了siz跟誤判率,那麼布隆過濾器會產相應的雜湊函式跟陣列。
綜上:我們可以利用布隆過濾器,將redis快取擊穿制在一個可容的範圍內。
12 哨兵模式
如果Master異常,則會進行Master-Slave切換,將其中一Slae作為Master,將之前的Master作為Slave
下線:
①主觀下線:Subjectively Down,簡稱 SDOWN,指的是當前 Sentinel 例項對某個redis伺服器做出的下線判斷。
②客觀下線:Objectively Down, 簡稱 ODOWN,指的是多個 Sentinel 例項在對Master Server做出 SDOWN 判斷,並且透過 SENTINEL is-master-down-by-addr 命令互相交流之後,得出的Master Server下線判斷,然後開啟failover.
工作原理:
(1)每個Sentinel以每秒鐘一次的頻率向它所知的Master,Slave以及其他 Sentinel 例項傳送一個 PING 命令 ;
(2)如果一個例項(instance)距離最後一次有效回覆 PING 命令的時間超過 down-after-milliseconds 選項所指定的值, 則這個例項會被 Sentinel 標記為主觀下線;
(3)如果一個Master被標記為主觀下線,則正在監視這個Master的所有 Sentinel 要以每秒一次的頻率確認Master的確進入了主觀下線狀態;
(4)當有足夠數量的 Sentinel(大於等於配置檔案指定的值)在指定的時間範圍內確認Master的確進入了主觀下線狀態, 則Master會被標記為客觀下線 ;
(5)在一般情況下, 每個 Sentinel 會以每 10 秒一次的頻率向它已知的所有Master,Slave傳送 INFO 命令
(6)當Master被 Sentinel 標記為客觀下線時,Sentinel 向下線的 Master 的所有 Slave 傳送 INFO 命令的頻率會從 10 秒一次改為每秒一次 ;
(7)若沒有足夠數量的 Sentinel 同意 Master 已經下線, Master 的客觀下線狀態就會被移除;
若 Master 重新向 Sentinel 的 PING 命令返回有效回覆, Master 的主觀下線狀態就會被移除;
13 悲觀鎖
執行操作前假設當前的操作肯定(或有很大機率)會被打斷(悲觀)。基於這個假設,我們在做操作前就會把相關資源鎖定,不允許自己執行期間有其他操作干擾。
Redis不支援悲觀鎖。Redis作為快取伺服器使用時,以讀操作為主,很少寫操作,相應的操作被打斷的機率較少。不採用悲觀鎖是為了防止降低效能。
14 樂觀鎖
執行操作前假設當前操作不會被打斷(樂觀)。基於這個假設,我們在做操作前不會鎖定資源,萬一發生了其他操作的干擾,那麼本次操作將被放棄。
15 持久化
(1)RDB持久化:
每隔一段時間,將記憶體中的資料集寫到磁碟
Redis會單獨建立(fork)一個子程序來進行持久化,會先將資料寫入到個臨時檔案中,待持久化過程都結束了,再用這個臨時檔案替換上次持久化好的檔案。整個過程中,主程序是不進行任何IO操作的,這就確保了極高的效能如果需要進行大規模資料的恢復,且對於資料恢復的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。
儲存策略:
save 9 00 1 900 秒內如果至少有 1 個 key 的值變化,則儲存
save 300 10 300 秒內如果至少有 10 個 key 的值變化,則儲存
save 60 1 0000 60 秒內如果至10000 個 key 的值變化,則儲存
(2)AOF 持久化: 以日誌形式記錄每個更新((總結、改)操作
Redis重新啟動時讀取這個檔案,重新執行新建、修改資料的命令恢復資料。
儲存策略:
appendfsync always:每次產生一條新的修改資料的命令都執行儲存操作;效率低,但是安全!
appendfsync everysec:每秒執行一次儲存操作。如果在未儲存當前秒內操作時發生了斷電,仍然會導致一部分資料丟失(即1秒鐘的資料)。
appendfsync no:將資料庫儲存操作的觸發時機交給作業系統來進行排程更快,也更不安全的選擇。
推薦(並且也是預設)的措施為每秒 fsync 一次, 這種 fsync 策略可以兼顧速度和安全性。
缺點:
1 比起RDB佔用更多的磁碟空間
2 恢復備份速度要慢
3 每次讀寫都同步的話,有一定的效能壓力
4 存在個別Bug,造成恢復不能
(3)選擇策略:
可讀的日誌文字,透過操作AOF
官方推薦:
如果對資料不敏感,可以選單獨用RDB;不建議單獨用AOF,因為可能出現Bug;如果只是做純記憶體快取,可以都不用
16 Redis提供了哪幾種持久化方式?
RDB持久化方式能夠在指定的時間間隔能對你的資料進行快照儲存。
AOF持久化方式記錄每次對伺服器寫的操作,當伺服器重啟的時候會重新執行這些命令來恢復原始的資料,AOF命令以redis協議追加儲存每次寫的操作到檔案末尾.Redis還能對AOF檔案進行後臺重寫,使得AOF檔案的體積不至於過大。
如果你只希望你的資料在伺服器執行的時候存在,你也可以不使用任何持久化方式。
你也可以同時開啟兩種持久化方式,在這種情況下,當redis重啟的時候會優先載入AOF檔案來恢復原始的資料,因為在通常情況下AOF檔案儲存的資料集要比RDB檔案儲存的資料集要完整。
17 如何選擇合適的持久化方式?
一般來說, 如果想達到足以媲美PostgreSQL的資料安全性, 你應該同時使用兩種持久化功能。如果你非常關心你的資料, 但仍然可以承受數分鐘以內的資料丟失,那麼你可以只使用RDB持久化。
有很多使用者都只使用AOF持久化,但並不推薦這種方式:因為定時生成RDB快照(snapshot)非常便於進行資料庫備份, 並且 RDB 恢復資料集的速度也要比AOF恢復的速度要快,除此之外, 使用RDB還可以避免之前提到的AOF程式的bug。
18 分散式Redis是前期做還是後期規模上來了再做好?為什麼?
既然Redis是如此的輕量(單例項只使用1M記憶體),為防止以後的擴容,最好的辦法就是一開始就啟動較多例項。即便你只有一臺伺服器,你也可以一開始就讓Redis以分散式的方式執行,使用分割槽,在同一臺伺服器上啟動多個例項。
一開始就多設定幾個Redis例項,例如32或者64個例項,對大多數使用者來說這操作起來可能比較麻煩,但是從長久來看做這點犧牲是值得的。
這樣的話,當你的資料不斷增長,需要更多的Redis伺服器時,你需要做的就是僅僅將Redis例項從一臺服務遷移到另外一臺伺服器而已(而不用考慮重新分割槽的問題)。一旦你添加了另一臺伺服器,你需要將你一半的Redis例項從第一臺機器遷移到第二臺機器。
19 Redis的記憶體佔用情況怎麼樣?
給你舉個例子: 100萬個鍵值對(鍵是0到999999值是字串“hello world”)在我的32位的Mac筆記本上 用了100MB。同樣的資料放到一個key裡只需要16MB, 這是因為鍵值有一個很大的開銷。 在Memcached上執行也是類似的結果,但是相對Redis的開銷要小一點點,因為Redis會記錄型別資訊引用計數等等。
當然,大鍵值對時兩者的比例要好很多。
64位的系統比32位的需要更多的記憶體開銷,尤其是鍵值對都較小時,這是因為64位的系統裡指標佔用了8個位元組。 但是,當然,64位系統支援更大的記憶體,所以為了執行大型的Redis伺服器或多或少的需要使用64位的系統。
20 都有哪些辦法可以降低Redis的記憶體使用情況呢?
如果你使用的是32位的Redis例項,可以好好利用Hash,list,sorted set,set等集合型別資料,因為通常情況下很多小的Key-Value可以用更緊湊的方式存放到一起。
21 檢視Redis使用情況及狀態資訊用什麼命令?
info
22 Redis的記憶體用完了會發生什麼?
如果達到設定的上限,Redis的寫命令會返回錯誤資訊(但是讀命令還可以正常返回。)或者你可以將Redis當快取來使用配置淘汰機制,當Redis達到記憶體上限時會沖刷掉舊的內容。
23 redis是單執行緒的,為什麼那麼快?
1)完全基於記憶體,絕大部分請求是純粹的記憶體操作,非常快速。資料存在記憶體中,類似於HashMap,HashMap的優勢就是查詢和操作的時間複雜度都是O(1)
2)資料結構簡單,對資料操作也簡單,Redis中的資料結構是專門進行設計的
3)採用單執行緒,避免了不必要的上下文切換和競爭條件,也不存在多程序或者多執行緒導致的切換而消耗 CPU,不用去考慮各種鎖的問題,不存在加鎖釋放鎖操作,沒有因為可能出現死鎖而導致的效能消耗
4)使用多路I/O複用模型,非阻塞IO
5)使用底層模型不同,它們之間底層實現方式以及與客戶端之間通訊的應用協議不一樣,Redis直接自己構建了VM 機制 ,因為一般的系統呼叫系統函式的話,會浪費一定的時間去移動和請求
24 Redis是單執行緒的,如何提高多核CPU的利用率?
可以在同一個伺服器部署多個Redis的例項,並把他們當作不同的伺服器來使用,在某些時候,無論如何一個伺服器是不夠的, 所以,如果你想使用多個CPU,你可以考慮一下分片(shard)。
25 一個Redis例項最多能存放多少的keys?List、Set、Sorted Set他們最多能存放多少元素?
理論上Redis可以處理多達
的keys,並且在實際中進行了測試,每個例項至少存放了2億5千萬的keys。我們正在測試一些較大的值。
任何list、set、和sorted set都可以放
個元素。
換句話說,Redis的儲存極限是系統中的可用記憶體值。
26 Redis常見效能問題和解決方案?
(1) Master最好不要做任何持久化工作,如RDB記憶體快照和AOF日誌檔案
(2) 如果資料比較重要,某個Slave開啟AOF備份資料,策略設定為每秒同步一次
(3) 為了主從複製的速度和連線的穩定性,Master和Slave最好在同一個區域網內
(4) 儘量避免在壓力很大的主庫上增加從庫
(5) 主從複製不要用圖狀結構,用單向連結串列結構更為穩定,即:Master <- Slave1 <- Slave2 <- Slave3…
這樣的結構方便解決單點故障問題,實現Slave對Master的替換。如果Master掛了,可以立刻啟用Slave1做Master,其他不變。
27 Redis相比memcached有哪些優勢?
(1) memcached所有的值均是簡單的字串,redis作為其替代者,支援更為豐富的資料型別
(2) redis的速度比memcached快很多
redis可以持久化其資料28 MySQL裡有2000w資料,redis中只存20w的資料,如何保證redis中的資料都是熱點資料?
redis記憶體資料集大小上升到一定大小的時候,就會施行資料淘汰策略。
29 Redis有哪幾種資料淘汰策略?
noeviction:返回錯誤當記憶體限制達到並且客戶端嘗試執行會讓更多記憶體被使用的命令(大部分的寫入指令,但DEL和幾個例外)
allkeys-lru: 嘗試回收最少使用的鍵(LRU),使得新新增的資料有空間存放。
volatile-lru: 嘗試回收最少使用的鍵(LRU),但僅限於在過期集合的鍵,使得新新增的資料有空間存放。
allkeys-random: 回收隨機的鍵使得新新增的資料有空間存放。
volatile-random: 回收隨機的鍵使得新新增的資料有空間存放,但僅限於在過期集合的鍵。
volatile-ttl: 回收在過期集合的鍵,並且優先回收存活時間(TTL)較短的鍵,使得新新增的資料有空間存放。
30 Redis叢集方案應該怎麼做?都有哪些方案?
(1)twemproxy,大概概念是,它類似於一個代理方式,使用方法和普通redis無任何區別,設定好它下屬的多個redis例項後,使用時在本地需要連線redis的地方改為連線twemproxy,它會以一個代理的身份接收請求並使用一致性hash演算法,將請求轉接到具體redis,將結果再返回twemproxy。使用方式簡便(相對redis只需修改連線埠),對舊專案擴充套件的首選。 問題:twemproxy自身單埠例項的壓力,使用一致性hash後,對redis節點數量改變時候的計算值的改變,資料無法自動移動到新的節點。
(2)codis,目前用的最多的叢集方案,基本和twemproxy一致的效果,但它支援在 節點數量改變情況下,舊節點資料可恢復到新hash節點。
(3)redis cluster3.0自帶的叢集,特點在於他的分散式演算法不是一致性hash,而是hash槽的概念,以及自身支援節點設定從節點。具體看官方文件介紹。
(4)在業務程式碼層實現,起幾個毫無關聯的redis例項,在程式碼層,對key 進行hash計算,然後去對應的redis例項操作資料。 這種方式對hash層程式碼要求比較高,考慮部分包括,節點失效後的替代演算法方案,資料震盪後的自動指令碼恢復,例項的監控,等等。
31 說說Redis雜湊槽的概念?
Redis叢集沒有使用一致性hash,而是引入了雜湊槽的概念,Redis叢集有16384個雜湊槽,每個key透過CRC16校驗後對16384取模來決定放置哪個槽,叢集的每個節點負責一部分hash槽。
32 Redis叢集最大節點個數是多少?
16384個。
33 怎麼測試Redis的連通性?
ping
34 修改配置不重啟Redis會實時生效嗎?
針對執行例項,有許多配置選項可以透過 CONFIG SET 命令進行修改,而無需執行任何形式的重啟。 從 Redis 2.2 開始,可以從 AOF 切換到 RDB 的快照永續性或其他方式而不需要重啟 Redis。檢索 ‘CONFIG GET *’ 命令獲取更多資訊。
但偶爾重新啟動是必須的,如為升級 Redis 程式到新的版本,或者當你需要修改某些目前 CONFIG 命令還不支援的配置引數的時候。
35 Redis有哪些適合的場景?
(1)會話快取(Session Cache)
最常用的一種使用Redis的情景是會話快取(session cache)。用Redis快取會話比其他儲存(如Memcached)的優勢在於:Redis提供持久化。當維護一個不是嚴格要求一致性的快取時,如果使用者的購物車資訊全部丟失,大部分人都會不高興的,現在,他們還會這樣嗎?
幸運的是,隨著 Redis 這些年的改進,很容易找到怎麼恰當的使用Redis來快取會話的文件。甚至廣為人知的商業平臺Magento也提供Redis的外掛。
(2)全頁快取(FPC)
除基本的會話token之外,Redis還提供很簡便的FPC平臺。回到一致性問題,即使重啟了Redis例項,因為有磁碟的持久化,使用者也不會看到頁面載入速度的下降,這是一個極大改進,類似PHP本地FPC。
再次以Magento為例,Magento提供一個外掛來使用Redis作為全頁快取後端。
此外,對WordPress的使用者來說,Pantheon有一個非常好的外掛 wp-redis,這個外掛能幫助你以最快速度載入你曾瀏覽過的頁面。
(3)佇列
Reids在記憶體儲存引擎領域的一大優點是提供 list 和 set 操作,這使得Redis能作為一個很好的訊息佇列平臺來使用。Redis作為佇列使用的操作,就類似於本地程式語言(如Python)對 list 的 push/pop 操作。
如果你快速地在Google中搜索“Redis queues”,你馬上就能找到大量的開源專案,這些專案的目的就是利用Redis建立非常好的後端工具,以滿足各種佇列需求。例如,Celery有一個後臺就是使用Redis作為broker,你可以從這裡去檢視。
(4)排行榜/計數器
Redis在記憶體中對數字進行遞增或遞減的操作實現的非常好。集合(Set)和有序集合(Sorted Set)也使得我們在執行這些操作的時候變的非常簡單,Redis只是正好提供了這兩種資料結構。所以,我們要從排序集合中獲取到排名最靠前的10個使用者–我們稱之為“user_scores”,我們只需要像下面一樣執行即可:
當然,這是假定你是根據你使用者的分數做遞增的排序。如果你想返回使用者及使用者的分數,你需要這樣執行:
ZRANGE user_scores 0 10 WITHSCORES
Agora Games就是一個很好的例子,用Ruby實現的,它的排行榜就是使用Redis來儲存資料的,你可以在這裡看到。
(5)釋出/訂閱
最後(但肯定不是最不重要的)是Redis的釋出/訂閱功能。釋出/訂閱的使用場景確實非常多。我已看見人們在社交網路連線中使用,還可作為基於釋出/訂閱的指令碼觸發器,甚至用Redis的釋出/訂閱功能來建立聊天系統!(不,這是真的,你可以去核實)。