Redis教程 一、入門 1. 什麼是NoSql NoSQL一詞最早出現於1998年,是Carlo Strozzi開發的一個輕量、開源、不提供SQL功能的關係資料庫。2009年,Last.fm的Johan Oskarsson發起了一次關於分散式開源資料庫的討論,來自Rackspace的Eric Ev ...
一、入門
1. 什麼是NoSql
NoSQL一詞最早出現於1998年,是Carlo Strozzi開發的一個輕量、開源、不提供SQL功能的關係資料庫。2009年,Last.fm的Johan Oskarsson發起了一次關於分散式開源資料庫的討論,來自Rackspace的Eric Evans再次提出了NoSQL的概念,這時的NoSQL主要指非關係型、分散式、不提供ACID的資料庫設計模式。它不同於傳統的關係資料庫,兩者存在許多顯著的不同點,其中最重要的是NoSQL不使用SQL作為查詢語言。其數據存儲可以不需要固定的表格模式。
2. Redis簡介
Redis是使用c語言開發的一個高性能鍵值資料庫。常用於分散式系統中的緩存、電商秒殺、排行榜、訪問量統計、分散式會話共用等高併發應用場景。Redis可以通過一些鍵值類型來存儲數據。其數據類型包括字元類型、散列類型、列表類型、集合類型、有序集合類型。
3. 安裝Redis
訪問Redis官網https://redis.io/download下載最新的版本 。
解壓並編譯安裝
$ tar xzf redis-5.0.3.tar.gz
$ cd redis-5.0.3
$ make install
Redis官網並沒有提供windows版本,但可以前往https://github.com/tporadowski/redis/releases下載windows的個人編譯版本(註意:並不是最新的版本)。
4. 啟動服務
4.1 前端啟動
在redis的src目錄有一個redis-server文件,用於啟動一個redis服務。
redis的預設埠為6379,當客戶端需要連接到redis服務時,就通過服務端的IP地址以及這個埠進行連接。也可以修改這個預設埠。在redis的根目錄下有一個redis.conf文件,它是redis的核心配置文件,redis的所有配置信息都在此文件中。如果需要修改埠,我們在配置文件中找到port配置,並將6379改為其他的埠號。
修改完後需要重新啟動redis服務,需要註意的是,在使用redis-server啟動服務時需要指定redis.conf文件的絕對路徑,否則redis將以預設的配置啟動一個服務實例。
前端啟動的模式我們可以在終端看到redis的啟動信息和相關的操作日誌,但此時如果關閉了終端或者使用control+c將會立即停止redis服務。
4.2 後端啟動
所謂後端啟動,就是以一個獨立的進程來運行一個redis服務。首先修改redis.conf文件,找到daemonize選項並設置為yes,如下圖:
保存退出後重新啟動redis服務,此時redis將以後臺進程的方式啟動服務。終端沒有顯示相關的啟動信息,並且啟動完成後,終端可以繼續執行其他的操作。
5. 客戶端連接
5.1 Redis客戶端
在redis的src目錄下有一個redis-cli命令,這個就是官方提供的redis客戶端,可以使用它來連接和操作redis。當然,這僅僅只是一個命令行的客戶端程式,在實際的開發中會有不同的平臺語言,因此官網也提供了對各種語言的客戶端實現,在實際的項目開發中使用不同語言的客戶端來操作redis。例如官網提供了一個Java的客戶端Jedis。
1)使用redis-cli
可以使用使用官方自帶的redis-cli客戶端來連接redis服務。參數-h為連接redis伺服器的IP地址,-p為redis的埠號。連接完成後就可以對redis進行操作了,我們使用簡單的set和get命令來進行存儲和訪問操作。
2)退出客戶端
如果想要退出客戶端的連接只需要在連接的狀態下輸入quit或者exit即可。
3)身份認證
預設連接Redis時是不需要認證密碼的,我們可以為其設置一個連接的認證密碼。首先在redis.conf中找到requirepass配置項,取消註釋並設置一個密碼。
保存後重啟服務,在連接客戶端時加上-a參數並輸入配置的密碼。
連接時也可以不指定密碼也可以正常連接,但在操作Redis時候會提示一個錯誤,要求輸入認證密碼。這時使用auth命令來輸入密碼即可。
如果設置了認證密碼,在關閉客戶端時也同樣需要指定。
5.2 可視化客戶端
也可以使用第三方的redis的可視化客戶端RDM(redis-desktop-manager),它同時提供了各種系統平臺的編譯版本,安裝後即可使用。下載地址:
點擊左上角的Connect to Redis Server,在彈出的視窗中填寫相關的Name(連接名稱)、Address(連接地址)、埠號以及認證密碼(Auth),點擊OK即可。
這裡我們看到連接redis後預設有16個庫(0 ~ 15),這是redis預設的配置,可以在redis.conf中可以找到相應的選項並修改預設數量。
當我們使用客戶端連接redis時,預設選擇的是index為0的資料庫,然而也可以使用select命令選擇其他資料庫。例如選擇index為15的資料庫,如下操作:
6. 停止服務
如果使用前端啟動redis,可以使用control+c或者kill命令來殺掉進程的方式關閉redis(註意:control+c並不能停止後端啟動的redis),但這些方式都是強制性的關閉redis,由於redis保存的數據先會存儲在記憶體,如果此時強制關閉,將導致redis還沒將數據持久化到文件中就退出,可能會照成部分的數據丟失。因此,應該使用正常的退出方式來停止redis服務,正常退出redis同樣使用redis-cli客戶端。
上面的命令表示關閉本機埠為6379的redis服務。
二、基礎
1. 數據類型及常用API
Redis支持五種數據類型:string(字元串),hash(哈希),list(列表),set(集合)及sorted set(zset:有序集合)。
1.1 string(字元串)
String 是 redis 最基本的類型,一個 key 對應一個 value。它是二進位安全的,可以包含任何數據,如jpg圖片或者序列化的對象。
1)SET
語法:set key value
賦值操作。
2)GET
語法:get key
取值操作。
3)GETSET
語法:getset key value
取值並賦值。
4)MSET
語法:mset key value [key value ...]
同時設置多個鍵值。
5)MGET
語法:mget key [key ...]
獲取多個鍵值。
6)DEL
語法:del key [key ...]
刪除一個或多個鍵值對。
7)INCR
語法:incr key
當存儲的字元串是整數時,讓當前鍵值遞增,並返回遞增或增加後的值。
8)INCRBY
語法:incrby key increment*
當存儲的字元串是整數時,讓當前鍵值增加指定的數值,並返回遞增或增加後的值。
9)DECR
語法:decr key
讓當前鍵值遞減,並返回遞減或減少後的值。
10)DECRBY
語法:decrby key decrement
讓當前鍵值減少指定的數值,並返回遞減或減少後的值。
11)APPEND
語法:append key value
向鍵值的末尾追加value。如果鍵不存在則將該鍵的值設置為value,即相當於 SET key value。返回值是追加後字元串的總長度。
12)獲取字元串長度(STRLEN)
STRLEN命令返回鍵值的長度,如果鍵不存在則返回0。
1.2 hash(哈希)
hash是一個string類型的field和value的映射表,而field只能是String類型,hash特別適合用於存儲對象。
1)HSET
語法:HSET key field value
HSET一次只能設置一個欄位值。HSET命令不區分插入和更新操作,當執行插入操作時HSET命令返回1,當執行更新操作時返回0。
2)HMSET
語法:HMSET key field value [field value ...]
HMSET和HSET作用一樣,只不過一次可以設置多個欄位值。
3)HSETNX
語法:HSETNX key field value
當欄位不存在時賦值,類似HSET。區別在於如果欄位存在,該命令不執行任何操作。
例如:hsetnx user name zing
說明:如果user中不存在name欄位則設置name的值為zing,否則不做任何操作。
4)HGET
語法:HGET key field
HGET一次只能獲取一個欄位值。
5)HMGET
語法:HMGET key field [field ...]
HMGET一次可以獲取多個欄位值。
6)HGETALL
語法:HGETALL key
獲取所有欄位值。
7)HDEL
語法:HDEL key field [field...]
可以刪除一個或多個欄位,返回值是被刪除的欄位個數。
8)HINCRBY
語法:HINCRBY key field increment
為某個欄位增加數值。
9)HEXISTS
語法:HEXISTS key field
判斷欄位是否存在,存在則返回1,否則返回0。
10)HKEYS
語法:HKEYS key
獲取所有的欄位名。
11)HVALS
語法:HVALS key
獲取所有欄位的值。
12)HLEN
語法:HLEN key
獲取欄位數量。
1.3 list(列表)
Redis的list是採用來鏈表來存儲的,所以對於Redis的list數據類型的操作,是操作list的兩端數據來操作的。
1)LPUSH
語法:LPUSH key value [value ...]
向列表左邊添加元素。
2)RPUSH
語法:RPUSH key value [value ...]
向列表右邊添加元素。
3)LRANGE
語法:LRANGE key start stop
LRANGE命令是列表類型最常用的命令之一,用於獲取列表中的某一片段,將返回start到stop之間的所有元素(包含兩端的元素),索引從0開始。索引可以是負數,如:-1代表最後邊的一個元素。
4)LPOP
語法:LPOP key
LPOP命令從列表左邊彈出一個元素,會分兩步完成:第一步是將列表左邊的元素從列表中移除。第二步是返回被移除的元素值。
5)RPOP
語法:RPOP key
RPOP命令從列表右邊彈出一個元素,步驟與LPOP類似,第一步是將列表右邊的元素從列表中移除。第二步是返回被移除的元素值。
6)LLEN
語法:LLEN key
獲取列表中元素的個數
7)LREM
語法:LREM key count value
LREM命令會刪除列表中前count個值為value的元素,返回實際刪除的元素個數。根據count值的不同,該命令的執行方式會有所不同:
當count>0時, LREM會從列表左邊開始刪除。
當count<0時, LREM會從列表右邊開始刪除。
當count=0時,LREM刪除所有值為value的元素。
8)LINDEX
語法:LINDEX key index
獲得指定索引的元素值。
9)LSET
語法:LSET key index value
設置指定索引的元素值。
10)LTRIM
語法:LTRIM key start stop
只保留列表的指定片段
11)LINSERT
語法:LINSERT key BEFORE|AFTER pivot value
LINSERT首先會在列表中從左到右查找值為pivot的元素,然後根據第二個參數是BEFORE還是AFTER來決定將value插入到該元素的前面還是後面。
12)RPOPLPUSH
語法:RPOPLPUSH source destination
將一個列表的最後一個元素轉移到另一個列表的最前面
1.4 set(集合)
Redis 的 Set 是 String 類型的無序集合。集合成員是唯一的,這就意味著集合中不能出現重覆的數據。
1)SADD
語法:SADD key member [member ...]
增加一個或多個元素。
2)SREM
語法:SREM key member [member ...]
移除一個或多個元素。
3)SMEMBERS
語法:SMEMBERS key
獲得集合中的所有元素。
4)SISMEMBER
語法:SISMEMBER key member
判斷元素是否存在集合中。存在返回1,否則返回0。
5)SDIFF
語法:SDIFF key [key ...]
查找屬於集合A並且不屬於集合B的元素。(差集運算)
6)SINTER
語法:SINTER key [key ...]
查找屬於集合A且屬於集合B的元素。(交集運算)
7)SUNION
語法:SUNION key [key ...]
查找屬於集合A或者屬於集合B的元素。(合併運算)
8)SCARD
語法:SCARD key
獲取集合中元素的個數。
9)SPOP
語法:SPOP key [count]
從集合中彈出一個或多個元素,由count指定。如果不指定count,預設彈出一個。由於集合是無序的,所有SPOP命令會從集合中隨機選擇一個元素彈出。
1.5 zset(有序集合)
zset又稱sorted set,稱之為有序集合,可排序的,但是唯一。和set的不同支出在於zet會給集合中的元素添加一個分數,然後通過這個分數進行排序。
1)ZADD
語法:ZADD key score member [score member ...]
向有序集合中加入一個或多個元素和該元素的分數,如果該元素已經存在則會用新的分數替換原有的分數。返回值是新加入到集合中的元素個數,不包含之前已經存在的元素。
2)ZSCORE
語法:ZSCORE key member
獲取元素的分數。
3)ZREM
語法:ZREM key member [member ...]
移除有序集合中的一個或多個成員,不存在的成員將被忽略。
4)ZRANGE
語法:ZRANGE key start stop [WITHSCORES]
按照元素分數從小到大的順序返回索引從start到stop之間的所有元素(包含兩端的元素)。如果需要獲得元素的分數可以在命令尾部加上WITHSCORES參數。
5)ZREVRANGE
語法:ZREVRANGE key start stop [WITHSCORES]
按照元素分數從大到小的順序返回索引從start到stop之間的所有元素(包含兩端的元素)。如果需要獲得元素的分數的可以在命令尾部加上WITHSCORES參數。
6)ZRANK
語法:ZRANK key member
獲取元素排名(從小到大)。
7)ZREVRANK
語法:ZREVRANK key member
獲取元素排名(從大到小)。
8)ZRANGEBYSCORE
語法:ZRANGEBYSCORE key min max WITHSCORES
獲得指定分數範圍的元素。
9)ZINCRBY
語法:ZINCRBY key increment member
增加某個元素的分數,並返回更改後的分數。
10)ZCARD
語法:ZCARD key
獲取集合元素的數量。
11)ZCOUNT
語法:ZCOUNT key min max
獲取指定分數範圍內的元素個數。
12)ZREMRANGEBYRANK
語法:ZREMRANGEBYRANK key start stop
按照排名範圍刪除元素。
13)ZREMRANGEBYSCORE
語法:ZREMRANGEBYSCORE key min max
按照分數範圍刪除元素。
2. Redis鍵(Keys)
Redis鍵是二進位安全的,這意味著你可以使用任何二進位序列作為鍵,從像”foo” 這樣的字元串到一個 JPEG文件的內容。空字元串也是合法的鍵。
2.1 鍵的一些設計規則
-
不要使用太長的鍵。例如,不要使用一個1024位元組的鍵,不僅是因為占用記憶體,而且在數據集中查找key時需要多次耗時的key比較。
-
不要使用太短的key。例如,user:1001比u1001更具有實際意義,相對於key本身以及value對象來說,增加的空間微乎其微。當然,短的鍵會消耗少的記憶體,需要找到平衡點。
-
規範一種模式 (schema)。用冒號或者下橫線來連接多單詞欄位,例如:”user:1000”或者"user_1000"。
2.2 Key的常用API
1)KEYS
語法:keys pattern
返回指定pattern的所有key
2)EXISTS
語法:exists key
判斷一個key是否存在。存在返回後1,否則返回0。
3)RENAME
語法:rename key newkey
重命名key
4)TYPE
語法:type key
根據key返回value的類型。
5)EXPIRE
語法:expire key seconds
設置key的生存時間。Redis的數據是緩存在記憶體中的,然後很多時候數據一般都會設置一個過期時間(即到期後銷毀數據,從而釋放更多的記憶體)。過期時間預設以秒為單位,預設值為-1,表示永不過期。
也可以在設值的時候指定過期時間(秒)
6)TTL
語法:ttl key
查看key剩餘的過期時間。
7)PERSIST
語法:persist key
清除key的過期時間。
8)PEXPIRE
語法:pexpire key
以毫秒為單位設置key的過期時間。
也可以在設值的時候指定過期的時間(毫秒)
3. 持久化
3.1 簡介
Redis是一個支持持久化的記憶體資料庫,可以將記憶體中的數據同步到磁碟保證持久化。我們知道Redis會將數據緩存在記憶體中,如果沒有持久化,在伺服器關閉或重啟之後數據會丟失。為了保證數據的安全以及效率,Redis會周期性的把更新的數據寫入磁碟或者把修改操作寫入追加的記錄文件。而Redis提供了RDB和AOF兩種持久化策略。
3.2 RDB
Redis預設是會以快照RDB的形式將數據持久化到磁碟的一個dump.rdb二進 制文件。當Redis決定要持久化時,會 fork 一個子進程將數據寫到磁碟上一個臨時的RDB文件中,當子進程完成寫操作後,將原來的RDB替換掉。而Redis會在滿足某些條件後會進行持久化,並且可以對其進行配置。
配置RDB
在redis.conf文件中找到“Save the DB on disk”的配置,我們可以根據需要來修改這Redis的RDB持久化策略。
說明:
save 900 1(如果在900秒之內有1次操作,則執行快照保存)
save 300 10(如果在300秒內有10次操作,則執行快照保存)
save 60 10000(如果在1分鐘之內有10000個次操作,則執行快照保存)
SAVE和BGSAVE
我們可以在客戶端直接使用SAVE或者BGSAVE命令立即將Redis的數據持久化到RDB文件中。他們兩者的區別在於BGSAVE命令會fork一個子進程在後臺進行持久化,主進程可以繼續處理客戶端發送的命令(非阻塞)。而SAVE命令需要等待Redis持久化完成後才可以繼續處理客戶端發送的命令(阻塞)。
RDB優點
RDB非常適合用於數據備份, 可以在當天內每小時備份一次,或者每個月的每天都進行備份。 如果遇到斷電或者宕機等其他一些災難情況,可以隨時將數據集還原。
RDB缺點
如果對數據的完整性和安全性要求非常高,要求每一次的操作數據都能持久化到文件中,這時RDB就不太適合了。因為RDB是按照時間範圍的操作次數為條件促發持久化,如果未滿足這些觸發條件,Redis並不會將數據保存到文件,導致數據丟失。例如:save 60 10000,如果在1分鐘之內有9000次的操作,如果此時伺服器異常退出或宕機,由於未滿足條件,將導致丟失這1分鐘的數據。
3.3 AOF
AOF持久化可以記錄每個寫操作,將Redis執行過的所有寫指令(讀操作不記錄)保存到appendonly.aof文件中,並且只允許追加文件而不可以改寫文件。在Redis啟動的時候會讀取該文件重新構建緩存數據。在打開AOF持久化機制之後,Redis每當接收到一條寫命令,會先寫入系統緩存,然後每隔一定時間(預設是每秒鐘)fsync一次(寫入到指定文件)。
啟用AOF
AOF持久化預設是關閉的,如果要啟用AOF,需要在redis.conf配置文件中啟用該功能,將appendonly no設置為appendonly yes。
所有寫操作預設保存在appendonly.aof文件中,可以自行修改保存的路徑和文件名。
同步策略
AOF提供了三種同步策略:
-
always(每次寫操作就執行一次fsync)
-
everysec(每秒執行一次fsync,預設)
-
no(不執行fsync)
AOF重寫
AOF會記錄Redis所有的寫操作命令,但這種方式會造成一個問題,就是隨著時間的推移,大量頻繁的操作將導致AOF文件體積的急劇增長,對系統會造成影響。為瞭解決以上的問題, Redis就需要對AOF文件進行重寫。重寫的過程會創建一個新的AOF文件來代替原有的AOF文件, 而新AOF文件和原有AOF 文件保存的數據狀態是一致的,但新文件的體積將變得儘可能地小。以下兩種方式會觸發AOF重寫。
1)手動出發
在客戶端直接向Redis發送BGREWRITEAOF命令,這個命令會通過移除AOF文件中的冗餘命令來重寫(rewrite)AOF文件。
2)自動觸發
其實在啟用了AOF之後(appendonly yes),Redis會依據redis.conf配置文件中的auto-aof-rewrite-percentage選項和auto-aof-rewrite-min-size選項來自動執行BGREWRITEAOF命令。
說明:
例如設置了auto-aof-rewrite-percentage為100和auto-aof-rewrite-min-size為64mb,那麼當AOF文件的體積大於64MB時,並且AOF文件的體積比上一次重寫之後的體積大一倍(100%)的,Redis將執行BGREWRITEAOF命令進行重寫。
AOF優點
AOF彌補了RDB按照時間範圍的操作次數為條件的缺點,即使在預設的策略中發生故障,最多也只會丟失一秒鐘的數據,更大程度的保證了數據的安全性。
AOF缺點
AOF會保存每一次的寫操作,這將導致AOF文件的體積通常要大於RDB文件。如果選用always策略,則表示每一次操作都會記錄到AOF文件中,從性能的角度上來說會低於RDB。當然,使用預設的everysec策略進行持久化性能還是非常可觀的。
3.4 混合持久化
在實際應用中,通常會同時使用RDB和AOF兩種持久化來找到一個最佳的平衡點,即能保證性能的同時最大程度保證數據的安全。因此需要RDB和AOF兩者同時進行合理的設置和調整。而從Redis 4.0開始,官方提供了一種更加方便的混合持久化配置。
未啟用混合持久化
在未啟用混合持久化之前,如果我們往Redis寫入一條記時,RDB文件會保存操作的鍵值數據,AOF文件則保存的是寫操作的指令,我們可以分別查看一下這兩個文件的內容。
使用cat命令查看RDB文件
然而顯示的內容並不太直觀也不易理解,因此可以藉助Redis提供的redis-check-rdb工具進行查看。
RDB文件中會保存Redis的相關信息以及存儲的keys數量和相關的活期時間。接下來我們繼續查看AOF文件的內容,直接使用cat命名進行查看。
結果顯示AOF文件中保存的是相關的操作指令。
啟用混合持久化
要使用混合持久化,除了在redis.conf文件中啟用AOF(將appendonly設置為yes),還需要將aof-use-rdb-preamble設置為yes。
設置完重新啟用Redis服務。啟用了混合持久化之後,使用BGREWRITEAOF命令執行一次AOF重寫,同時向Redis插入一條新的數據。
然後再次使用cat命令再次查看AOF文件,這時會發現啟用混合持久化之後的AOF文件內容和未啟用時的AOF文件內容不一樣。這是因為此時產生的AOF文件是一個RDB-AOF的混合文件,Redis會基於某種協議將此文件的前半部分存儲RDB的數據,後半部分存儲的是AOF的操作命令。
4. 事務
Redis事務可以一次執行多個命令(批量命令操作),並且是一個單獨的隔離操作。事務中的所有命令都會按順序地執行。事務在執行的過程中,不會被其他客戶端發送來的命令請求所打斷。
4.1 事務操作
Redis事務主要由MULTI 、 EXEC、DISCARD、WATCH和UNWATCH這些基礎命令構成。
1)MULTI
語法:MULTI
用於標記事務的開始,後續客戶端執行的命令都將被存入一個命令隊列,直到執行EXEC時,這些命令才會被執行。
2)EXEC
語法:EXEC
執行命令隊列中的所有命令,但如果在啟用一個事務之前執行了WATCH命令,那麼只有當WATCH所監控的keys沒有被修改的前提下,EXEC命令才能執行事務隊列中的所有命令,並返回所有命令的執行結果,否則EXEC將放棄當前事務中的所有命令。
3)DISCARD
語法:DISCARD
取消事務隊列中的所有命令,並將當前連接的狀態恢復為非事務狀態。如果WATCH命令被使用,會自動執行UNWATCH取消監視的所有keys。
4)WATCH
語法:WATCH key[key...]
WATCH命令類似於關係型資料庫的樂觀鎖,可以在啟用事務之前監視某些keys的變化。在MULTI命令執行之前,可以指定需要監視的keys,在執行EXEC之前,如果被監控的keys發生修改,EXEC將放棄執行該隊列中的所有指令。並且WATCH命令可以監控一個或多個鍵,一旦其中有一個鍵被修改(或刪除),之後的事務就不會執行。
首先打開一個客戶端,並使用watch命令監視user:1001的key,接著使用multi啟用事務。
然後打開第二個客戶端,並修改key為user:1001的value為user01。