寫於2014年7月,redis2.8
Redis簡介
Redis是什麼?
Redis是一個開源的使用ANSI C語言編寫,支持網絡,基於內存亦可持久化,分佈式的key-value數據庫,並提供多種語言的API 。特點是高性能,持久存儲,適應高併發的應用場景。目前已被許多公司採用,稍大點的互聯網公司幾乎都用了,比如:Github、新浪微博、京東等等。
Redis特性
速度快
Redis使用標準C編寫實現,而且將所有數據加載到內存中,所以速度非常快。官方提供的數據表明,在一個普通的Linux機器上,Redis讀寫速度分別達到81000/s和110000/s。
持久化
通常,Redis將數據存儲於內存中。通過兩種方式可以實現數據持久化:使用截圖的方式,將內存中的數據不斷寫入磁盤;或使用類似MySQL的日誌方式,記錄每次更新的日誌。前者性能較高,但是可能會引起一定程度的數據丟失;後者相反。
數據結構
可以將Redis看做“數據結構服務器”。目前,Redis支持5種數據結構。
自動操作
Redis對不同數據類型的操作是自動的,因此設置或增加key值,從一個集合中增加或刪除一個元素都能安全的操作。
提供API的語言
Redis支持多種語言,諸如C、C++、C#、Ruby、 Python、 PHP、 Erlang、 Tcl、 Perl、 Lua、 Java、 Scala、 Clojure、Go等等。
主-從複製
Redis支持簡單而快速的主-從複製。官方提供了一個數據,Slave在21秒即完成了對Amazon網站10G key set的複製。
集羣
從3.0版本開始支持集羣,可以實現多主、多從。目前處於beta階段,還沒有客戶端支持此功能。
Redis數據類型
Redis並不是簡單的key-value存儲,實際上它是一個數據結構服務器,支持不同類型的值。也就是說,你不必僅僅把字符串當作鍵所指向的值。下列這些數據類型都可作爲值類型,常用的有5種。
string(字符串)
list(雙向鏈表)
set(無序集合)
zset(有序集合)
hash(hash表)
Redis 鍵(key)
可以用任何二進制序列作爲key值,從形如”foo”的簡單字符串到一個JPEG文件的內容都可以。空字符串也是有效key值。
關於key的幾條規則:
不用太長的鍵值。例如1024字節的鍵值就不好,不僅因爲消耗內存,而且在數據中查找這類鍵值的計算成本很高。
太短的鍵值通常也不是好主意,如果你要用“u:1000:pwd”來代替“user:1000:password”,這沒有什麼問題,但後者更易閱讀,並且由此增加的空間消耗相對於key object和value object本身來說很小。當然,短的鍵值會節省一點兒空間。
最好堅持一種模式。例如:“object-type:id:field”就是個不錯的注意,像這樣“user:1000:password”。Redis key 相關命令
exits key 測試指定key是否存在,返回1表示存在,0不存在
del key1 key2 ….keyN 刪除給定key,返回刪除key的數目,0表示給定key都不存在
type key 返回給定key的value值類型。返回 none 表示不存在key,string字符類型,list 鏈表類型 set無序集合類型…
keys pattern 返回匹配指定模式的所有key
randomkey 返回從當前數據庫中隨機選擇的一個key,如果數據庫是空的,返回空串
rename oldkey newkey 原子的重命名一個key,如果newkey存在,將會被覆蓋,返回1表示成功,0失敗。可能是oldkey不存在或者和newkey相同
dbsize 返回當前數據庫的key數量
expire key seconds 爲key指定過期時間,單位是秒。返回1成功,0表示key已經設置過過期時間或者不存在
select db-index 通過索引選擇數據庫,默認連接的數據庫所有是0,默認數據庫數是16個。返回1表示成功,0失敗
move key db-index 將key從當前數據庫移動到指定數據庫。返回1成功。0 如果key不存在,或者已經在指定數據庫中
flushdb 刪除當前數據庫中所有key,此方法不會失敗。慎用
flushall 刪除所有數據庫中的所有key,此方法不會失敗。更加慎用
string類型
特點:
string是redis最基本的類型,而且string類型是二進制安全的。意思是redis的string可以包含任何數據。比如jpeg圖片或者序列化的對象。
從內部實現來看其實string可以看作byte數組,最大上限是1G字節。
string類型的值也可視爲integer,從而可以讓“incr”命令族操作。
在list、set和zset中包含的獨立的元素類型都是string類型。應用場景:
String是最常用的一種數據類型,普通的key/value存儲。如果你只用這種類型,Redis就像一個可以持久化的memcached服務器。當然redis對string類型的操作比memcached多很多啊。string數據類型常用命令
set key value 設置key對應的值爲string類型的value,返回1表示成功,0失敗
setnx key value 同上,如果key已經存在,返回0 。nx 是not exist的意思
get key 獲取key對應的string值,如果key不存在返回nil
getset key value 原子的設置key的值,並返回key的舊值。如果key不存在返回nil
mget key1 key2 … keyN 一次獲取多個key的值,如果對應key不存在,則對應返回nil。
mset key1 value1 … keyN valueN 一次設置多個key的值,成功返回1表示所有的值都設置了,失敗返回0表示沒有任何值被設置
msetnx key1 value1 … keyN valueN 同上,但是不會覆蓋已經存在的key
incr key
對key的值做加加操作,並返回新的值。注意incr一個不是int的value會返回錯誤,incr一個不存在的key,則設置key爲1decr key 同上,但是做的是減減操作,decr一個不存在key,則設置key爲-1
incrby key integer 同incr,加指定值 ,key不存在時候會設置key,並認爲原來的value是 0
decrby key integer 同decr,減指定值。decrby完全是爲了可讀性,我們完全可以通過incrby一個負值來實現同樣效果,反之一樣。
append key value 給指定key的字符串值追加value,返回新字符串值的長度。
List類型
特點:
redis的list類型其實就是一個每個子元素都是string類型的雙向鏈表。這意味着即使在一個list中有數百萬個元素,在頭部或尾部添加一個元素的操作,其時間複雜度也是常數級別的。可以通過push,pop操作從鏈表的頭部或者尾部添加刪除元素。這使得list既可以用作棧,也可以用作隊列list的最大長度是2^32-1個元素
應用場景
Redis list應用場景非常多,也是Redis最重要的數據結構之一,比如微博的關注列表,粉絲列表等都可以用Redis的list結構來實現;博客實現中,可爲每篇日誌設置一個list,在該list中推入進博客評論;也可以使用redis list實現消息隊列。
List數據類型常用命令
lpush key string 在key對應list的頭部添加字符串元素,返回1表示成功,0表示key存在且不是list類型
rpush key string 同上,在尾部添加
llen key 返回key對應list的長度,key不存在返回0,如果key對應類型不是list返回錯誤
lrange key start end 返回指定區間內的元素,下標從0開始,負值表示從後面計算,-1表示倒數第一個元素 ,key不存在返回空列表
ltrim key start end 截取list,保留指定區間內元素,成功返回1,key不存在返回錯誤
lset key index value 設置list中指定下標的元素值,成功返回1,key或者下標不存在返回錯誤
lrem key count value 從key對應list中刪除count個和value相同的元素。count爲0時候刪除全部
lpop key 從list的頭部刪除元素,並返回刪除元素。如果key對應list不存在或者是空返回nil,如果key對應值不是list返回錯誤
rpop 同上,但是從尾部刪除
blpop key1…keyN timeout 從左到右掃描返回對第一個非空list進行lpop操作並返回,比如blpop list1 list2 list3 0,如果list不存在list2,list3都是非空則對list2做lpop並返回從list2中刪除的元素。如果所有的list都是空或不存在,則會阻塞timeout秒,timeout爲0表示一直阻塞。當阻塞時,如果有client對key1…keyN中的任意key進行push操作,則第一在這個key上被阻塞的client會立即返回。如果超時發生,則返回nil。有點像unix的select或者poll
brpop 同blpop,一個是從頭部刪除一個是從尾部刪除
rpoplpush srckey destkey 從srckey對應list的尾部移除元素並添加到destkey對應list的頭部,最後返回被移除的元素值,整個操作是原子的.如果srckey是空或者不存在返回nil
Set 類型
特點
set就是redis string的無序集合,不允許有重複元素
set的最大元素數是2^32-1
對set的操作還有交集、並集、差集等應用場景
Set對外提供的功能與list類似,當你需要存儲一個列表數據,又不希望出現重複數據時,set 是一個很好的選擇,並且set提供了判斷某個成員是否在一個set集合內的接口,這個也是list所不能提供的。可以用Redis set結構實現SNS中的好友推薦和blog的tag功能。
Set 類型常用命令
sadd key member 添加一個string元素到,key對應的set集合中,成功返回1,如果元素以及在集合中返回0,key對應的set不存在返回錯誤
srem key member
從key對應set中移除給定元素,成功返回1,如果member在集合中不存在或者key不存在返回0,如果key對應的不是set類型的值返回錯誤spop key 刪除並返回key對應set中隨機的一個元素, set是空或者key不存在返回nil
srandmember key 同spop,隨機取set中的一個元素,但是不刪除元素
smove srckey dstkey member
從srckey對應set中移除member並添加到dstkey對應set中,整個操作是原子的。scard key 返回set的元素個數,如果set是空或者key不存在返回0
sismember key member 判斷member是否在set中,存在返回1
sinter key1 key2…keyN 返回所有給定key的交集
sinterstore dstkey key1…keyN 同sinter,但是會同時將交集存到dstkey下
sunion key1 key2…keyN 返回所有給定key的並集
sunionstore dstkey key1…keyN 同sunion,並同時保存並集到dstkey下
sdiff key1 key2…keyN 返回key1與所有key的不同元素
sdiffstore dstkey key1…keyN 同sdiff,並同時保存差集到dstkey下
smembers key 返回key對應set的所有元素,結果是無序的
Sorted set 類型
特點
Sorted set也是string類型元素的集合,不同的是每個元素都會關聯一個double類型的score。有序集合是通過一個dual-ported 數據結構實現的,它包含一個精簡的有序列表和一個hash table,因此添加一個元素的時間複雜度是O(log(N))
Sorted set的最大元素數是2^32-1
對於已經有序的zset,仍然可以使用sort命令,通過指定asc|desc參數對其進行排序(但這次服務器要耗費CPU了)應用場景
當你需要一個有序的並且不重複的集合列表,那麼可以選擇sorted set數據結構;使用sorted set甚至可以構建有優先級的隊列系統;排行榜應用,取TOP N操作。Sorted set 類型常用命令
zadd key score member 添加元素到集合,元素在集合中存在則更新對應score
zrem key member 刪除指定元素,1表示成功,如果元素不存在返回0
zincrby key incr member 增加對應member的score值,然後移動元素並保持skip
list保持有序。返回更新後的score值zrank key member 返回指定元素在集合中的排名(下標),集合中元素是按score從小到大排序的
zrevrank key member 同上,但是集合中元素是按score從大到小排序
zrange key start end 從集合中去指定區間的元素。返回的是有序結果
zrevrange key start end 同上,返回結果是按score逆序的
zrangebyscore key min max 返回集合中score在給定區間的元素
zcount key min max 返回集合中score在給定區間的數量
zcard key 返回集合中元素個數
zscore key element 返回給定元素對應的score
zremrangebyrank key min max 刪除集合中排名在給定區間的元素
zremrangebyscore key min max 刪除集合中score在給定區間的元素
Hash 類型
特點
redis hash是一個string類型的field和value的映射表。它的添加,刪除操作都是O(1) 。hash特別適合用於存儲對象。
將一個對象存儲在hash類型中會佔用更少的內存,並且可以更方便的存取整個對象。
在Hash中可以只保存有限的幾個“域”,而不是將所有的“域”作爲key,這可以節省內存應用場景
比如,我們存儲供應商酒店價格的時候可以採取此結構,用酒店編碼作爲Key,RatePlan+RoomType作爲Filed,價格信息作爲Value。
Hash類型常用命令
hset key field value 設置hash field爲指定值,如果key不存在,則先創建
hget key field 獲取指定的hash field
hmget key filed1….fieldN 獲取全部指定的hash filed
hmset key filed1 value1 … filedN valueN 同時設置hash的多個field
hincrby key field integer 將指定的hash filed 加上給定值
hexists key field 測試指定field是否存在
hdel key field 刪除指定的hash field
hlen key 返回指定hash的field數量
hkeys key 返回hash的所有field
hvals key 返回hash的所有value
hgetall 返回hash的所有filed和value
Redis排序
Redis支持對list,set和sorted set元素的排序。排序命令是sort。
命令格式如下
SORT key [BY pattern] [LIMIT start count] [GET pattern] [ASC|DESC] [ALPHA] [STORE dstkey]
例如:
Redis客戶端
Hiredis is the official C client. Support for the whole command set, pipelining, event driven programming.
其他各語言、各種客戶端由不同的人或者組織參考官方客戶端實現了部分或者全部功能,又根據語言特性增加了新的功能,使用時需要精心選擇。如Go語言就有如下客戶端
- Go gosexy/redis客戶端示例
實例
普通版解碼過程中,需要查詢或者插入數據庫信息,大量併發查詢導致查詢數據庫慢,而且嚴重影響數據庫在其他方面的響應時間。普通版的LOG將會很多,可能達到日增量千萬LOG以上,對數據庫的查詢將會達到數億以上。
爲減少解碼的複雜度,對redis進行了封裝,只需要調用相應的API即可。下面的測試結果是隻選了其中的一種查詢進行測試。測試的查詢相當於數據庫裏的查詢:select t.cnname,t.code_id from data_type_def t where t.group_name=’USER_EVENT’ and t.enname=’app_call_connect_success’;
Redis Vs memcached
下面的內容是來自Redis作者在stackoverflow上的一個回答,對應的問題是《Is memcached a dinosaur in comparison to Redis?》
沒有必要過於關注性能,因爲二者的性能都已經足夠高了。由於Redis只使用單核,而Memcached可以使用多核,所以二者比較起來,平均每一個核上,Redis在存儲小數據時比Memcached性能更高。而在100k以上的數據中,Memcached性能要高於Redis。雖然Redis最近也在存儲大數據的性能上進行優化,但是比起Memcached,還是稍有遜色。說了這麼多,結論是,無論你使用哪一個,每秒處理請求的次數都不會成爲瓶頸。
在內存使用效率上,如果使用簡單的key-value存儲,Memcached的內存利用率更高。而如果Redis採用hash結構來做key-value存儲,由於其組合式的壓縮,其內存利用率會高於Memcached。當然,這和你的應用場景和數據特性有關。
如果你對數據持久化和數據同步有所要求,那麼推薦你選擇Redis。因爲這兩個特性Memcached都不具備。即使你只是希望在升級或者重啓系統後緩存數據不會丟失,選擇Redis也是明智的。
當然,最後還得說到你的具體應用需求。Redis相比Memcached來說,擁有更多的數據結構,並支持更豐富的數據操作。通常在Memcached裏,你需要將數據拿到客戶端來進行類似的修改再set回去。這大大增加了網絡IO的次數和數據體積。在Redis中,這些複雜的操作通常和一般的GET/SET一樣高效。所以,如果你需要緩存能夠支持更復雜的結構和操作,那麼Redis會是不錯的選擇。
參考資料
Redis官網 http://redis.io/
Redis命令參考 http://redis.readthedocs.org/en/latest/index.html
Redis數據庫結構設計 http://blog.nosqlfan.com/html/3476.html
十五分鐘介紹Redis數據結構 http://blog.nosqlfan.com/html/3202.html
使用Redis實現LBS的應用 http://www.qixing318.com/article/4086427961.html