Redis詳解(原理,安裝,配置,使用,命令)

一、Redis介紹

Redis是一個開源的使用ANSI C語言編寫、支持網絡、可基於內存亦可持久化的日誌型、Key-Value數據庫,並提供多種語言的API。從2010年3月15日起,Redis的開發工作由VMware主持。

Redis能運行在大多數POSIX(Linux, *BSD, OS X 和Solaris等)系統上,官方沒有支持Windows的版本。目前最新的版本是2.2.11,這個版本主要是修復了一個2.2.7版本中遍歷方式優化帶來的一個bug。
和普通的Key-Value結構不同,Redis的Key支持靈活的數據結構,除了strings,還有hashes、lists、 sets 和sorted sets等結構。正是這些靈活的數據結構,豐富了Redis的應用場景,能滿足更多業務上的靈活存儲需求。
Redis的數據都保存在內存中,而且底層實現上是自己寫了epoll event loop部分,而沒有采用開源的libevent等通用框架,所以讀寫效率很高。爲了實現數據的持久化,Redis支持定期刷新(可通過配置實現)或寫日誌的方式來保存數據到磁盤。

1、數據類型

作爲Key-value型數據庫,Redis也提供了鍵(Key)和鍵值(Value)的映射關係。但是,除了常規的數值或字符串,Redis的鍵值還可以是以下形式之一:
●Lists (列表)
●Sets (集合)
●Sorted sets (有序集合)
●Hashes (哈希表)
鍵值的數據類型決定了該鍵值支持的操作。Redis支持諸如列表、集合或有序集合的交集、並集、查集等高級原子操作;同時,如果鍵值的類型是普通數字,Redis則提供自增等原子操作。

2、持久化

通常,Redis將數據存儲於內存中,或被配置爲使用虛擬內存。通過兩種方式可以實現數據持久化:使用截圖的方式,將內存中的數據不斷寫入磁盤;或使用類似MySQL的日誌方式,記錄每次更新的日誌。前者性能較高,但是可能會引起一定程度的數據丟失;後者相反。

3、主從同步

Redis支持將數據同步到多臺從庫上,這種特性對提高讀取性能非常有益。

4、性能

相比需要依賴磁盤記錄每個更新的數據庫,基於內存的特性無疑給Redis帶來了非常優秀的性能。讀寫操作之間有顯著的性能差異。

5、提供API的語言

●C
●C++
●C#
●Clojure
●Common Lisp
●Erlang
●Haskell
●Java
●Javascript
●Lua
●Objective-C
●Perl
●PHP
●Python
●Ruby
●Scala
●Go
●Tcl

6、適用場合

毫無疑問,Redis開創了一種新的數據存儲思路,使用Redis,我們不用在面對功能單調的數據庫時,把精力放在如何把大象放進冰箱這樣的問題上,而是利用Redis靈活多變的數據結構和數據操作,爲不同的大象構建不同的冰箱。希望你喜歡這個比喻。
下面是Redis適用的一些場景:
(1)、取最新N個數據的操作
比如典型的取你網站的最新文章,通過下面方式,我們可以將最新的5000條評論的ID放在Redis的List集合中,並將超出集合部分從數據庫獲取。
使用LPUSH latest.comments命令,向list集合中插入數據
插入完成後再用LTRIM latest.comments 0 5000命令使其永遠只保存最近5000個ID
然後我們在客戶端獲取某一頁評論時可以用下面的邏輯
FUNCTION get_latest_comments(start,num_items):
id_list = redis.lrange(“latest.comments”,start,start+num_items-1)
IF id_list.length < num_items
id_list = SQL_DB(“SELECT … ORDER BY time LIMIT …”)
END
RETURN id_list
END
如果你還有不同的篩選維度,比如某個分類的最新N條,那麼你可以再建一個按此分類的List,只存ID的話,Redis是非常高效的。
(2)、排行榜應用,取TOP N操作
這個需求與上面需求的不同之處在於,前面操作以時間爲權重,這個是以某個條件爲權重,比如按頂的次數排序,這時候就需要我們的sorted set出馬了,將你要排序的值設置成sorted set的score,將具體的數據設置成相應的value,每次只需要執行一條ZADD命令即可。
(3)、需要精準設定過期時間的應用
比如你可以把上面說到的sorted set的score值設置成過期時間的時間戳,那麼就可以簡單地通過過期時間排序,定時清除過期數據了,不僅是清除Redis中的過期數據,你完全可以把Redis裏這個過期時間當成是對數據庫中數據的索引,用Redis來找出哪些數據需要過期刪除,然後再精準地從數據庫中刪除相應的記錄。
(4)、計數器應用
Redis的命令都是原子性的,你可以輕鬆地利用INCR,DECR命令來構建計數器系統。
(5)、Uniq操作,獲取某段時間所有數據排重值
這個使用Redis的set數據結構最合適了,只需要不斷地將數據往set中扔就行了,set意爲集合,所以會自動排重。
(6)、實時系統,反垃圾系統
通過上面說到的set功能,你可以知道一個終端用戶是否進行了某個操作,可以找到其操作的集合並進行分析統計對比等。沒有做不到,只有想不到。
(7)、Pub/Sub構建實時消息系統
Redis的Pub/Sub系統可以構建實時的消息系統,比如很多用Pub/Sub構建的實時聊天系統的例子。
(8)、構建隊列系統
使用list可以構建隊列系統,使用sorted set甚至可以構建有優先級的隊列系統。
(9)、緩存
這個不必說了,性能優於Memcached,數據結構更多樣化。

