redis + 主從 + 持久化 + 分片 + 集羣 + spring集成

Redis是一個基於內存的數據庫,其不只讀寫速度快,每秒能夠執行大約110000的寫操做,81000的讀取操做,並且其支持存儲字符串,哈希結構,鏈表,集合豐富的數據類型。因此獲得不少開發者的青睞。加之其支持主從、持久化等功能,3.0版本開始正式提供分片技術、讓其在大型互聯網應用中大顯身手,本文經過實際操做和理論相配合,對redis進行詳細地闡述。html

1、redis的安裝與使用java

下載直接去redis的官網http://redis.io/進行不一樣操做系統對應的版本。本文中採用的redis的版本爲3.2.五、linux平臺,安裝過程以下node

[root@hbase usr]# tar -zxf redis-3.2.5.tar.gz 
[root@hbase usr]# cd redis-3.2.5
[root@hbase redis-3.2.5]# ll
[root@hbase redis-3.2.5]# make
[root@hbase redis-3.2.5]# cd src
[root@hbase src]# ll

以後咱們會發現其中redis-server和redis-cli,這兩個文件分別對應啓動redis的服務端和客戶端,啓動服務端linux

[root@hbase src]# ./redis-server 
11579:M 13 Nov 15:07:01.399 # Warning: 32 bit instance detected but no memory limit set. Setting 3 GB maxmemory limit with 'noeviction' policy now.
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 3.2.5 (00000000/0) 32 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 11579
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

11579:M 13 Nov 15:07:01.404 # Server started, Redis version 3.2.5
11579:M 13 Nov 15:07:01.409 * The server is now ready to accept connections on port 6379

能夠看到,redis正常啓動,6379 是 redis 服務端口,這個端口在redis.conf中能夠進行配置,稍後咱們講解配置文件的時候會提到。不要關閉這個窗口,由於當前redis-server不是在後臺運行,咱們另起一個窗口,在當前目錄下進行客戶端鏈接服務端。redis

[hadoop@hbase src]$ ./redis-cli 
127.0.0.1:6379> 

說明一切正常,linux環境下的redis安裝成功,至於windows下的安裝過程相對更加簡單,只需打開.exe文件便可,不在詳細演示算法

2、redis數據類型spring

2.1 string數據庫

字符串類型是Redis中最爲基礎的數據存儲類型,它在Redis中是二進制安全的,在Redis中字符串類型的Value最多能夠容納的數據長度是512M。除了get、set、做外,Redis還提供了其餘的一些諸如追加、遞增等功能。apache

set key value O(1) 設定該key對應的value,若是該Key已經存在,則覆蓋其原有值。get key O(1) 獲取指定Key的value,若是該Key不存在,返回nil。windows

setnx key value O(1) 若是指定的Key不存在,則設定該Key持有指定字符串value,此時其效果等價於set命令。若是該Key已經存在,該命令將不作任何操做。 

 1 127.0.0.1:6379> set hello word
 2 OK
 3 127.0.0.1:6379> get hello
 4 "word"
 5 127.0.0.1:6379> set hello world
 6 OK
 7 127.0.0.1:6379> set hello world
 8 OK
 9 127.0.0.1:6379> get hello
10 "world"
11 127.0.0.1:6379> get world
12 (nil)
13 127.0.0.1:6379> set hello world_new
14 OK
15 127.0.0.1:6379> get hello
16 "world_new"
17 127.0.0.1:6379> setnx hello nihao
18 (integer) 0
19 127.0.0.1:6379> setnx new_hello nihao
20 (integer) 1
View Code

mset key value [key value ...] O(N) N表示指定Key的數量。該命令能夠當作是屢次迭代執行set命令。

mget key [key ...] O(N) N表示獲取Key的數量。返回全部指定key的value,若是其中某個key不存在,該key的value將返回nil。 

msetnx key value [key value ...] O(N) N表示指定key的數量。該命令原子性的完成參數中全部key/value的設置操做,其具體行爲能夠當作是屢次迭代執行setnx命令。若是在這一批keys中有任意一個key已經存在,那麼該操做將所有回滾,即全部的修改都不會生效。 1表示全部keys都設置成功,0則表示沒有任何key被修改。 

 1 127.0.0.1:6379> mset key1 hello key2 world
 2 OK
 3 127.0.0.1:6379> mget key1 key2
 4 1) "hello"
 5 2) "world"
 6 127.0.0.1:6379> mget key1 key3
 7 1) "hello"
 8 2) (nil)
 9 127.0.0.1:6379> msetnx key1 nihao key3 hi
10 (integer) 0
11 127.0.0.1:6379> msetnx key3 nihao key4 hi
12 (integer) 1
View Code

append key value  O(1) 若key已經存在,將value的數據追加到對應key的value的末尾。若是該key不存在,append命令將會建立一個新的key/value。

strlen key O(1) 返回指定Key的字符值長度,若是該Key不存在,返回0。

decr key O(1) 將指定key的value原子性的遞減1。若是該key不存在,其初始值爲0,在decr以後其值爲-1。若是value的值不能轉換爲整型值,該操做將執行失敗。

incr key O(1) 將指定key的value原子性的遞增1。若是該Key不存在,其初始值爲0,在incr以後其值爲1。若是value的值不能轉換爲整型值,該操做將執行失敗。 

decrby key decrement O(1) 將指定key的value原子性的減小decrement,其餘同decr。

incrby key increment O(1) 將指定key的value原子性的增長increment,其餘同incr。 

 1 127.0.0.1:6379> append k1 hello
 2 (integer) 5
 3 127.0.0.1:6379> append k1 world
 4 (integer) 10
 5 127.0.0.1:6379> get k1
 6 "helloworld"
 7 127.0.0.1:6379> strlen k1
 8 (integer) 10
 9 127.0.0.1:6379> set k2 1
10 OK
11 127.0.0.1:6379> incr k2
12 (integer) 2
13 127.0.0.1:6379> get k2
14 "2"
15 127.0.0.1:6379> decr k2
16 (integer) 1
17 127.0.0.1:6379> get k2
18 "1"
19 127.0.0.1:6379> incrby k2 5
20 (integer) 6
21 127.0.0.1:6379> decrby k2 5
22 (integer) 1
23 127.0.0.1:6379> get k2
24 "1"
View Code

2.2 redis之數據類型list

在Redis中,List類型是按照插入順序排序的字符串鏈表。和數據結構中的普通鏈表同樣,咱們能夠在其頭部(left)和尾部(right)添加新的元素,該操做也能夠在常量時間內完成。在插入時,若是該鍵並不存在,Redis將爲該鍵建立一個新的鏈表。與此相反,若是鏈表中全部的元素均被移除,那麼該鍵也將會被從數據庫中刪除。List中能夠包含的最大元素數量是4294967295。 

lpush key value [value ...] O(1) 在指定key所對應的List頭部插入全部values。若是該Key不存在,則插入以前建立一個與該key關聯的空鏈表。

lpop key O(1) 返回並彈出指定key對應鏈表的第一個元素。若是該Key不存在,返回nil。

lrange key start stop start和end都是0-len,即0表示鏈表頭部的第一個元素。其中start的值也能夠爲負值,-1將表示鏈表中的最後一個元素,即尾部元素,-2表示倒數第二個並以此類推。該命令在獲取元素時,start和end位置上的元素也會被取出。若是start的值大於鏈表中元素的數量,空鏈表將會被返回。若是end的值大於元素的數量,該命令則獲取從start(包括start)開始,鏈表中剩餘的全部元素。 

lpushx key value O(1) 當指定的key存在時,在其所關聯的list的頭部插入參數中給出的value,不然將不會有任何操做發生。    

lrem key count value O(N) 在指定key關聯的鏈表中,刪除前count個值等於value的元素。若是count大於0,從頭向尾遍歷並刪除,若是count小於0,則從尾向頭遍歷並刪除。若是count等於0,則刪除鏈表中全部等於value的元素。若是指定的key不存在,則直接返回0。

llen key O(1) 返回指定key關聯的鏈表中元素的數量,若是該Key不存在,則返回0。。

lset  key index value O(N) 設定鏈表中指定位置的值爲新值,其中0表示第一個元素,即頭部元素,-1表示尾部元素。 

 1 127.0.0.1:6379> lpush k1 v1 v2 v3
 2 (integer) 3
 3 127.0.0.1:6379> lrange k1 0 2
 4 1) "v3" 2) "v2" 3) "v1"
 5 127.0.0.1:6379> lpop k1
 6 "v3"
 7 127.0.0.1:6379> lrange k1 0 2
 8 1) "v2" 2) "v1"
 9 127.0.0.1:6379> lpush k1 v4
10 (integer) 3
11 127.0.0.1:6379> lrange k1 0 2
12 1) "v4" 2) "v2" 3) "v1"
13 127.0.0.1:6379> lpush k1 v4
14 (integer) 4
15 127.0.0.1:6379> lpush k1 v4
16 (integer) 5
17 127.0.0.1:6379> lpush k1 v4
18 (integer) 6
19 127.0.0.1:6379> lrange k1 0 5
20 1) "v4" 2) "v4" 3) "v4" 4) "v4" 5) "v2" 6) "v1"
21 127.0.0.1:6379> lrem k1 2 v4  # 刪除前兩個值爲v4的元素
22 (integer) 2
23 127.0.0.1:6379> lrange k1 0 3
24 1) "v4" 2) "v4" 3) "v2" 4) "v1"
25 127.0.0.1:6379> llen k1
26 (integer) 4
27 127.0.0.1:6379> lset k1 1 k5  #設置索引爲1的值爲k5
28 OK
29 127.0.0.1:6379> lrange k1 0 3
30 1) "v4" 2) "k5" 3) "v2" 4) "v1"
View Code

rpush key value [value ...] O(1) 在指定key所對應的List尾部插入全部values。若是該Key不存在,則插入以前建立一個與該key關聯的空鏈表。

rpop key O(1) 返回並彈出指定key對應鏈表的最後一個元素。若是該Key不存在,返回nil。

rpushx key value O(1) 當指定的key存在時,在其所關聯的list的尾部插入參數中給出的value,不然將不會有任何操做發生。  

 1 127.0.0.1:6379> lrange k1 0 3
 2 1) "v4" 2) "k5" 3) "v2" 4) "v1"
 3 127.0.0.1:6379> rpushx k1 k6
 4 (integer) 5
 5 127.0.0.1:6379> lrange k1 0 4
 6 1) "v4" 2) "k5" 3) "v2" 4) "v1" 5) "k6"
 7 127.0.0.1:6379> rpush k1 k7 k8  #在尾部添加元素
 8 (integer) 7
 9 127.0.0.1:6379> lrange k1 0 6
10 1) "v4" 2) "k5" 3) "v2" 4) "v1" 5) "k6" 6) "k7" 7) "k8"  
11 127.0.0.1:6379> rpop k1  #彈出尾部的元素
12 "k8"
13 127.0.0.1:6379> lrange k1 0 5
14 1) "v4" 2) "k5" 3) "v2" 4) "v1" 5) "k6" 6) "k7"
15 127.0.0.1:6379> 
View Code

2.3 hash

Redis hash 是一個string類型的field和value的映射表,hash特別適合用於存儲對象。每個Hash能夠存儲4294967295個鍵值對。

