Redis入門

內(nèi)容來(lái)自Redis實(shí)戰(zhàn)(Redis in Action)。

一、介紹

Redis 是一個(gè)開源的使用 ANSI C 語(yǔ)言編寫、支持網(wǎng)絡(luò)、可基于內(nèi)存亦可持久化的日志型、 Key-Value 數(shù)據(jù)庫(kù),并提供多種語(yǔ)言的 API。從 2010 年 3 月 15 日起,Redis 的開發(fā)工作由 VMware 主持。

Redis 是一個(gè) Key-Value 存儲(chǔ)系統(tǒng)。和 Memcached 類似,它支持存儲(chǔ)的 value 類型相對(duì)更多, 包括 string(字符串)、list(鏈表)、set(集合)和 zset(有序集合)。這些數(shù)據(jù)類型都支持 push/pop、 add/remove 及取交集并集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎(chǔ) 上,Redis 支持各種不同方式的排序。與 memcached 一樣,為了保證效率,數(shù)據(jù)都是緩存在 內(nèi)存中。區(qū)別的是 Redis 會(huì)周期性的把更新的數(shù)據(jù)寫入磁盤或者把修改操作寫入追加的記錄 文件,并且在此基礎(chǔ)上實(shí)現(xiàn)了 master-slave(主從)同步。

  • Redis 適用的一些場(chǎng)景
  • 取最新 N 個(gè)數(shù)據(jù)的操作
  • 排行榜應(yīng)用,取 TOP N 操作
  • 需要精準(zhǔn)設(shè)定過(guò)期時(shí)間的應(yīng)用
  • 計(jì)數(shù)器應(yīng)用
    Redis 的命令都是原子性的,你可以輕松地利用 INCR,DECR 命令來(lái)構(gòu)建計(jì)數(shù)器系統(tǒng)。
  • Uniq 操作,獲取某段時(shí)間所有數(shù)據(jù)排重值
    這個(gè)使用 Redis 的 set 數(shù)據(jù)結(jié)構(gòu)最合適了,只需要不斷地將數(shù)據(jù)往 set 中扔就行了,set 意為 集合,所以會(huì)自動(dòng)排重。
  • 實(shí)時(shí)系統(tǒng),反垃圾系統(tǒng)
  • Pub/Sub 構(gòu)建實(shí)時(shí)消息系統(tǒng)
  • 構(gòu)建隊(duì)列系統(tǒng)
  • 緩存
    性能優(yōu)于 Memcached,數(shù)據(jù)結(jié)構(gòu)更多樣化。

二、安裝與配置

登錄遠(yuǎn)程主機(jī):ssh 用戶名@IP地址 ,然后輸入密碼。
進(jìn)入想要安裝Redis的目錄,執(zhí)行:

$ wget http://download.redis.io/releases/redis-3.2.9.tar.gz
$ tar xzf redis-3.2.9.tar.gz
$ cd redis-3.2.9
$ make

啟動(dòng)Redis服務(wù)

$ src/redis-server

如果出現(xiàn)下圖,就說(shuō)明啟動(dòng)成功。


image.png

但是這個(gè)服務(wù)不是后臺(tái)的,如果想讓Redis以后臺(tái)服務(wù)的形式運(yùn)行,可以修改配置文件。
解壓后的文件夾redis-3.2.9內(nèi)有一個(gè)redis.conf的文件,可以修改配置參數(shù),并在啟動(dòng)Redis的時(shí)候指定該配置文件,使其按照配置啟動(dòng)。
比如,
修改默認(rèn)端口6379為6380:port 6380
修改為后臺(tái)運(yùn)行:daemonize yes
修改后,在剛才的窗口中按Control+C鍵,關(guān)閉前臺(tái)Redis服務(wù),指定配置文件重新啟動(dòng)

`$ src/redis-server ./redis.conf`

此時(shí),沒有任何提示(沒有消息就是好消息),不放心可以查看當(dāng)前進(jìn)程

$ ps -ef |grep -i redis

#可以在控制臺(tái)看到如下的信息
xxx    3940 27646  0 14:25 pts/1    00:00:00 src/redis-server 127.0.0.1:6380

現(xiàn)在,用Redis客戶端與該服務(wù)交互,執(zhí)行

