




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、Redis學(xué)習(xí)總結(jié)一、 redis 環(huán)境搭建1.簡介 redis是一個(gè)開源的key-value數(shù)據(jù)庫。它又經(jīng)常被認(rèn)為是一個(gè)數(shù)據(jù)結(jié)構(gòu)服務(wù)器。因?yàn)樗膙alue不僅包括基本的string類型還有 list,set ,sorted set和hash類型。當(dāng)然這些類型的元素也都是string類型。也就是說list,set這些集合類型也只能包含string 類型。你可以在這些類型上做很多原子性的操作。比如對(duì)一個(gè)字符value追加字符串(APPEND命令)。加加或者減減一個(gè)數(shù)字字符串(INCR命令,當(dāng) 然是按整數(shù)處理的).可以對(duì)lis
2、t類型進(jìn)行push,或者pop元素操作(可以模擬棧和隊(duì)列)。對(duì)于set類型可以進(jìn)行一些集合相關(guān)操作 (intersection union difference)。memcache也有類似與+,-的命令。不過memcache的 value只包括string類型。遠(yuǎn)沒有redis的value類型豐富。和memcahe一樣為了性能。redis的數(shù)據(jù)通常都是放到內(nèi)存中的。當(dāng)然 redis可以每間隔一定時(shí)間將內(nèi)存中數(shù)據(jù)寫入到磁盤以防止數(shù)據(jù)丟失。redis也支持主從復(fù)制機(jī)制(master-slave replication)。redis的其他特性包括簡單的事務(wù)支持和 發(fā)布訂閱(pub/sub)通道功能,
3、而且redis配置管理非常簡單。還有各種語言版本的開源客戶端類庫。2.安裝下載地址:2.0目前是最新穩(wěn)定版可以在linux下運(yùn)行如下命令進(jìn)行安裝$ tar xzf redis-2.0.4.tar.gz$ cd redis-2.0.4$ makemake完后 redis-2.0.4目錄下會(huì)出現(xiàn)編譯后的redis服務(wù)程序redis-server,還有用于測(cè)試的客戶端程序redis-cli下面啟動(dòng)redis服務(wù).$./redis-server注意這種方式啟動(dòng)redis 使用的是默認(rèn)配置。也可以通過啟動(dòng)參數(shù)告訴redis使用指定配置文件使用下面命令啟動(dòng).$ ./redis-server redis.c
4、onfredis.conf是一個(gè)默認(rèn)的配置文件。我們可以根據(jù)需要使用自己的配置文件。啟動(dòng)redis服務(wù)進(jìn)程后,就可以使用測(cè)試客戶端程序redis-cli和redis服務(wù)交互了.比如$ ./redis-cliredis> set foo barOKredis> get foo"bar"這里演示了get和set命令操作簡單類型value的例子。foo是key ,bar是個(gè)string類型的value沒linux的可以通過這個(gè)在線的來練習(xí),當(dāng)然在線版的很多管理相關(guān)的命令是不支持的。http:/try.redis-3.java客戶端hello,world客戶端jar包地
5、址 1.2.6。最新版2.0的還沒release在eclipse中新建一個(gè)java項(xiàng)目,然后添加jredis包引用。下面是個(gè)hello,world程序package jredisStudy;import org.jredis.*;import org.jredis.ri.alphazero.JRedisClient;public class App public static void main(String args) try JRedis jr = new JRedisClient("5",6379); /redis服務(wù)地址和端口號(hào) String
6、 key = "mKey" jr.set(key, "hello,redis!"); String v = new String(jr.get(key); String k2 = "count" jr.incr(k2); jr.incr(k2); System.out.println(v); System.out.println(new String(jr.get(k2); catch (Exception e) / TODO: handle exception 好了redis環(huán)境已經(jīng)搭建好了。后面會(huì)寫寫redis的各種類型和類型相關(guān)
7、的命令和一些具體的應(yīng)用場(chǎng)景二、 redis 數(shù)據(jù)類型本文介紹下redis支持的各種數(shù)據(jù)類型包括string,list ,set ,sorted set 和hashTechnorati 標(biāo)簽: redis cache list 存儲(chǔ)1. keysredis本質(zhì)上一個(gè)key-value db,所以我們首先來看看他的key.首先key也是字符串類型,但是key中不能包括邊界字符由于key不是binary safe的字符串,所以像"my key"和"mykeyn"這樣包含空格和換行的key是不允許的順便說一下在redis內(nèi)部并不限制使用bin
8、ary字符,這是redis協(xié)議限制的。"rn"在協(xié)議格式中會(huì)作為特殊字符。redis 1.2以后的協(xié)議中部分命令已經(jīng)開始使用新的協(xié)議格式了(比如MSET)。總之目前還是把包含邊界字符當(dāng)成非法的key吧,免得被bug糾纏。 另外關(guān)于key的一個(gè)格式約定介紹下,object-type:id:field。比如user:1000:password,blog:xxidxx:title還有key的長度最好不要太長。道理很明顯占內(nèi)存啊,而且查找時(shí)候相對(duì)短key也更慢。不過也推薦過短的key,比如u:1000:pwd,這樣的。顯然沒上面的user:1000:pass
9、word可讀性好。下面介紹下key相關(guān)的命令exits key 測(cè)試指定key是否存在,返回1表示存在,0不存在del key1 key2 .keyN 刪除給定key,返回刪除key的數(shù)目,0表示給定key都不存在type key 返回給定key的value類型。返回 none 表示不存在key,string字符類型,list 鏈表類型 set 無序集合類型.keys pattern 返回匹配指定模式的所有key,下面給個(gè)例子randomkey 返回從當(dāng)前數(shù)據(jù)庫中隨機(jī)選擇的一個(gè)key,如果當(dāng)前數(shù)據(jù)庫是空的,返回空串rename oldkey newkey 原子的重命名一個(gè)key,如
10、果newkey存在,將會(huì)被覆蓋,返回1表示成功,0失敗。可能是oldkey不存在或者和newkey相同renamenx oldkey newkey 同上,但是如果newkey存在返回失敗dbsize 返回當(dāng)前數(shù)據(jù)庫的key數(shù)量expire key seconds 為key指定過期時(shí)間,單位是秒。返回1成功,0表示key已經(jīng)設(shè)置過過期時(shí)間或者不存在ttl key 返回設(shè)置過過期時(shí)間的key的剩余過期秒數(shù) -1表示key不存在或者沒有設(shè)置過過期時(shí)間select db-index 通過索引選擇數(shù)據(jù)庫,默認(rèn)連接的數(shù)據(jù)庫所有是0,默認(rèn)數(shù)據(jù)庫數(shù)是16個(gè)。返回1表示成功,0失敗move key db-ind
11、ex 將key從當(dāng)前數(shù)據(jù)庫移動(dòng)到指定數(shù)據(jù)庫。返回1成功。0 如果key不存在,或者已經(jīng)在指定數(shù)據(jù)庫中flushdb 刪除當(dāng)前數(shù)據(jù)庫中所有key,此方法不會(huì)失敗。慎用flushall 刪除所有數(shù)據(jù)庫中的所有key,此方法不會(huì)失敗。更加慎用2. string 類型string是redis最基本的類型,而且string類型是二進(jìn)制安全的。意思是redis的string可以包含任何數(shù)據(jù)。比如jpg圖片或者序列化的對(duì)象。從內(nèi)部實(shí)現(xiàn)來看其實(shí)string可以看作byte數(shù)組,最大上限是1G字節(jié)。下面是string類型的定義。struct sdshdr long len; long free; c
12、har buf;buf是個(gè)char數(shù)組用于存貯實(shí)際的字符串內(nèi)容。其實(shí)char和c#中的byte是等價(jià)的,都是一個(gè)字節(jié)len是buf數(shù)組的長度,free是數(shù)組中剩余可用字節(jié)數(shù)。由此可以理解為什么string類型是二進(jìn)制安全的了。因?yàn)樗举|(zhì)上就是個(gè)byte數(shù)組。當(dāng)然可以包含任何數(shù)據(jù)了。另外string類型可以被部分命令按int處理.比如incr等命令,下面詳細(xì)介紹。還有redis的其他類型像list,set,sorted set ,hash它們包含的元素與都只能是string類型。如果只用string類型,redis就可以被看作加上持久化特性的memcached.當(dāng)然redis對(duì)string類型的
13、操作比memcached多很多啊。如下:set key value 設(shè)置key對(duì)應(yīng)的值為string類型的value,返回1表示成功,0失敗setnx key value 同上,如果key已經(jīng)存在,返回0 。nx 是not exist的意思get key 獲取key對(duì)應(yīng)的string值,如果key不存在返回nilgetset key value 原子的設(shè)置key的值,并返回key的舊值。如果key不存在返回nilmget key1 key2 . keyN 一次獲取多個(gè)key的值,如果對(duì)應(yīng)key不存在,則對(duì)應(yīng)返回nil。下面是個(gè)實(shí)驗(yàn),首先清空當(dāng)前數(shù)據(jù)庫,然后設(shè)置k1,k2.獲取時(shí)k3對(duì)應(yīng)返回ni
14、lredis> flushdbOKredis> dbsize(integer) 0redis> set k1 aOKredis> set k2 bOKredis> mget k1 k2 k31. "a"2. "b"3. (nil)mset key1 value1 . keyN valueN 一次設(shè)置多個(gè)key的值,成功返回1表示所有的值都設(shè)置了,失敗返回0表示沒有任何值被設(shè)置msetnx key1 value1 . keyN valueN 同上,但是不會(huì)覆蓋已經(jīng)存在的keyincr key 對(duì)key的值做加加操作,并返回新的
15、值。注意incr一個(gè)不是int的value會(huì)返回錯(cuò)誤,incr一個(gè)不存在的key,則設(shè)置key為1decr key 同上,但是做的是減減操作,decr一個(gè)不存在key,則設(shè)置key為-1incrby key integer 同incr,加指定值 ,key不存在時(shí)候會(huì)設(shè)置key,并認(rèn)為原來的value是 0decrby key integer 同decr,減指定值。decrby完全是為了可讀性,我們完全可以通過incrby一個(gè)負(fù)值來實(shí)現(xiàn)同樣效果,反之一樣。substr 返回截取過的key的字符串值,注意并不修改key的值。下標(biāo)是從0開始的.(redis在2.0版本以后不包括2.0,使用的方法是g
16、etrange 參數(shù)相同。)append key value 給指定key的字符串值追加value,返回新字符串值的長度。下面給個(gè)例子redis> set k helloOKredis> append k ,world(integer) 11redis> get k"hello,world"substr key start endredis> substr k 0 8"hello,wor"redis> get k"hello,world"3. listredis的list類型其實(shí)就是一個(gè)每個(gè)子
17、元素都是string類型的雙向鏈表。所以lrpush和lrpop命令的算法時(shí)間復(fù)雜度都是O(1)另外list會(huì)記錄鏈表的長度。所以llen操作也是O(1).鏈表的最大長度是(2的32次方-1)。我們可以通過push,pop操作從鏈表的頭部或者尾部添加刪除元素。這使得list既可以用作棧,也可以用作隊(duì)列。有意思的是list的pop操作還有阻塞版本的。當(dāng)我們lrpop一個(gè)list對(duì)象是,如果list是空,或者不存在,會(huì)立即返回nil。但是阻塞版本的blrpop可以則可以阻塞,當(dāng)然可以加超時(shí)時(shí)間,超時(shí)后也會(huì)返回nil。為什么要阻塞版本的pop呢,主要是為了避免輪詢。舉個(gè)簡單的例子如果我們用list來
18、實(shí)現(xiàn)一個(gè)工作隊(duì)列。執(zhí)行任務(wù)的thread可以調(diào)用阻塞版本的pop去獲取任務(wù)這樣就可以避免輪詢?nèi)z查是否有任務(wù)存在。當(dāng)任務(wù)來時(shí)候工作線程可以立即返回,也可以避免輪詢帶來的延遲。ok下面介紹list相關(guān)命令lpush key string 在key對(duì)應(yīng)list的頭部添加字符串元素,返回1表示成功,0表示key存在且不是list類型rpush key string 同上,在尾部添加llen key 返回key對(duì)應(yīng)list的長度,key不存在返回0,如果key對(duì)應(yīng)類型不是list返回錯(cuò)誤lrange key start end 返回指定區(qū)間內(nèi)的元素,下標(biāo)從0開始,負(fù)值表示從后面計(jì)算,-1表示倒數(shù)第一個(gè)
19、元素 ,key不存在返回空列表ltrim key start end 截取list,保留指定區(qū)間內(nèi)元素,成功返回1,key不存在返回錯(cuò)誤lset key index value 設(shè)置list中指定下標(biāo)的元素值,成功返回1,key或者下標(biāo)不存在返回錯(cuò)誤lrem key count value 從key對(duì)應(yīng)list中刪除count個(gè)和value相同的元素。count為0時(shí)候刪除全部lpop key 從list的頭部刪除元素,并返回刪除元素。如果key對(duì)應(yīng)list不存在或者是空返回nil,如果key對(duì)應(yīng)值不是list返回錯(cuò)誤rpop 同上,但是從尾部刪除blpop key1.keyN t
20、imeout 從左到右掃描返回對(duì)第一個(gè)非空list進(jìn)行l(wèi)pop操作并返回,比如blpop list1 list2 list3 0 ,如果list不存在list2,list3都是非空則對(duì)list2做lpop并返回從list2中刪除的元素。如果所有的list都是空或不存在,則會(huì)阻塞timeout秒,timeout為0表示一直阻塞。當(dāng)阻塞時(shí),如果有client對(duì)key1.keyN中的任意key進(jìn)行push操作,則第一在這個(gè)key上被阻塞的client會(huì)立即返回。如果超時(shí)發(fā)生,則返回nil。有點(diǎn)像unix的select或者pollbrpop 同blpop,一個(gè)是從頭部刪除一個(gè)是從尾部刪除rpoplpu
21、sh srckey destkey 從srckey對(duì)應(yīng)list的尾部移除元素并添加到destkey對(duì)應(yīng)list的頭部,最后返回被移除的元素值,整個(gè)操作是原子的.如果srckey是空或者不存在返回nil4. setredis的set是string類型的無序集合。set元素最大可以包含(2的32次方-1)個(gè)元素。set的是通過hash table實(shí)現(xiàn)的,所以添加,刪除,查找的復(fù)雜度都是O(1)。hash table會(huì)隨著添加或者刪除自動(dòng)的調(diào)整大小。需要注意的是調(diào)整hash table大小時(shí)候需要同步(獲取寫鎖)會(huì)阻塞其他讀寫操作。可能不久后就會(huì)改用跳表(skip list)來實(shí)現(xiàn)跳表已經(jīng)在sort
22、ed set中使用了。關(guān)于set集合類型除了基本的添加刪除操作,其他有用的操作還包含集合的取并集(union),交集(intersection),差集(difference)。通過這些操作可以很容易的實(shí)現(xiàn)sns中的好友推薦和blog的tag功能。下面詳細(xì)介紹set相關(guān)命令sadd key member 添加一個(gè)string元素到,key對(duì)應(yīng)的set集合中,成功返回1,如果元素以及在集合中返回0,key對(duì)應(yīng)的set不存在返回錯(cuò)誤srem key member 從key對(duì)應(yīng)set中移除給定元素,成功返回1,如果member在集合中不存在或者key不存在返回0,如果key對(duì)應(yīng)的不是set類型的值返回
23、錯(cuò)誤spop key 刪除并返回key對(duì)應(yīng)set中隨機(jī)的一個(gè)元素,如果set是空或者key不存在返回nilsrandmember key 同spop,隨機(jī)取set中的一個(gè)元素,但是不刪除元素smove srckey dstkey member 從srckey對(duì)應(yīng)set中移除member并添加到dstkey對(duì)應(yīng)set中,整個(gè)操作是原子的。成功返回1,如果member在srckey中不存在返回0,如果key不是set類型返回錯(cuò)誤scard key 返回set的元素個(gè)數(shù),如果set是空或者key不存在返回0sismember key member 判斷member是否在set中,存在返回1,0表示不
24、存在或者key不存在sinter key1 key2.keyN 返回所有給定key的交集sinterstore dstkey key1.keyN 同sinter,但是會(huì)同時(shí)將交集存到dstkey下sunion key1 key2.keyN 返回所有給定key的并集sunionstore dstkey key1.keyN 同sunion,并同時(shí)保存并集到dstkey下sdiff key1 key2.keyN 返回所有給定key的差集sdiffstore dstkey key1.keyN 同sdiff,并同時(shí)保存差集到dstkey下smembers key 返回key對(duì)應(yīng)set的所有元素,結(jié)果是無
25、序的5 sorted set和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)用的是雙向鏈表,這樣就可以逆序
26、從尾部取元素。sorted set最經(jīng)常的使用方式應(yīng)該是作為索引來使用.我們可以把要排序的字段作為score存儲(chǔ),對(duì)象的id當(dāng)元素存儲(chǔ)。下面是sorted set相關(guān)命令zadd key score member 添加元素到集合,元素在集合中存在則更新對(duì)應(yīng)scorezrem key member 刪除指定元素,1表示成功,如果元素不存在返回0zincrby key incr member 增加對(duì)應(yīng)member的score值,然后移動(dòng)元素并保持skip list保持有序。返回更新后的score值z(mì)rank key member 返回指定元素在集合中的排名(下標(biāo)),集合中元素是按score從小到大
27、排序的zrevrank key member 同上,但是集合中元素是按score從大到小排序zrange key start end 類似lrange操作從集合中去指定區(qū)間的元素。返回的是有序結(jié)果zrevrange key start end 同上,返回結(jié)果是按score逆序的zrangebyscore key min max 返回集合中score在給定區(qū)間的元素zcount key min max 返回集合中score在給定區(qū)間的數(shù)量zcard key 返回集合中元素個(gè)數(shù)zscore key element 返回給定元素對(duì)應(yīng)的scorezremrangebyrank key mi
28、n max 刪除集合中排名在給定區(qū)間的元素zremrangebyscore key min max 刪除集合中score在給定區(qū)間的元素6. hash 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)來存儲(chǔ)的。這個(gè)zipmap其實(shí)并不是hash table,但是zipmap相比正
29、常的hash實(shí)現(xiàn)可以節(jié)省不少hash本身需要的一些元數(shù)據(jù)存儲(chǔ)開銷。盡管zipmap的添加,刪除,查找都是O(n),但是由于一般對(duì)象的field數(shù)量都不太多。所以使用zipmap也是很快的,也就是說添加刪除平均還是O(1)。如果field或者value的大小超出一定限制后,redis會(huì)在內(nèi)部自動(dòng)將zipmap替換成正常的hash實(shí)現(xiàn). 這個(gè)限制可以在配置文件中指定redis> set test dsfOKredis> set tast dsafOKredis> set tist adffOKredis> keys t*1. "tist"2. "
30、;tast"3. "test"redis> keys tiast1. "tist"2. "tast"redis> keys t?st1. "tist"2. "tast"3. "test"hash-max-zipmap-entries 64 #配置字段最多64個(gè)hash-max-zipmap-value 512 #配置value最大為512字節(jié)下面介紹hash相關(guān)命令hset key field value 設(shè)置hash field為指定值,如果key不存
31、在,則先創(chuàng)建hget key field 獲取指定的hash fieldhmget key filed1.fieldN 獲取全部指定的hash filedhmset key filed1 value1 . filedN valueN 同時(shí)設(shè)置hash的多個(gè)fieldhincrby key field integer 將指定的hash filed 加上給定值hexists key field 測(cè)試指定field是否存在hdel key field 刪除指定的hash fieldhlen key 返回指定hash的field數(shù)量hkeys key 返回hash的所有fieldhvals
32、 key 返回hash的所有valuehgetall 返回hash的所有filed和value三、 redis 排序本篇文章介紹下redis排序命令.redis支持對(duì)list,set和sorted set元素的排序。排序命令是sort 完整的命令格式如下: SORT key BY pattern LIMIT start count GET pattern ASC|DESC ALPHA STORE dstkey 下面我們一一說明各種命令選項(xiàng) (1)sort key 這個(gè)是最簡單的情況,沒有任何選項(xiàng)就是簡單的對(duì)集合自身元素排序并返回排序結(jié)果.下面
33、給個(gè)例子redis> lpush ml 12(integer) 1redis> lpush ml 11(integer) 2redis> lpush ml 23(integer) 3redis> lpush ml 13(integer) 4redis> sort ml1. "11"2. "12"3. "13"4. "23"(2)ASC|DESC ALPHA sort默認(rèn)的排序方式(asc)是從小到大排的,當(dāng)然也可以按照逆序或者按字符順序排。逆序可以加上desc選項(xiàng),想按字母順
34、序排可以加alpha選項(xiàng),當(dāng)然alpha可以和desc一起用。下面是個(gè)按字母順序排的例子redis> lpush mylist baidu(integer) 1redis> lpush mylist hello(integer) 2redis> lpush mylist xhan(integer) 3redis> lpush mylist soso(integer) 4redis> sort mylist1. "soso"2. "xhan"3. "hello"4. "baidu"red
35、is> sort mylist alpha1. "baidu"2. "hello"3. "soso"4. "xhan"redis> sort mylist desc alpha1. "xhan"2. "soso"3. "hello"4. "baidu"(3)BY pattern 除了可以按集合元素自身值排序外,還可以將集合元素內(nèi)容按照給定pattern組合成新的key,并按照新
36、key中對(duì)應(yīng)的內(nèi)容進(jìn)行排序。下面的例子接著使用第一個(gè)例子中的ml集合做演示: redis> set name11 nihaoOKredis> set name12 woOKredis> set name13 shiOKredis> set name23 lalaOKredis> sort ml by name* 1. "13"2. "23"3. "11"4. "12"*代表了ml中的元素值,所以這個(gè)排序是按照name12 name13 name23 name23這
37、四個(gè)key對(duì)應(yīng)值排序的,當(dāng)然返回的還是排序后ml集合中的元素 (對(duì)排序結(jié)果有疑問可看最下面的FAQ)(4)GET pattern 上面的例子都是返回的ml集合中的元素。我們也可以通過get選項(xiàng)去獲取指定pattern作為新key對(duì)應(yīng)的值??磦€(gè)組合起來的例子 redis> sort ml by name* get name* alpha1. "lala"2. "nihao"3. "shi"4. "wo"這 次返回的就不在是ml中的元素了,而是name12 name13 name23
38、 name23對(duì)應(yīng)的值。當(dāng)然排序是按照name12 name13 name23 name23值并根據(jù)字母順序排的。另外get選項(xiàng)可以有多個(gè)。看例子(#特殊符號(hào)引用的是原始集合也就是ml)redis> sort ml by name* get name* get # alpha1. "lala"2. "23"3. "nihao"4. "11"5. "shi"6. "13"7. "wo"8. "12"最后在還有一個(gè)引用hash類型字段
39、的特殊字符->,下面是例子redis> hset user1 name hanjie(integer) 1redis> hset user11 name hanjie(integer) 1redis> hset user12 name 86(integer) 1redis> hset user13 name lxl(integer) 1redis> sort ml get user*->name1. "hanjie"2. "86"3. "lxl"4. (nil)很容易理解,注意當(dāng)對(duì)應(yīng)的user
40、23不存在時(shí)候返回的是nil (5) LIMIT start count 上面例子返回結(jié)果都是全部。limit選項(xiàng)可以限定返回結(jié)果的數(shù)量。例子redis> sort ml get name* limit 1 21. "wo"2. "shi"start下標(biāo)是從0開始的,這里的limit選項(xiàng)意思是從第二個(gè)元素開始獲取2個(gè) (6)STORE dstkey 如果對(duì)集合經(jīng)常按照固定的模式去排序,那么把排序結(jié)果緩存起來會(huì)減少不少cpu開銷.使用store選項(xiàng)可以將排序內(nèi)容保存到指定key中。保存的類型是lis
41、tredis> sort ml get name* limit 1 2 store cl(integer) 2redis> type cllistredis> lrange cl 0 -11. "wo"2. "shi"這個(gè)例子我們將排序結(jié)果保存到了cl中 功能介紹完后,再討論下關(guān)于排序的一些問題。如果我們有多個(gè)redis server的話,不同的key可能存在于不同的server上。比如name12 name13 name23 name23,很有可能分別在四個(gè)不同的server
42、上存貯著。這種情況會(huì)對(duì)排序性能造成很大的影響。redis作者在他的blog上提到了這個(gè)問題的解 決辦法,就是通過key tag將需要排序的key都放到同一個(gè)server上 。由于具體決定哪個(gè)key存在哪個(gè)服務(wù)器上一般都是在client端hash的辦法來做的。我們可以通過只對(duì)key的部分進(jìn)行hash.舉個(gè)例子假如我們 的client如果發(fā)現(xiàn)key中包含。那么只對(duì)key中包含的內(nèi)容進(jìn)行hash。我們將四個(gè)name相關(guān)的key,都這樣命名name12 name13 name23 name23,于是client 程序就會(huì)把他們都放到同一server上。不知道jredis實(shí)現(xiàn)了沒。
43、; 還有一個(gè)問題也比較嚴(yán)重。如果要sort的集合非常大的話排序就會(huì)消耗很長時(shí)間。由于redis單線程的,所以長時(shí)間的排序操作會(huì)阻塞其他client的 請(qǐng)求。解決辦法是通過主從復(fù)制機(jī)制將數(shù)據(jù)復(fù)制到多個(gè)slave上。然后我們只在slave上做排序操作。并進(jìn)可能的對(duì)排序結(jié)果緩存。另外就是一個(gè)方案是就 是采用sorted set對(duì)需要按某個(gè)順序訪問的集合建立索引。 實(shí)例:redis> sadd tom:friend:list 123 #tom的好友列表 里面是好友的uid 1 redis> sadd tom:friend
44、:list 456 1 redis> sadd tom:friend:list 789 1 redis> sadd tom:friend:list 101 1 redis> set uid:sort:123 1000 #uid對(duì)應(yīng)的成績 OK redis> set uid:sort:456 6000 OK redis> set uid:sort:789 100 OK redis> set uid:sort:101 5999 OK redis> set uid:123 "'uid':123,'name':'
45、;lucy'" #增加uid對(duì)應(yīng)好友信息 OK redis> set uid:456 "'uid':456,'name':'jack'" OK redis> set uid:789 "'uid':789,'name':'marry'" OK redis> set uid:101 "'uid':101,'name':'icej'" OK redis> s
46、ort tom:friend:list by uid:sort:* get uid:* #從好友列表中獲得id與uid:sort字段匹配后排序,并根據(jù)排序后的順序,用key在uid表獲得信息 1. 'uid':789,'name':'marry' 2. 'uid':123,'name':'lucy' 3. 'uid':101,'name':'icej' 4. 'uid':456,'name':'jack'
47、 redis> sort tom:friend:list by uid:sort:* get uid:* get uid:sort:* 1. 'uid':789,'name':'marry' 2. 100 3. 'uid':123,'name':'lucy' 4. 1000 5. 'uid':101,'name':'icej' 6. 5999 7. 'uid':456,'name':'jack' 8
48、. 6000 FAQ:1.sort ml by name* get name* get # 為什么會(huì)按照shi lala nihao wo的順序排下來,這個(gè)跟單純的排序name*和name * alpha的結(jié)果都不一樣 這個(gè)問題要從redis的實(shí)現(xiàn)邏輯上來分析了 a)list在插入后 ,默認(rèn)是按照時(shí)間的先后反序排列的 , lrange ml 0 -1,結(jié)果是:13 23 11 12. 這是因?yàn)閘ist插入時(shí)是將最新的item插入到鏈表頭 b)sort m1
49、 by name* 確定是會(huì)按照name*的值進(jìn)行排序的.但當(dāng)name*對(duì)應(yīng)的value不是num型并且沒有設(shè)置alpha的時(shí)候,會(huì)導(dǎo)致排序分值都是相同的,因?yàn)槌绦驅(qū)裯ame*對(duì)應(yīng)的值嘗試轉(zhuǎn)換為nun型 c)這就會(huì)導(dǎo)致sort ml by name*會(huì)按照ml的自然順序進(jìn)行排列了if (alpha) if (sortby) vectorj.u.cmpobj = getDecodedObject(byval); else if (byval->encoding = REDIS_ENCODING_RAW) vectorj.u.score = strtod
50、(byval->ptr,NULL); else if (byval->encoding = REDIS_ENCODING_INT) /* Don't need to decode the object if it's * integer-encoded (the only encoding supported) so * far. We can just cast it */ vectorj.u.score = (long)byval->ptr; else redisAssert(1 != 1); 四、 redis 事務(wù)redis對(duì)事務(wù)的支持目前還比較簡單。r
51、edis只能保證一個(gè)client發(fā)起的事務(wù)中的命令可以連續(xù)的執(zhí)行,而中間不會(huì)插入其他client的命令。 由于redis是單線程來處理所有client的請(qǐng)求的所以做到這點(diǎn)是很容易的。一般情況下redis在接受到一個(gè)client發(fā)來的命令后會(huì)立即處理并 返回處理結(jié)果,但是當(dāng)一個(gè)client在一個(gè)連接中發(fā)出multi命令有,這個(gè)連接會(huì)進(jìn)入一個(gè)事務(wù)上下文,該連接后續(xù)的命令并不是立即執(zhí)行,而是先放到一 個(gè)隊(duì)列中。當(dāng)從此連接受到exec命令后,redis會(huì)順序的執(zhí)行隊(duì)列中的所有命令。并將所有命令的運(yùn)行結(jié)果打包到一起返回給client.然后此連接就 結(jié)束事務(wù)上下文。下面可以看一個(gè)例子redis> m
52、ultiOKredis> incr aQUEUEDredis> incr bQUEUEDredis> exec1. (integer) 12. (integer) 1從這個(gè)例子我們可以看到incr a ,incr b命令發(fā)出后并沒執(zhí)行而是被放到了隊(duì)列中。調(diào)用exec后倆個(gè)命令被連續(xù)的執(zhí)行,最后返回的是兩條命令執(zhí)行后的結(jié)果我們可以調(diào)用discard命令來取消一個(gè)事務(wù)。接著上面例子redis> multiOKredis> incr aQUEUEDredis> incr bQUEUEDredis> discardOKredis> get a"
53、1"redis> get b"1"可以發(fā)現(xiàn)這次incr a incr b都沒被執(zhí)行。discard命令其實(shí)就是清空事務(wù)的命令隊(duì)列并退出事務(wù)上下文。 雖說redis事務(wù)在本質(zhì)上也相當(dāng)于序列化隔離級(jí)別的了。但是由于事務(wù)上下文的命令只排隊(duì)并不立即執(zhí)行,所以事務(wù)中的寫操作不能依賴事務(wù)中的讀操作結(jié)果??聪旅胬觬edis> multiOKredis> get aQUEUEDredis> get bQUEUEDredis> exec1. "1"2. "1"發(fā)現(xiàn)問題了吧。假如我們想用事務(wù)實(shí)現(xiàn)inc
54、r操作怎么辦?可以這樣做嗎?redis> get a"1"redis> multiOKredis> set a 2QUEUEDredis> exec1. OKredis> get a,"2"結(jié)論很明顯這樣是不行的。這樣和 get a 然后直接set a是沒區(qū)別的。很明顯由于get a 和set a并不能保證兩個(gè)命令是連續(xù)執(zhí)行的(get操作不在事務(wù)上下文中)。很可能有兩個(gè)client同時(shí)做這個(gè)操作。結(jié)果我們期望是加兩次a從原來的1變成3. 但是很有可能兩個(gè)client的get a,取到都是1,造成最終加兩次結(jié)果卻是2。主要問題
55、我們沒有對(duì)共享資源a的訪問進(jìn)行任何的同步也就是說redis沒提供任何的加鎖機(jī)制來同步對(duì)a的訪問。還好redis 2.1后添加了watch命令,可以用來實(shí)現(xiàn)樂觀鎖??磦€(gè)正確實(shí)現(xiàn)incr命令的例子,只是在前面加了watch aredis> watch aOKredis> get a"1"redis> multiOKredis> set a 2QUEUEDredis> exec1. OKredis> get a,"2"watch 命令會(huì)監(jiān)視給定的key,當(dāng)exec時(shí)候如果監(jiān)視的key從調(diào)用watch后發(fā)生過變化,則整個(gè)事務(wù)會(huì)
56、失敗。也可以調(diào)用watch多次監(jiān)視多個(gè)key.這 樣就可以對(duì)指定的key加樂觀鎖了。注意watch的key是對(duì)整個(gè)連接有效的,事務(wù)也一樣。如果連接斷開,監(jiān)視和事務(wù)都會(huì)被自動(dòng)清除。當(dāng)然了 exec,discard,unwatch命令都會(huì)清除連接中的所有監(jiān)視.redis的事務(wù)實(shí)現(xiàn)是如此簡單,當(dāng)然會(huì)存在一些問題。第一個(gè)問題是redis只能保證事務(wù)的每個(gè)命令連續(xù)執(zhí)行,但是如果事務(wù)中的一個(gè)命令失敗了,并不回滾其他命令,比如使用的命令類型不匹配。redis> set a 5OKredis> lpush b 5(integer) 1redis> set c 5OKredis> mul
57、tiOKredis> incr aQUEUEDredis> incr bQUEUEDredis> incr cQUEUEDredis> exec1. (integer) 62. (error) ERR Operation against a key holding the wrong kind of value3. (integer) 6可以看到雖然incr b失敗了,但是其他兩個(gè)命令還是執(zhí)行了。最 后一個(gè)十分罕見的問題是 當(dāng)事務(wù)的執(zhí)行過程中,如果redis意外的掛了。很遺憾只有部分命令執(zhí)行了,后面的也就被丟棄了。當(dāng)然如果我們使用的append-only file方式持
58、久化,redis會(huì)用單個(gè)write操作寫入整個(gè)事務(wù)內(nèi)容。即是是這種方式還是有可能只部分寫入了事務(wù)到磁盤。發(fā)生部分寫入事務(wù)的情況 下,redis重啟時(shí)會(huì)檢測(cè)到這種情況,然后失敗退出??梢允褂胷edis-check-aof工具進(jìn)行修復(fù),修復(fù)會(huì)刪除部分寫入的事務(wù)內(nèi)容。修復(fù)完后就 能夠重新啟動(dòng)了。五、 redis pipelineredis是一個(gè)cs模式的tcp server,使用和http類似的請(qǐng)求響應(yīng)協(xié)議。一個(gè)client可以通過一個(gè)socket連接發(fā)起多個(gè)請(qǐng)求命令。每個(gè)請(qǐng)求命令發(fā)出后client通常 會(huì)阻塞并等待redis服務(wù)處理,redis處理完后請(qǐng)求命令后會(huì)將結(jié)果通過響應(yīng)報(bào)文返回給clien
59、t。基本的通信過程如下Client: INCR XServer: 1Client: INCR XServer: 2Client: INCR XServer: 3Client: INCR XServer: 4基 本上四個(gè)命令需要8個(gè)tcp報(bào)文才能完成。由于通信會(huì)有網(wǎng)絡(luò)延遲,假如從client和server之間的包傳輸時(shí)間需要0.125秒。那么上面的四個(gè)命 令8個(gè)報(bào)文至少會(huì)需要1秒才能完成。這樣即使redis每秒能處理100個(gè)命令,而我們的client也只能一秒鐘發(fā)出四個(gè)命令。這顯示沒有充分利用 redis的處理能力。除了可以利用mget,mset 之類的單條命令處理多個(gè)key的命令外我們還可以利用pipeline的方式從client打包多條命令一起發(fā)出,不需要等待單條命令的響應(yīng)返回,而redis服務(wù)端會(huì)處理完多條命令后會(huì)將多條命令的處理結(jié)果打包到一起返回給客戶端。通信過程如下Client: INCR XClient: INCR XClient: INCR XClient: INCR XServer: 1Server: 2Server: 3Server: 4假 設(shè)不會(huì)因?yàn)閠cp 報(bào)文過長而被拆分??赡軆蓚€(gè)tcp報(bào)文就能完成四條命令,client可以將四個(gè)inc
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- it耗材采購合同范本
- 勞動(dòng)服務(wù)合同范本
- 包辦野餐服務(wù)合同范本
- 農(nóng)業(yè)水費(fèi)征收合同范本
- 勞務(wù)咨詢派遣合同范本
- 東易日盛設(shè)計(jì)合同范本
- 兼職領(lǐng)隊(duì)合同范本
- 單位內(nèi)部組織合同范本
- 出租鋼管吊籃合同范例
- 企業(yè)貸款借款合同范本
- H3C-CAS虛擬化平臺(tái)詳細(xì)介紹
- 小學(xué)生韻母in、ing常見漢字與區(qū)分練習(xí)
- 藥房品種類別及數(shù)量清單
- 機(jī)關(guān)檔案管理工作培訓(xùn)PPT課件
- 初中物理人教版八年級(jí)下冊(cè) 第1節(jié)牛頓第一定律 課件
- 網(wǎng)站培訓(xùn)內(nèi)容trswcm65表單選件用戶手冊(cè)
- 連續(xù)平壓熱壓機(jī) 三篇 俞敏等
- 空調(diào)系統(tǒng)維保記錄表格模板
- 打印版-圓與二次函數(shù)綜合題精練(帶答案)
- 各種閥門CAD圖
- 工程結(jié)算書標(biāo)準(zhǔn)
評(píng)論
0/150
提交評(píng)論