hset key field value O(1) 爲指定的key設置field/value對,若key不存在,則建立新key,並建立field/value對,若該key中已經存在,則用新值覆蓋其原有值。

hget key field O(1) 返回指定key中指定field所對應的值,若key或field不存在,返回nil。

hmget key field [field ...] O(N) 獲取指定fields關聯的一組values。若是請求的field不存在,其值返回nil。

hmset key field value [field value ...] O(N) 逐個依次設置參數中給出的field/value對。若是其中某個field已經存在,則用新值覆蓋原有值。若是key不存在,則建立新key,同時設定參數中的field/value。

hsetnx key field value O(1) 只有當key或field不存在時,爲指定的key設定field/value對,不然該命令不會進行任何操做。

 1 127.0.0.1:6379> hset k1 f1 v1
 2 (integer) 1
 3 127.0.0.1:6379> hset k1 f2 v2
 4 (integer) 1
 5 127.0.0.1:6379> hget k1 f1
 6 "v1"
 7 127.0.0.1:6379> hmget k1 f1 f2
 8 1) "v1" 2) "v2"
 9 127.0.0.1:6379> hmset k1 f3 v3 f4 v4
10 OK
11 127.0.0.1:6379> hmget k1 f1 f2 f3 f4
12 1) "v1" 2) "v2" 3) "v3" 4) "v4"
13 127.0.0.1:6379> hsetnx k1 f1 v5
14 (integer) 0
15 127.0.0.1:6379> hsetnx k1 f5 v5
16 (integer) 1
17 127.0.0.1:6379> hmget k1 f1 f2 f3 f4 f5
18 1) "v1" 2) "v2" 3) "v3" 4) "v4" 5) "v5"
View Code

hkeys key O(N) 返回指定key的全部fields名。

hvals key O(N) 返回指定Key的全部values名。

hexists key field O(1) 判斷指定key中的指定field是否存在。1表示存在,0表示field或key不存在。

hlen key O(1) 獲取該key所包含的field的數量。返回key包含的field數量,若是key不存在,返回0。

hdel key field [field ...] O(N) 從指定key的hash中刪除指定的多個字段,若是不存在的字段將被忽略。

hincrby key field increment O(1) 增長指定key中指定field對應的value的值。若是key或field不存在,該命令將會建立一個新key或新field。 

 1 127.0.0.1:6379> hkeys k1
 2 1) "f1" 2) "f2" 3) "f3" 4) "f4" 5) "f5"
 3 127.0.0.1:6379> hvals k1
 4 1) "v1" 2) "v2" 3) "v3" 4) "v4" 5) "v5"
 5 127.0.0.1:6379> hexists k1 f1
 6 (integer) 1
 7 127.0.0.1:6379> hlen k1 
 8 (integer) 5
 9 127.0.0.1:6379> hdel k1 f5
10 (integer) 1
11 127.0.0.1:6379> hset k1 f5 1
12 (integer) 1
13 127.0.0.1:6379> hvals k1
14 1) "v1" 2) "v2" 3) "v3" 4) "v4" 5) "1"
15 127.0.0.1:6379> hincrby k1 f5 2
16 (integer) 3
17 127.0.0.1:6379> hvals k1
18 1) "v1" 2) "v2" 3) "v3" 4) "v4" 5) "3"
View Code

2.4 set

在Redis中, Set類型看做爲沒有排序的字符集合,和List類型同樣,咱們也能夠在該類型的數據值上執行添加、刪除或判斷某一元素是否存在等操做。set可包含的最大元素數量是4294967295。set集合中不容許出現重複的元素。 

sadd key member [member ...] O(N) 若該Key不存在,該命令將會建立一個新的set。如有的成員在set中已經存在,該成員將被忽略,而其它成員仍將會被正常插入。

spop key O(1) 隨機的移除並返回set中的某一成員。

scard key O(1) 獲取set中成員的數量。

sismember key member O(1) 判斷參數中指定成員是否已經存在於與key所在的set集合中。

smembers key O(N) 獲取與該key關聯的set中全部的成員。     

srem key member [member ...] O(N) 從與key關聯的set中刪除參數中指定的成員,不存在的參數成員將被忽略。

 1 127.0.0.1:6379> sadd k1 m1
 2 (integer) 1
 3 127.0.0.1:6379> sadd k1 m2
 4 (integer) 1
 5 127.0.0.1:6379> scard k1
 6 (integer) 2
 7 127.0.0.1:6379> spop k1
 8 "m2"
 9 127.0.0.1:6379> sadd k1 m3
10 (integer) 1
11 127.0.0.1:6379> sismember k1 m3
12 (integer) 1
13 127.0.0.1:6379> smembers k1
14 1) "m3"
15 2) "m1"
16 127.0.0.1:6379> srem k1 m1
17 (integer) 1
18 127.0.0.1:6379> smembers k1
19 1) "m3"
View Code

sdiff key [key ...] O(N) 返回第一個key所關聯的set和其後全部keys所關聯的sets中成員的差別。

sinter  key [key ...] O(N*M) 返回參數中全部keys關聯的sets中成員的交集。

sunion key [key ...] O(N) 返回參數中全部keys關聯的sets中成員的並集。  

127.0.0.1:6379> smembers k1
1) "m2"
2) "m1"
3) "m3"
127.0.0.1:6379> smembers k2
1) "m3"
2) "m1"
3) "m4"
127.0.0.1:6379> sdiff k1 k2
1) "m2"
127.0.0.1:6379> sinter k1 k2
1) "m1"
2) "m3"
127.0.0.1:6379> sunion k1 k2
1) "m3"
2) "m1"
3) "m2"
4) "m4"
View Code

 2.5 sorted set

sorted-set和set類型極爲類似,都不容許重複的成員出如今一個Set中。它們之間的主要差異是sorted-set中的每個成員都會有一個分數(score)與之關聯,Redis正是經過分數來爲集合中的成員進行從小到大的排序。

zadd key score member [score] [member] O(log(N)) 添加參數中指定的全部成員及其分數到指定key的sorted-sett中。

zcard key O(1) 獲取與該key相關聯的sorted-set中包含的成員數量。

zscore key member O(1) 獲取指定Key的指定成員的分數。若是該成員存在,以字符串的形式返回其分數,不然返回nil。

zcount key min max O(log(N)+M) 用於獲取分數(score)在min和max之間的成員數量。min和max表示的範圍是閉區間範圍,即min <= score <= max內的成員將被返回。

zincrby key increment member O(log(N)) 將爲指定Key中的指定成員增長指定的分數。

zrange key start stop [WITHSCORES] O(log(N)+M)  返回順序在start和stop指定範圍內的成員列表。

zrangebyscore key min max [WITHSCORES] [LIMIT offset count] O(log(N)+M) 將返回分數在min和max之間的全部成員列表。

zrem key member [member ...] O(M log(N)) 移除參數中指定的成員,其中不存在的成員將被忽略。

zremrangebyscore key min max O(log(N)+M) 刪除分數在min和max之間的全部成員,即知足表達式min <= score <= max的全部成員。 

 1 127.0.0.1:6379> zadd k1 1 m1
 2 (integer) 1
 3 127.0.0.1:6379> zadd k1 2 m2
 4 (integer) 1
 5 127.0.0.1:6379> zadd k1 3 m3
 6 (integer) 1
 7 127.0.0.1:6379> zcard k1
 8 (integer) 3
 9 127.0.0.1:6379> zscore k1 m1
10 "1"
11 127.0.0.1:6379> zscore k1 m2
12 "2"
13 127.0.0.1:6379> zcount k1 2 3
14 (integer) 2
15 127.0.0.1:6379> zincrby k1 3 m3
16 "6"
17 127.0.0.1:6379> zrange k1 1 10
18 1) "m2"
19 2) "m3"
20 127.0.0.1:6379> zrange k1 0 10
21 1) "m1"
22 2) "m2"
23 3) "m3"
24 127.0.0.1:6379> zcount k1 0 10
25 (integer) 3
26 127.0.0.1:6379> zrangebyscore k1 0 6
27 1) "m1"
28 2) "m2"
29 3) "m3"
30 127.0.0.1:6379> zrem k1 m1
31 (integer) 1
32 127.0.0.1:6379> zcard k1
33 (integer) 2
34 127.0.0.1:6379> zremrangebyscore k1 2 3
35 (integer) 1
36 127.0.0.1:6379> zremrangebyscore k1 2 10
37 (integer) 1
38 127.0.0.1:6379> zcard k1
39 (integer) 0
View Code

3、redis的相關命令 

keys pattern O(N) 獲取全部匹配pattern參數的Keys。須要說明的是,在咱們的正常操做中應該儘可能避免對該命令的調用,由於對於大型數據庫而言,該命令是很是耗時的。pattern支持glob-style的通配符格式,如*表示任意一個或多個字符,?表示任意字符,[abc]表示方括號中任意一個字母。
del key [key ...] O(N) 從數據庫刪除中參數中指定的keys,若是指定鍵不存在,則直接忽略。
exists key O(1) 判斷指定鍵是否存在。 1表示存在,0表示不存在。
move key db O(1) 將當前數據庫中指定的鍵key移動到參數中指定的數據庫中。若該key在目標數據庫中已經存在,或者在當前數據庫中不存在,該命令將不作任何操做並返回0。 移動成功返回1,不然0。
rename key newkey O(1) 爲指定指定的鍵從新命名,若是兩個keys的命令相同,或者是源key不存在,該命令都會返回相關的錯誤信息。若是newKey已經存在,則直接覆蓋。
renamenx key newkey O(1) 若是新值不存在,則將參數中的原值修改成新值。其它條件和rename一致。1表示修改爲功,不然0。
expire key seconds O(1) 該命令爲指定的key設定超時的秒數,在超過該時間後,key被自動的刪除。若是該Key在超時以前被修改,與該鍵關聯的超時將被移除。1表示超時被設置,0則表示Key不存在,或不能被設置。
expireat key timestamp O(1) 該命令的邏輯功能和expire徹底相同,差異是該命令指定的超時時間是絕對時間,而不是相對時間。該時間參數是Unix timestamp格式的,即從1970年1月1日開始所流經的秒數。1表示超時被設置,0則表示Key不存在,或不能被設置。
ttl key O(1) 獲取該鍵所剩的超時描述。若是該鍵不存在或沒有超時設置,則返回-1。
type key O(1) 獲取與參數中指定鍵關聯值的類型,該命令將以字符串的格式返回。 返回的字符串爲string、list、set、hash和zset,若是key不存在返回none。

 1 127.0.0.1:6379> keys *
 2 (empty list or set)
 3 127.0.0.1:6379> set str string
 4 OK
 5 127.0.0.1:6379> hset hash1 f1 v1
 6 (integer) 1
 7 127.0.0.1:6379> sadd set1 v1
 8 (integer) 1
 9 127.0.0.1:6379> zadd sortedset1 1 v1