# 啟動(dòng)Redis客戶端:默認(rèn)端口是6379,所以要指定端口為6380
$ src/redis-cli -h 127.0.0.1 -p 6380
127.0.0.1:6380> set name laoyue
OK
127.0.0.1:6380> get name
"laoyue"
127.0.0.1:6380> 
# 要退出Redis客戶端,按Control+C鍵或輸入quit回車。

Redis服務(wù)器默認(rèn)只允許本機(jī)訪問(wèn)。如果想要遠(yuǎn)程訪問(wèn)Redis,修改配置文件中的bind參數(shù)。

更多配置

daemonize:
    默認(rèn)情況下,redis 不是在后臺(tái)運(yùn)行的,如果需要在后臺(tái)運(yùn)行,把該項(xiàng)的值更改為 yes
pidfile
    當(dāng) Redis 在后臺(tái)運(yùn)行的時(shí)候,Redis 默認(rèn)會(huì)把 pid 文件放在/var/run/redis.pid,
    你可以配置到其他地址。當(dāng)運(yùn)行多個(gè) redis 服務(wù)時(shí),需要指定不同的 pid 文件和端口
bind
    指定 Redis 只接收來(lái)自于該 IP 地址的請(qǐng)求,如果不進(jìn)行設(shè)置,
    那么將處理所有請(qǐng)求,在生產(chǎn)環(huán)境中最好設(shè)置該項(xiàng)
port
    監(jiān)聽端口,默認(rèn)為 6379
timeout 
    設(shè)置客戶端連接時(shí)的超時(shí)時(shí)間,單位為秒。
    當(dāng)客戶端在這段時(shí)間內(nèi)沒有發(fā)出任何指令, 那么關(guān)閉該連接
loglevel
    log 等級(jí)分為 4 級(jí),debug, verbose, notice, 和 warning。
    生產(chǎn)環(huán)境下一般開啟 notice
logfile
    配置 log 文件地址,默認(rèn)使用標(biāo)準(zhǔn)輸出,即打印在命令行終端的窗口上
databases
    設(shè)置數(shù)據(jù)庫(kù)的個(gè)數(shù),可以使用 SELECT <dbid>命令來(lái)切換數(shù)據(jù)庫(kù)。默認(rèn)使用的數(shù)據(jù)庫(kù)是 0
save
    設(shè)置 Redis 進(jìn)行數(shù)據(jù)庫(kù)鏡像的頻率。
      if(在 60 秒之內(nèi)有 10000 個(gè) keys 發(fā)生變化時(shí)){
         進(jìn)行鏡像備份
      }else if(在 300 秒之內(nèi)有 10 個(gè) keys 發(fā)生了變化){
         進(jìn)行鏡像備份
      }else if(在 900 秒之內(nèi)有 1 個(gè) keys 發(fā)生了變化){
         進(jìn)行鏡像備份
      }
rdbcompression :在進(jìn)行鏡像備份時(shí),是否進(jìn)行壓縮
dbfilename :鏡像備份文件的文件名
dir
    數(shù)據(jù)庫(kù)鏡像備份的文件放置的路徑。這里的路徑跟文件名要分開配置是因?yàn)?Redis 在進(jìn)行備份時(shí),
    先會(huì)將當(dāng)前數(shù)據(jù)庫(kù)的狀態(tài)寫入到一個(gè)臨時(shí)文件中,等備份完成時(shí),再把該臨時(shí)文件替換為上面所指定的
    文件,而這里的臨時(shí)文件和上面所配置的備份文件都會(huì)放 在這個(gè)指定的路徑當(dāng)中
slaveof: 設(shè)置該數(shù)據(jù)庫(kù)為其他數(shù)據(jù)庫(kù)的從數(shù)據(jù)庫(kù)
masterauth :當(dāng)主數(shù)據(jù)庫(kù)連接需要密碼驗(yàn)證時(shí),在這里指定
requirepass
    設(shè)置客戶端連接后進(jìn)行任何其他指定前需要使用的密碼。
    警告:因?yàn)?redis 速度相當(dāng)快, 所以在一臺(tái)比較好的服務(wù)器下,一個(gè)外部的用戶可以在一秒鐘
    進(jìn)行 150K 次的密碼嘗試, 這意味著你需要指定非常非常強(qiáng)大的密碼來(lái)防止暴力破解。