二、安裝及使用

步驟一: 下載Redis
下載安裝包:wget http://download.redis.io/releases/redis-3.0.6.tar.gz
[root@localhost 4setup]# wget http://download.redis.io/releases/redis-3.0.6.tar.gz
步驟二: 編譯源程序
[root@localhost 4setup]# ll
[root@localhost 4setup]# tar xzf redis-3.0.6.tar.gz
[root@localhost 4setup]# cd redis-3.0.6
[root@localhost redis-2.2.12]# make
cd src && make all
make[1]: Entering directory `/root/4setup/redis-3.0.6/src’
步驟三: 啓動Redis服務
src/redis-server
[root@localhost redis-2.2.12]# src/redis-server
Redis 服務端的默認連接端口是 6379。
使用指定配置文件啓動
src/redis-server redis.conf
步驟四: 將Redis作爲 Linux 服務隨機啓動
vi /etc/rc.local, 使用vi編輯器打開隨機啓動配置文件,並在其中加入下面一行代碼。
/root/4setup/redis-3.0.6/src/redis-server
步驟五: 客戶端連接驗證
新打開一個Session輸入:src/redis-cli,如果出現下面提示,那麼您就可以開始Redis之旅了。
[root@localhost redis-3.0.6]# src/redis-cli
redis 127.0.0.1:6379>
步驟六: 查看Redis日誌
查看服務器端session,即可對Redis的運行狀況進行查看或分析了。
[6246] 05 Aug 19:24:33 – 0 clients connected (0 slaves), 539544 bytes in use
[6246] 05 Aug 19:24:37 – Accepted 127.0.0.1:51381
[6246] 05 Aug 19:24:38 – 1 clients connected (0 slaves), 547372 bytes in use
以上的幾個步驟就OK了!!這樣一個簡單的Redis數據庫就可以暢通無阻地運行起來了。
步驟七: 停止Redis實例
最簡單的方法是在啓動實例的session中,直接使用Control-C來將實例停止。
我們還可以用客戶端來停止服務,如可以用shutdown來停止Redis實例, 具體如下:
[root@localhost redis-3.0.6]# src/redis-cli shutdown

三、配置Redis

使用配置文件啓動:src/redis-server redis.conf
主要配置項:
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 命令來切換數據庫。默認使用的數據庫是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,以便能夠儘可能快的釋放內存。

四、操作Redis

1、插入數據
redis 127.0.0.1:6379> set name wwl
OK
設置一個key-value對。
2、查詢數據
redis 127.0.0.1:6379> get name
“wwl”
取出key所對應的value。
3、刪除鍵值
redis 127.0.0.1:6379> del name
刪除這個key及對應的value。
4、驗證鍵是否存在
redis 127.0.0.1:6379> exists name
(integer) 0
其中0,代表此key不存在;1代表存在。

五、各類型的基本操作

1)strings類型及操作

string是最簡單的類型,你可以理解成與Memcached是一模一樣的類型,一個key對應一個value,其上支持的操作與Memcached的操作類似。但它的功能更豐富。
string類型是二進制安全的。意思是redis的string可以包含任何數據,比如jpg圖片或者序列化的對象。從內部實現來看其實string可以看作byte數組,最大上限是1G字節,下面是string類型的定義:
struct sdshdr {
long len;
long free;
char buf[];
};
len是buf數組的長度。
free是數組中剩餘可用字節數,由此可以理解爲什麼string類型是二進制安全的了,因爲它本質上就是個byte數組,當然可以包含任何數據了
buf是個char數組用於存貯實際的字符串內容,其實char和c#中的byte是等價的,都是一個字節。
另外string類型可以被部分命令按int處理.比如incr等命令,如果只用string類型,redis就可以被看作加上持久化特性的memcached。當然redis對string類型的操作比memcached還是多很多的,具體操作方法如下:
1、set
設置key對應的值爲string類型的value。
例如我們添加一個name= HongWan的鍵值對,可以這樣做:
redis 127.0.0.1:6379> set name HongWan
OK
redis 127.0.0.1:6379>
2、setnx
設置key對應的值爲string類型的value。如果key已經存在,返回0,nx是not exist的意思。
例如我們添加一個name= HongWan_new的鍵值對,可以這樣做:
redis 127.0.0.1:6379> get name
“HongWan”
redis 127.0.0.1:6379> setnx name HongWan_new
(integer) 0
redis 127.0.0.1:6379> get name
“HongWan”
redis 127.0.0.1:6379>
由於原來name有一個對應的值,所以本次的修改不生效,且返回碼是0。
3、setex
設置key對應的值爲string類型的value,並指定此鍵值對應的有效期。
例如我們添加一個haircolor= red的鍵值對,並指定它的有效期是10秒,可以這樣做:
redis 127.0.0.1:6379> setex haircolor 10 red
OK
redis 127.0.0.1:6379> get haircolor
“red”
redis 127.0.0.1:6379> get haircolor
(nil)
redis 127.0.0.1:6379>
可見由於最後一次的調用是10秒以後了,所以取不到haicolor這個鍵對應的值。
4、setrange
設置指定key的value值的子字符串。
例如我們希望將HongWan的126郵箱替換爲gmail郵箱,那麼我們可以這樣做:
redis 127.0.0.1:6379> get name
[email protected]
redis 127.0.0.1:6379> setrange name 8 gmail.com
(integer) 17
redis 127.0.0.1:6379> get name
[email protected]
redis 127.0.0.1:6379>
其中的8是指從下標爲8(包含8)的字符開始替換
5、mset
一次設置多個key的值,成功返回ok表示所有的值都設置了,失敗返回0表示沒有任何值被設置。
redis 127.0.0.1:6379> mset key1 HongWan1 key2 HongWan2
OK
redis 127.0.0.1:6379> get key1
“HongWan1″
redis 127.0.0.1:6379> get key2
“HongWan2″
redis 127.0.0.1:6379>
6、msetnx
一次設置多個key的值,成功返回ok表示所有的值都設置了,失敗返回0表示沒有任何值被設置,但是不會覆蓋已經存在的key。
redis 127.0.0.1:6379> get key1
“HongWan1″
redis 127.0.0.1:6379> get key2
“HongWan2″
redis 127.0.0.1:6379> msetnx key2 HongWan2_new key3 HongWan3
(integer) 0
redis 127.0.0.1:6379> get key2
“HongWan2″
redis 127.0.0.1:6379> get key3
(nil)
可以看出如果這條命令返回0,那麼裏面操作都會回滾,都不會被執行。
7、get
獲取key對應的string值,如果key不存在返回nil。
例如我們獲取一個庫中存在的鍵name,可以很快得到它對應的value
redis 127.0.0.1:6379> get name
“HongWan”
redis 127.0.0.1:6379>
我們獲取一個庫中不存在的鍵name1,那麼它會返回一個nil以表時無此鍵值對
redis 127.0.0.1:6379> get name1
(nil)
redis 127.0.0.1:6379>
8、getset
設置key的值,並返回key的舊值。
redis 127.0.0.1:6379> get name
“HongWan”
redis 127.0.0.1:6379> getset name HongWan_new
“HongWan”
redis 127.0.0.1:6379> get name
“HongWan_new”
redis 127.0.0.1:6379>
接下來我們看一下如果key不存的時候會什麼樣兒?
redis 127.0.0.1:6379> getset name1 aaa
(nil)
redis 127.0.0.1:6379>
可見,如果key不存在,那麼將返回nil
9、getrange
獲取指定key的value值的子字符串。
具體樣例如下:
redis 127.0.0.1:6379> get name
[email protected]
redis 127.0.0.1:6379> getrange name 0 6
“HongWan”
redis 127.0.0.1:6379>
字符串左面下標是從0開始的
redis 127.0.0.1:6379> getrange name -7 -1
“126.com”
redis 127.0.0.1:6379>
字符串右面下標是從-1開始的
redis 127.0.0.1:6379> getrange name 7 100
“@126.com”
redis 127.0.0.1:6379>
當下標超出字符串長度時,將默認爲是同方向的最大下標
10、mget
一次獲取多個key的值,如果對應key不存在,則對應返回nil。
具體樣例如下:
redis 127.0.0.1:6379> mget key1 key2 key3
1) “HongWan1″
2) “HongWan2″
3) (nil)
redis 127.0.0.1:6379>
key3由於沒有這個鍵定義,所以返回nil。
11、incr
對key的值做加加操作,並返回新的值。注意incr一個不是int的value會返回錯誤,incr一個不存在的key,則設置key爲1
redis 127.0.0.1:6379> set age 20
OK
redis 127.0.0.1:6379> incr age
(integer) 21
redis 127.0.0.1:6379> get age
“21”
redis 127.0.0.1:6379>
12、incrby
同incr類似,加指定值 ,key不存在時候會設置key,並認爲原來的value是 0
redis 127.0.0.1:6379> get age
“21”
redis 127.0.0.1:6379> incrby age 5
(integer) 26
redis 127.0.0.1:6379> get name
[email protected]
redis 127.0.0.1:6379> get age
“26”
redis 127.0.0.1:6379>
13、decr
對key的值做的是減減操作,decr一個不存在key,則設置key爲-1
redis 127.0.0.1:6379> get age
“26”
redis 127.0.0.1:6379> decr age
(integer) 25
redis 127.0.0.1:6379> get age
“25”
redis 127.0.0.1:6379>
14、decrby
同decr,減指定值。
redis 127.0.0.1:6379> get age
“25”
redis 127.0.0.1:6379> decrby age 5
(integer) 20
redis 127.0.0.1:6379> get age
“20”
redis 127.0.0.1:6379>
decrby完全是爲了可讀性,我們完全可以通過incrby一個負值來實現同樣效果,反之一樣。
redis 127.0.0.1:6379> get age
“20”
redis 127.0.0.1:6379> incrby age -5
(integer) 15
redis 127.0.0.1:6379> get age
“15”
redis 127.0.0.1:6379>
15、append
給指定key的字符串值追加value,返回新字符串值的長度。例如我們向name的值追加一個@126.com字符串,那麼可以這樣做:
redis 127.0.0.1:6379> append name @126.com
(integer) 15
redis 127.0.0.1:6379> get name
[email protected]
redis 127.0.0.1:6379>
16、strlen
取指定key的value值的長度。
redis 127.0.0.1:6379> get name
“HongWan_new”
redis 127.0.0.1:6379> strlen name
(integer) 11
redis 127.0.0.1:6379> get age
“15”
redis 127.0.0.1:6379> strlen age
(integer) 2
redis 127.0.0.1:6379>

2)hash

Redis hash是一個string類型的field和value的映射表.它的添加、刪除操作都是O(1)(平均)。hash特別適合用於存儲對象。相較於將對象的每個字段存成單個string類型。將一個對象存儲在hash類型中會佔用更少的內存,並且可以更方便的存取整個對象。省內存的原因是新建一個hash對象時開始是用zipmap(又稱爲small hash)來存儲的。這個zipmap其實並不是hash table,但是zipmap相比正常的hash實現可以節省不少hash本身需要的一些元數據存儲開銷。儘管zipmap的添加,刪除,查找都是O(n),但是由於一般對象的field數量都不太多。所以使用zipmap也是很快的,也就是說添加刪除平均還是O(1)。如果field或者value的大小超出一定限制後,Redis會在內部自動將zipmap替換成正常的hash實現. 這個限制可以在配置文件中指定
hash-max-zipmap-entries 64 #配置字段最多64個。
hash-max-zipmap-value 512 #配置value最大爲512字節。
1、hset
設置hash field爲指定值,如果key不存在,則先創建。
redis 127.0.0.1:6379> hset myhash field1 Hello
(integer) 1
redis 127.0.0.1:6379>
2、hsetnx
設置hash field爲指定值,如果key不存在,則先創建。如果field已經存在,返回0,nx是not exist的意思。
redis 127.0.0.1:6379> hsetnx myhash field “Hello”
(integer) 1
redis 127.0.0.1:6379> hsetnx myhash field “Hello”
(integer) 0
redis 127.0.0.1:6379>
第一次執行是成功的,但第二次執行相同的命令失敗,原因是field已經存在了。
3、hmset
同時設置hash的多個field。
redis 127.0.0.1:6379> hmset myhash field1 Hello field2 World
OK
redis 127.0.0.1:6379>
4、hget
獲取指定的hash field。
redis 127.0.0.1:6379> hget myhash field1
“Hello”
redis 127.0.0.1:6379> hget myhash field2
“World”
redis 127.0.0.1:6379> hget myhash field3
(nil)
redis 127.0.0.1:6379>
由於數據庫沒有field3,所以取到的是一個空值nil。
5、hmget
獲取全部指定的hash filed。
redis 127.0.0.1:6379> hmget myhash field1 field2 field3
1) “Hello”
2) “World”
3) (nil)
redis 127.0.0.1:6379>
由於數據庫沒有field3,所以取到的是一個空值nil。
6、hincrby
指定的hash filed 加上給定值。
redis 127.0.0.1:6379> hset myhash field3 20
(integer) 1
redis 127.0.0.1:6379> hget myhash field3
“20”
redis 127.0.0.1:6379> hincrby myhash field3 -8
(integer) 12
redis 127.0.0.1:6379> hget myhash field3
“12”
redis 127.0.0.1:6379>
在本例中我們將field3的值從20降到了12,即做了一個減8的操作。
7、hexists
測試指定field是否存在。
redis 127.0.0.1:6379> hexists myhash field1
(integer) 1
redis 127.0.0.1:6379> hexists myhash field9
(integer) 0
redis 127.0.0.1:6379>
通過上例可以說明field1存在,但field9是不存在的。
8、hlen
返回指定hash的field數量。
redis 127.0.0.1:6379> hlen myhash
(integer) 4
redis 127.0.0.1:6379>
通過上例可以看到myhash中有4個field。
9、hdel
返回指定hash的field數量。
redis 127.0.0.1:6379> hlen myhash
(integer) 4
redis 127.0.0.1:6379> hdel myhash field1
(integer) 1
redis 127.0.0.1:6379> hlen myhash
(integer) 3
redis 127.0.0.1:6379>
10、hkeys
返回hash的所有field。
redis 127.0.0.1:6379> hkeys myhash
1) “field2″
2) “field”
3) “field3″
redis 127.0.0.1:6379>
說明這個hash中有3個field。
11、hvals
返回hash的所有value。
redis 127.0.0.1:6379> hvals myhash
1) “World”
2) “Hello”
3) “12”
redis 127.0.0.1:6379>
說明這個hash中有3個field。
12、hgetall
獲取某個hash中全部的filed及value。
redis 127.0.0.1:6379> hgetall myhash
1) “field2″
2) “World”
3) “field”
4) “Hello”
5) “field3″
6) “12”
redis 127.0.0.1:6379>
可見,一下子將myhash中所有的field及對應的value都取出來了。

3)list

Redis的list類型其實就是一個每個子元素都是string類型的雙向鏈表。鏈表的最大長度是(2的32次方)。我們可以通過push,pop操作從鏈表的頭部或者尾部添加刪除元素。這使得list既可以用作棧,也可以用作隊列。
有意思的是list的pop操作還有阻塞版本的,當我們[lr]pop一個list對象時,如果list是空,或者不存在,會立即返回nil。但是阻塞版本的b[lr]pop可以則可以阻塞,當然可以加超時時間,超時後也會返回nil。爲什麼要阻塞版本的pop呢,主要是爲了避免輪詢。舉個簡單的例子如果我們用list來實現一個工作隊列。執行任務的thread可以調用阻塞版本的pop去獲取任務這樣就可以避免輪詢去檢查是否有任務存在。當任務來時候工作線程可以立即返回,也可以避免輪詢帶來的延遲。說了這麼多,接下來看一下實際操作的方法吧:
1、lpush
在key對應list的頭部添加字符串元素:
redis 127.0.0.1:6379> lpush mylist “world”
(integer) 1
redis 127.0.0.1:6379> lpush mylist “hello”
(integer) 2
redis 127.0.0.1:6379> lrange mylist 0 -1
1) “hello”
2) “world”
redis 127.0.0.1:6379>
在此處我們先插入了一個world,然後在world的頭部插入了一個hello。其中lrange是用於取mylist的內容。
2、rpush
在key對應list的尾部添加字符串元素:
redis 127.0.0.1:6379> rpush mylist2 “hello”
(integer) 1
redis 127.0.0.1:6379> rpush mylist2 “world”
(integer) 2
redis 127.0.0.1:6379> lrange mylist2 0 -1
1) “hello”
2) “world”
redis 127.0.0.1:6379>
在此處我們先插入了一個hello,然後在hello的尾部插入了一個world。
3、linsert
在key對應list的特定位置之前或之後添加字符串元素:
redis 127.0.0.1:6379> rpush mylist3 “hello”
(integer) 1
redis 127.0.0.1:6379> rpush mylist3 “world”
(integer) 2
redis 127.0.0.1:6379> linsert mylist3 before “world” “there”
(integer) 3
redis 127.0.0.1:6379> lrange mylist3 0 -1
1) “hello”
2) “there”
3) “world”
redis 127.0.0.1:6379>
在此處我們先插入了一個hello,然後在hello的尾部插入了一個world,然後又在world的前面插入了there。
4、lset
設置list中指定下標的元素值(下標從0開始):
redis 127.0.0.1:6379> rpush mylist4 “one”
(integer) 1
redis 127.0.0.1:6379> rpush mylist4 “two”
(integer) 2
redis 127.0.0.1:6379> rpush mylist4 “three”
(integer) 3
redis 127.0.0.1:6379> lset mylist4 0 “four”
OK
redis 127.0.0.1:6379> lset mylist4 -2 “five”
OK
redis 127.0.0.1:6379> lrange mylist4 0 -1
1) “four”
2) “five”
3) “three”
redis 127.0.0.1:6379>
在此處我們依次插入了one,two,three,然後將標是0的值設置爲four,再將下標是-2的值設置爲five。
5、lrem
從key對應list中刪除count個和value相同的元素。
count>0時,按從頭到尾的順序刪除,具體如下:
redis 127.0.0.1:6379> rpush mylist5 “hello”
(integer) 1
redis 127.0.0.1:6379> rpush mylist5 “hello”
(integer) 2
redis 127.0.0.1:6379> rpush mylist5 “foo”
(integer) 3
redis 127.0.0.1:6379> rpush mylist5 “hello”
(integer) 4
redis 127.0.0.1:6379> lrem mylist5 2 “hello”
(integer) 2
redis 127.0.0.1:6379> lrange mylist5 0 -1
1) “foo”
2) “hello”
redis 127.0.0.1:6379>
count<0時,按從尾到頭的順序刪除,具體如下:
redis 127.0.0.1:6379> rpush mylist6 “hello”
(integer) 1
redis 127.0.0.1:6379> rpush mylist6 “hello”
(integer) 2
redis 127.0.0.1:6379> rpush mylist6 “foo”
(integer) 3
redis 127.0.0.1:6379> rpush mylist6 “hello”
(integer) 4
redis 127.0.0.1:6379> lrem mylist6 -2 “hello”
(integer) 2
redis 127.0.0.1:6379> lrange mylist6 0 -1
1) “hello”
2) “foo”
redis 127.0.0.1:6379>
count=0時,刪除全部,具體如下:
redis 127.0.0.1:6379> rpush mylist7 “hello”
(integer) 1
redis 127.0.0.1:6379> rpush mylist7 “hello”
(integer) 2
redis 127.0.0.1:6379> rpush mylist7 “foo”
(integer) 3
redis 127.0.0.1:6379> rpush mylist7 “hello”
(integer) 4
redis 127.0.0.1:6379> lrem mylist7 0 “hello”
(integer) 3
redis 127.0.0.1:6379> lrange mylist7 0 -1
1) “foo”
redis 127.0.0.1:6379>
6、ltrim
保留指定key 的值範圍內的數據:
redis 127.0.0.1:6379> rpush mylist8 “one”
(integer) 1
redis 127.0.0.1:6379> rpush mylist8 “two”
(integer) 2
redis 127.0.0.1:6379> rpush mylist8 “three”
(integer) 3
redis 127.0.0.1:6379> rpush mylist8 “four”
(integer) 4
redis 127.0.0.1:6379> ltrim mylist8 1 -1
OK
redis 127.0.0.1:6379> lrange mylist8 0 -1
1) “two”
2) “three”
3) “four”
redis 127.0.0.1:6379>
7、lpop
從list的頭部刪除元素,並返回刪除元素:
redis 127.0.0.1:6379> lrange mylist 0 -1
1) “hello”
2) “world”
redis 127.0.0.1:6379> lpop mylist
“hello”
redis 127.0.0.1:6379> lrange mylist 0 -1
1) “world”
redis 127.0.0.1:6379>
8、rpop
從list的尾部刪除元素,並返回刪除元素:
redis 127.0.0.1:6379> lrange mylist2 0 -1
1) “hello”
2) “world”
redis 127.0.0.1:6379> rpop mylist2
“world”
redis 127.0.0.1:6379> lrange mylist2 0 -1
1) “hello”
redis 127.0.0.1:6379>
9、rpoplpush
從第一個list的尾部移除元素並添加到第二個list的頭部,最後返回被移除的元素值,整個操作是原子的.如果第一個list是空或者不存在返回nil:
redis 127.0.0.1:6379> lrange mylist5 0 -1
1) “three”
2) “foo”
3) “hello”
redis 127.0.0.1:6379> lrange mylist6 0 -1
1) “hello”
2) “foo”
redis 127.0.0.1:6379> rpoplpush mylist5 mylist6
“hello”
redis 127.0.0.1:6379> lrange mylist5 0 -1
1) “three”
2) “foo”
redis 127.0.0.1:6379> lrange mylist6 0 -1
1) “hello”
2) “hello”
3) “foo”
redis 127.0.0.1:6379>
10、lindex
返回名稱爲key的list中index位置的元素:
redis 127.0.0.1:6379> lrange mylist5 0 -1
1) “three”
2) “foo”
redis 127.0.0.1:6379> lindex mylist5 0
“three”
redis 127.0.0.1:6379> lindex mylist5 1
“foo”
redis 127.0.0.1:6379>
11、llen
返回key對應list的長度:
redis 127.0.0.1:6379> llen mylist5
(integer) 2
redis 127.0.0.1:6379>

 

4)sets

Redis的set是string類型的無序集合。set元素最大可以包含(2的32次方)個元素。
set的是通過hash table實現的,所以添加、刪除和查找的複雜度都是O(1)。hash table會隨着添加或者刪除自動的調整大小。需要注意的是調整hash table大小時候需要同步(獲取寫鎖)會阻塞其他讀寫操作,可能不久後就會改用跳錶(skip list)來實現,跳錶已經在sorted set中使用了。關於set集合類型除了基本的添加刪除操作,其他有用的操作還包含集合的取並集(union),交集(intersection),差集(difference)。通過這些操作可以很容易的實現sns中的好友推薦和blog的tag功能。下面詳細介紹set相關命令:
1、sadd
向名稱爲key的set中添加元素:
redis 127.0.0.1:6379> sadd myset “hello”
(integer) 1
redis 127.0.0.1:6379> sadd myset “world”
(integer) 1
redis 127.0.0.1:6379> sadd myset “world”
(integer) 0
redis 127.0.0.1:6379> smembers myset
1) “world”
2) “hello”
redis 127.0.0.1:6379>
本例中,我們向myset中添加了三個元素,但由於第三個元素跟第二個元素是相同的,所以第三個元素沒有添加成功,最後我們用smembers來查看myset中的所有元素。
2、srem
刪除名稱爲key的set中的元素member:
redis 127.0.0.1:6379> sadd myset2 “one”
(integer) 1
redis 127.0.0.1:6379> sadd myset2 “two”
(integer) 1
redis 127.0.0.1:6379> sadd myset2 “three”
(integer) 1
redis 127.0.0.1:6379> srem myset2 “one”
(integer) 1
redis 127.0.0.1:6379> srem myset2 “four”
(integer) 0
redis 127.0.0.1:6379> smembers myset2
1) “three”
2) “two”
redis 127.0.0.1:6379>
本例中,我們向myset2中添加了三個元素後,再調用srem來刪除one和four,但由於元素中沒有four所以,此條srem命令執行失敗。
3、spop
隨機返回並刪除名稱爲key的set中一個元素:
redis 127.0.0.1:6379> sadd myset2 “one”
(integer) 1
redis 127.0.0.1:6379> sadd myset2 “two”
(integer) 1
redis 127.0.0.1:6379> sadd myset2 “three”
(integer) 1
redis 127.0.0.1:6379> srem myset2 “one”
(integer) 1
redis 127.0.0.1:6379> srem myset2 “four”
(integer) 0
redis 127.0.0.1:6379> smembers myset2
1) “three”
2) “two”
redis 127.0.0.1:6379>
本例中,我們向myset3中添加了三個元素後,再調用spop來隨機刪除一個元素,可以看到three元素被刪除了。
4、sdiff
返回所有給定key與第一個key的差集:
redis 127.0.0.1:6379> sadd myset2 “one”
(integer) 1
redis 127.0.0.1:6379> sadd myset2 “two”
(integer) 1
redis 127.0.0.1:6379> sadd myset2 “three”
(integer) 1
redis 127.0.0.1:6379> srem myset2 “one”
(integer) 1
redis 127.0.0.1:6379> srem myset2 “four”
(integer) 0
redis 127.0.0.1:6379> smembers myset2
1) “three”
2) “two”
redis 127.0.0.1:6379>
本例中,我們可以看到myset2中的元素與myset3中不同的只是three,所以只有three被查出來了,而不是three和one,因爲one是myset3的元素。
我們也可以將myset2和myset3換個順序來看一下結果:
redis 127.0.0.1:6379> sdiff myset3 myset2
1) “one”
redis 127.0.0.1:6379>
這個結果中只顯示了,myset3中的元素與myset2中不同的元素。
5、sdiffstore
返回所有給定key與第一個key的差集,並將結果存爲另一個key:
redis 127.0.0.1:6379> smembers myset2
1) “three”
2) “two”
redis 127.0.0.1:6379> smembers myset3
1) “two”
2) “one”
redis 127.0.0.1:6379> sdiffstore myset4 myset2 myset3
(integer) 1
redis 127.0.0.1:6379> smembers myset4
1) “three”
redis 127.0.0.1:6379>
6、sinter
返回所有給定key的交集:
redis 127.0.0.1:6379> smembers myset2
1) “three”
2) “two”
redis 127.0.0.1:6379> smembers myset3
1) “two”
2) “one”
redis 127.0.0.1:6379> sinter myset2 myset3
1) “two”
redis 127.0.0.1:6379>
通過本例的結果可以看出, myset2和myset3的交集two被查出來了。
7、sinterstore
返回所有給定key的交集,並將結果存爲另一個key
redis 127.0.0.1:6379> smembers myset2
1) “three”
2) “two”
redis 127.0.0.1:6379> smembers myset3
1) “two”
2) “one”
redis 127.0.0.1:6379> sinterstore myset5 myset2 myset3
(integer) 1
redis 127.0.0.1:6379> smembers myset5
1) “two”
redis 127.0.0.1:6379>
通過本例的結果可以看出, myset2和myset3的交集被保存到myset5中了
8、sunion
返回所有給定key的並集
redis 127.0.0.1:6379> smembers myset2
1) “three”
2) “two”
redis 127.0.0.1:6379> smembers myset3
1) “two”
2) “one”
redis 127.0.0.1:6379> sunion myset2 myset3
1) “three”
2) “one”
3) “two”
redis 127.0.0.1:6379>
通過本例的結果可以看出, myset2和myset3的並集被查出來了
9、sunionstore
返回所有給定key的並集,並將結果存爲另一個key
redis 127.0.0.1:6379> smembers myset2
1) “three”
2) “two”
redis 127.0.0.1:6379> smembers myset3
1) “two”
2) “one”
redis 127.0.0.1:6379> sunionstore myset6 myset2 myset3
(integer) 3
redis 127.0.0.1:6379> smembers myset6
1) “three”
2) “one”
3) “two”
redis 127.0.0.1:6379>
通過本例的結果可以看出, myset2和myset3的並集被保存到myset6中了
10、smove
從第一個key對應的set中移除member並添加到第二個對應set中
redis 127.0.0.1:6379> smembers myset2
1) “three”
2) “two”
redis 127.0.0.1:6379> smembers myset3
1) “two”
2) “one”
redis 127.0.0.1:6379> smove myset2 myset7 three
(integer) 1
redis 127.0.0.1:6379> smembers myset7
1) “three”
redis 127.0.0.1:6379>
通過本例可以看到,myset2的three被移到myset7中了
11、scard
返回名稱爲key的set的元素個數
redis 127.0.0.1:6379> scard myset2
(integer) 1
redis 127.0.0.1:6379>
通過本例可以看到,myset2的成員數量爲1
12、sismember
測試member是否是名稱爲key的set的元素
redis 127.0.0.1:6379> smembers myset2
1) “two”
redis 127.0.0.1:6379> sismember myset2 two
(integer) 1
redis 127.0.0.1:6379> sismember myset2 one
(integer) 0
redis 127.0.0.1:6379>
通過本例可以看到,two是myset2的成員,而one不是。
13、srandmember
隨機返回名稱爲key的set的一個元素,但是不刪除元素
redis 127.0.0.1:6379> smembers myset3
1) “two”
2) “one”
redis 127.0.0.1:6379> srandmember myset3
“two”
redis 127.0.0.1:6379> srandmember myset3
“one”
redis 127.0.0.1:6379>

5)sorted sets

和set一樣sorted set也是string類型元素的集合,不同的是每個元素都會關聯一個double類型的score。sorted set的實現是skip list和hash table的混合體。
當元素被添加到集合中時,一個元素到score的映射被添加到hash table中,所以給定一個元素獲取score的開銷是O(1),另一個score到元素的映射被添加到skip list,並按照score排序,所以就可以有序的獲取集合中的元素。添加,刪除操作開銷都是O(log(N))和skip list的開銷一致,redis的skip list實現用的是雙向鏈表,這樣就可以逆序從尾部取元素。sorted set最經常的使用方式應該是作爲索引來使用.我們可以把要排序的字段作爲score存儲,對象的id當元素存儲。下面是sorted set相關命令
1、zadd
向名稱爲key的zset中添加元素member,score用於排序。如果該元素已經存在,則根據score更新該元素的順序
redis 127.0.0.1:6379> zadd myzset 1 “one”
(integer) 1
redis 127.0.0.1:6379> zadd myzset 2 “two”
(integer) 1
redis 127.0.0.1:6379> zadd myzset 3 “two”
(integer) 0
redis 127.0.0.1:6379> zrange myzset 0 -1 withscores
1) “one”
2) “1”
3) “two”
4) “3”
redis 127.0.0.1:6379>
本例中我們向myzset中添加了one和two,並且two被設置了2次,那麼將以最後一次的設置爲準,最後我們將所有元素都顯示出來並顯示出了元素的score。
2、zrem
刪除名稱爲key的zset中的元素member
redis 127.0.0.1:6379> zrange myzset 0 -1 withscores
1) “one”
2) “1”
3) “two”
4) “3”
redis 127.0.0.1:6379> zrem myzset two
(integer) 1
redis 127.0.0.1:6379> zrange myzset 0 -1 withscores
1) “one”
2) “1”
redis 127.0.0.1:6379>
可以看到two被刪除了
3、zincrby
如果在名稱爲key的zset中已經存在元素member,則該元素的score增加increment;否則向集合中添加該元素,其score的值爲increment
redis 127.0.0.1:6379> zadd myzset2 1 “one”
(integer) 1
redis 127.0.0.1:6379> zadd myzset2 2 “two”
(integer) 1
redis 127.0.0.1:6379> zincrby myzset2 2 “one”
“3”
redis 127.0.0.1:6379> zrange myzset2 0 -1 withscores
1) “two”
2) “2”
3) “one”
4) “3”
redis 127.0.0.1:6379>
本例中將one的score從1增加了2,增加到了3
4、zrank
返回名稱爲key的zset中member元素的排名(按score從小到大排序)即下標
redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
1) “one”
2) “1”
3) “two”
4) “2”
5) “three”
6) “3”
7) “five”
8) “5”
redis 127.0.0.1:6379> zrank myzset3 two
(integer) 1
redis 127.0.0.1:6379>
本例中將two的下標是1,我這裏取的是下標,而不是score
5、zrevrank
返回名稱爲key的zset中member元素的排名(按score從大到小排序)即下標
redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
1) “one”
2) “1”
3) “two”
4) “2”
5) “three”
6) “3”
7) “five”
8) “5”
redis 127.0.0.1:6379> zrank myzset3 two
(integer) 1
redis 127.0.0.1:6379>
按從大到小排序的話two是第三個元素,下標是2
6、zrevrange
返回名稱爲key的zset(按score從大到小排序)中的index從start到end的所有元素
redis 127.0.0.1:6379> zrevrange myzset3 0 -1 withscores
1) “five”
2) “5”
3) “three”
4) “3”
5) “two”
6) “2”
7) “one”
8) “1”
redis 127.0.0.1:6379>
首先按score從大到小排序,再取出全部元素
7、zrangebyscore
返回集合中score在給定區間的元素
redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
1) “one”
2) “1”
3) “two”
4) “2”
5) “three”
6) “3”
7) “five”
8) “5”
redis 127.0.0.1:6379> zrangebyscore myzset3 2 3 withscores
1) “two”
2) “2”
3) “three”
4) “3”
redis 127.0.0.1:6379>
本例中,返回了score在2~3區間的元素
8、zcount
返回集合中score在給定區間的數量
redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
1) “one”
2) “1”
3) “two”
4) “2”
5) “three”
6) “3”
7) “five”
8) “5”
redis 127.0.0.1:6379> zcount myzset3 2 3
(integer) 2
redis 127.0.0.1:6379>
本例中,計算了score在2~3之間的元素數目
9、zcard
返回集合中元素個數
redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
1) “one”
2) “1”
3) “two”
4) “2”
5) “three”
6) “3”
7) “five”
8) “5”
redis 127.0.0.1:6379> zcard myzset3
(integer) 4
redis 127.0.0.1:6379>
從本例看出myzset3這個集全的元素數量是4
10、zscore
返回給定元素對應的score
redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
1) “one”
2) “1”
3) “two”
4) “2”
5) “three”
6) “3”
7) “five”
8) “5”
redis 127.0.0.1:6379> zscore myzset3 two
“2”
redis 127.0.0.1:6379>
此例中我們成功的將two的score取出來了。
11、zremrangebyrank
刪除集合中排名在給定區間的元素
redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
1) “one”
2) “1”
3) “two”
4) “2”
5) “three”
6) “3”
7) “five”
8) “5”
redis 127.0.0.1:6379> zremrangebyrank myzset3 3 3
(integer) 1
redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
1) “one”
2) “1”
3) “two”
4) “2”
5) “three”
6) “3”
redis 127.0.0.1:6379>
在本例中我們將myzset3中按從小到大排序結果的下標爲3的元素刪除了。
12、zremrangebyscore
刪除集合中score在給定區間的元素
redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
1) “one”
2) “1”
3) “two”
4) “2”
5) “three”
6) “3”
redis 127.0.0.1:6379> zremrangebyscore myzset3 1 2
(integer) 2
redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores
1) “three”
2) “3”
redis 127.0.0.1:6379>
在本例中我們將myzset3中按從小到大排序結果的score在1~2之間的元素刪除了。

發佈了17 篇原創文章 · 獲贊 1 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章