10 (integer) 1
11 127.0.0.1:6379> lpush list1 v1 v2
12 (integer) 2
13 127.0.0.1:6379> keys *
14 1) "hash1"
15 2) "sortedset1"
16 3) "list1"
17 4) "str"
18 5) "set1"
19 127.0.0.1:6379> keys s*
20 1) "sortedset1"
21 2) "str"
22 3) "set1"
23 127.0.0.1:6379> exists list1
24 (integer) 1
25 127.0.0.1:6379> rename list1 list2
26 OK
27 127.0.0.1:6379> keys *
28 1) "hash1"
29 2) "sortedset1"
30 3) "str"
31 4) "list2"
32 5) "set1"
33 127.0.0.1:6379> type list2
34 list
35 127.0.0.1:6379> type str
36 string
37 127.0.0.1:6379> set str2 v2
38 OK
39 127.0.0.1:6379> expire str2 10
40 (integer) 1
41 127.0.0.1:6379> ttl str2
42 (integer) 6
43 127.0.0.1:6379> ttl str2
44 (integer) -2
45 127.0.0.1:6379> keys *
46 1) "hash1"
47 2) "sortedset1"
48 3) "str"
49 4) "list2"
50 5) "set1"
51 127.0.0.1:6379> move str 1
52 (integer) 1
53 127.0.0.1:6379> keys *
54 1) "hash1"
55 2) "sortedset1"
56 3) "list2"
57 4) "set1"
58 127.0.0.1:6379> select 1
59 OK
60 127.0.0.1:6379[1]> keys *
61 1) "str"
62 127.0.0.1:6379[1]> select 0
63 OK
64 127.0.0.1:6379> del set1
65 (integer) 1
66 127.0.0.1:6379> keys *
67 1) "hash1"
68 2) "sortedset1"
69 3) "list2"
View Code

4、redis的事務

1). 全部命令順序執行,期間,Redis不會再爲其它客戶端的請求提供任何服務,從而保證了事物中的全部命令被原子的執行。
2). 和關係型數據庫中的事務不一樣的是,在Redis事務中若是有某一條命令執行失敗,其後的命令仍然會被繼續執行。
3). 咱們能夠經過MULTI命令開啓一個事務,有關係型數據庫開發經驗的人能夠將其理解爲"BEGIN TRANSACTION"語句。在該語句以後執行的命令都將被視爲事務以內的操做,最後咱們能夠經過執行EXEC/DISCARD命令來提交/回滾該事務內的全部操做。這兩個Redis命令可被視爲等同於關係型數據庫中的COMMIT/ROLLBACK語句。

multi 用於標記事務的開始,其後執行的命令都將被存入命令隊列,直到執行exec時,這些命令纔會被原子的執行。 始終返回OK
exec 執行在一個事務內命令隊列中的全部命令,同時將當前鏈接的狀態恢復爲正常狀態,即非事務狀態。若是在事務中執行了watch命令,那麼只有當watch所監控的keys沒有被修改的前提下,exec命令才能執行事務隊列中的全部命令,不然exec將放棄當前事務中的全部命令。 原子性的返回事務中各條命令的返回結果。若是在事務中使用了watch,一旦事務被放棄,exec將返回NULL-multi-bulk回覆。

 1 127.0.0.1:6379> multi
 2 OK
 3 127.0.0.1:6379> set k1 string
 4 QUEUED
 5 #因爲k1爲字符串類型,因此incr會報錯,可是之後其餘命令正常執行
 6 127.0.0.1:6379> incr k1
 7 QUEUED
 8 127.0.0.1:6379> set k1 newstring
 9 QUEUED
10 127.0.0.1:6379> get k1
11 QUEUED
12 127.0.0.1:6379> exec
13 1) OK
14 2) (error) ERR value is not an integer or out of range
15 3) OK
16 4) "newstring"
View Code

discard 回滾事務隊列中的全部命令,同時再將當前鏈接的狀態恢復爲正常狀態,即非事務狀態。若是watch命令被使用,該命令將unwatch全部的Keys。
watch key [key ...] O(1) 在multi命令執行以前,能夠指定待監控的keys,然而在執行exec以前,若是被監控的keys發生修改,exec將放棄執行該事務隊列中的全部命令。
unwatch O(1) 取消當前事務中指定監控的keys,若是執行了exec或discard命令,則無需手工執行該命令,由於事務中全部被監控的keys都將自動取消。
 

 1 127.0.0.1:6379> set id 1
 2 OK
 3 127.0.0.1:6379> set name n1
 4 OK
 5 127.0.0.1:6379> set age 12
 6 OK
 7 127.0.0.1:6379> watch id
 8 OK
 9 127.0.0.1:6379> multi 
10 OK
11 127.0.0.1:6379> set name n2
12 QUEUED
13 127.0.0.1:6379> incr age
14 QUEUED
15 127.0.0.1:6379> exec
16 (nil)
17 127.0.0.1:6379> get age
18 "12"
19 127.0.0.1:6379> get name
20 "n1"
View Code

 注意,在提交事務以前,則執行exec命令以前,咱們在另外一個窗口對id進行修改(set id 2),能夠看出,該事務沒有執行成功

5、redis的主從複製

1). 同一個Master能夠同步多個Slaves節點。

2). Slave一樣能夠接受其它Slaves的鏈接和同步請求。

3). Master Server是以非阻塞的方式爲Slaves提供服務。因此在Master-Slave同步期間,客戶端仍然能夠提交查詢或修改請求。

4). Slave Server一樣是以非阻塞的方式完成數據同步。在同步期間,若是有客戶端提交查詢請求,Redis則返回同步以前的數據。

5). 爲了分載Master的讀操做壓力,Slave服務器能夠爲客戶端提供只讀操做的服務,寫服務仍然必須由Master來完成。從而實現讀寫分離

在Slave啓動並鏈接到Master以後,它將主動發送一個SYNC命令。此後Master將啓動後臺存盤進程,同時收集全部接收到的用於修改數據集的命令,在後臺進程執行完畢後,Master將傳送整個數據庫文件到Slave,以完成一次徹底同步。而Slave服務器在接收到數據庫文件數據以後將其存盤並加載到內存中。此後,Master繼續將全部已經收集到的修改命令,和新的修改命令依次傳送給Slaves,Slave將在本次執行這些數據修改命令,從而達到最終的數據同步。若Master和Slave之間的連接出現斷連現象,Slave能夠自動重連Master,可是在鏈接成功以後,一次徹底同步將被自動執行。 

同時啓動兩個Redis服務器,能夠考慮在同一臺機器上啓動兩個Redis服務器,分別監聽不一樣的端口,如6379和6380。複製redis.conf並命名爲slave.conf,編輯該配置文件,在84行位置將其中監聽的端口改成6380:配置以下port 6380,分配啓動兩個server,啓動時能夠將配置文件做爲啓動命令的參數。命令以下:redis-server redis.conf ,當咱們把兩個server都啓動時,能夠進行如下步驟:

1 redis-cli -p 6380
View Code

經過不一樣的端口來連接服務端,此時,當前客戶端連接的6380端口的服務端,咱們讓這個服務端當作slave節點的角色。執行以下命令

slaveof 127.0.0.1 6379
View Code

當返回ok時,這裏我Master-Slave創建成功。在監聽端口爲6379的服務器上咱們用客戶端進行操做

1 [root@hbase redis-3.2.5]# src/redis-cli -p 6379
2 127.0.0.1:6379> set k1 v1
3 OK
4 127.0.0.1:6379> hset k2 f2 v2
5 (integer) 1
6 127.0.0.1:6379> 
View Code

在slave節點,獲取該值:

1 [root@hbase redis-3.2.5]# src/redis-cli -p 6380
2 127.0.0.1:6380> slaveof 127.0.0.1 6379
3 OK
4 127.0.0.1:6380> keys *
5 1) "k1"
6 2) "k2"
7 127.0.0.1:6380> get k1
8 "v1"
View Code

說明兩個節點主從已經同步。實現了主從同步的效果。須要注意的是:上面的方式只是保證了在執行slaveof命令以後,redis_6380成爲了redis_6379的slave,一旦服務(redis_6380)從新啓動以後,他們之間的複製關係將終止。若是但願長期保證這兩個服務器之間的Replication關係,能夠在redis_6380的配置文件中作以下修改:

# slaveof <masterip> <masterport>改成slaveof 127.0.0.1 6379

保存退出。這樣就能夠保證Redis_6380服務程序在每次啓動後都會主動創建與Redis_6379的Replication鏈接了。

6、redis的持久化 

6.一、Redis提供的持久化機制: 

1). RDB持久化:該機制是指在指定的時間間隔內將內存中的數據集快照寫入磁盤。 

2). AOF持久化:該機制將以日誌的形式記錄服務器所處理的每個寫操做,在Redis服務器啓動之初會讀取該文件來從新構建數據庫,以保證啓動後數據庫中的數據是完整的。

6.二、RDB機制的優點和劣勢:

優點:
1). 採用該方式,整個Redis數據庫將只包含一個文件,經過這樣的備份策略,一旦系統出現災難性故障,咱們能夠很是容易的進行恢復。
2). 性能最大化,對於Redis的服務進程而言,在開始持久化時,它惟一須要作的只是fork出子進程,再由子進程完成這些持久化的工做,這樣能夠極避免服務進程執行IO操做。
劣勢:

1). 若是你想保證數據的高可用性,那麼RDB將不是一個很好的選擇。由於系統一旦在定時持久化以前出現宕機現象,此前沒有來得及寫入磁盤的數據都將丟失。

2). 因爲RDB是經過fork子進程來協助完成數據持久化工做的,所以,若是當數據集較大時,可能會致使整個服務器中止服務必定的時間。

6.三、AOF機制的優點和劣勢: 

優點
1). 帶來更高的數據安全性,即數據持久性。Redis中提供了3中同步策略,即每秒同步、每修改同步和不一樣步。事實上,每秒同步也是異步完成的,其效率也是很是高的,所差的是一旦系統出現宕機現象,那麼這一秒鐘以內修改的數據將會丟失。而每修改同步,咱們能夠將其視爲同步持久化,即每次發生的數據變化都會被當即記錄到磁盤中。能夠預見,這種方式在效率上是最低的。

2). 因爲該機制對日誌文件的寫入操做採用的是append模式,所以在寫入過程當中即便出現宕機現象,也不會破壞日誌文件中已經存在的內容。然而若是咱們本次操做只是寫入了一半數據就出現了系統崩潰問題,在Redis下一次啓動以前,能夠經過redis-check-aof工具來解決數據一致性的問題。

3). 若是日誌過大,Redis能夠自動啓用rewrite機制。即Redis以append模式不斷的將修改數據寫入到老的磁盤文件中,同時Redis還會建立一個新的文件用於記錄此期間有哪些修改命令被執行。所以在進行rewrite切換時能夠更好的保證數據安全性。

4). AOF包含一個格式清晰、易於理解的日誌文件用於記錄全部的修改操做。事實上,咱們也能夠經過該文件完成數據的重建。
劣勢
1). 對於相同數量的數據集而言,AOF文件一般要大於RDB文件。
2). 根據同步策略的不一樣,AOF在運行效率上每每會慢於RDB。

介紹完理論以後,咱們配置redis的持久化方案:

rdb方案,在redis.conf中以下配置(默認配置) 

1 save 900 1              #在900秒(15分鐘)以後,若是至少有1個key發生變化,則dump內存快照。
2 save 300 10            #在300秒(5分鐘)以後,若是至少有10個key發生變化,則dump內存快照。
3 save 60 10000        #在60秒(1分鐘)以後,若是至少有10000個key發生變化,則dump內存快照。
View Code

aof方案的配置:

1 在Redis的配置文件中存在三種同步方式,它們分別是:
2 appendfsync always     #每次有數據修改發生時都會寫入AOF文件。
3 appendfsync everysec  #每秒鐘同步一次,該策略爲AOF的缺省策略。
4 appendfsync no          #從不一樣步。高效可是數據不會被持久化。
View Code

7、redis的分片

分片(partitioning)就是將你的數據拆分到多個 Redis 實例的過程,Redis 引入另外一種哈希槽(hash slot)的概念。Redis 集羣中內置了 16384 個哈希槽,當須要在 Redis 集羣中放置一個 key-value 時,redis 先對 key 使用 crc16 算法得出結果,而後對 16384 求餘數,這樣每一個 key 對應一個編號在 0-16383 之間的哈希槽,redis 會根據節點數量大體均等的將哈希槽映射到不一樣節點。

原來的redis分片實現:

客戶端分片(Client side partitioning),客戶端直接選擇正確的節點來寫入和讀取指定鍵。

代理協助分片(Proxy assisted partitioning),客戶端發送請求到一個能夠理解 Redis 協議的代理上,而不是直接發送請求到 Redis 實例上。代理會根據配置好的分片模式,來保證轉發請求到正確的 Redis 實例,並返回響應給客戶端。

查詢路由(Query routing),發送查詢到一個隨機實例,這個實例會保證轉發查詢到正確的節點。 

新版本Redis的解決辦法:

Redis3.0版的一大特性就是支持集羣(Cluster)功能。Redis集羣是自動分片和高可用的首選方式。集羣的特色在於擁有和單機實例一樣的功能,同時在網絡分區後可以提供必定的可訪問性以及對主數據庫故障恢復的支持。

======================= 如下概念摘自網絡===================

集羣節點屬性: 

每一個節點在集羣中都有一個獨一無二的 ID , 該 ID 是一個十六進制表示的 160 位隨機數, 在節點第一次啓動時由 /dev/urandom 生成。節點會將它的 ID 保存到配置文件, 只要這個配置文件不被刪除, 節點就會一直沿用這個 ID 。節點 ID 用於標識集羣中的每一個節點。 一個節點能夠改變它的 IP 和端口號, 而不改變節點 ID 。 集羣能夠自動識別出 IP/端口號的變化, 並將這一信息經過 Gossip 協議廣播給其餘節點知道。

節點握手:

節點老是應答(accept)來自集羣鏈接端口的鏈接請求, 並對接收到的 PING 數據包進行回覆, 即便這個 PING 數據包來自不可信的節點。然而, 除了 PING 以外, 節點會拒絕其餘全部並不是來自集羣節點的數據包。要讓一個節點認可另外一個節點同屬於一個集羣, 只有如下兩種方法:

一、一個節點能夠經過向另外一個節點發送 MEET 信息, 來強制讓接收信息的節點認可發送信息的節點爲集羣中的一份子。 一個節點僅在管理員顯式地向它發送CLUSTER MEET ip port 命令時, 纔會向另外一個節點發送 MEET 信息。

二、若是一個可信節點向另外一個節點傳播第三者節點的信息, 那麼接收信息的那個節點也會將第三者節點識別爲集羣中的一份子。 也便是說, 若是 A 認識 B , B 認識 C , 而且 B 向 A 傳播關於 C 的信息, 那麼 A 也會將 C 識別爲集羣中的一份子, 並嘗試鏈接 C 。

這意味着若是咱們將一個/一些新節點添加到一個集羣中, 那麼這個/這些新節點最終會和集羣中已有的其餘全部節點鏈接起來。這說明只要管理員使用 CLUSTER MEET 命令顯式地指定了可信關係, 集羣就能夠自動發現其餘節點。這種節點識別機制經過防止不一樣的 Redis 集羣由於 IP 地址變動或者其餘網絡事件的發生而產生意料以外的聯合(mix), 從而使得集羣更具健壯性。當節點的網絡鏈接斷開時, 它會主動鏈接其餘已知的節點。

MOVED 轉向:

一個 Redis 客戶端能夠向集羣中的任意節點(包括從節點)發送命令請求。 節點會對命令請求進行分析, 若是該命令是集羣能夠執行的命令, 那麼節點會查找這個命令所要處理的鍵所在的槽。若是要查找的哈希槽正好就由接收到命令的節點負責處理, 那麼節點就直接執行這個命令。若是所查找的槽不是由該節點處理的話, 節點將查看自身內部所保存的哈希槽到節點 ID 的映射記錄, 並向客戶端回覆一個 MOVED 錯誤。爲了讓客戶端的轉向操做盡量地簡單, 節點在 MOVED 錯誤中直接返回目標節點的 IP 和端口號, 而不是目標節點的 ID 。客戶端應該記錄(memorize)下「槽 3999 由節點 127.0.0.1:6381 負責處理「這一信息, 這樣當再次有命令須要對槽 3999 執行時, 客戶端就能夠加快尋找正確節點的速度。當集羣處於穩定狀態時, 全部客戶端最終都會保存有一個哈希槽至節點的映射記錄(map of hash slots to nodes), 使得集羣很是高效: 客戶端能夠直接向正確的節點發送命令請求, 無須轉向、代理或者其餘任何可能發生單點故障(single point failure)的實體(entiy)。除了 MOVED 轉向錯誤以外, 一個客戶端還應該能夠處理稍後介紹的 ASK 轉向錯誤。

集羣在線重配置:

Redis 集羣支持在集羣運行的過程當中添加或者移除節點。實際上, 節點的添加操做和節點的刪除操做能夠抽象成同一個操做, 那就是, 將哈希槽從一個節點移動到另外一個節點。所以, 實現 Redis 集羣在線重配置的核心就是將槽從一個節點移動到另外一個節點的能力。 由於一個哈希槽實際上就是一些鍵的集合, 因此 Redis 集羣在重哈希(rehash)時真正要作的, 就是將一些鍵從一個節點移動到另外一個節點。要理解 Redis 集羣如何將槽從一個節點移動到另外一個節點, 咱們須要對 CLUSTER 命令的各個子命令進行介紹, 這些命理負責管理集羣節點的槽轉換表(slots translation table)。如下是 CLUSTER 命令可用的子命令:

CLUSTER ADDSLOTS slot1 [slot2] ... [slotN]

CLUSTER DELSLOTS slot1 [slot2] ... [slotN]

CLUSTER SETSLOT slot NODE node

CLUSTER SETSLOT slot MIGRATING node

CLUSTER SETSLOT slot IMPORTING node

最開頭的兩條命令 ADDSLOTS 和 DELSLOTS 分別用於向節點指派(assign)或者移除節點, 當槽被指派或者移除以後, 節點會將這一信息經過 Gossip 協議傳播到整個集羣。 ADDSLOTS 命令一般在新建立集羣時, 做爲一種快速地將各個槽指派給各個節點的手段來使用。CLUSTER SETSLOT slot NODE node 子命令能夠將指定的槽 slot 指派給節點 node 。至於 CLUSTER SETSLOT slot MIGRATING node 命令和 CLUSTER SETSLOT slot IMPORTING node 命令, 前者用於將給定節點 node 中的槽 slot 遷移出節點, 然後者用於將給定槽 slot導入到節點 node :當一個槽被設置爲 MIGRATING 狀態時, 原來持有這個槽的節點仍然會繼續接受關於這個槽的命令請求, 但只有命令所處理的鍵仍然存在於節點時, 節點纔會處理這個命令請求。若是命令所使用的鍵不存在與該節點, 那麼節點將向客戶端返回一個 -ASK 轉向(redirection)錯誤, 告知客戶端, 要將命令請求發送到槽的遷移目標節點。當一個槽被設置爲 IMPORTING 狀態時, 節點僅在接收到 ASKING 命令以後, 纔會接受關於這個槽的命令請求。若是客戶端沒有向節點發送 ASKING 命令, 那麼節點會使用 -MOVED 轉向錯誤將命令請求轉向至真正負責處理這個槽的節點。上面關於 MIGRATING 和 IMPORTING 的說明有些難懂, 讓咱們用一個實際的實例來講明一下。假設如今, 咱們有 A 和 B 兩個節點, 而且咱們想將槽 8 從節點 A 移動到節點 B , 因而咱們:向節點 B 發送命令 CLUSTER SETSLOT 8 IMPORTING A,向節點 A 發送命令 CLUSTER SETSLOT 8 MIGRATING B,每當客戶端向其餘節點發送關於哈希槽 8 的命令請求時, 這些節點都會向客戶端返回指向節點 A 的轉向信息:若是命令要處理的鍵已經存在於槽 8 裏面, 那麼這個命令將由節點 A 處理。若是命令要處理的鍵未存在於槽 8 裏面(好比說,要向槽添加一個新的鍵), 那麼這個命令由節點 B 處理。這種機制將使得節點 A 再也不建立關於槽 8 的任何新鍵。與此同時, 一個特殊的客戶端 redis-trib 以及 Redis 集羣配置程序(configuration utility)會將節點 A 中槽 8 裏面的鍵移動到節點 B 。

鍵的移動操做由如下兩個命令執行:

CLUSTER GETKEYSINSLOT slot count

上面的命令會讓節點返回 count 個 slot 槽中的鍵, 對於命令所返回的每一個鍵, redis-trib 都會向節點 A 發送一條 MIGRATE 命令, 該命令會將所指定的鍵原子地(atomic)從節點 A 移動到節點 B (在移動鍵期間,兩個節點都會處於阻塞狀態,以避免出現競爭條件)。

如下爲 MIGRATE 命令的運做原理:

MIGRATE target_host target_port key target_database id timeout執行 MIGRATE 命令的節點會鏈接到 target 節點, 並將序列化後的 key 數據發送給 target , 一旦 target 返回 OK , 節點就將本身的 key 從數據庫中刪除。從一個外部客戶端的視角來看, 在某個時間點上, 鍵 key 要麼存在於節點 A , 要麼存在於節點 B , 但不會同時存在於節點 A 和節點 B 。由於 Redis 集羣只使用 0 號數據庫, 因此當 MIGRATE 命令被用於執行集羣操做時, target_database 的值老是 0 。target_database 參數的存在是爲了讓 MIGRATE 命令成爲一個通用命令, 從而能夠做用於集羣之外的其餘功能。咱們對 MIGRATE 命令作了優化, 使得它即便在傳輸包含多個元素的列表鍵這樣的複雜數據時, 也能夠保持高效。不過, 儘管 MIGRATE 很是高效, 對一個鍵很是多、而且鍵的數據量很是大的集羣來講, 集羣重配置仍是會佔用大量的時間, 可能會致使集羣沒辦法適應那些對於響應時間有嚴格要求的應用程序。

ASK 轉向:

