簡介
Redis 是一個 Key-Value 存儲系統。和 Memcached 類似,它支持存儲的 value 類型相對更多,包括 string(字符串)、 list(鏈表)、 set(集合)和 zset(有序集合)。這些數據類型都支持 push/pop、add/remove 及取交集并集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎上, Redis 支持各種不同方式的排序。與 memcached 一樣,為了保證效率,數據都是緩存在內存中。區別的是 Redis 會周期性的把更新的數據寫入磁盤或者把修改操作寫入追加的記錄文件,并且在此基礎上實現了 master-slave(主從)同步。
原子性:一個操作的不可以再分,操作要么執行,要么不執行。
初識 Redis
Redis 是一個開源的使用 ANSI C 語言編寫、支持網絡、可基于內存亦可持久化的日志型、Key-Value數據庫,并提供多種語言的API。
數據類型
作為 Key-value 型數據庫, Redis 也提供了鍵(Key)和鍵值(Value)的映射關系。但是,除了常規的數值或字符串, Redis 的鍵值還可以是以下形式之一:
- Lists (列表)
- Sets (集合)
- Sorted sets (有序集合)
- Hashes (哈希表)
鍵值的數據類型決定了該鍵值支持的操作。 Redis 支持諸如列表、集合或有序集合的交集、并集、查集等高級原子操作;同時,如果鍵值的類型是普通數字,Redis 則提供自增等原子操作。
持久化
Redis 將數據存儲于內存中,或被配置為使用虛擬內存。通過兩種方式可以實現數據持久化:使用截圖的方式,將內存中的數據不斷寫入磁盤;或使用類似 MySQL 的日志方式,記錄每次更新的日志。前者性能較高,但是可能會引起一定程度的數據丟失;后者相反。
主從同步
Redis 支持將數據同步到多臺從庫上,這種特性對提高讀取性能非常有益。
性能
相比需要依賴磁盤記錄每個更新的數據庫,基于內存的特性無疑給 Redis 帶來了非常優秀的性能。讀寫操作之間有顯著的性能差異。
適用場合
毫無疑問, Redis 開創了一種新的數據存儲思路,使用 Redis,我們不用在面對功能單調的數據庫時,把精力放在如何把大象放進冰箱這樣的問題上,而是利用 Redis 靈活多變的數據結構和數據操作,為不同的大象構建不同的冰箱。
下面是 Redis 適用的一些場景:
-
取最新 N 個數據的操作
比如典型的取你網站的最新文章,通過下面方式,我們可以將最新的 5000 條評論的 ID 放在Redis 的 List 集合中,并將超出集合部分從數據庫獲取。
使用 LPUSH latest.comments<ID>命令,向 list 集合中插入數據
插入完成后再用 LTRIM latest.comments 0 5000 命令使其永遠只保存最近 5000 個 ID -
排行榜應用,取 TOP N 操作
需要使用到 sorted set ,將你要排序的值設置成 sorted set 的 score(僅限支持float型 ),將具體的數據設置成相應的 value,每次只需要執行一條 ZADD 命令即可。
-
需要精準設定過期時間的應用
比如你可以把上面說到的 sorted set 的 score 值設置成過期時間的時間戳,那么就可以簡單地通過過期時間排序,定時清除過期數據了,不僅是清除 Redis 中的過期數據,你完全可以把 Redis 里這個過期時間當成是對數據庫中數據的索引,用 Redis 來找出哪些數據需要過期刪除,然后再精準地從數據庫中刪除相應的記錄。
-
計數器應用
Redis 的命令都是原子性的,你可以輕松地利用 INCR, DECR 命令來構建計數器系統。
redis中incr、incrby、decr、decrby屬于string數據結構,它們是原子性遞增或遞減操作。
- incr遞增1并返回遞增后的結果;
- incrby根據指定值做遞增或遞減操作并返回遞增或遞減后的結果(incrby遞增或遞減取決于傳入值的正負);
- decr遞減1并返回遞減后的結果;
- decrby根據指定值做遞增或遞減操作并返回遞增或遞減后的結果(decrby遞增或遞減取決于傳入值的正負);
-
Uniq 操作,獲取某段時間所有數據排重值
這個使用 Redis 的 set 數據結構最合適了,只需要不斷地將數據往 set 中扔就行了, set 集合會自動排重。
-
實時系統,反垃圾系統
通過上面說到的 set 功能,你可以知道一個終端用戶是否進行了某個操作,可以找到其操作的集合并進行分析統計對比等。
-
Pub/Sub 構建實時消息系統
Redis 的 Pub/Sub 系統可以構建實時的消息系統,比如很多用 Pub/Sub 構建的實時聊天系統的例子。 -
構建隊列系統
使用 list 可以構建隊列系統,使用 sorted set 甚至可以構建有優先級的隊列系統 -
緩存
數據都是緩存在內存中,效率更高。
Redis 安裝
使用 Docker 安裝方式,運行下面命令:
# 安裝命令
docker run -itd --name redis -p 6379:6379 redis
# 查看 Redis 運行信息
docker ps
# 連接 redis 服務
docker exec -it redis /bin/bash
redis-cli
Redis 配置
-
daemonize:
默認情況下, redis 不是在后臺運行的,如果需要在后臺運行,把該項的值更改為 yes。 -
pidfile
當 Redis 在后臺運行的時候, Redis 默認會把 pid 文件放在/var/run/redis.pid,你可以配置到其他地址。當運行多個 redis 服務時,需要指定不同的 pid 文件和端口。 -
bind
指定 Redis 只接收來自于該 IP 地址的請求,如果不進行設置,那么將處理所有請求,在生產環境中最好設置該項。 -
port
監聽端口,默認為 6379。 -
timeout
設置客戶端連接時的超時時間,單位為秒。當客戶端在這段時間內沒有發出任何指令,那么關閉該連接。 -
loglevel
log 等級分為 4 級,debug, verbose, notice, 和 warning。生產環境下一般開啟 notice。 -
logfile
配置 log 文件地址,默認使用標準輸出,即打印在命令行終端的窗口上。 -
databases
設置數據庫的個數,可以使用 SELECT <dbid>命令來切換數據庫。默認使用的數據庫是 0。 -
save
設置 Redis 進行數據庫鏡像的頻率。
if(在 60 秒之內有 10000 個 keys 發生變化時){
進行鏡像備份
}else if(在 300 秒之內有 10 個 keys 發生了變化){
進行鏡像備份
}else if(在 900 秒之內有 1 個 keys 發生了變化){
進行鏡像備份
} -
rdbcompression
在進行鏡像備份時,是否進行壓縮。 -
dbfilename
鏡像備份文件的文件名。 -
dir
數據庫鏡像備份的文件放置的路徑。這里的路徑跟文件名要分開配置是因為 Redis 在進行備份時,先會將當前數據庫的狀態寫入到一個臨時文件中,等備份完成時,再把該該臨時文件替換為上面所指定的文件,而這里的臨時文件和上面所配置的備份文件都會放在這個指定的路徑當中。 -
slaveof
設置該數據庫為其他數據庫的從數據庫。 -
masterauth
當主數據庫連接需要密碼驗證時,在這里指定。 -
requirepass
設置客戶端連接后進行任何其他指定前需要使用的密碼。警告:因為 redis 速度相當快,所以在一臺比較好的服務器下,一個外部的用戶可以在一秒鐘進行 150K 次的密碼嘗試,這意味著你需要指定非常非常強大的密碼來防止暴力破解。
-
maxclients
限制同時連接的客戶數量。當連接數超過這個值時, redis 將不再接收其他連接請求,客戶端嘗試連接時將收到 error 信息。 -
maxmemory
設置 redis 能夠使用的最大內存。當內存滿了的時候,如果還接收到 set 命令, redis 將先嘗試剔除設置過 expire 信息的 key,而不管該 key 的過期時間還沒有到達。**在刪除時,將按照過期時間進行刪除,最早將要被過期的 key 將最先被刪除。如果帶有 expire 信息的 key 都刪光了,那么將返回錯誤。**這樣, redis 將不再接收寫請求,只接收 get 請求。maxmemory 的設置比較適合于把 redis 當作于類似 memcached 的緩存來使用。 -
appendonly
默認情況下, redis 會在后臺異步的把數據庫鏡像備份到磁盤,但是該備份是非常耗時的,而且備份也不能很頻繁,如果發生諸如拉閘限電、拔插頭等狀況,那么將造成比較大范圍的數據丟失。所以 redis 提供了另外一種更加高效的數據庫備份及災難恢復方式。開啟 append only 模式之后, redis 會把所接收到的每一次寫操作請求都追加到appendonly.aof 文件中,當 redis 重新啟動時,會從該文件恢復出之前的狀態。但是這樣會造成 appendonly.aof 文件過大,所以 redis 還支持了 BGREWRITEAOF 指令,對appendonly.aof 進行重新整理。所以我認為推薦生產環境下的做法為關閉鏡像,開啟appendonly.aof,同時可以選擇在訪問較少的時間每天對 appendonly.aof 進行重寫一次。 -
appendfsync
設置對 appendonly.aof 文件進行同步的頻率。 always 表示每次有寫操作都進行同步,everysec 表示對寫操作進行累積,每秒同步一次。這個需要根據實際業務場景進行配置 -
vm-enabled
是否開啟虛擬內存支持。因為 redis 是一個內存數據庫,而且當內存滿的時候,無法接收新的寫請求,所以在 redis 2.0 中,提供了虛擬內存的支持。但是需要注意的是, redis中,所有的 key 都會放在內存中,在內存不夠時,只會把 value 值放入交換區。這樣保證了雖然使用虛擬內存,但性能基本不受影響,同時,你需要注意的是你要把vm-max-memory 設置到足夠來放下你的所有的 key -
vm-swap-file
設置虛擬內存的交換文件路徑 -
vm-max-memory
這里設置開啟虛擬內存之后, redis 將使用的最大物理內存的大小。默認為 0, redis 將把他所有的能放到交換文件的都放到交換文件中,以盡量少的使用物理內存。在生產環境下,需要根據實際情況設置該值,最好不要使用默認的 0 -
vm-page-size
設置虛擬內存的頁大小,如果你的 value 值比較大,比如說你要在 value 中放置博客、新聞之類的所有文章內容,就設大一點,如果要放置的都是很小的內容,那就設小一點。 -
vm-pages
設置交換文件的總的 page 數量,需要注意的是, page table 信息會放在物理內存中,每8 個 page 就會占據 RAM 中的 1 個 byte。總的虛擬內存大小 = vm-page-size * vm-pages。 -
vm-max-threads
設置 VM IO 同時使用的線程數量。因為在進行內存交換時,對數據有編碼和解碼的過程,所以盡管 IO 設備在硬件上本上不能支持很多的并發讀寫,但是還是如果你所保存的 vlaue 值比較大,將該值設大一些,還是能夠提升性能的。 -
glueoutputbuf
把小的輸出緩存放在一起,以便能夠在一個 TCP packet 中為客戶端發送多個響應,具體原理和真實效果我不是很清楚。所以根據注釋,你不是很確定的時候就設置成 yes。 -
hash-max-zipmap-entries
在 redis 2.0 中引入了 hash 數據結構。當 hash 中包含超過指定元素個數并且最大的元素沒有超過臨界時, hash 將以一種特殊的編碼方式(大大減少內存使用)來存儲,這里可以設置這兩個臨界值 -
activerehashing
開啟之后, redis 將在每 100 毫秒時使用 1 毫秒的 CPU 時間來對 redis 的 hash 表進行重新 hash,可以降低內存的使用。當你的使用場景中,有非常嚴格的實時性需要,不能夠接受 Redis 時不時的對請求有 2 毫秒的延遲的話,把這項配置為 no。如果沒有這么嚴格的實時性要求,可以設置為 yes,以便能夠盡可能快的釋放內存。
簡單操作數據庫
-
插入數據
127.0.0.1:6379> set name Jacob OK
-
查詢數據
127.0.0.1:6379> get name "Jacob"
-
刪除數據
127.0.0.1:6379> del name (integer) 1127.0.0.1:6379> del name3 (integer) 0
其中 integer 表示:被刪除 key 的數量。
-
驗證 key 是否存在
127.0.0.1:6379> exists name (integer) 1127.0.0.1:6379> exists name2 (integer) 0
其中 0,代表此 key 不存在; 1 代表存在。