maxclients
    限制同時(shí)連接的客戶數(shù)量。當(dāng)連接數(shù)超過(guò)這個(gè)值時(shí),redis 將不再接收其他連接請(qǐng)求, 
    客戶端嘗試連接時(shí)將收到 error 信息。
maxmemory
    設(shè)置 redis 能夠使用的最大內(nèi)存。
    當(dāng)內(nèi)存滿了的時(shí)候,如果還接收到 set 命令,redis 將先嘗試剔除設(shè)置過(guò)expire信息的key,
    而不管該 key 的過(guò)期時(shí)間還沒有到達(dá)。在刪除時(shí),將按照過(guò)期時(shí)間進(jìn)行刪除,最早將要被過(guò)期的
    key 將最先被刪除。如果帶有expire 信息的key都刪光了,那么將返回錯(cuò)誤。
    這樣,redis 將不再接收寫請(qǐng)求,只接收get請(qǐng)求。 maxmemory 的設(shè)置比較適合于把 redis 
    當(dāng)作于類似 memcached 的緩存來(lái)使用。
appendonly
    默認(rèn)情況下,redis 會(huì)在后臺(tái)異步的把數(shù)據(jù)庫(kù)鏡像備份到磁盤,但是該備份是非常耗時(shí)的,
    而且備份也不能很頻繁,如果發(fā)生諸如拉閘限電、拔插頭等狀況,那么將造成比較 大范圍的數(shù)據(jù)丟失。
    所以 redis 提供了另外一種更加高效的數(shù)據(jù)庫(kù)備份及災(zāi)難恢復(fù)方式。 開啟 append only 模式
    之后,redis 會(huì)把所接收到的每一次寫操作請(qǐng)求都追加到 appendonly.aof 文件中,
    當(dāng)redis重新啟動(dòng)時(shí),會(huì)從該文件恢復(fù)出之前的狀態(tài)。但是這樣會(huì)造成 appendonly.aof文件過(guò)大,
    所以 redis 還支持了 BGREWRITEAOF 指令,對(duì) appendonly.aof 進(jìn)行重新整理。
    所以我認(rèn)為推薦生產(chǎn)環(huán)境下的做法為關(guān)閉鏡像,開啟 appendonly.aof,同時(shí)可以選擇在訪問(wèn)
    較少的時(shí)間每天對(duì) appendonly.aof 進(jìn)行重寫一次。
appendfsync
    設(shè)置對(duì) appendonly.aof 文件進(jìn)行同步的頻率。always 表示每次有寫操作都進(jìn)行同步, 
    everysec 表示對(duì)寫操作進(jìn)行累積,每秒同步一次。
    這個(gè)需要根據(jù)實(shí)際業(yè)務(wù)場(chǎng)景進(jìn)行配置
vm-enabled
    是否開啟虛擬內(nèi)存支持。因?yàn)?redis 是一個(gè)內(nèi)存數(shù)據(jù)庫(kù),而且當(dāng)內(nèi)存滿的時(shí)候,
    無(wú)法接收新的寫請(qǐng)求,所以在 redis 2.0 中,提供了虛擬內(nèi)存的支持。    
    但是需要注意的是,redis 中,所有的 key 都會(huì)放在內(nèi)存中,在內(nèi)存不夠時(shí),
    只會(huì)把 value 值放入交換區(qū)。這樣保證了雖然使用虛擬內(nèi)存,但性能基本不受影響,
    同時(shí),你需要注意的是你要把 vm-max-memory 設(shè)置到足夠來(lái)放下你的所有的 key
vm-swap-file :設(shè)置虛擬內(nèi)存的交換文件路徑
vm-max-memory
    這里設(shè)置開啟虛擬內(nèi)存之后,redis 將使用的最大物理內(nèi)存的大小。
    默認(rèn)為 0,redis 將 把他所有的能放到交換文件的都放到交換文件中,以盡量少的使用物理內(nèi)存。
    在生產(chǎn)環(huán) 境下,需要根據(jù)實(shí)際情況設(shè)置該值,最好不要使用默認(rèn)的 0
vm-page-size
    設(shè)置虛擬內(nèi)存的頁(yè)大小,如果你的 value 值比較大,比如說(shuō)你要在 value 中放置博客、
     新聞之類的所有文章內(nèi)容,就設(shè)大一點(diǎn),如果要放置的都是很小的內(nèi)容,那就設(shè)小一點(diǎn)。