在以前介紹 MOVED 轉向的時候, 咱們說除了 MOVED 轉向以外, 還有另外一種 ASK 轉向。當節點須要讓一個客戶端長期地(permanently)將針對某個槽的命令請求發送至另外一個節點時, 節點向客戶端返回 MOVED 轉向。另外一方面, 當節點須要讓客戶端僅僅在下一個命令請求中轉向至另外一個節點時, 節點向客戶端返回 ASK 轉向。好比說, 在咱們上一節列舉的槽 8 的例子中, 由於槽 8 所包含的各個鍵分散在節點 A 和節點 B 中, 因此當客戶端在節點 A 中沒找到某個鍵時, 它應該轉向到節點 B 中去尋找, 可是這種轉向應該僅僅影響一次命令查詢, 而不是讓客戶端每次都直接去查找節點 B : 在節點 A 所持有的屬於槽 8 的鍵沒有所有被遷移到節點 B 以前, 客戶端應該先訪問節點 A , 而後再訪問節點 B 。由於這種轉向只針對 16384 個槽中的其中一個槽, 因此轉向對集羣形成的性能損耗屬於可接受的範圍。由於上述緣由, 若是咱們要在查找節點 A 以後, 繼續查找節點 B , 那麼客戶端在向節點 B 發送命令請求以前, 應該先發送一個 ASKING 命令, 不然這個針對帶有IMPORTING 狀態的槽的命令請求將被節點 B 拒絕執行。接收到客戶端 ASKING 命令的節點將爲客戶端設置一個一次性的標誌(flag), 使得客戶端能夠執行一次針對 IMPORTING 狀態的槽的命令請求。從客戶端的角度來看, ASK 轉向的完整語義(semantics)以下:

一、若是客戶端接收到 ASK 轉向, 那麼將命令請求的發送對象調整爲轉向所指定的節點。

二、先發送一個 ASKING 命令,而後再發送真正的命令請求。

三、沒必要更新客戶端所記錄的槽 8 至節點的映射: 槽 8 應該仍然映射到節點 A , 而不是節點 B 。

一旦節點 A 針對槽 8 的遷移工做完成, 節點 A 在再次收到針對槽 8 的命令請求時, 就會向客戶端返回 MOVED 轉向, 將關於槽 8 的命令請求長期地轉向到節點 B 。注意, 即便客戶端出現 Bug , 過早地將槽 8 映射到了節點 B 上面, 但只要這個客戶端不發送 ASKING 命令, 客戶端發送命令請求的時候就會趕上 MOVED 錯誤, 並將它轉向回節點 A 。

 
容錯:

節點失效檢測,如下是節點失效檢查的實現方法:

一、當一個節點向另外一個節點發送 PING 命令, 可是目標節點未能在給定的時限內返回 PING 命令的回覆時, 那麼發送命令的節點會將目標節點標記爲 PFAIL(possible failure,可能已失效)。等待 PING 命令回覆的時限稱爲「節點超時時限(node timeout)」, 是一個節點選項(node-wise setting)。

二、每次當節點對其餘節點發送 PING 命令的時候, 它都會隨機地廣播三個它所知道的節點的信息, 這些信息裏面的其中一項就是說明節點是否已經被標記爲 PFAIL或者 FAIL 。當節點接收到其餘節點發來的信息時, 它會記下那些被其餘節點標記爲失效的節點。 這稱爲失效報告(failure report)。

三、若是節點已經將某個節點標記爲 PFAIL , 而且根據節點所收到的失效報告顯式, 集羣中的大部分其餘主節點也認爲那個節點進入了失效狀態, 那麼節點會將那個失效節點的狀態標記爲 FAIL 。

四、一旦某個節點被標記爲 FAIL , 關於這個節點已失效的信息就會被廣播到整個集羣, 全部接收到這條信息的節點都會將失效節點標記爲 FAIL 。

簡單來講, 一個節點要將另外一個節點標記爲失效, 必須先詢問其餘節點的意見, 而且獲得大部分主節點的贊成才行。由於過時的失效報告會被移除, 因此主節點要將某個節點標記爲 FAIL 的話, 必須以最近接收到的失效報告做爲根據。

從節點選舉:一旦某個主節點進入 FAIL 狀態, 若是這個主節點有一個或多個從節點存在, 那麼其中一個從節點會被升級爲新的主節點, 而其餘從節點則會開始對這個新的主節點進行復制。新的主節點由已下線主節點屬下的全部從節點中自行選舉產生, 如下是選舉的條件:

一、這個節點是已下線主節點的從節點。

二、已下線主節點負責處理的槽數量非空。

三、從節點的數據被認爲是可靠的, 也便是, 主從節點之間的複製鏈接(replication link)的斷線時長不能超過節點超時時限(node timeout)乘以REDIS_CLUSTER_SLAVE_VALIDITY_MULT 常量得出的積。

若是一個從節點知足了以上的全部條件, 那麼這個從節點將向集羣中的其餘主節點發送受權請求, 詢問它們, 是否容許本身(從節點)升級爲新的主節點。若是發送受權請求的從節點知足如下屬性, 那麼主節點將向從節點返FAILOVER_AUTH_GRANTED 受權, 贊成從節點的升級要求:

一、發送受權請求的是一個從節點, 而且它所屬的主節點處於 FAIL 狀態。

二、在已下線主節點的全部從節點中, 這個從節點的節點 ID 在排序中是最小的。

三、這個從節點處於正常的運行狀態: 它沒有被標記爲 FAIL 狀態, 也沒有被標記爲 PFAIL 狀態。

一旦某個從節點在給定的時限內獲得大部分主節點的受權, 它就會開始執行如下故障轉移操做:

一、經過 PONG 數據包(packet)告知其餘節點, 這個節點如今是主節點了。

二、經過 PONG 數據包告知其餘節點, 這個節點是一個已升級的從節點(promoted slave)。

三、接管(claiming)全部由已下線主節點負責處理的哈希槽。

四、顯式地向全部節點廣播一個 PONG 數據包, 加速其餘節點識別這個節點的進度, 而不是等待定時的 PING / PONG 數據包。

全部其餘節點都會根據新的主節點對配置進行相應的更新:

一、全部被新的主節點接管的槽會被更新。

二、已下線主節點的全部從節點會察覺到 PROMOTED 標誌, 並開始對新的主節點進行復制。

三、若是已下線的主節點從新回到上線狀態, 那麼它會察覺到 PROMOTED 標誌, 並將自身調整爲現任主節點的從節點。

在集羣的生命週期中, 若是一個帶有 PROMOTED 標識的主節點由於某些緣由轉變成了從節點, 那麼該節點將丟失它所帶有的 PROMOTED 標識 

======================= 以上概念摘自網絡===================

 搭建redis集羣環境須要執行的ruby的腳本,因此須要安裝ruby的環境。建議用yum進行安裝,因爲具體的操做環境不相同,因此具體操做過程還需視操做環境而定 

1 [root@root java]# yum install ruby
2 [root@root java]# yum install rubygems
3 [root@root java]# gem install redis
View Code

期間會出現選擇選項,鍵入yes便可。當出現Successfully installed redis-3.3.1  1 gem installed,說明redis集羣須要的ruby環境安裝成功。開始搭建redis環境

建立redis-cluster文件夾,並在其中建立6379,6380,6381文件夾,修改redis.conf文件,並將其中的端口分別設置成6379,6380,6381,redis.conf中的其餘配置爲

daemonize yes

cluster-enabled yes

cluster-config-file nodes.conf

cluster-node-timeout 5000

appendonly yes

結構目錄以下:

 1 [root@storm1 java]# cd redis-cluster/
 2 [root@storm1 redis-cluster]# ll
 3 total 12
 4 drwxr-xr-x. 2 root root 4096 Nov 14 05:50 6379
 5 drwxr-xr-x. 2 root root 4096 Nov 14 05:51 6380
 6 drwxr-xr-x. 2 root root 4096 Nov 14 05:52 6381
 7 [root@storm1 redis-cluster]# cd 6379
 8 [root@storm1 6379]# cat redis.conf 
 9 port 6379
10 daemonize yes
11 cluster-enabled yes
12 cluster-config-file nodes.conf
13 cluster-node-timeout 5000
14 appendonly yes[root@storm1 6379]# more ../6380/redis.conf 
15 port 6380
16 daemonize yes
17 cluster-enabled yes
18 cluster-config-file nodes.conf
19 cluster-node-timeout 5000
20 appendonly yes
21 [root@storm1 6379]# 
View Code

分別啓動這3個redis實例,並建立集羣,讓三個實例互相通信:

 1 [root@storm1 redis-3.2.5]# src/redis-trib.rb create --replicas 0 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381
 2 >>> Creating cluster
 3 >>> Performing hash slots allocation on 3 nodes...
 4 Using 3 masters:
 5 127.0.0.1:6379
 6 127.0.0.1:6380
 7 127.0.0.1:6381
 8 M: 76d37cdb954e0c293cec5c6bc27015af40d4a59f 127.0.0.1:6379
 9    slots:0-5460 (5461 slots) master
10 M: f18ab812b7f9e933639b3afdab964039ddd3ceba 127.0.0.1:6380
11    slots:5461-10922 (5462 slots) master
12 M: 644f9bca1af9cc9e3f1543ab5f0b434d11ff59b0 127.0.0.1:6381
13    slots:10923-16383 (5461 slots) master
14 Can I set the above configuration? (type 'yes' to accept): yes
15 >>> Nodes configuration updated
16 >>> Assign a different config epoch to each node
17 >>> Sending CLUSTER MEET messages to join the cluster
18 Waiting for the cluster to join....
19 >>> Performing Cluster Check (using node 127.0.0.1:6379)
20 M: 76d37cdb954e0c293cec5c6bc27015af40d4a59f 127.0.0.1:6379
21    slots:0-5460 (5461 slots) master
22    0 additional replica(s)
23 M: 644f9bca1af9cc9e3f1543ab5f0b434d11ff59b0 127.0.0.1:6381
24    slots:10923-16383 (5461 slots) master
25    0 additional replica(s)
26 M: f18ab812b7f9e933639b3afdab964039ddd3ceba 127.0.0.1:6380
27    slots:5461-10922 (5462 slots) master
28    0 additional replica(s)
29 [OK] All nodes agree about slots configuration.
30 >>> Check for open slots...
31 >>> Check slots coverage...
32 [OK] All 16384 slots covered.
View Code

至此redis集羣即搭建成功,簡單進行測試一下

1 [root@storm1 redis-3.2.5]# src/redis-cli -c -p 6379
2 127.0.0.1:6379> set k1 v1
3 -> Redirected to slot [12706] located at 127.0.0.1:6381
4 OK
5 127.0.0.1:6381> exit
6 [root@storm1 redis-3.2.5]# src/redis-cli -c -p 6381
7 127.0.0.1:6381> keys *
8 1) "k1"
9 127.0.0.1:6381> 
View Code

能夠看到,雖然咱們第一次鏈接的是6379端口,redis cluster 自動幫咱們重定向到 6381 。在6381端口的實例中出現了咱們以前設置的k1,說明整個集羣是工做的。

8、redis的管理命令

config get parameter 用於讀取服務器的運行時參數,可是並非全部的配置參數均可以經過該命令進行讀取。該命令的參數接受glob風格的模式匹配規則,所以若是參數中包含模式元字符,那麼全部匹配的參數都將以key/value方式被列出。若是參數是*,那麼該命令支持的全部參數都將被列出。

