Redis是一個開源(BSD許可),內存數據結構存儲,用做數據庫,緩存和消息代理。它支持數據結構,如 字符串,散列,列表,集合,帶有範圍查詢的排序集,位圖,超級日誌和帶有半徑查詢的地理空間索引。Redis具備內置複製,Lua腳本,LRU驅逐,事務和不一樣級別的磁盤持久性,並經過Redis Sentinel提供高可用性和Redis Cluster自動分區。linux
你能夠 對這些類型運行原子操做,例如附加到字符串 ; 遞增哈希值 ; 將元素推送到列表中 ; 計算集合交集, 並集和差別 ; 或者在排序集中得到排名最高的成員。git
爲了實現其出色的性能,Redis使用 內存數據集。根據您的使用狀況,您能夠經過 每隔一段時間將數據集轉儲到磁盤或經過將每一個命令附加到日誌來保留它。若是您只須要功能豐富的網絡內存緩存,則能夠選擇禁用持久性。github
Redis還支持簡單到設置的主從異步複製,具備很是快速的非阻塞第一次同步,自動從新鏈接以及在網絡分割上的部分從新同步。redis
官方沒有windows版本的支持,可是微軟維護這一個windows 64位的redis版本,代碼託管在github上,可使用該地址進行下載,https://github.com/MicrosoftArchive/redis/releases數據庫
按照須要進行下載文件,解壓後redis對應的服務程序爲redis-server.exe,配置文件爲 redis.windows.conf,啓動完成後,使用redis-cli.ext -h127.0.0.1 -p6379 來對redis數據庫進行操做。windows
到官網下載redis的安裝包 Redis官網 下載對應的linux的操做系統的安裝包(分爲穩定,不穩定和測試三個版本)。數組
具體操做以下:緩存
# 下載源碼包
wget http://download.redis.io/releases/redis-4.0.11.tar.gz
# 解壓
tar xzf redis-4.0.11.tar.gz
# 切換工做目錄
cd redis-4.0.11
# make 編譯
make
# 編譯好的二進制文件在src目錄下。
# 能夠自行拷貝進行使用,也可使用make install命令安裝。
# 若是執行make install 默認文件被放到/usr/local/bin/下,也可使用 PREFIX=/to/path 參數來指定存放位置
make install PREFIX=/usr/local/
redis的配置文件位於redis目錄下,文件名爲redis.conf,配置文件的修改能夠經過修改配置文件重啓redis來使配置文件生效,或者使用CONFIG SET|GET 命令來進行動態配置。安全
Redis是個支持持久化的內存數據庫,redis須要常常將內存中的數據同步到磁盤來保證持久化。服務器
RDB 方式爲默認的快照方式。
配置
# 該配置通常爲默認配置
save 900 1 #在900秒(15分鐘)以後,若是至少有1個key發生變化,則dump內存快照。
save 300 10 #在300秒(5分鐘)以後,若是至少有10個key發生變化,則dump內存快照。
save 60 10000 #在60秒(1分鐘)以後,若是至少有10000個key發生變化,則dump內存快照。
工做原理
RDB方式持久化命令以下:
命令 | 說明 |
---|---|
SAVE | 運行後會阻塞Redis服務器進程,直到RDB文件建立完畢,在阻塞過程過程當中服務器不處理任何來自外界的請求不管讀仍是寫(阻塞全部請求)。 |
BGSAVE | 會產生一個子進程,由此子進程來處理建立RDB文件任務,而服務器的父進程繼續響應外部請求。 |
BGREWRITEAOF | 用於異步執行一個 AOF(AppendOnly File) 文件重寫操做。重寫會建立一個當前 AOF 文件的體積優化版本。 即便 Bgrewriteaof 執行失敗,也不會有任何數據丟失,由於舊的 AOF 文件在 Bgrewriteaof 成功以前不會被修改。 (注意: 從 Redis 2.4 開始, AOF 重寫由 Redis 自行觸發, BGREWRITEAOF 僅僅用於手動觸發重寫操做。 ) |
LASTSAVE | 返回最近一次 Redis 成功將數據保存到磁盤上的時間,以 UNIX 時間戳格式表示。 |
BGSAVE
在執行過程當中不會阻塞請求,可是不是任何請求均可以執行,在服務器執行BGSAVE
期間,對於執行SAVE
、BGSAVE
和BGREWRITEAOF
這三個命令會有全部不一樣。
在BGSAVE執行期間 | |
---|---|
執行SAVE命令 | 會被服務器拒絕,服務器禁止SAVE命令和BGSAVE同時執行,由於不可能讓兩個命令去調用同一函數而後去操做同一個RDB文件。 |
執行BGSAVE命令 | 會被服務器拒絕,由於已經有一個在進行了,不必再容許一個 。 |
執行BGREWRITEAOF命令 | 會被延遲執行,BGSAVE子進程完成後,纔會執行BGREWRITEAOF命令 。 |
在BGSAVE執行期間 | |
---|---|
執行BGSAVE命令 | 會被拒絕,這兩個命令沒有衝突的地方,只是同時執行會產生大量磁盤寫操做,會影響性能,因此這是一個規則上的拒絕,不是一個技術上的拒絕 |
BGSAVE 工做原理
Redis使用fork函數複製一份當前進程(父進程)的副本(子進程)。
父進程繼續接收並處理客戶端發來的命令,而子進程開始將內存中的數據寫入硬盤中的臨時文件。
當子進程寫入完全部數據後會用該臨時文件替換舊的RDB文件,至此一次快照操做完成。
查看rds文件配置
經過使用CONFIG GET
命令能夠查看持久化數據保存的位置。
> config get dir
1) "dir"
2) "E:\\redis\\redis3.0"
> config get dbfilename
1) "dbfilename"
2) "dump.rdb"
RDB方式優勢
RDB是個很是緊湊的文件,保存了redis在某個時間點上的數據集,使得咱們能夠經過定時備份RDB文件來實現Redis數據庫備份和災難恢復,也能夠將其傳送到其餘的數據中心用於保存。
RDB能夠最大化redis的性能,執行RDB持久化時只須要fork一個子進程,並由子進程進行持久化工做,父進程不須要處理任何磁盤I/O操做。
RDB在恢復大數據集時比AOF要快,啓動效率要高許多。
RDB文件是通過壓縮(能夠配置rdbcompression參數以禁用壓縮節省CPU佔用)的二進制格式,因此佔用的空間會小於內存中的數據大小,更加利於傳輸。
RDB方式缺點
每次快照持久化都是將內存數據完整寫入到磁盤一次,並非增量的只同步增數據。若是數據量大的話,並且寫操做比較多,必然會引發大量的磁盤io操做,可能會嚴重影響性能。
快照方式是在必定間隔時間作一次的,因此若是redis意外down掉的話,就會丟失最後一次快照後的全部修改,有一些數據丟失的風險。
client的save
或者bgsave
命令通知redis作一次快照持久化不推薦。
緣由:save操做是在主線程中保存快照的,因爲redis是用一個主線程來處理全部 client的請求,這種方式會阻塞全部client請求。因此不推薦使用。
RDB 方式注意事項
Redis模式會運行16個數據庫(編號爲0---15),在執行保存的過程當中不管是SAVE
觸發仍是BGSAVE
觸發,都是會把全部非空
數據庫進行保存的。
默認AOF 方式是關閉的。
RDB方式若是redis 服務意外中止運行後,會將最新寫入的數據丟失,在某些嚴格要求的項目中不是一個可行的方案。此時AOF能夠解決這個問題,AOF 方式是在redis 1.1 版本中可用。
AOF 方式是在寫入內存數據的同時將操做命令保存到日誌文件中。 當你從新啓動redis 服務時,它將從新根據AOF以重建狀態。這種方式相似於傳統數據庫服務器的事務日誌 。
若是遇到在追加日誌的時候遇到意外,可使用redis-check-aof工具進行日誌修復。
由於採用了追加方式,因此AOF會愈來愈大(這一點又和傳統數據庫不同,傳統數據庫事務日誌文件都比較小),所以redis有另一個機制就是AOF文件重寫,當AOF文件達到一個設定的閾值後,會自動啓動AOF文件壓縮,只保留能夠恢復數據的最小指令集。
配置
# 在配置文件中打開AOF
appendonly yes
# aof方式文件名
appendfilename "appendonly.aof"
# 每次執行寫入都會執行同步,最安全也最慢,執行write()和fsync()系統調用。
# appendfsync always
# 每秒執行一次同步,默認,執行write()和fsync()系統調用。
appendfsync everysec
# 不主動進行同步操做,而是徹底交由操做系統來作(即每30秒一次),最快也最不安全,只執行write()。
# appendfsync no
AOF 持久化原理
當AOF 持久化開啓後,對數據庫進行一次更新操做後,更新命令會被追加到aof_buf
緩衝區的末尾,而後緩衝區寫入到AOF 文件。
AOF文件中記錄的內容就是對數據更新操做的指令。這個文件自己就是以文原本記錄的。
對redis
進行了以下操做:
> set 40kuai 40
OK
> get 40kuai 40
(error) ERR wrong number of arguments for 'get' command
> get 40kuai
"40"
> del 40kuai
(integer) 1
下面咱們來查看下appendonly.aof
文件的內容:
*2
$6
SELECT
$1
0
*3
$3
set
$6
40kuai
$2
40
*2
$3
del
$6
40kuai
分別解釋下各個字段的含義:
字符 | 含義 |
---|---|
*2 | 表示2個參數 |
$6 | 第一個參數長度爲6 |
SELECT | 第一個參數 |
$1 | 第二個參數的長度爲1 |
0 | 第二個參數 |
注意:這裏能夠看出 appendonly.aof
文件中記錄的都是對數據進行操做的命令,對於用戶使用GET
進行查詢的操做並無記錄。
AOF 重寫實現原理
由於AOF持久化是經過記錄命令的方式來保存數據庫狀態的,隨着時間的推移AOF文件確定會逐漸增大,若是不加以控制會對AOF持久化性能以及數據恢復形成影響。
以一個列表爲例來講明重寫的意義:
> rpush list a b
(integer) 2
> rpush list c
(integer) 3
> lrange list 0 1
1) "a"
2) "b"
根據AOF的原理,上面的操做須要將2條命令追加到appendonly.aof
文件當中,其實咱們看到list
最後的狀態是值a,b,c
。當使用appendonly.aof
文件進行恢復時,要實現最後的狀態,須要追加2 條命令,因此在大量內存讀寫的業務裏AOF文件增加的很快。爲了解決這個問題,Redis提供了AOF重寫功能。
AOF重寫就是建立一個新的AOF文件來替換現有的AOF文件,實際上AOF重寫並不對現有的舊AOF文件進行操做。當進行重寫的時候直接從數據庫裏去獲取list的最新狀態,而後在新的AOF文件中直接寫一條rpushlist B C D E F命令,從而避免寫5條的操做,這樣AOF文件的增加速度就會下降,同時容量也不會特別大。
AOF重寫程序aof_rewrite函數去完成建立新的AOF文件的任務,可是該函數並不會由Redis主進程去直接調用,而是使用子進程後臺去執行(BGREWRITEAOF,該命令其實就是執行aof_rewrite,只不過是由子進程去調用的),這時主進程就會不被阻塞,那麼就能夠在執行重寫的過程當中父進程能夠繼續對外提供響應。整個過程以下:
當重寫被觸發時父進程調用一個函數,該函數建立一個子進程用於執行BGREWRITEAOF
,該子進程建立一個臨時文件,而後父進程繼續對外提供讀寫服務。
子進程遍歷數據庫,將每一個鍵值的最新狀態輸出到臨時文件中,在BGREWRITEAOF過程當中,父進程把全部對數據庫的更新命令同時寫入到AOF緩衝區和AOF重寫緩衝區(aof_rewrite_buf_blocks),AOF緩衝區(aof_buf)會繼續同步到現有AOF文件中(通常狀況下在AOF重寫期間不建議把AOF緩衝區的內容同步到現有的AOF文件中,這會下降性能,默認爲NO)。
AOF重寫完成後子進程通知父進程,父進程調用信號處理函數。
信號處理函數會阻塞父進程對外提供讀寫操做(時間很短,不阻塞就又會出現數據不一致的狀況),而後將AOF重寫緩衝區的內容寫入到新的AOF文件中,最後用新的AOF文件替換現有AOF文件(改名操做)。
# yes : 在日誌重寫時,不進行命令追加操做,而只是將其放在緩衝區裏,避免與命令的追加形成DISK IO上的衝突。
# no : 在日誌重寫時,命令追加操做照常進行。
no-appendfsync-on-rewrite no
# 當目前的AOF文件大小超過上一次重寫時的AOF文件大小的百分之多少時會再次進行重寫,若是以前沒有重寫過,則以啓動時的AOF文件大小爲依據
auto-aof-rewrite-percentage 100
# 容許重寫的最小AOF文件大小
auto-aof-rewrite-min-size 64mb
AOF 方式優勢
該機制能夠帶來更高的數據安全性,即數據持久性。
因爲該機制對日誌文件的寫入操做採用的是append模式,所以在寫入過程當中即便出現宕機現象,也不會破壞日誌文件中已經存在的內容。然而若是咱們本次操做只是寫入了一半數據就出現了系統崩潰問題,不用擔憂,在Redis下一次啓動以前,咱們能夠經過redis-check-aof工具來幫助咱們解決數據一致性的問題。
若是日誌過大,Redis能夠自動啓用rewrite機制。即Redis以append模式不斷的將修改數據寫入到老的磁盤文件中,同時Redis還會建立一個新的文件用於記錄此期間有哪些修改命令被執行。所以在進行rewrite切換時能夠更好的保證數據安全性。
AOF包含一個格式清晰、易於理解的日誌文件用於記錄全部的修改操做。事實上,也能夠經過該文件完成數據的重建。
AOF 方式缺點
對於相同數量的數據集而言,AOF文件一般要大於RDB文件,持久化文件會變的愈來愈大。
根據同步策略的不一樣,AOF在運行效率上每每會慢於RDB。
虛擬內存方式和diskstore方式這裏不作說明
redis 鍵
Redis的鍵是二進制安全的,這意味着您可使用任何二進制序列做爲鍵 。
Redis String類型是能夠與Redis密鑰關聯的最簡單的值類型。它是Memcached中惟一的數據類型。
使用SET和GET命令是咱們設置和檢索字符串值的方式。請注意,即便密鑰與非字符串值相關聯,SET也將替換已存在於密鑰中的任何現有值。
SET命令有有趣的選項,這是做爲附加參數。例如,若是密鑰已經存在,我可能會要求SET失敗,或者相反,若是密鑰已經存在,它只會成功:詳情
> set mykey newval nx
(nil)
> set mykey newval xx
OK
# EX seconds - 設置指定的過時時間,以秒爲單位。
# PX 毫秒 - 設置指定的過時時間,以毫秒爲單位。
# NX - 僅設置密鑰(若是密鑰尚不存在)。
# XX - 僅設置密鑰(若是密鑰已存在)。
字符串的操做還有一些其餘的命令,以下:
> set counter 100
OK
> incr counter
(integer) 101
> incr counter
(integer) 102
> incrby counter 50
(integer) 152
INCR
: 解析字符串值做爲整數,以一增長它,最後將得到的值做爲新的值。還有其餘相似的命令,如INCRBY, DECR和DECRBY。在內部,它始終是相同的命令,以稍微不一樣的方式運做。 (INCR是原子操做,即便是針對相同密鑰發佈INCR的多個客戶端也不會進入競爭狀態 )
GETSET
: 將鍵設置爲新值,並將舊值做爲結果返回 。
在單個命令中設置或檢索多個鍵的值的能力對於減小延遲也是有用的。所以,有MSET和MGET命令:
> mset a 10 b 20 c 30
OK
> mget a b c # 使用MGET時,Redis返回值數組。
1) "10"
2) "20"
3) "30"
EXISTS
:返回1或0以表示數據庫中是否存在給定鍵。
DEL
:刪除鍵和關聯值,不管值是什麼。
> set mykey hello
OK
> exists mykey
(integer) 1
> del mykey
(integer) 1
> exists mykey
(integer) 0
能夠看到DEL自己如何返回1或0,具體取決於密鑰是否被刪除(它是否存在)(沒有具備該名稱的密鑰)。
有許多與密鑰空間相關的命令,但上面兩個是與TYPE命令一塊兒必不可少的命令,它返回存儲在指定鍵中的值的類型:
> set mykey x
OK
> type mykey
string
> del mykey
(integer) 1
> type mykey
none
redis strings 其餘命令說明
命令 | 說明 |
---|---|
INCR key | 將 key 中儲存的數字值增一。 |
INCRBY key num | 將 key 所儲存的值加上給定的增量值(num)。 |
DECR key | 將 key 中儲存的數字值減一。 |
DECRBY key num | key 所儲存的值減去給定的減量值。 |
APPEND key value | 若是 key 已經存在而且是一個字符串, APPEND 命令將指定的 value 追加到該 key 原來值的末尾。 |
默認狀況下鍵是沒有生存時間的,永不過時,除非使用del來清除鍵。
設置到期時間
設置到期時間方法入下:
strings類型,SET命令是能夠直接經過EX,PX來指定過時時間。
全部類型均可以使用,EXPIRE、PEXPIRE、EXPIREAT、PEXPIREAT 這四個命令來進行生存時間的設置。
命令 | 說明 |
---|---|
EXPIRE KEY #s | 將KEY的生存時間設置爲#秒 |
PEXPIRE KEY #ms | 將KEY的生存時間設置爲#毫秒 |
EXPIREAT KEY timestamp | 將KEY的生存時間設置爲UNIX時間戳,單位爲秒 |
PEXPIREAT KEY timestamp | 將KEY的生存時間設置爲UNIX時間戳,單位爲毫秒 |
TIME | 一個包含兩個字符串的列表: 第一個字符串是當前時間(以 UNIX 時間戳格式表示),而第二個字符串是當前這一秒鐘已經逝去的微秒數。 |
上面這4個命令只是單位和表現形式上的不一樣,但實際上EXPIRE、PEXPIRE以及EXPIREAT命令的執行最後都會使用PEXPIREAT來實行。
查看key的到期時間
Key的到期時間可使用 TTL
和PTTL
來進行查看,分別返回秒和毫秒單位級別。
清除key的到期時間
可使用PERSIST
命令移除一個鍵的過時時間 。
> set key 100
OK
> EXPIRE key 100
(integer) 1
> get key
"100"
> ttl key
(integer) 92
> PERSIST key
(integer) 1
> ttl key
(integer) -1
到期時間返回值說明
返回值 | 說明 |
---|---|
-2 | 過時且已刪除 |
-1 | 沒有過時時間設置,即永不過時 |
>0 | 表示距離過時還有多少秒或者毫秒 |