vm-pages
    設(shè)置交換文件的總的 page 數(shù)量,需要注意的是,page table 信息會(huì)放在物理內(nèi)存中,
    每 8 個(gè) page 就會(huì)占據(jù) RAM 中的 1 個(gè) byte。
    總的虛擬內(nèi)存大小 = vm-page-size * vm-pages
vm-max-threads
    設(shè)置 VM IO 同時(shí)使用的線程數(shù)量。因?yàn)樵谶M(jìn)行內(nèi)存交換時(shí),對(duì)數(shù)據(jù)有編碼和解碼的過(guò)程,
    所以盡管 IO 設(shè)備在硬件上本上不能支持很多的并發(fā)讀寫,
    但是還是如果你所保存的vlaue值比較大,將該值設(shè)大一些,還是能夠提升性能的
glueoutputbuf
    把小的輸出緩存放在一起,以便能夠在一個(gè) TCP packet 中為客戶端發(fā)送多個(gè)響應(yīng),
    具體原理和真實(shí)效果我不是很清楚。所以根據(jù)注釋,你不是很確定的時(shí)候就設(shè)置成 yes
hash-max-zipmap-entries
    在 redis 2.0 中引入了 hash 數(shù)據(jù)結(jié)構(gòu)。當(dāng) hash 中包含超過(guò)指定元素個(gè)數(shù)并且最大的
    元素沒有超過(guò)臨界時(shí),hash 將以一種特殊的編碼方式(大大減少內(nèi)存使用)來(lái)存儲(chǔ),
    這里可以設(shè)置這兩個(gè)臨界值
activerehashing
    開啟之后,redis 將在每100毫秒時(shí)使用1毫秒的CPU時(shí)間來(lái)對(duì)redis的 hash 表進(jìn)行重新hash,
    可以降低內(nèi)存的使用。當(dāng)你的使用場(chǎng)景中,有非常嚴(yán)格的實(shí)時(shí)性需要,不能夠接受 Redis 
    時(shí)不時(shí)的對(duì)請(qǐng)求有 2 毫秒的延遲的話,把這項(xiàng)配置為 no。
    如果沒有這么嚴(yán)格的實(shí)時(shí)性要求,可以設(shè)置為 yes,
    以便能夠盡可能快的釋放內(nèi)存

三、數(shù)據(jù)類型及操作

3.1 strings

string 類型是二進(jìn)制安全的。意思是 redis 的 string 可以包含任何數(shù)據(jù),比如 jpg 圖片或者序 列化的對(duì)象。從內(nèi)部實(shí)現(xiàn)來(lái)看其實(shí) string 可以看作 byte 數(shù)組,最大上限是 1G 字節(jié)。</br>
常見操作

#
# set 和setnx :OK說(shuō)明操作成功;nx表示not exist
#
127.0.0.1:6380> set name laoyue
OK
127.0.0.1:6380> setnx name yueyue
(integer) 0
127.0.0.1:6380> get name
"laoyue"
127.0.0.1:6380> 
#
# setex:設(shè)置 key 對(duì)應(yīng)的值為 string 類型的 value,并指定此鍵值對(duì)應(yīng)的有效期。
#        下例表示有效期10s
#
127.0.0.1:6380> setex gender 10 male
OK
127.0.0.1:6380> get gender
"male"
127.0.0.1:6380> get gender
"male"
127.0.0.1:6380> get gender
(nil)
#
# setrange key offset value:替換value字符串的一部分
#
127.0.0.1:6380> set mail 1234567@qq.com
OK
127.0.0.1:6380> get mail
"1234567@qq.com"
127.0.0.1:6380> setrange mail 5 abc@gmail.com
(integer) 18
127.0.0.1:6380> get mail
"12345abc@gmail.com"
#
# mset key value [key value, key value...]:批量設(shè)置key value
# msetnx key value [key value, key value...]:區(qū)別是不會(huì)覆蓋已經(jīng)存在的key
#
127.0.0.1:6380> mset address smailroom phone 123456789
OK
127.0.0.1:6380> get address
"smailroom"
127.0.0.1:6380> get phone
"123456789"
127.0.0.1:6380> 
#
# get相關(guān)
# get key :根據(jù)key獲取value
# getset key value :設(shè)置 key 的值,并返回 key 的舊值。
# getrange key start end:獲取指定 key 的 value 值的子字符串。
# mget key1 key2 ...:一次獲取多個(gè) key 的值,如果對(duì)應(yīng) key 不存在,則對(duì)應(yīng)返回 nil。
#
# incr key:對(duì) key 的值做加加操作,并返回新的值。
#          注意 ,incr 一個(gè)不是 int 的 value 會(huì)返回錯(cuò)誤,
#          key 不存在時(shí)候會(huì)設(shè)置 key,并認(rèn)為原來(lái)的 value 是 0
# incrby key increment:incr是加1,incrby是加increment
# 對(duì)應(yīng)的減操作為:decr和decrby(key 不存在時(shí)候會(huì)設(shè)置 key,并認(rèn)為原來(lái)的 value 是 0)
# append key value:給指定 key 的字符串值追加 value,返回新字符串值的長(zhǎng)度。
# strlen key:取指定 key 的 value 值的長(zhǎng)度。
3.2 hashes