config set parameter value 該命令用於配置Redis服務器的運行時參數,在設置成功以後無需重啓即可生效。然而並不是全部的參數均可以經過該命令進行動態設置。
dbsize 返回當前打開的數據庫中keys的數量。
flushall  清空當前服務器管理的數據庫中的全部keys,不只限於當前打開的數據庫。
flushdb  清空當前數據庫中的全部keys。
info  獲取和服務器運行情況相關的一些列統計數字。
save 設置RDB持久化模式的保存策略。
shutdown  中止全部的客戶端,同時以阻塞的方式執行內存數據持久化。若是AOF模式被啓用,則將緩存中的數據flush到AOF文件。退出服務器。
slaveof host port 該命令用於修改slave服務器的主從複製設置。
slowlog subcommand [argument] 該命令主要用於讀取執行時間較長的命令。因爲slowlog隊列不會被持久化到磁盤,所以Redis在收集命令時不會對性能產生很大的影響。一般咱們能夠將參數"slowlog-log-slower-than"設置爲0,以便收集全部命令的執行時間。該命令還包含如下幾個子命令:
1). slowlog get N: 從slowlog隊列中讀取命令信息,N表示最近N條命令的信息。
2). slowlog len:獲取slowlog隊列的長度。
3). slowlog reset:清空slowlog中的內容。

 1 redis 127.0.0.1:6379> config get port
 2 1) "port"
 3 2) "6379"
 4 redis 127.0.0.1:6379> keys *
 5 1) "k1"
 6 redis 127.0.0.1:6379> flushdb
 7 OK
 8 redis 127.0.0.1:6379> keys *
 9 (empty list or set)
10 redis 127.0.0.1:6379> dbsize
11 (integer) 0
12 redis 127.0.0.1:6379> set k1 v1
13 OK
14 redis 127.0.0.1:6379> dbsize
15 (integer) 1
View Code

9、redis的java操做

maven依賴 

1 <dependency>
2     <groupId>redis.clients</groupId>
3     <artifactId>jedis</artifactId>
4     <version>2.6.2</version>
5     <type>jar</type>
6     <scope>compile</scope>
7 </dependency>
View Code

 java代碼:

 1 import redis.clients.jedis.Jedis;
 2 
 3 public class RedisDao {
 4 
 5     public static void main(String[] args) {
 6         Jedis jedis = new Jedis("127.0.0.1", 6379);
 7         jedis.set("k2", "v2");
 8         System.out.println(jedis.get("k2"));
 9         jedis.hset("k3", "f1", "v1");
10         System.out.println(jedis.hget("k3", "f1"));
11         System.out.println(jedis.keys("*"));
12         jedis.close();
13     }
14 }
View Code

10、redis與spring整合 

10.1 引入jedis包和spring包

10.2 spring-mvc.xml 

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
 3     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd" default-autowire="byName">
 4 
 5     <bean id="redisClient" class="com.eztcn.commons.redis.RedisClientFactoryBean">
 6         <!-- 單個應用中的連接池最大連接數,默認8 -->
 7         <property name="maxTotal" value="150" />
 8         <!-- 單個應用中的連接池最大空閒數,默認8 -->
 9         <property name="maxIdle" value="50" />
10         <!-- 單個應用中的連接池最大連接數,默認8 -->
11         <property name="minIdle" value="30" />
12         <!-- 設置在每一次取對象時測試ping -->
13         <property name="testOnBorrow" value="false" />
14         <!-- host:port -->
15           <property name="ipConfString" value="192.168.1.60:7001" /> 
16     </bean>
17 </beans>
View Code

 固然須要在spring配置文件中引入該配置文件:<import resource="spring/spring-config-redis.xml" />

10.3 RedisClientFactoryBean.java 

 1 package com.commons.redis;
 2 
 3 import org.apache.commons.lang3.StringUtils;
 4 import org.springframework.beans.factory.FactoryBean;
 5 
 6 public class RedisClientFactoryBean implements FactoryBean<RedisClient> {
 7     private RedisClientConfig redisClientConfig = new RedisClientConfig();
 8 
 9     public RedisClient getObject() throws Exception {
10         if (StringUtils.isNotBlank(this.redisClientConfig.getIpConfString())) {
11             return new RedisClient(this.redisClientConfig);
12         }
13         throw new RedisInitializerException("RedisClient init parameter masterConfString is empty,please check spring config file!");
14     }
15 
16     public Class<?> getObjectType() {
17         return RedisClient.class;
18     }
19 
20     public boolean isSingleton() {
21         return true;
22     }
23 
24     public void setIpConfString(String string) {
25         this.redisClientConfig.setIpConfString(string);
26     }
27 
28     public void setMaxTotal(int maxTotal) {
29         this.redisClientConfig.setMaxTotal(maxTotal);
30     }
31 
32     public void setMaxIdle(int maxIdle) {
33         this.redisClientConfig.setMaxIdle(maxIdle);
34     }
35 
36     public void setMinIdle(int minIdle) {
37         this.redisClientConfig.setMinIdle(minIdle);
38     }
39 
40     public void setTestOnBorrow(boolean flag) {
41         this.redisClientConfig.setTestOnBorrow(flag);
42     }
43 }
View Code

10.4 RedisClientConfig.java

 1 package com.commons.redis;
 2 
 3 import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
 4 
 5 /**
 6  * 
 7  * @描述 : 配置redis的相關屬性
 8  * @建立時間: 2015年7月20日上午11:05:53
 9  *
10  */
11 public class RedisClientConfig {
12     private GenericObjectPoolConfig jedisPoolConfig = new GenericObjectPoolConfig();
13     
14     private String ipConfString;
15 
16     /**
17      * 
18      * @描述 : 單個應用中的連接池最大連接數
19      * @建立時間: 2015年7月20日上午11:11:10
20      *
21      * @param maxTotal
22      */
23     public void setMaxTotal(int maxTotal) {
24         this.jedisPoolConfig.setMaxTotal(maxTotal);
25     }
26 
27     /**
28      * @描述 :單個應用中的連接池最大空閒數 
29      * @建立時間: 2015年7月20日上午11:11:28
30      *
31      * @param maxIdle
32      */
33     
34     
35     public void setMaxIdle(int maxIdle) {
36         this.jedisPoolConfig.setMaxIdle(maxIdle);
37     }
38 
39     
40     /**
41      * @描述 : 單個應用中的連接池最大連接數
42      * @建立時間: 2015年7月20日上午11:11:43
43      *
44      * @param maxIdle
45      */
46     public void setMinIdle(int minIdle) {
47         this.jedisPoolConfig.setMinIdle(minIdle);
48     }
49 
50     /**
51      * @描述 : 設置在每一次取對象時測試ping 
52      * @建立時間: 2015年7月20日上午11:11:58
53      *
54      * @param flag
55      */
56     public void setTestOnBorrow(boolean flag) {
57         this.jedisPoolConfig.setTestOnBorrow(flag);
58     }
59 
60     public GenericObjectPoolConfig getJedisPoolConfig() {
61         return this.jedisPoolConfig;
62     }
63 
64     public String getIpConfString() {
65         return this.ipConfString;
66     }
67 
68     public void setIpConfString(String ipConfString) {
69         this.ipConfString = ipConfString;
70     }
71 }
View Code

