string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。前端
string類型是Redis最基本的數據類型,一個鍵最大能存儲512MB。web
hash(map) 是一個鍵值對集合,特別適合用於存儲對象。每一個 hash 能夠存儲 2的32 - 1次方 鍵值對(40多億)。redis
list 列表是簡單的字符串列表,按照插入順序進行排序,能夠添加一個元素導列表的頭部(左邊)或者尾部(右邊)。算法
set 集合是string類型的無需集合,經過哈希表實現,添加,刪除,查找的複雜度都是O(1)。若插入相同元素時,第二次的插入將被忽略。數據庫
zset 有序集合,也是string類型元素的集合,且不容許重複的成員。vim
MemcacheDB是一個分佈式、key-value形式的持久存儲系統。它不是一個緩存組件,而是一個基於對象存取的、可靠的、快速的持久存儲引擎後端
Redis的主要缺點是數據庫容量受到物理內存的限制,不能用做海量數據的高性能讀寫,所以Redis適合的場景主要侷限在較小數據量的高性能操做和運算上。數組
用redis實現分佈式鎖緩存
緩存算法: 安全
回收策略:
volatile-lru:從已設置過時時間的數據集中挑選最近最少使用的數據進行淘汰,Redis將回收那些超時的(僅僅是超時的)鍵值對,即:它只淘汰那些超時的鍵值對。
allkeys-lru:從數據集中挑選最近最少使用的數據進行淘汰,淘汰最近最少使用的key-value,Redis將對全部(不只僅是超時的)的鍵值對採用最近最少使用的淘汰策略。
volatile-lfu:淘汰最近最不經常使用的key-value,Redis將淘汰在必定時期內被訪問次數最少的超時鍵值對。
allkeys-lfu:淘汰最近最不經常使用的key-value,Redis將對全部的鍵值對採用最近最不經常使用的淘汰策略。
volatile-random:從已設置過時時間的數據集中任意選擇數據進行淘汰。採用隨機淘汰策略刪除超時的鍵值對。
allkeys-random:從數據集中任意選擇數據進行淘汰。採用隨機淘汰策略刪除全部的鍵值對,這個策略不經常使用。
volatile-ttl:從已設置過時時間的數據集中挑選將要過時的數據進行淘汰。採用刪除存活時間最短的鍵值對策略。
noeviction:禁止驅逐數據,不淘汰任何鍵值對。當內存達到限制的最大內存而且客戶端還在繼續執行會佔用內存的命令時,會返回錯誤。當內存滿時,若是進行讀操做,例如get命令它將正常工做,而作寫操做它將返回錯誤。即:當Redis採用這個策略內存達到最大的時候,它就只能讀不能寫了。
Redis默認採用noeviction策略。
通常的經驗規則:
緩存雪崩:多是由於數據未加載到緩存中,或者在設置緩存採用了相同的過時時間,致使緩存在某一時刻同時大面積失效,從而致使全部請求都轉發到數據庫去查詢,致使數據庫CPU和內存負載太高,甚至宕機。
解決思路:
緩存穿透:是指查詢一個必定不存在的數據,因爲緩存是請求數據不命中時被動寫入的,而且出於容錯考慮,若是從存儲層查不到數據則不寫入緩存,這將致使這個不存在的數據每次請求都要到存儲層去查詢,在流量大時數據庫可能就掛掉了,通俗說就是惡意用戶模擬請求不少緩存中不存在的數據,因爲緩存中都沒有,致使這些請求短期內直接落在了數據庫上,致使數據庫異常。從系統層面來看像是穿透了緩存層直接達到db。
解決思路:
空值緩存:一種比較簡單的解決辦法,在第一次查詢完不存在的數據後,將該key與對應的空值也放入緩存中,只不過設定爲較短的失效時間,最長不超過五分鐘。這樣則能夠應對短期的大量的該key攻擊,設置爲較短的失效時間是由於該值可能業務無關,存在乎義不大,且該次的查詢也未必是攻擊者發起,無太久存儲的必要,故能夠早點失效。
布隆過濾器(bloom filter):相似於哈希表的一種算法,將全部可能存在的數據哈希到一個足夠大的bitmap中,在進行數據庫查詢以前會使用這個bitmap進行過濾,若是一個必定不存在的數據會被這個bitmap攔截掉,從而避免了對底層存儲系統的查詢壓力。
緩存擊穿:對於一些設置了過時時間的key,若是這些key在某些時間點被超高併發地訪問,是一種很是「熱點」的數據。這個時候可能會發生緩存被「擊穿」的問題,和緩存雪崩的區別在於:緩存擊穿是針對某一/幾個key緩存,緩存雪崩則是不少key。當緩存在某個時間點過時的時候,剛好在這個時間點對這個Key有大量的併發請求過來,這些請求發現緩存過時通常都會從後端DB加載數據並回設到緩存,這個時候大併發的請求可能會瞬間把後端DB壓垮。
好比:微博有一個熱門話題的功能,用戶對於熱門話題的搜索量每每在一些時刻會大大的高於其餘話題,這種咱們成爲系統的「熱點「,因爲系統中對這些熱點的數據緩存也存在失效時間,在熱點的緩存到達失效時間時,此時可能依然會有大量的請求到達系統,沒有了緩存層的保護,這些請求一樣的會到達db從而可能引發故障。擊穿與雪崩的區別即在於擊穿是對於特定的熱點數據來講,而雪崩是所有數據。
解決思路:
緩存併發:若是網站併發訪問高,一個緩存若是失效,可能出現多個進程同時查詢DB,同時設置緩存的狀況,若是併發確實很大,這也可能形成DB壓力過大,還有緩存頻繁更新的問題。
解決思路:對緩存查詢加鎖,若是KEY不存在,就加鎖,而後查DB入緩存,而後解鎖;其餘進程若是發現有鎖就等待,而後等解鎖後返回數據或者進入DB查詢。
緩存預熱:目的就是在系統上線前,將數據加載到緩存中。
解決思路:數據量不大的話,在系統啓動的時候直接加載。或者本身寫個簡單的緩存預熱程序。
Redis 事務容許一組命令在單一步驟中執行。事務有兩個特色:
MULTI:標記一個事務塊的開始。
EXEC:執行全部事務塊內的命令。
DISCARD:取消事務,放棄執行事務塊內的全部命令。
WATCH key[key ...]:監視一個或多個key,若事務在執行這個key以前被其餘命令所改動,那麼事務將被打斷。
UNWATCH:取消 WATCH 命令對全部 key 的監視。
舉個栗子:
redis 127.0.0.1:6379> MULTI OK redis 127.0.0.1:6379> SET book-name "Mastering C++ in 21 days" QUEUED redis 127.0.0.1:6379> GET book-name QUEUED redis 127.0.0.1:6379> SADD tag "C++" "Programming" "Mastering Series" QUEUED redis 127.0.0.1:6379> SMEMBERS tag QUEUED redis 127.0.0.1:6379> EXEC 1) OK 2) "Mastering C++ in 21 days" 3) (integer) 3 4) 1) "Mastering Series" 2) "C++" 3) "Programming"
第一種方式(修改配置文件) Sudo vim /etc/redis/redis.conf 命令模式搜索requirepass,把註釋掉的那行打開 # requirepass footbared requirepass 123456 第二種方式:直接在redis中設置,只對當前啓動有效 設置密碼:config set requirepass 123456 取消密碼:config set requirepass 「」
RDB (快照Snapshot)工做原理: 將databases中的key-value的二進制形式存儲在了rdb文件中。先將數據存在內存,而後當數據累計達到某些設定的閥值的時候,就會觸發一次DUMP操做,將變化的數據一次性寫入數據文件(RDB文件)。
AOF 工做原理: 是將數據也是先存在內存,可是在存儲的時候會使用調用fsync來完成對本次寫操做的日誌記錄,這個日誌揭露文件實際上是一個基於Redis網絡交互協議的文本文件。AOF調用fsync也不是說所有都是無阻塞的,在某些系統上可能出現fsync阻塞進程的狀況,對於這種狀況能夠經過配置修改,但默認狀況不要修改。AOF最關鍵的配置就是關於調用fsync追加日誌文件的平率,有兩種預設頻率,always每次記錄進來都添加,everysecond 每秒添加一次。兩個配置各有所長後面分析。因爲是採用日誌追加的方式來持久話數據,因此引出了第二個日誌的概念:rewrite. 後面介紹它的由來。
性能:
RDB方式的性能明顯高於AOF方式,RDB採用壓縮的二進制方式存儲數據,數據文件比較小,加載快速。存儲的時候是按照配置項中的save策略來存儲,每次都是聚合不少數據批量存儲,寫入的效率很好,而AOF則通常都是工做在實時存儲或者準實時模式下。相對來講存儲的頻率高,效率卻偏低。
數據安全:
AOF數據安全性高於RDB存儲,Snapshot存儲是基於累計批量的思想,也就是在容許的狀況下,累計的數據越多那麼寫入效率也就越高,但數據的累計是靠時間的積累完成的,那麼若是在長時間數據不寫入RDB,但Redis又遇到了崩潰,那麼沒有寫入的數據就沒法恢復了,可是AOF方式恰恰相反,根據AOF配置的存儲頻率的策略能夠作到最少的數據丟失和較高的數據恢復能力。
1).Master寫內存快照,save命令調度rdbSave函數,會阻塞主線程的工做,當快照比較大時對性能影響是很是大的,會間斷性暫停服務,因此Master最好不要保存寫內存快照。
2).Master AOF持久化,若是不重寫AOF文件,這個持久化方式對性能的影響是最小的,可是AOF文件會不斷增大,AOF文件過大會影響Master重啓的恢復速度。Master最好不要作任何持久化工做,包括內存快照和AOF日誌文件,特別是不要啓用內存快照作持久化,若是數據比較關鍵,可以使用某個Slave開啓AOF備份數據,策略爲每秒同步一次。
3).Master調用 BGREWRITEAOF 重寫AOF文件,AOF在重寫的時候會佔大量的CPU和內存資源,致使服務load太高,出現短暫服務暫停現象。
4).Redis主從複製的性能問題,爲了主從複製的速度和鏈接的穩定性,Slave和Master最好在同一個局域網內
(1)會話緩存(Session Cache)最常使用,優點在於:Redis提供持久化。好比用戶的購物車數據。
(2)全頁緩存(FPC)
(3)隊列 ,Reids提供的 list 和 set 操做,這使得Redis能做爲一個很好的消息隊列平臺來使用。Redis做爲隊列使用的操做,相似於Python當中對 list 的 push/pop 操做。
(4)排行榜/計數器
缺點:
Redis 的主從複製採用全量複製,複製過程當中主機會 fork出一個子進程對內存作一份快照,並將子進程的內存快照保存爲文件發送給從機,這一過程須要確保主機有足夠多的空餘內存。若快照文件較大,對集羣的服務能力會產生較大的影響,並且複製過程是在從機新加入集羣或者從機和主機網絡斷開重連時都會進行,也就是網絡波動都會形成主機和從機間的一次全量的數據複製,這對實際的系統運營形成了不小的麻煩
Redis宕機?
主從模式下的宕機區分:
注:以上過程很容易配置錯誤,可使用簡單的方法:redis的哨兵(sentinel)的功能。
哨兵(sentinel)的原理:Redis提供了sentinel(哨兵)機制經過哨兵模式啓動redis後,自動監控master/slave的運行狀態,基本原理是:心跳機制+投票裁決。
心跳機制:每一個sentinel會向其它sentinal、master、slave定時發送消息,以確認對方是否「活」着,若是發現對方在指定時間(可配置)內未迴應,則暫時認爲對方已掛(所謂的「主觀認爲宕機」 Subjective Down,簡稱SDOWN)。
投票裁決:若"哨兵羣"中的多數sentinel,都報告某一master沒響應,系統才認爲該master"完全死亡"(即:客觀上的真正down機,Objective Down,簡稱ODOWN),經過必定的vote算法,從剩下的slave節點中,選一臺提高爲master,而後自動修改相關配置。
哨兵的配置:複製redis中sentinel.conf,根據狀況進行配置
在默認狀況下, Redis 將數據庫快照保存在名字爲 dump.rdb
的二進制文件中。能夠對 Redis 進行設置, 讓它在「 N
秒內數據集至少有 M
個改動」這一條件被知足時, 自動保存一次數據集。
執行保存操做:調用 SAVE 或者 BGSAVE ,手動讓 Redis 進行數據集保存操做。一個栗子,save 60 1000 會讓 Redis 在知足「 60
秒內有至少有 1000
個鍵被改動」這一條件時, 自動保存一次數據集。這種持久化方式被稱爲快照(snapshot)。
SAVE
:阻塞redis的服務器進程,直到RDB
文件
被建立完畢。BGSAVE
:派生(fork)一個子進程來建立新的RDB文件
,記錄接收到BGSAVE
當時的數據庫狀態,父進程繼續處理接收到的命令,子進程完成文件的建立以後,會發送信號給父進程,而與此同時,父進程處理命令的同時,經過輪詢來接收子進程的信號。
當Redis須要保存 dump.rdb 文件時,執行如下操做:
fork()
,同時擁有父進程和子進程。這種工做方式使得 Redis 能夠從寫時複製(copy-on-write)機制中獲益。
fork
出一個子進程,而後這個子進程就會處理接下來的全部保存工做,父進程無須執行任何磁盤 I/O 操做。
fork()
建立出一個子進程,並由子進程來進行實際的持久化工做。 在數據集比較龐大時, fork()
可能會很是耗時,形成服務器在某某毫秒內中止處理客戶端; 若是數據集很是巨大,而且 CPU 時間很是緊張的話,那麼這種中止時間甚至可能會長達整整一秒。 雖然 AOF 重寫也須要進行 fork()
,但不管 AOF 重寫的執行間隔有多長,數據的耐久性都不會有任何損失。建立子線程和生成rdb文件會佔用大量 的系統資源和處理時間
# dbfilename:配置RDB文件的名稱,默認叫 dump.rdb dbfilename dump.rdb # dir:配置的RDB文件存儲在本地的路徑,若是是在 /redis/redis-3.0.6/src 下啓動的redis-cli,則數據會存儲在當前src目錄下 dir ./ # snapshot觸發時機的配置:save <seconds> <changes> , 可經過 save 「」 關閉snapshot功能 # changes:對於此值設置需謹慎,要評估系統的變動操做密集程度 save 900 1 # 更改了1個key的時候,間隔900秒後,至少有一個變動操做,進行持久化存儲snapshot save 300 10 # 更改了10個key的時候,間隔300s進行持久化存儲 save 60 10000 # 更改10000個key的時候,間隔360s進行存儲。 # 當生成 RDB 文件出錯沒法繼續時,是不然色客戶端的「變動操做」,是否繼續處理 Redis 寫命令,默認爲不處理。「錯誤」可能由於磁盤已滿/磁盤故障/OS級別異常等 stop-writes-on-bgsave-error yes # 是否對rdb文件進行壓縮,默認爲「yes」,壓縮每每意味着「額外的cpu消耗」,同時也意味這較小的文件尺寸以及較短的 rdbcompression yes
# 是否對 RDB 文件進行校驗和校驗
rdbchecksum
Redis shutdown模擬服務器宕機
mv dump.rdb dump.rdb.bak
中止redis服務器service redis stop
啓動redis-server /etc/redis/redis.conf redis-cli 查詢keys * cp dump.rdb.bak dump.rdb ps aux | grep redis Kill -9 xxxx 中止redis服務器service redis stop 重啓redis-server 重啓redis-cli 查詢keys *
快照功能並非很是耐久(durable): 若是 Redis 由於某些緣由而形成故障停機, 那麼服務器將丟失最近寫入、且仍未保存到快照中的那些數據。若是對於數據追求徹底耐久能力(full durability)的要求,快照功能就不太適用。從 1.1 版本開始, Redis 增長了一種徹底耐久的持久化方式: AOF 持久化。
經過修改配置文件來打開 AOF 功能:appendonly yes 。每當 Redis 執行一個改變數據集的命令時(好比 SET key value [EX seconds] [PX milliseconds] [NX|XX]), 這個命令就會被追加到 AOF 文件的末尾(對數據的每一條修改命令追加到aof文件)。這樣的話,當 Redis 從新啓時, 程序就能夠經過從新執行 AOF 文件中的命令來達到重建數據集的目的。RDB持久化至關於備份數據庫狀態,而AOF持久化是備份數據庫接收到的命令。
AOF文件生成的過程:命令追加、文件寫入、文件同步
由於 AOF 的運做方式是不斷地將命令追加到文件的末尾,按照記錄日誌的方式去工做的,因此隨着寫入命令的不斷增長,成千上萬的數據插入必然致使日誌文件的擴大,AOF 文件的體積也會變得愈來愈大。舉個栗子:若是你對一個計數器調用了 100 次 INCR key , 那麼僅僅是爲了保存這個計數器的當前值, AOF 文件就須要使用 100 條記錄(entry)。然而實際上,只使用一條 SET key value [EX seconds] [PX milliseconds] [NX|XX] 命令已經足以保存計數器的當前值了, 其他 99 條記錄實際上都是多餘的。
爲了處理這種狀況, Redis 支持另外一種特性:能夠在不打斷服務客戶端的狀況下,對 AOF 文件進行重建(rebuild):執行 BGREWRITEAOF 命令:將日誌文件中的全部數據都從新寫到另一個新的日誌文件中,不一樣的是,在舊文件當中對於key的屢次操做,只會保留最終值的那次操做命令記錄到日誌文件中。Redis 2.2 須要本身手動執行 BGREWRITEAOF 命令; Redis 2.4 則能夠自動觸發 AOF 重寫。
兩個配置須要注意:
auto-aof-rewrite-percentage 100 (當前寫入日誌文件的大小佔到初始日誌文件大小的某個百分比時觸發Rewrite)
auto-aof-rewrite-min-size 64mb (本次Rewrite最小的寫入數據量)
兩個條件須要同時知足。
AOF 重寫和 RDB 建立快照同樣,都巧妙地利用了寫時複製機制。
如下是 AOF 重寫的執行步驟:
fork()
,如今同時擁有父進程和子進程。
fsync
)一次寫命令,就算髮生故障停機,最多丟失1s的數據。( fsync
會在後臺線程執行,因此主線程能夠繼續努力地處理命令請求)。seek)
, 即便日誌由於某些緣由而包含了未寫入完整的命令(好比寫入時磁盤已滿,寫入中途停機等), redis-check-aof
工具也能夠輕易地修復這種問題。
fsync
策略,AOF 的速度可能會慢於 RDB 。 在通常狀況下, 每秒 fsync
的性能依然很是高, 而關閉 fsync
可讓 AOF 的速度和 RDB 同樣快, 即便在高負荷之下也是如此。 不過在處理巨大的寫入載入時,RDB 能夠提供更有保證的最大延遲時間(latency)。
# 是否打開 AOF 持久化功能,默認爲「no」,可經過「yes」來開啓AOF功能 appendonly yes # 只有在「yes」下,aof重寫/文件同步等特性纔會生效 # 指定AOF文件的名稱 appendfilename appendonly.aof # 同步頻率:指定AOF操做時,文件的同步策略,有三個合法值:always everysec no,默認爲everysec 會影響到服務器間隔多久完成一次命令的記錄。 # always:每一條aof記錄都當即同步到文件,這是最安全的方式,但大量磁盤操做和阻塞延遲形成IO開支大,速度最慢不推薦。 # everysec:將緩存區的內容每隔一秒寫入AOF文件中,性能和安全都比較中庸,是Redis官方推薦的方式。 # no :寫入AOF文件中的操做由操做系統決定,Redis不直接調用。通常而言爲了提升效率,操做系統會等待緩存區被填滿,纔會開始同步數據到磁盤。在物理服務器故障時,數據丟失量會因OS配置有關 appendfsync everysec # 在aof-rewrite期間,appendfsync是否暫緩文件同步,"no"表示「不暫緩」,「yes」表示「暫緩」,默認爲「no」 no-appendfsync-on-rewrite no # aof文件rewrite觸發的最小文件尺寸(mb,gb),只有大於此aof文件大於此尺寸是纔會觸發rewrite,默認「64mb」,建議「512mb」 auto-aof-rewrite-min-size 64mb # 相對於「上一次」rewrite,本次rewrite觸發時aof文件應該增加的百分比。 # 每一次rewrite以後,redis都會記錄下此時「新aof」文件的大小(例如A),那麼當aof文件增加到A*(1 + p)以後,觸發下一次rewrite,每一次aof記錄的添加都會檢測當前aof文件的尺寸。
auto-aof-rewrite-percentage 100
# 當前AOF文件啓動新的日誌重寫過程的最小值,避免剛剛啓動Reids時因爲文件尺寸較小致使頻繁的重寫。 auto-aof-rewrite-min-size 64mb
- AOF更加安全,能夠將數據更加及時的同步到文件中,可是AOF須要較多的磁盤IO開支,AOF文件尺寸較大,文件內容恢復數度相對較慢
- RDB(snapshot),安全性較差,它是「正常時期」數據備份以及 master-slave 數據同步的最佳手段,文件尺寸較小,恢復數度較快。
(1)不要僅僅使用RDB,由於那樣會致使你丟失不少數據
(2)也不要僅僅使用AOF,由於那樣有兩個問題,第一,經過AOF作冷備的操做,沒有RDB作冷備來的恢復速度更快; 第二,RDB每次簡單粗暴生成數據快照更加健壯,能夠避免AOF這種複雜的備份和恢復機制的bug 。
(3)綜合使用AOF和RDB兩種持久化機制,用AOF來保證數據不丟失,做爲數據恢復的第一選擇; 用RDB來作不一樣程度的冷備,在AOF文件都丟失或損壞不可用的時候,還可使用RDB來進行快速的數據恢復。
在 Redis 2.2 或以上版本,能夠在不重啓的狀況下,從 RDB 切換到 AOF :
dump.rdb
文件建立一個備份。redis-cli> CONFIG SET appendonly yes redis-cli> CONFIG SET save ""
步驟 3 執行的第一條命令開啓了 AOF 功能: Redis 會阻塞直到初始 AOF 文件建立完成爲止, 以後 Redis 會繼續處理命令請求, 並開始將寫入命令追加到 AOF 文件末尾。
步驟 3 執行的第二條命令用於關閉 RDB 功能。 這一步是可選的, 若是你願意的話, 也能夠同時使用 RDB 和 AOF 這兩種持久化功能。
別忘了在 redis.conf
中打開 AOF 功能! 不然服務器重啓以後, 以前經過 CONFIG SET
設置的配置就會被遺忘, 程序會按原來的配置來啓動服務器。
AOF
更安全,可將數據及時同步到文件中,但須要較多的磁盤IO,AOF文件
尺寸較大,文件內容恢復相對較慢, 也更完整。RDB
持久化,安全性較差,它是正常時期數據備份及 master-slave
數據同步的最佳手段,文件尺寸較小,恢復數度較快。
官方建議:
find
命令來刪除過時的快照: 好比能夠保留最近 48 小時內的每小時快照, 還能夠保留最近一兩個月的每日快照。
從數據集中任意選擇數據進行淘汰