Redis hash是一個(gè)string類型的field和value的映射表.它的添加、刪除操作都是O(1()平均)。 hash 特別適合用于存儲(chǔ)對(duì)象。相較于將對(duì)象的每個(gè)字段存成單個(gè) string 類型。將一個(gè)對(duì)象存 儲(chǔ)在 hash 類型中會(huì)占用更少的內(nèi)存,并且可以更方便的存取整個(gè)對(duì)象。省內(nèi)存的原因是新 建一個(gè) hash 對(duì)象時(shí)開始是用 zipmap(又稱為 small hash)來(lái)存儲(chǔ)的。這個(gè) zipmap 其實(shí)并不 是 hash table,但是 zipmap 相比正常的 hash 實(shí)現(xiàn)可以節(jié)省不少 hash 本身需要的一些元數(shù)據(jù) 存儲(chǔ)開銷。盡管 zipmap 的添加,刪除,查找都是 O(n),但是由于一般對(duì)象的 field 數(shù)量都不 太多。所以使用 zipmap 也是很快的,也就是說(shuō)添加刪除平均還是 O(1)。如果 field 或者 value 的大小超出一定限制后,Redis 會(huì)在內(nèi)部自動(dòng)將 zipmap 替換成正常的 hash 實(shí)現(xiàn). 這個(gè)限制可 以在配置文件中指定
hash-max-zipmap-entries 64 #配置字段最多 64 個(gè)
hash-max-zipmap-value 512 #配置 value 最大為 512 字節(jié)</br>
常用操作

# 假如對(duì)象user有屬性:name,age,gender,address,phone。
# 現(xiàn)在將user1存在Redis中:(該對(duì)象的key取為user1)
#
# hset key field value:設(shè)置屬性field的值為value
# hsetnx key field value :如果 key 不存在,則先創(chuàng)建。如果 field 已經(jīng)存在,返回 0
# hmset key field1 value1 [field2 value2...]:批量設(shè)置
# hget key field:獲取key的指定field的值。
# hmget key field1 value1 [field2 value2...]:獲取全部指定的filed的值。
#
#
127.0.0.1:6380> hset user1 name laoyue
(integer) 1
127.0.0.1:6380> hmset user1 age 27 address beijing gender male phone 111111
OK
127.0.0.1:6380> hget user1 name
"laoyue"
127.0.0.1:6380> hmget user1 name age gender address phone
1) "laoyue"
2) "27"
3) "male"
4) "beijing"
5) "111111"
127.0.0.1:6380> 
#
# hincrby key field increment:指定的filed 加上給定值increment(可正可負(fù)),返回修改后的值
# hexists key field:測(cè)試指定 field 是否存在,返回1或0
# hlen key:返回指定 hash 的 field 數(shù)量。
# hdel key field1 [field2, field3...]:刪除一個(gè)或多個(gè)field
# hkeys key:返回 hash 的所有 field。
# hvals key :返回 hash 的所有 value。
# hgetall key:獲取某個(gè) hash 中全部的 filed 及 value。
#
127.0.0.1:6380> hincrby user1 age -2
(integer) 25
127.0.0.1:6380> hexists user1 address
(integer) 1
127.0.0.1:6380> hlen user1
(integer) 5
127.0.0.1:6380> hdel user1 age phone
(integer) 2
127.0.0.1:6380> hlen user1
(integer) 3
127.0.0.1:6380> hkeys user1
1) "name"
2) "address"
3) "gender"
127.0.0.1:6380> hvals user1
1) "laoyue"
2) "beijing"
3) "male"
127.0.0.1:6380> hgetall user1
1) "name"
2) "laoyue"
3) "address"
4) "beijing"
5) "gender"
6) "male"
127.0.0.1:6380>
3.3 lists