10.5 RedisClient.java

  1 package com.commons.redis;
  2 
  3 import java.util.List;
  4 import java.util.Map;
  5 import java.util.Set;
  6 
  7 import org.apache.commons.lang3.StringUtils;
  8 import org.apache.commons.logging.Log;
  9 import org.apache.commons.logging.LogFactory;
 10 
 11 import redis.clients.jedis.BinaryClient;
 12 import redis.clients.jedis.Jedis;
 13 import redis.clients.jedis.JedisPool;
 14 
 15 public class RedisClient {
 16     private static final Log LOG = LogFactory.getLog(RedisClient.class);
 17     private RedisClientConfig redisClientConfig;
 18     private JedisPool jedisPool;
 19 
 20     public RedisClient(RedisClientConfig redisClientConfig) {
 21         this.redisClientConfig = redisClientConfig;
 22         init();
 23     }
 24 
 25     /**
 26      * 
 27      * @描述 : 初始化,配置ip和端口
 28      * @建立時間: 2015年7月20日下午1:43:29
 29      *
 30      */
 31     private void init() {
 32         LOG.info("redis client init start~");
 33         String ip = "";
 34         int port;
 35         if (StringUtils.isNotBlank(this.redisClientConfig.getIpConfString())) {
 36             String[] ipPortArray = this.redisClientConfig.getIpConfString().split(":");
 37             if (ipPortArray.length == 1) {
 38                 throw new RedisInitializerException(ipPortArray + " is not include host:port or host:port after split \":\"");
 39             }
 40             ip = ipPortArray[0];
 41             port = Integer.valueOf(ipPortArray[1]).intValue();
 42         } else {
 43             throw new RuntimeException("init throw exception");
 44         }
 45         LOG.info("write redis client connect ip:" + ip + ",port:" + port);
 46         this.jedisPool = new JedisPool(this.redisClientConfig.getJedisPoolConfig(), ip, port);
 47     }
 48 
 49     /**
 50      * 
 51      * @描述 : 設置鍵值對
 52      * @建立時間: 2015年7月20日下午1:44:10
 53      *
 54      * @param key
 55      * @param value
 56      * @return
 57      * @throws RedisAccessException
 58      */
 59     public String set(String key, String value) throws RedisAccessException {
 60         Jedis client = null;
 61         try {
 62             client = jedisPool.getResource();
 63             return client.set(key, value);
 64         } catch (Exception e) {
 65             LOG.error(e.getMessage(), e);
 66             throw new RedisAccessException(e);
 67         } finally {
 68             if (null != client) {
 69                 jedisPool.returnResourceObject(client);
 70             }
 71         }
 72     }
 73 
 74     /**
 75      * 
 76      * @描述 : 將值 value 關聯到 key ,並將 key 的生存時間設爲 seconds (以秒爲單位)。若是 key 已經存在, SETEX
 77      *     命令將覆寫舊值。
 78      * @建立時間: 2015年7月20日下午1:44:36
 79      *
 80      * @param key
 81      * @param seconds
 82      * @param value
 83      * @return
 84      * @throws RedisAccessException
 85      */
 86     public String set(String key, int seconds, String value) throws RedisAccessException {
 87         Jedis client = null;
 88         try {
 89             client = jedisPool.getResource();
 90             return client.setex(key, seconds, value);
 91         } catch (Exception e) {
 92             LOG.error(e.getMessage(), e);
 93             throw new RedisAccessException(e);
 94         } finally {
 95             if (null != client) {
 96                 jedisPool.returnResourceObject(client);
 97             }
 98         }
 99     }
100 
101     /**
102      * 
103      * @描述 : 若是 key 已經存在而且是一個字符串, APPEND 命令將 value 追加到 key 原來的值的末尾。 若是 key 不存在,
104      *     APPEND 就簡單地將給定 key 設爲 value ,就像執行 SET key value 同樣。
105      * @建立時間: 2015年7月20日下午1:45:55
106      *
107      * @param key
108      * @param value
109      * @return
110      * @throws RedisAccessException
111      */
112     public Long append(String key, String value) throws RedisAccessException {
113         Jedis client = null;
114         try {
115             client = jedisPool.getResource();
116             return client.append(key, value);
117         } catch (Exception e) {
118             LOG.error(e.getMessage(), e);
119             throw new RedisAccessException(e);
120         } finally {
121             if (null != client) {
122                 jedisPool.returnResourceObject(client);
123             }
124         }
125     }
126 
127     /**
128      * 
129      * @描述 : 返回 key 所關聯的字符串值。若是 key 不存在那麼返回特殊值 null 。 假如 key
130      *     儲存的值不是字符串類型,返回一個錯誤,由於 GET 只能用於處理字符串值。
131      * @建立時間: 2015年7月20日下午1:47:10
132      *
133      * @param key
134      * @return
135      * @throws RedisAccessException
136      */
137     public String get(String key) throws RedisAccessException {
138         Jedis client = null;
139         try {
140             client = jedisPool.getResource();
141             return client.get(key);
142         } catch (Exception e) {
143             LOG.error(e.getMessage(), e);
144             throw new RedisAccessException(e);
145         } finally {
146             if (null != client) {
147                 jedisPool.returnResourceObject(client);
148             }
149         }
150     }
151 
152     /**
153      * 
154      * @描述 : 刪除給定的一個或多個 key 。 不存在的 key 會被忽略。
155      * @建立時間: 2015年7月20日下午1:48:37
156      *
157      * @param key
158      * @return
159      * @throws RedisAccessException
160      */
161     public Long del(String key) throws RedisAccessException {
162         Jedis client = null;
163         try {
164             client = jedisPool.getResource();
165             return client.del(key);
166         } catch (Exception e) {
167             LOG.error(e.getMessage(), e);
168             throw new RedisAccessException(e);
169         } finally {
170             if (null != client) {
171                 jedisPool.returnResourceObject(client);
172             }
173         }
174     }
175 
176     /**
177      * 
178      * @描述 : 檢查給定 key 是否存在。
179      * @建立時間: 2015年7月20日下午1:48:48
180      *
181      * @param key
182      * @return
183      * @throws RedisAccessException
184      */
185     public Boolean exists(String key) throws RedisAccessException {
186         Jedis client = null;
187         try {
188             client = jedisPool.getResource();
189             return client.exists(key);
190         } catch (Exception e) {
191             LOG.error(e.getMessage(), e);
192             throw new RedisAccessException(e);
193         } finally {
194             if (null != client) {
195                 jedisPool.returnResourceObject(client);
196             }
197         }
198     }
199 
200     /**
201      * @描述 : 爲給定 key 設置生存時間,當 key 過時時(生存時間爲 0 ),它會被自動刪除。
202      * @建立時間: 2015年7月20日下午1:49:29
203      *
204      * @param key
205      * @param seconds
206      * @return
207      * @throws RedisAccessException
208      */
209     public Long expire(String key, int seconds) throws RedisAccessException {
210         Jedis client = null;
211         try {
212             client = jedisPool.getResource();
213             return client.expire(key, seconds);
214         } catch (Exception e) {
215             LOG.error(e.getMessage(), e);
216             throw new RedisAccessException(e);
217         } finally {
218             if (null != client) {
219                 jedisPool.returnResourceObject(client);
220             }
221         }
222     }
223     
224     
225     
226     /**
227      * @描述 : 爲給定 key 設置生存時間,當 key 過時時(生存時間爲 0 ),它會被自動刪除。
228      * @建立時間: 2015年7月20日下午1:49:29
229      *
230      * @param key
231      * @param seconds
232      * @return
233      * @throws RedisAccessException
234      */
235     public Long expireAt(String key, long unixTime) throws RedisAccessException {
236         Jedis client = null;
237         try {
238             client = jedisPool.getResource();
239             return client.expireAt(key,unixTime);
240         } catch (Exception e) {
241             LOG.error(e.getMessage(), e);
242             throw new RedisAccessException(e);
243         } finally {
244             if (null != client) {
245                 jedisPool.returnResourceObject(client);
246             }
247         }
248     }
249 
250     /**
251      * 
252      * @描述 : 將給定 key 的值設爲 value ,並返回 key 的舊值(old value)。當 key
253      *     存在但不是字符串類型時,返回一個錯誤。
254      * @建立時間: 2015年7月20日下午1:50:28
255      *
256      * @param key
257      * @param value
258      * @return
259      * @throws RedisAccessException
260      */
261     public String getSet(String key, String value) throws RedisAccessException {
262         Jedis client = null;
263         try {
264             client = jedisPool.getResource();
265             return client.getSet(key, value);
266         } catch (Exception e) {
267             LOG.error(e.getMessage(), e);
268             throw new RedisAccessException(e);
269         } finally {
270             if (null != client) {
271                 jedisPool.returnResourceObject(client);
272             }
273         }
274     }
275 
276     /**
277      * 
278      * @描述 : 將 key 的值設爲 value ,當且僅當 key 不存在。若給定的 key 已經存在,則 SETNX 不作任何動做。
279      * @建立時間: 2015年7月20日下午1:52:07
280      *
281      * @param key
282      * @param value
283      * @return
284      * @throws RedisAccessException
285      */
286     public Long setnx(String key, String value) throws RedisAccessException {
287         Jedis client = null;
288         try {
289             client = jedisPool.getResource();
290             return client.setnx(key, value);
291         } catch (Exception e) {
292             LOG.error(e.getMessage(), e);
293             throw new RedisAccessException(e);
294         } finally {
295             if (null != client) {
296                 jedisPool.returnResourceObject(client);
297             }
298         }
299     }
300 
301     /**
302      * 
303      * @描述 : 將哈希表 key 中的域 field 的值設爲 value 。 若是 key 不存在,一個新的哈希表被建立並進行 HSET操做。
304      *     若是域 field 已經存在於哈希表中,舊值將被覆蓋。
305      * @建立時間: 2015年7月20日下午1:53:23
306      *
307      * @param key
308      * @param field
309      * @param value
310      * @return
311      * @throws RedisAccessException
312      */
313     public Long hset(String key, String field, String value) throws RedisAccessException {
314         Jedis client = null;
315         try {
316             client = jedisPool.getResource();
317             return client.hset(key, field, value);
318         } catch (Exception e) {
319             LOG.error(e.getMessage(), e);
320             throw new RedisAccessException(e);
321         } finally {
322             if (null != client) {
323                 jedisPool.returnResourceObject(client);
324             }
325         }
326     }
327 
328     /**
329      * 
330      * @描述 :返回哈希表 key 中給定域 field 的值。
331      * @建立時間: 2015年7月20日下午1:54:24
332      *
333      * @param key
334      * @param field
335      * @return
336      * @throws RedisAccessException
337      */
338     public String hget(String key, String field) throws RedisAccessException {
339         Jedis client = null;
340         try {
341             client = jedisPool.getResource();
342             return client.hget(key, field);
343         } catch (Exception e) {
344             LOG.error(e.getMessage(), e);
345             throw new RedisAccessException(e);
346         } finally {
347             if (null != client) {
348                 jedisPool.returnResourceObject(client);
349             }
350         }
351     }
352 
353     /**
354      * 
355      * @描述 : 將哈希表 key 中的域 field 的值設置爲 value ,當且僅當域 field 不存在。若域 field
356      *     已經存在,該操做無效。 若是 key 不存在,一個新哈希表被建立並執行 HSETNX 命令。
357      * @建立時間: 2015年7月20日下午1:54:44
358      *
359      * @param key
360      * @param field
361      * @param value
362      * @return
363      * @throws RedisAccessException
364      */
365     public Long hsetnx(String key, String field, String value) throws RedisAccessException {
366         Jedis client = null;
367         try {
368             client = jedisPool.getResource();
369             return client.hsetnx(key, field, value);
370         } catch (Exception e) {
371             LOG.error(e.getMessage(), e);
372             throw new RedisAccessException(e);
373         } finally {
374             if (null != client) {
375                 jedisPool.returnResourceObject(client);
376             }
377         }
378     }
379 
380     /**
381      * 
382      * @描述 :同時將多個 field-value (域-值)對設置到哈希表 key 中。此命令會覆蓋哈希表中已存在的域。 若是 key
383      *     不存在,一個空哈希表被建立並執行 HMSET 操做。
384      * @建立時間: 2015年7月20日下午1:58:26
385      *
386      * @param key
387      * @param hash
388      * @return
389      * @throws RedisAccessException
390      */
391     public String hmset(String key, Map<String, String> hash) throws RedisAccessException {
392         Jedis client = null;
393         try {
394             client = jedisPool.getResource();
395             return client.hmset(key, hash);
396         } catch (Exception e) {
397             LOG.error(e.getMessage(), e);
398             throw new RedisAccessException(e);
399         } finally {
400             if (null != client) {
401                 jedisPool.returnResourceObject(client);
402             }
403         }
404     }
405 
406     /**
407      * 
408      * @描述 : 返回哈希表 key 中,一個或多個給定域的值。若是給定的域不存在於哈希表,那麼返回一個 null 值。 由於不存在的 key
409      *     被看成一個空哈希表來處理,因此對一個不存在的 key 進行 HMGET 操做將返回一個只帶有 null 值的表。
410      * @建立時間: 2015年7月20日下午1:57:32
411      *
412      * @param key
413      * @param fields
414      * @return
415      * @throws RedisAccessException
416      */
417     public List<String> hmget(String key, String[] fields) throws RedisAccessException {
418         Jedis client = null;
419         try {
420             client = jedisPool.getResource();
421             return client.hmget(key, fields);
422         } catch (Exception e) {
423             LOG.error(e.getMessage(), e);
424             throw new RedisAccessException(e);
425         } finally {
426             if (null != client) {
427                 jedisPool.returnResourceObject(client);
428             }
429         }
430     }
431 
432     /**
433      * 
434      * @描述 :刪除哈希表 key 中的一個或多個指定域,不存在的域將被忽略。
435      * @建立時間: 2015年7月20日下午1:59:32
436      *
437      * @param key
438      * @param fields
439      * @return
440      * @throws RedisAccessException
441      */
442     public Long hdel(String key, String[] fields) throws RedisAccessException {
443         Jedis client = null;
444         try {
445             client = jedisPool.getResource();
446             return client.hdel(key, fields);
447         } catch (Exception e) {
448             LOG.error(e.getMessage(), e);
449             throw new RedisAccessException(e);
450         } finally {
451             if (null != client) {
452                 jedisPool.returnResourceObject(client);
453             }
454         }
455     }
456 
457     /**
458      * 
459      * @描述 : 返回哈希表 key 中域的數量。
460      * @建立時間: 2015年7月20日下午2:00:13
461      *
462      * @param key
463      * @return
464      * @throws RedisAccessException
465      */
466     public Long hlen(String key) throws RedisAccessException {
467         Jedis client = null;
468         try {
469             client = jedisPool.getResource();
470             return client.hlen(key);
471         } catch (Exception e) {
472             LOG.error(e.getMessage(), e);
473             throw new RedisAccessException(e);
474         } finally {
475             if (null != client) {
476                 jedisPool.returnResourceObject(client);
477             }
478         }
479     }
480 
481     /**
482      * 
483      * @描述 :返回哈希表 key 中的全部域。
484      * @建立時間: 2015年7月20日下午2:00:59
485      *
486      * @param key
487      * @return
488      * @throws RedisAccessException
489      */
490     public Set<String> hkeys(String key) throws RedisAccessException {
491         Jedis client = null;
492         try {
493             client = jedisPool.getResource();
494             return client.hkeys(key);
495         } catch (Exception e) {
496             LOG.error(e.getMessage(), e);
497             throw new RedisAccessException(e);
498         } finally {
499             if (null != client) {
500                 jedisPool.returnResourceObject(client);
501             }
502         }
503     }
504 
505     /**
506      * 
507      * @描述 : 返回哈希表 key 中全部域的值。
508      * @建立時間: 2015年7月20日下午2:01:06
509      *
510      * @param key
511      * @return
512      * @throws RedisAccessException
513      */
514     public List<String> hvals(String key) throws RedisAccessException {
515         Jedis client = null;
516         try {
517             client = jedisPool.getResource();
518             return client.hvals(key);
519         } catch (Exception e) {
520             LOG.error(e.getMessage(), e);
521             throw new RedisAccessException(e);
522         } finally {
523             if (null != client) {
524                 jedisPool.returnResourceObject(client);
525             }
526         }
527     }
528 
529     /**
530      * 
531      * @描述 : 返回哈希表 key 中,全部的域和值。在返回值裏,緊跟每一個域名(field
532      *     name)以後是域的值(value),因此返回值的長度是哈希表大小的兩倍。
533      * @建立時間: 2015年7月20日下午2:01:36
534      *
535      * @param key
536      * @return
537      * @throws RedisAccessException
538      */
539     public Map<String, String> hgetAll(String key) throws RedisAccessException {
540         Jedis client = null;
541         try {
542             client = jedisPool.getResource();
543             return client.hgetAll(key);
544         } catch (Exception e) {
545             LOG.error(e.getMessage(), e);
546             throw new RedisAccessException(e);
547         } finally {
548             if (null != client) {
549                 jedisPool.returnResourceObject(client);
550             }
551         }
552     }
553 
554     /**
555      * 
556      * @描述 :查看哈希表 key 中,給定域 field 是否存在。
557      * @建立時間: 2015年7月20日下午2:02:38
558      *
559      * @param key
560      * @param field
561      * @return
562      * @throws RedisAccessException
563      */
564     public Boolean hexists(String key, String field) throws RedisAccessException {
565         Jedis client = null;
566         try {
567             client = jedisPool.getResource();
568             return client.hexists(key, field);
569         } catch (Exception e) {
570             LOG.error(e.getMessage(), e);
571             throw new RedisAccessException(e);
572         } finally {
573             if (null != client) {
574                 jedisPool.returnResourceObject(client);
575             }
576         }
577     }
578 
579     /**
580      * 
581      * @描述 : 將一個或多個值 value 插入到列表 key 的表尾(最右邊)。
582      * @建立時間: 2015年7月20日下午2:02:44
583      *
584      * @param key
585      * @param values
586      * @return
587      * @throws RedisAccessException
588      */
589     public Long rpush(String key, String[] values) throws RedisAccessException {
590         Jedis client = null;
591         try {
592             client = jedisPool.getResource();
593             return client.rpush(key, values);
594         } catch (Exception e) {
595             LOG.error(e.getMessage(), e);
596             throw new RedisAccessException(e);
597         } finally {
598             if (null != client) {
599                 jedisPool.returnResourceObject(client);
600             }
601         }
602     }
603 
604     /**
605      * 
606      * @描述 : 將值 value 插入到列表 key 的表尾,當且僅當 key 存在而且是一個列表。
607      * @建立時間: 2015年7月20日下午2:03:20
608      *
609      * @param key
610      * @param value
611      * @return
612      * @throws RedisAccessException
613      */
614     public Long rpushx(String key, String value) throws RedisAccessException {
615         Jedis client = null;
616         try {
617             client = jedisPool.getResource();
618             return client.rpushx(key, new String[] { value });
619         } catch (Exception e) {
620             LOG.error(e.getMessage(), e);
621             throw new RedisAccessException(e);
622         } finally {
623             if (null != client) {
624                 jedisPool.returnResourceObject(client);
625             }
626         }
627     }
628 
629     /**
630      * 
631      * @描述 : 將一個或多個值 value 插入到列表 key 的表頭
632      * @建立時間: 2015年7月20日下午2:04:13
633      *
634      * @param key
635      * @param values
636      * @return
637      * @throws RedisAccessException
638      */
639     public Long lpush(String key, String[] values) throws RedisAccessException {
640         Jedis client = null;
641         try {
642             client = jedisPool.getResource();
643             return client.lpush(key, values);
644         } catch (Exception e) {
645             LOG.error(e.getMessage(), e);
646             throw new RedisAccessException(e);
647         } finally {
648             if (null != client) {
649                 jedisPool.returnResourceObject(client);
650             }
651         }
652     }
653 
654     /**
655      * 
656      * @描述 : 將值 value 插入到列表 key 的表頭,當且僅當 key 存在而且是一個列表。 和 LPUSH 命令相反,當 key 不存在時,
657      *     LPUSHX 命令什麼也不作。
658      * @建立時間: 2015年7月20日下午2:05:09
659      *
660      * @param key
661      * @param value
662      * @return
663      * @throws RedisAccessException
664      */
665     public Long lpushx(String key, String value) throws RedisAccessException {
666         Jedis client = null;
667         try {
668             client = jedisPool.getResource();
669             return client.lpushx(key, new String[] { value });
670         } catch (Exception e) {
671             LOG.error(e.getMessage(), e);
672             throw new RedisAccessException(e);
673         } finally {
674             if (null != client) {
675                 jedisPool.returnResourceObject(client);
676             }
677         }
678     }
679 
680     /**
681      * 
682      * @描述 : 返回列表 key 的長度。若是 key 不存在,則 key 被解釋爲一個空列表,返回 0 . 若是 key
683      *     不是列表類型,返回一個錯誤。
684      * @建立時間: 2015年7月20日下午2:05:25
685      *
686      * @param key
687      * @return
688      * @throws RedisAccessException
689      */
690     public Long llen(String key) throws RedisAccessException {
691         Jedis client = null;
692         try {
693             client = jedisPool.getResource();
694             return client.llen(key);
695         } catch (Exception e) {
696             LOG.error(e.getMessage(), e);
697             throw new RedisAccessException(e);
698         } finally {
699             if (null != client) {
700                 jedisPool.returnResourceObject(client);
701             }
702         }
703     }
704 
705     /**
706      * 
707      * @描述 : 返回列表 key 中,下標爲 index 的元素。
708      * @建立時間: 2015年7月20日下午2:05:37
709      *
710      * @param key
711      * @param index
712      * @return
713      * @throws RedisAccessException
714      */
715     public String lindex(String key, long index) throws RedisAccessException {
716         Jedis client = null;
717         try {
718             client = jedisPool.getResource();
719             return client.lindex(key, index);
720         } catch (Exception e) {
721             LOG.error(e.getMessage(), e);
722             throw new RedisAccessException(e);
723         } finally {
724             if (null != client) {
725                 jedisPool.returnResourceObject(client);
726             }
727         }
728     }
729 
730     /**
731      * 
732      * @描述 : 將列表 key 下標爲 index 的元素的值設置爲 value 。當 index 參數超出範圍,或對一個空列表( key
733      *     不存在)進行 LSET 時,返回一個錯誤。
734      * @建立時間: 2015年7月20日下午2:07:06
735      *
736      * @param key
737      * @param index
738      * @param value
739      * @return
740      * @throws RedisAccessException
741      */
742     public String lset(String key, long index, String value) throws RedisAccessException {
743         Jedis client = null;
744         try {
745             client = jedisPool.getResource();
746             return client.lset(key, index, value);
747         } catch (Exception e) {
748             LOG.error(e.getMessage(), e);
749             throw new RedisAccessException(e);
750         } finally {
751             if (null != client) {
752                 jedisPool.returnResourceObject(client);
753             }
754         }
755     }
756 
757     /**
758      * 
759      * @描述 : 移除並返回列表 key 的頭元素。
760      * @建立時間: 2015年7月20日下午2:07:10
761      *
762      * @param key
763      * @return
764      * @throws RedisAccessException
765      */
766     public String lpop(String key) throws RedisAccessException {
767         Jedis client = null;
768         try {
769             client = jedisPool.getResource();
770             return client.lpop(key);
771         } catch (Exception e) {
772             LOG.error(e.getMessage(), e);
773             throw new RedisAccessException(e);
774         } finally {
775             if (null != client) {
776                 jedisPool.returnResourceObject(client);
777             }
778         }
779     }
780 
781     /**
782      * 
783      * @描述 : 移除並返回列表 key 的尾元素。
784      * @建立時間: 2015年7月20日下午2:07:13
785      *
786      * @param key
787      * @return
788      * @throws RedisAccessException
789      */
790     public String rpop(String key) throws RedisAccessException {
791         Jedis client = null;
792         try {
793             client = jedisPool.getResource();
794             return client.rpop(key);
795         } catch (Exception e) {
796             LOG.error(e.getMessage(), e);
797             throw new RedisAccessException(e);
798         } finally {
799             if (null != client) {
800                 jedisPool.returnResourceObject(client);
801             }
802         }
803     }
804 
805     /**
806      * 
807      * @描述 : 將值 value 插入到列表 key 當中,位於值 pivot 以前或以後。當 pivot 不存在於列表 key 時,不執行任何操做。
808      *     key 不存在時, key 被視爲空列表,不執行任何操做。 若是 key 不是列表類型,返回一個錯誤。
809      * @建立時間: 2015年7月20日下午2:07:37
810      *
811      * @param key
812      * @param where
813      * @param pivot
814      * @param value
815      * @return
816      * @throws RedisAccessException
817      */
818     public Long linsert(String key, BinaryClient.LIST_POSITION where, String pivot, String value) throws RedisAccessException {
819         Jedis client = null;
820         try {
821             client = jedisPool.getResource();
822             return client.linsert(key, where, pivot, value);
823         } catch (Exception e) {
824             LOG.error(e.getMessage(), e);
825             throw new RedisAccessException(e);
826         } finally {
827             if (null != client) {
828                 jedisPool.returnResourceObject(client);
829             }
830         }
831     }
832     
833     /**
834      * @描述 : 將 key 中儲存的數字值增一。若是 key 不存在,那麼 key 的值會先被初始化爲 0 ,而後再執行 INCR 操做。
835      * @建立時間: 2014-6-16下午2:31:58
836      * 
837      * @param key
838      * @return
839      * @throws RedisAccessException
840      */
841     public Long incr(String key) throws RedisAccessException {
842         Jedis client = null;
843         try {
844             client = jedisPool.getResource();
845             return client.incr(key);
846         } catch (Exception e) {
847             LOG.error(e.getMessage(), e);
848             throw new RedisAccessException(e);
849         } finally {
850             if (null != client) {
851                 jedisPool.returnResourceObject(client);
852             }
853         }
854     }
855     
856     
857     /**
858      * @描述 :  將 key 所儲存的值加上增量 increment 。若是 key 不存在,那麼 key 的值會先被初始化爲 0 ,而後再執行  INCRBY 命令。
859      * @建立時間: 2014-6-16下午2:31:58
860      * 
861      * @param key
862      * @return
863      * @throws RedisAccessException
864      */
865     public double incrBy(String key,long value) throws RedisAccessException {
866         Jedis client = null;
867         try {
868             client = jedisPool.getResource();
869             return client.incrBy(key, value);
870         } catch (Exception e) {
871             LOG.error(e.getMessage(), e);
872             throw new RedisAccessException(e);
873         } finally {
874             if (null != client) {
875                 jedisPool.returnResourceObject(client);
876             }
877         }
878     }
879 
880 }
View Code

OK,這個關於redis的相關內容更新完畢! 

本文地址: http://www.cnblogs.com/gzy-blog/p/6058849.html

相關文章
相關標籤/搜索