redis入門指南第二版讀書筆記
作者:李子驊
讀者:張劍
Redis是以高性能著稱的內(nèi)存數(shù)據(jù)庫贼急,通常用來做緩存服務(wù)器涝缝。通常人們把它當(dāng)作memcached的替代品漓帚。
同時圍繞Redis也形成了很多產(chǎn)品工具鏈奔坟,Redis的命令也成了一種協(xié)議识藤,有些模仿者使用同樣的命令但是在某些方面有所側(cè)重。
通過replication/persistentce和client-side sharding等特性祷蝌,用戶可以很方便地將Redis擴展成數(shù)百GB數(shù)據(jù)每秒處理上百次請求的系統(tǒng)茅撞。
Redis的5種數(shù)據(jù)結(jié)構(gòu)
我們把Redis歸類為內(nèi)存NOSQL Key—Value數(shù)據(jù)庫。
Redis可以存儲key與五種不同類型的value巨朦。
Value的五種類型分別是String米丘,List,Set糊啡,HashSet拄查,Zset。
特別說明:
String? ? 中存放的是一個元素棚蓄,可改變或追加其內(nèi)容(json對象可以壓縮為二進制字符串保存)
List Set? 中存放的是一組元素堕扶,List以雙向鏈表方式存儲元素,Set是無序不可重復(fù)的元素集合
Hash? ? ? 中存放的是一組key-value元素梭依,可看成Map的集合
Sorted Set 中存放的是一組元素稍算,不同的是每個元素都會關(guān)聯(lián)一個double類型的score
1.簡單類型? String
get,set役拴,del
2.鏈表類型? List? 可重復(fù) 有序
lpush和rpush? 加入到list的頭和尾
lpop和rpop? ? 從list的頭和尾出棧
lindex? ? ? ? 根據(jù)指定位置獲取item
lrange? ? ? ? 獲取某個范圍內(nèi)的items
eg:
lrange list-key 0 -1? ? 取出list-key中的所有values
利用List可以有幾種變化邪蛔,比如可以當(dāng)作堆棧先進后出,也可以當(dāng)作隊列先進先出
lpush和lpop結(jié)合使用就是堆棧
lpush和rpop結(jié)合使用就是隊列
3.Set類型? Set? ? 不可重復(fù) 無序
sadd? ? ? ? ? 添加元素
smembers? ? ? 返回所有元素
sismember? ? ? 查看元素是否在set中
srem? ? ? ? ? 如果存在扎狱,則刪除該元素
說明:
以上3種類型存放的都是元素
4.Hash 類型? HashSet? 存放 key-value 組
hset? ? ? ? ? 在Hash表中存放key-value
hget? ? ? ? ? 在Hash表中根據(jù)指定key獲取value
hgetall? ? ? 返回Hash表中的所有key-value組
hdel? ? ? ? ? 如果存在侧到,根據(jù)key刪除value
eg:
可以一次性設(shè)置多個key-value組
hset hash_set_demo1 sub-key1 value1 sub-key2 value2
hget hash_set_demo1 sub-key1
hgetall hash_set_demo1
hdel hash_set_demo1 sub-key2
5.Sorted Sets類型? ? zset 排序的Set
zset-key? ? ? zset
element? ? ? score
Jack? ? ? ? 80
Cooper? ? ? 100
zadd? ? ? ? ? 添加一個元素到zset中
zrange? ? ? ? 從zset中獲取排序之后的多個元素
zrangebyscore? 獲得按分數(shù)排序后的元素
zrem? ? ? ? ? 如果存在,則從zset中刪除元素
eg:
zadd zset-key 60 Jack 80 Cooper 100 David
127.0.0.1:6379> zrange zset-key 0 -1 withscores
1) "Jack"
2) "60"
3) "Cooper"
4) "80"
5) "David"
6) "100"
127.0.0.1:6379> zrange zset-key 0 -1
1) "Jack"
2) "Cooper"
3) "David"
127.0.0.1:6379> zrangebyscore zset-key 85 100 withscores
1) "David"
2) "100"
127.0.0.1:6379> zrem zset-key Jack
(integer) 1
127.0.0.1:6379> zrem zset-key Cooper
(integer) 0
127.0.0.1:6379> zrange zset-key 0 -1 withscores
1) "David"
2) "100"
Redis的核心內(nèi)容
1.? 5種數(shù)據(jù)類型的核心命令
String類型
存放3種類型的value
字節(jié)(數(shù)組)值
整數(shù)
浮點數(shù)
說明:
整數(shù)有自增和自減操作
incr/decr? 整數(shù)自加1(自減1)
incrby/decrby key byNum? 整數(shù)自增(自減)指定值byNum
incrbyfloat key amount? ? 浮點數(shù)自增指定值amount
List類型? 棧和隊列類型淤击,允許兩頭進行出棧和入棧
lpush和rpush? 加入到list的頭和尾
lpop和rpop? ? 從list的頭和尾出棧
lindex? ? ? ? 根據(jù)指定位置獲取item
lrange key start end? ? ? 獲取某個范圍內(nèi)的items
ltrim? key start end? ? ? 剔除list中索引不在start ~ end 之間的元素
Set類型? ? 存放無序不可重復(fù)的元素
sadd key item? 添加元素
srem key item? 刪除元素
sismember key item? 查看item是否在set中
scard key? ? ? 返回set中元素數(shù)量
smembers? ? ? 返回set中所有元素
srandmember? key [count]? 從set中返回一個或count個隨機元素
spop key? ? ? 從set中刪除并返回一個隨機元素
smove? source-key dest-key? item? 將item元素從source-key 移到dest-key
兩個set類型的操作
sdiff? key1 [key2...]? 返回在key1中而不再其他key中的元素
sdiffstore
sinter key1 [key2...]? 返回所有key都有的元素
sinterstore
sunion key1 [key2...]? 返回多個key中的并集
sunionstore
Hash類型? 存放若干key-value匠抗,看做存放map的集合
hmget hash key [key...]? ? 從hash中根據(jù)多個key獲取對應(yīng)的value
hmset hash key value [key value ...]? 在hash中設(shè)置多個key及其對應(yīng)的value
hdel? hash key [key...]? ? 從hash中根據(jù)key刪除
hlen? hash key? ? ? ? ? ? ? 返回hash中的map元素數(shù)量
hexists? hash key? ? 對應(yīng)的key是否存在hash中
hkeys? hash? ? ? ? ? 獲取hash中所有的key
hvals? hash? ? ? ? ? 獲取hash中所有的value
hgetall hash? ? ? ? ? 獲取hash中所有的key-value鍵值對
hincrby hash key? ? ? 如果key中存儲的value是int,則value+1
Sorted Set類型? ? zset? 存放排序的元素
zadd key-name score member [score member ...] 增加一個元素污抬,并給元素一個對應(yīng)的score
zrem key-name member [member ...]? 刪除一個或多個元素
zcard key-name? 返回zset中元素數(shù)量
zincrby key-name incrment member
zcount key-name min max 返回score在min與max之間的元素汞贸,保護member 與其 對應(yīng)的 value
zrank key-name member? 返回member元素在zset中的位置
zscore key-name? ? ? ? 返回zset中所有元素數(shù)量
zrange key-name start stop? 返回score在min與max之間的元素
2.? 事務(wù)
和一般的關(guān)系數(shù)據(jù)庫類似,redis也支持事務(wù)印机。
但是redis的事務(wù)還是有所區(qū)別:
a.不能回滾矢腻,
b.即使其中一個命令有了運行錯誤(非語法錯誤),也不會影響到同一事務(wù)中其他命令的執(zhí)行射赛。
c.事務(wù)中的每個命令的執(zhí)行結(jié)果都是最后一起返回的多柑,所以無法將前一條命令的結(jié)果作為下一條命令的參數(shù)
結(jié)合WATCH命令
WATCH 命令可以監(jiān)控一個或多個鍵,一旦其中有一個鍵被修改(或刪除)楣责,之后的事務(wù)就不會執(zhí)行竣灌。監(jiān)控一直持續(xù)到 EXEC 命令
redis> MULTI
OK
redis> SADD "user:1:following" 2
QUEUED
redis> SADD "user:2:followers" 1
QUEUED
redis> EXEC
1) (integer) 1
2) (integer) 1
3.過期時間
過期時間經(jīng)常在訪問頻率控制和實現(xiàn)緩存中使用
EXPIRE session:29e3d 900
4.消息通知
利用消息通知聂沙,可以實現(xiàn)任務(wù)隊列,優(yōu)先級隊列初嘹,發(fā)布/訂閱模式
這里就用到了list的阻塞彈出命令及汉,不過下面沒有提到在消息通知和任務(wù)隊列里面常用的彈出推入命令(RPOPLPUSH)。
a.任務(wù)隊列
BRPOP命令和RPOP命令相似屯烦,唯一的區(qū)別是當(dāng)列表中沒有元素時BRPOP命令會一直阻塞住連接坷随,直到有新元素加入。
示例代碼:
loop
# 如果任務(wù)隊列中沒有新任務(wù)驻龟,BRPOP 命令會一直阻塞温眉,不會執(zhí)行 execute()。
$task = BRPOP queue, 0
# 返回值是一個數(shù)組(見下介紹)迅脐,數(shù)組第二個元素是我們需要的任務(wù)。
execute($task[1])
b.優(yōu)先級隊列
BRPOP 命令可以同時接收多個鍵豪嗽,其完整的命令格式為 BLPOP key [key …] timeout谴蔑,如 BLPOP queue:1 queue:2 0。意義是同時檢測多個鍵龟梦,如果所有鍵都沒有元素則阻塞隐锭,如果其中有一個鍵有元素則會從該鍵中彈出元素。
示例代碼:
loop
$task =BRPOP queue:confirmation.email,
queue:notification.email, 0
execute($task[1])
這時一旦發(fā)送確認郵件的任務(wù)被加入到 queue:confirmation.email 隊列中计贰,無論queue: notification.email還有多少任務(wù)钦睡,消費者都會優(yōu)先完成發(fā)送確認郵件的任務(wù)。
c.發(fā)布/訂閱模式
通過兩個命令實現(xiàn)發(fā)布/訂閱模式
PUBLISH
SUBSCRIBE
5.管道pipeline
管道和事務(wù)類似躁倒,不過管道的主要目的是為了減少來回通信次數(shù)荞怒,也就節(jié)省了來回的通信時間。
Redis 的底層通信協(xié)議對管道(pipelining)提供了支持秧秉。通過管道可以一次性發(fā)送多條命令并在執(zhí)行完后一次性將結(jié)果返回褐桌,當(dāng)一組命令中每條命令都不依賴于之前命令的執(zhí)行結(jié)果時就可以將這組命令一起通過管道發(fā)出。管道通過減少客戶端與 Redis 的通信次數(shù)來實現(xiàn)降低往返時延累計值的目的
6.排序
ALPHA參數(shù)
LIMIT參數(shù)
DESC/ASC參數(shù)
by參數(shù)
get參數(shù)
下面是sort在各種數(shù)據(jù)結(jié)構(gòu)的使用實例
$array_tag_ruby_posts = array(
'2', '11', '6', '12'
// , '26', '28'
);
$redis->del('tag:ruby:posts');
$redis->lpush('tag:ruby:posts', $array_tag_ruby_posts);
echo '----------sort1--------';
echo '
';
print_r($redis->lrange('tag:ruby:posts', 0, -1));
$option1_sort = array(
//? ? 'by' => 'weight_*',
//? ? 'get' => array('value_*', '#'),
'sort' => 'desc',
//? ? 'alpha' => true,
'limit' => array(1, 3),
'store' => 'result');
$redis->sort('tag:ruby:posts', $option1_sort);
echo '
';
//print_r($redis->type('result'));
print_r($redis->lrange('result', 0, -1));
echo '
----------sort2--------
';
$array_sortbylist = array(2, 1, 3);
$redis->del('sortbylist');
$redis->lpush('sortbylist', $array_sortbylist);
print_r($redis->lrange('sortbylist', 0, -1));
echo '
';
$redis->set('itemscore:1', 50);
$redis->set('itemscore:2', 100);
$redis->set('itemscore:3', -10);
$option2_sort = array(
'by' => 'itemscore:*',
//? ? 'get' => array('value_*', '#'),
'sort' => 'desc',
//? ? 'alpha' => true,
//? ? 'limit' => array(1, 3),
'store' => 'result2'
);
$redis->sort('sortbylist', $option2_sort);
print_r($redis->lrange('result2', 0, -1));
echo '
----------sort3--------
';
$redis->del(array('post:2', 'post:6', 'post:11', 'post:12', 'post:26', 'post:28'));
$post2 = array(
'title' => 'Windows 8 app designs',
'time' => '1352620100'
);
$post6 = array(
'title' => 'RethinkDB - An open-source distributed database built with love',
'time' => '1352620000'
);
$post11 = array(
'title' => 'The Nature of Ruby',
'time' => '1352619200'
);
$post12 = array(
'title' => 'Uses for cURL',
'time' => '1352619600'
);
$redis->hmset('post:2',$post2);
$redis->hmset('post:6',$post6);
$redis->hmset('post:11',$post11);
$redis->hmset('post:12',$post12);
$option3_sort = array(
'by' => 'post:*->time',
'get' => array('post:*->title','post:*->time', '#'),
'sort' => 'desc',
//? ? 'alpha' => true,
//? ? 'limit' => array(1, 3),
'store' => 'result3'
);
$redis->sort('tag:ruby:posts',$option3_sort);
print_r($redis->lrange('result3',0,-1));
7.節(jié)省空間
a.命名簡化
b.內(nèi)部編碼優(yōu)化
本書里面沒有的內(nèi)容
1.Redis HyperLogLog起始版本:2.8.9
Redis HyperLogLog是用來做基數(shù)統(tǒng)計的算法象迎。優(yōu)點是荧嵌,在輸入元素的數(shù)量或者體積非常非常大時鸿染,計算基數(shù)所需的空間總是固定的衷咽、并且是很小的。
在 Redis 里面博肋,每個 HyperLogLog 鍵只需要花費 12 KB 內(nèi)存汪厨,就可以計算接近 2^64 個不同元素的基 數(shù)赃春。這和計算基數(shù)時,元素越多耗費內(nèi)存就越多的集合形成鮮明對比劫乱。
注:因為HyperLogLog只會根據(jù)輸入元素來計算基數(shù)聘鳞,而不會存儲輸入元素本身薄辅,因此不會返回輸入的各個元素。
基數(shù)是什么抠璃? 對于["abc", "abc", "2", "3"]站楚,基數(shù)是["abc", "2", "3"],個數(shù)是3.
HyperLogLog通過下面三個命令:
pfadd key ele [ele2 ...]:添加指定元素到HyperLogLog中搏嗡,
pfcount key: 返回給定HyperLogLog的基數(shù)估算值
pfmerge destkey srckey [srckey2....]:講多個HyperLogLog合并到一個第一個HyperLogLog中