list 是一個(gè)鏈表結(jié)構(gòu),主要功能是 push、pop、獲取一個(gè)范圍的所有值等等,操作中 key 理 解為鏈表的名字。
Redis 的 list 類型其實(shí)就是一個(gè)每個(gè)子元素都是 string 類型的雙向鏈表。鏈表的最大長(zhǎng)度是(2 的 32 次方)。我們可以通過(guò) push,pop 操作從鏈表的頭部或者尾部添加刪除元素。這使得 list 既可以用作棧,也可以用作隊(duì)列。
有意思的是 list 的 pop 操作還有阻塞版本的,當(dāng)我們[lr]pop 一個(gè) list 對(duì)象時(shí),如果 list 是空, 或者不存在,會(huì)立即返回 nil。但是阻塞版本的 b[lr]pop 可以則可以阻塞,當(dāng)然可以加超時(shí)時(shí) 間,超時(shí)后也會(huì)返回 nil。為什么要阻塞版本的 pop 呢,主要是為了避免輪詢。舉個(gè)簡(jiǎn)單的 例子如果我們用 list 來(lái)實(shí)現(xiàn)一個(gè)工作隊(duì)列。執(zhí)行任務(wù)的 thread 可以調(diào)用阻塞版本的 pop 去獲 取任務(wù)這樣就可以避免輪詢?nèi)z查是否有任務(wù)存在。當(dāng)任務(wù)來(lái)時(shí)候工作線程可以立即返回, 也可以避免輪詢帶來(lái)的延遲。</br>
常用操作

#
# lpush key value [value, value...]:在key對(duì)應(yīng)list的頭部添加字符串元素
# rpush key value [value, value...]:在key對(duì)應(yīng)list的尾部添加字符串元素
# linsert key BEFORE|AFTER pivot value:
#                         在 key 對(duì)應(yīng) list 的特定位置之前或之后添加字符串元素
# lset key index value:設(shè)置list中指定下標(biāo)的元素值(下標(biāo)從 0 開始)
# lrem key count value:從key對(duì)應(yīng)list中刪除 count 個(gè)和 value 相同的元素。
#                       count>0 時(shí),按從頭到尾的順序刪除;
#                       count<0 時(shí),按從尾到頭的順序刪除;
#                       count=0 時(shí),刪除全部;
# ltrim key start stop:保留指定key的值范圍內(nèi)的數(shù)據(jù)
# lpop key :從 list 的頭部刪除一個(gè)元素,并返回刪除元素
# rpop key :從 list 的尾部刪除一個(gè)元素,并返回刪除元素
# rpoplpush source destination :
#           從第一個(gè)list(source)的尾部移除元素并添加到第二個(gè)list(destination)的頭部,
#           最后返回被移除的元素值;
#           整個(gè)操作是原子的.如果第一個(gè)list是空或者不存在返回nil
# lindex key index:返回key對(duì)應(yīng)list中index位置的元素
# llen key:返回key對(duì)應(yīng)list的長(zhǎng)度
#
3.4 sets

set 是集合,和我們數(shù)學(xué)中的集合概念相似,對(duì)集合的操作有添加刪除元素,有對(duì)多個(gè)集合求交并差等操作,操作中 key 理解為集合的名字。
Redis 的 set 是 string 類型的無(wú)序集合。set 元素最大可以包含(2 的 32 次方)個(gè)元素。
set 的是通過(guò) hash table 實(shí)現(xiàn)的,所以添加、刪除和查找的復(fù)雜度都是 O(1)。hash table 會(huì)隨 著添加或者刪除自動(dòng)的調(diào)整大小。需要注意的是調(diào)整 hash table 大小時(shí)候需要同步(獲取寫 鎖)會(huì)阻塞其他讀寫操作,可能不久后就會(huì)改用跳表(skip list)來(lái)實(shí)現(xiàn),跳表已經(jīng)在 sorted set 中使用了。關(guān)于 set 集合類型除了基本的添加刪除操作,其他有用的操作還包含集合的 取并集(union),交集(intersection),差集(difference)。通過(guò)這些操作可以很容易的實(shí)現(xiàn) sns 中的好友推薦和 blog的tag功能。

常用操作

#
# sadd key member [member, member...]:
#        向名稱為key的set中添加一個(gè)或多個(gè)元素;返回成功添加的元素個(gè)數(shù)
# srem key member [member, member...]:
#        刪除名稱為 key 的 set 中的元素 member;返回成功刪除的元素的個(gè)數(shù)
# smembers key:返回key對(duì)應(yīng)set的所有元素
# spop key [count]:
#        隨機(jī)返回并刪除名稱為key的set中count個(gè)元素(默認(rèn)為1)
# sdiff key [key, key...]:
#        返回所有給定 key 與第一個(gè) key 的差集
# sdiffstore destination key [key, key...]:
#        返回所有給定 key 與第一個(gè) key 的差集,并將結(jié)果存到destination中
# sinter key [key, key...]:返回所有給定 key 的交集
# sinterstore destination key [key, key...]:
#        返回所有給定 key 的交集,并將結(jié)果存到destination
# sunion key [key, key...]:返回所有給定 key 的并集
# sunionstore destination key [key, key...]:
#        返回所有給定 key 的并集,并將結(jié)果存到destination
#  smove source destination member:
#        從source set 中移除 member 并添加到destination set 中
#scard key:返回名稱為 key 的 set 的元素個(gè)數(shù)
# sismember key member:
#        測(cè)試 member 是否是名稱為 key 的 set 的元素 
#srandmember key [count]
#        隨機(jī)返回名稱為 key 的 set 的count個(gè)元素(不指定count則為1),但是不刪除元素
# 
3.5 sorted sets

sorted set 是 set 的一個(gè)升級(jí)版本,它在 set 的基礎(chǔ)上增加了一個(gè)順序?qū)傩?,這一屬性在添加 修改元素的時(shí)候可以指定,每次指定后,zset 會(huì)自動(dòng)重新按新的值調(diào)整順序??梢岳斫鉃橛?兩列的 mysql 表,一列存 value,一列存順序。操作中 key 理解為 zset 的名字。
和 set 一樣 sorted set 也是 string 類型元素的集合,不同的是每個(gè)元素都會(huì)關(guān)聯(lián)一個(gè) double 類型的 score。sorted set 的實(shí)現(xiàn)是 skip list 和 hash table 的混合體。
當(dāng)元素被添加到集合中時(shí),一個(gè)元素到 score 的映射被添加到 hash table 中,所以給定一個(gè) 元素獲取 score 的開銷是 O(1),另一個(gè) score 到元素的映射被添加到 skip list,并按照 score 排 序,所以就可以有序的獲取集合中的元素。添加,刪除操作開銷都是 O(log(N))和 skip list 的 開銷一致,redis 的 skip list 實(shí)現(xiàn)用的是雙向鏈表,這樣就可以逆序從尾部取元素。sorted set 最 經(jīng)常的使用方式應(yīng)該是作為索引來(lái)使用.我們可以把要排序的字段作為 score 存儲(chǔ),對(duì)象的 id 當(dāng)元素存儲(chǔ)。</br>
常用操作

#
# zadd key [NX|XX] [CH] [INCR] score member [score member ...]:
#      向名稱為key的zset中添加元素member,score 用于排序。
#      如果該元素已經(jīng)存在,則根據(jù) score 更新該元素的順序
# zrem key member [ member ...]
#      刪除名稱為 key 的 zset 中的元素 member
# zincrby key increment member:
#      如果在名稱為key的zset中已經(jīng)存在元素member,則該元素的 score 增加 increment;
#      否則向集合中添加該元素,其 score 的值為 increment
# zrank key member
#      返回名稱為 key 的 zset 中 member 元素的排名(按 score 從小到大排序)即下標(biāo)。
# zrevrank key member
#      返回名稱為key的zset中member元素的排名(按 score 從大到小排序)即下標(biāo)
# zrevrange key start stop [WITHSCORE]
#      返回名稱為 key 的 zset(按 score 從大到小排序)中的 index 從 start 到 end 的所有元素
# zrangebyscore key min max [WITHSCORES] [LIMIT offset count]
#      返回集合中 score 在給定區(qū)間的元素
# zcount key min max
#      返回集合中 score 在給定區(qū)間的數(shù)量
# zcard key
#      返回集合中元素個(gè)數(shù)
# zscore key member
#      返回給定元素對(duì)應(yīng)的 score
# zremrangebyrank key stat stop
#      刪除集合中排名在給定區(qū)間的元素
# zremrangebyscore key min max
#      刪除集合中score在給定區(qū)間的元素
#

四、Redis 常用命令

Redis 提供了豐富的命令(command)對(duì)數(shù)據(jù)庫(kù)和各種數(shù)據(jù)類型進(jìn)行操作,這些 command 可以在 Linux 終端使用。在編程時(shí),比如各類語(yǔ)言包,這些命令都有對(duì)應(yīng)的方法。下面將 Redis 提供的命令做一總結(jié)。

4.1 鍵值相關(guān)
#
# keys pattern:返回滿足給定 pattern 的所有 key
#
127.0.0.1:6380> keys *
1) "myset1"
2) "name"
3) "user1"
4) "mail"
5) "address"
6) "phone"
127.0.0.1:6380> keys m*
1) "myset1"
2) "mail"
127.0.0.1:6380>
#
# exists key [key, key ... ]:確認(rèn)一個(gè)或多個(gè)key 是否存在(返回存在的個(gè)數(shù))
# del key [key, key ... ]:刪除一個(gè)或多個(gè) key
# expire key seconds:設(shè)置一個(gè) key 的過(guò)期時(shí)間(單位:秒)
# move key db:將當(dāng)前數(shù)據(jù)庫(kù)中的 key 轉(zhuǎn)移到其它數(shù)據(jù)庫(kù)db中
# persist key:移除給定 key 的過(guò)期時(shí)間,就是一直有效
# randomkey:隨機(jī)返回所有keys中的一個(gè) key
# rename key newkey:重命名 key
# type key:返回值的類型
#
4.2 服務(wù)器相關(guān)
# ping :測(cè)試連接是否存活
# echo message:在命令行打印一些內(nèi)容
# select index:
#      選擇數(shù)據(jù)庫(kù)。
#      Redis 數(shù)據(jù)庫(kù)編號(hào)從 0~15,我們可以選擇任意一個(gè)數(shù)據(jù)庫(kù)來(lái)進(jìn)行數(shù)據(jù)的存取。
# quit:退出連接
# dbsize:返回當(dāng)前數(shù)據(jù)庫(kù)中 key 的數(shù)目
# info [session]:獲取服務(wù)器的信息和統(tǒng)計(jì)。
# monitor:實(shí)時(shí)轉(zhuǎn)儲(chǔ)收到的請(qǐng)求。
# config get 配置項(xiàng):獲取配置項(xiàng)的信息
# flushdb :刪除當(dāng)前選擇數(shù)據(jù)庫(kù)中的所有 key。
# flushall:刪除所有數(shù)據(jù)庫(kù)中的所有 key。
#
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • redis入門指南第二版讀書筆記 作者:李子驊 讀者:張劍 Redis是以高性能著稱的內(nèi)存數(shù)據(jù)庫(kù),通常用來(lái)做緩存服...
    cajan2閱讀 788評(píng)論 0 3
  • 網(wǎng)站推薦 redis在線嘗試與教程 redis中文官網(wǎng) 《Redis入門指南》 《Redis 設(shè)計(jì)與實(shí)現(xiàn)》 Red...
    treelake閱讀 67,002評(píng)論 0 29
  • 其實(shí)現(xiàn)在想想就是有點(diǎn)挺累的,就是有點(diǎn)不想面對(duì)現(xiàn)實(shí),因?yàn)楝F(xiàn)在自己還有后路可以逃避,所以就抓住了這樣小小的感冒可以放縱...
    阿冼Lou閱讀 178評(píng)論 0 0
  • 愛比奇跡還要美 只有做了父母,才開始懂得父母或者大人世界的無(wú)奈。 生活需要感恩
    Sophie菲哥閱讀 192評(píng)論 0 0
  • 有時(shí)候隨便走在路上,發(fā)現(xiàn)一個(gè)美女值得我回眸時(shí),我會(huì)想是什么打造了一個(gè)這樣的美女。當(dāng)我看到那個(gè)帥氣的持槍教官站在我們...
    哆啦A夢(mèng)暗戀紅雨閱讀 990評(píng)論 12 22