1 Redis介紹
1.1 什么是NoSql
為了解決高并發、高可擴展、高可用、大數據存儲問題而產生的數據庫解決方案,就是NoSql數據庫。
NoSQL,泛指非關系型的數據庫,NoSQL即Not-Only SQL,它可以作為關系型數據庫的良好補充。
1.2 Nosql數據庫分類
? 鍵值(Key-Value)存儲數據庫
相關產品: Tokyo Cabinet/Tyrant、Redis、Voldemort、Berkeley DB
典型應用: 內容緩存,主要用于處理大量數據的高訪問負載。
數據模型: 一系列鍵值對
優勢: 快速查詢
劣勢: 存儲的數據缺少結構化
? 列存儲數據庫
相關產品:Cassandra, HBase, Riak
典型應用:分布式的文件系統
數據模型:以列簇式存儲,將同一列數據存在一起
優勢:查找速度快,可擴展性強,更容易進行分布式擴展
劣勢:功能相對局限
? 文檔型數據庫
相關產品:CouchDB、MongoDB
典型應用:Web應用(與Key-Value類似,Value是結構化的)
數據模型: 一系列鍵值對
優勢:數據結構要求不嚴格
劣勢: 查詢性能不高,而且缺乏統一的查詢語法
? 圖形(Graph)數據庫
相關數據庫:Neo4J、InfoGrid、Infinite Graph
典型應用:社交網絡
數據模型:圖結構
優勢:利用圖結構相關算法。
劣勢:需要對整個圖做計算才能得出結果,不容易做分布式的集群方案。
1.3 什么是Redis
Redis是用C語言開發的一個開源的高性能鍵值對(key-value)數據庫。它通過提供多種鍵值數據類型來適應不同場景下的存儲需求,目前為止Redis支持的鍵值數據類型如
下:
字符串類型
散列類型
列表類型
集合類型
有序集合類型。
1.4 redis歷史發展
2008年,意大利的一家創業公司Merzia推出了一款基于MySQL的網站實時統計系統LLOOGG,然而沒過多久該公司的創始人 Salvatore Sanfilippo便 對MySQL的性能感到失望,于是他決定親自為LLOOGG量身定做一個數據庫,并于2009年開發完成,這個數據庫就是Redis。 不過Salvatore Sanfilippo并不滿足只將Redis用于LLOOGG這一款產品,而是希望更多的人使用它,于是在同一年Salvatore Sanfilippo將Redis開源發布,并開始和Redis的另一名主要的代碼貢獻者Pieter Noordhuis一起繼續著Redis的開發,直到今天。
Salvatore Sanfilippo自己也沒有想到,短短的幾年時間,Redis就擁有了龐大的用戶群體。Hacker News在2012年發布了一份數據庫的使用情況調查,結果顯示有近12%的公司在使用Redis。國內如新浪微博、街旁網、知乎網,國外如GitHub、Stack Overflow、Flickr等都是Redis的用戶。
VMware公司從2010年開始贊助Redis的開發, Salvatore Sanfilippo和Pieter Noordhuis也分別在3月和5月加入VMware,全職開發Redis。
1.5 redis的應用場景
緩存(數據查詢、短連接、新聞內容、商品內容等等)。(最多使用)
分布式集群架構中的session分離。
聊天室的在線好友列表。
任務隊列。(秒殺、搶購、12306等等)
應用排行榜。
網站訪問統計。
數據過期處理(可以精確到毫秒)
2 Redis安裝配置
2.1 Redis下載
官網地址:http://redis.io/
下載地址:http://download.redis.io/releases/redis-3.0.0.tar.gz
2.2 Redis安裝
Redis是C語言開發,建議在linux上運行,本教程使用Centos6.4作為安裝環境。
第一步:在VMware中安裝CentOS(參考Linux教程中的安裝虛擬機)
第二步:在Linux下安裝gcc環境(該步驟可以省略,CentOS中默認自帶C環境)
[root@linux02 redis-3.0.0]# yum install gcc-c++
第三步:將下載的Redis源碼包上傳到Linux服務器中
【需要切換到sftp窗口】
sftp> put -r "E:\03-teach\03-講課\0707\04-redis\res\redis-3.0.0.tar.gz"
第四步:解壓縮Redis源碼包
[root@linux02 ~]# tar -zxf redis-3.0.0.tar.gz
第五步:編譯redis源碼
[root@linux02 ~]# cd redis-3.0.0
[root@linux02 redis-3.0.0]# make
第六步:安裝redis
[root@linux02 redis-3.0.0]# make install PREFIX=/usr/local/redis0707
2.3 Redis啟動
2.3.1 前端啟動
? 啟動方式:
直接運行bin/redis-server將以前端模式啟動。
[root@linux02 bin]# ./redis-server
? 啟動缺點:
ssh命令窗口關閉則redis-server程序結束,不推薦使用此方法
? 啟動圖例:
? 前端啟動的關閉:ctrl+c
2.3.2 后端啟動
第一步:將redis源碼包中的redis.conf配置文件復制到/usr/local/redis/bin/下
[root@linux02 /]# cd /root/redis-3.0.0
[root@linux02 redis-3.0.0]# cp redis.conf /usr/local/redis0707/bin/
第二步:修改redis.conf,將daemonize由no改為yes
[root@redis01 bin2]# vim redis.conf
第三步:執行命令
[root@linux02 bin]# ./redis-server redis.conf
? 后端啟動的關閉方式
非正常關閉(不推薦使用):
[root@localhost-0723 bin]# kill 5528
正常關閉:
[root@localhost-0723 bin]# ./redis-cli shutdown
3 Redis客戶端
3.1 Redis自帶的客戶端
? 指定主機和端口
[root@localhost-0723 bin]# ./redis-cli -h 127.0.0.1 -p 6379
-h:redis服務器的ip地址
-p:redis實例的端口號
? 如果不指定主機和端口也可以
[root@localhost-0723 bin]# ./redis-cli
默認主機地址是127.0.0.1
默認端口是6379
3.2 圖形界面客戶端(了解)
前提:需要安裝圖形界面管理器
3.2.1 連接超時解決
遠程連接redis服務,需要關閉或者修改防火墻配置。
第一步:編輯iptables
[root@redis01 bin]# vim /etc/sysconfig/iptables
在命令模式下,選定要復制的那一行的末尾,然后點擊鍵盤yyp,就完成復制,然后修改。
第二步:重啟防火墻
[root@localhost-0723 redis-3.0.0]# service iptables restart
iptables:清除防火墻規則: [確定]
iptables:將鏈設置為政策 ACCEPT:filter [確定]
iptables:正在卸載模塊: [確定]
iptables:應用防火墻規則: [確定]
[root@localhost-0723 redis-3.0.0]#
注意:
默認一共是16個數據庫,每個數據庫之間是相互隔離。數據庫的數量是在redis.conf中配置的。
切換數據庫使用命令:select 數據庫編號
例如:select 1
3.3 Java客戶端Jedis
3.3.1 jedis介紹
Redis不僅是使用命令來操作,現在基本上主流的語言都有客戶端支持,比如java、C、C#、C++、php、Node.js、Go等。
在官方網站里列一些Java的客戶端,有Jedis、Redisson、Jredis、JDBC-Redis、等其中官方推薦使用Jedis和Redisson。 在企業中用的最多的就是Jedis,下面我們就重點學習下Jedis。
Jedis同樣也是托管在github上,地址:https://github.com/xetorthio/jedis
3.3.2 添加jar包
3.3.3 單實例連接
@Test
public void testJedis() {
//創建一個Jedis的連接
Jedis jedis = new Jedis("127.0.0.1", 6379);
//執行redis命令
jedis.set("mytest", "hello world, this is jedis client!");
//從redis中取值
String result = jedis.get("mytest");
//打印結果
System.out.println(result);
//關閉連接
jedis.close();
}
3.3.4 連接池連接
@Test
public void testJedisPool() {
//創建一連接池對象
JedisPool jedisPool = new JedisPool("127.0.0.1", 6379);
//從連接池中獲得連接
Jedis jedis = jedisPool.getResource();
String result = jedis.get("mytest");
System.out.println(result);
//關閉連接
jedis.close();
//關閉連接池
jedisPool.close();
}
3.3.5 Spring整合jedisPool(自學)
? 添加spring的jar包
? 配置spring配置文件applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
<!-- 連接池配置 -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<!-- 最大連接數 -->
<property name="maxTotal" value="30" />
<!-- 最大空閑連接數 -->
<property name="maxIdle" value="10" />
<!-- 每次釋放連接的最大數目 -->
<property name="numTestsPerEvictionRun" value="1024" />
<!-- 釋放連接的掃描間隔(毫秒) -->
<property name="timeBetweenEvictionRunsMillis" value="30000" />
<!-- 連接最小空閑時間 -->
<property name="minEvictableIdleTimeMillis" value="1800000" />
<!-- 連接空閑多久后釋放, 當空閑時間>該值 且 空閑連接>最大空閑連接數 時直接釋放 -->
<property name="softMinEvictableIdleTimeMillis" value="10000" />
<!-- 獲取連接時的最大等待毫秒數,小于零:阻塞不確定的時間,默認-1 -->
<property name="maxWaitMillis" value="1500" />
<!-- 在獲取連接的時候檢查有效性, 默認false -->
<property name="testOnBorrow" value="false" />
<!-- 在空閑時檢查有效性, 默認false -->
<property name="testWhileIdle" value="true" />
<!-- 連接耗盡時是否阻塞, false報異常,ture阻塞直到超時, 默認true -->
<property name="blockWhenExhausted" value="false" />
</bean>
<!-- redis單機 通過連接池 -->
<bean id="jedisPool" class="redis.clients.jedis.JedisPool"
destroy-method="close">
<constructor-arg name="poolConfig" ref="jedisPoolConfig" />
<constructor-arg name="host" value="192.168.242.130" />
<constructor-arg name="port" value="6379" />
</bean>
</beans>
? 測試代碼
@Test
public void testJedisPool() {
JedisPool pool = (JedisPool) applicationContext.getBean("jedisPool");
Jedis jedis = null;
try {
jedis = pool.getResource();
jedis.set("name", "lisi");
String name = jedis.get("name");
System.out.println(name);
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (jedis != null) {
// 關閉連接
jedis.close();
}
}
}
4 Redis數據類型
Redis中存儲數據是通過key-value存儲的,對于value的類型有以下幾種:
? 字符串
? Hash類型
? List
? Set
? SortedSet(zset)
PS:
在redis中的命令語句中,命令是忽略大小寫的,而key是不忽略大小寫的。
4.1 String類型
4.1.1 命令
4.1.1.1 賦值
語法:SET key value
127.0.0.1:6379> set test 123
OK
4.1.1.2 取值
語法:GET key
127.0.0.1:6379> get test
"123“
4.1.1.3 設置/獲取多個鍵值
語法:
MSET key value [key value …]
MGET key [key …]
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3
OK
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> mget k1 k3
- "v1"
- "v3"
4.1.1.4 取值并賦值
語法:GETSET key value
127.0.0.1:6379> getset s2 222
"111"
127.0.0.1:6379> get s2
"222"
4.1.1.5 刪除
語法:DEL key
127.0.0.1:6379> del test
(integer) 1
4.1.1.6 數值增減
? 遞增數字
當存儲的字符串是整數時,Redis提供了一個實用的命令INCR,其作用是讓當前鍵值遞增,并返回遞增后的值。
語法:INCR key
127.0.0.1:6379> incr num
(integer) 1
127.0.0.1:6379> incr num
(integer) 2
127.0.0.1:6379> incr num
(integer) 3
? 增加指定的整數
語法:INCRBY key increment
127.0.0.1:6379> incrby num 2
(integer) 5
127.0.0.1:6379> incrby num 2
(integer) 7
127.0.0.1:6379> incrby num 2
(integer) 9
? 遞減數值
語法:DECR key
127.0.0.1:6379> decr num
(integer) 9
127.0.0.1:6379> decr num
(integer) 8
? 減少指定的整數
語法:DECRBY key decrement
127.0.0.1:6379> decr num
(integer) 6
127.0.0.1:6379> decr num
(integer) 5
127.0.0.1:6379> decrby num 3
(integer) 2
127.0.0.1:6379> decrby num 3
(integer) -1
4.1.1.7 其它命令(自學)
4.1.1.7.1 向尾部追加值
APPEND的作用是向鍵值的末尾追加value。如果鍵不存在則將該鍵的值設置為value,即相當于 SET key value。返回值是追加后字符串的總長度。
語法:APPEND key value
127.0.0.1:6379> set str hello
OK
127.0.0.1:6379> append str " world!"
(integer) 12
127.0.0.1:6379> get str
"hello world!"
4.1.1.7.2 獲取字符串長度
STRLEN命令返回鍵值的長度,如果鍵不存在則返回0。
語法:STRLEN key
127.0.0.1:6379> strlen str
(integer) 0
127.0.0.1:6379> set str hello
OK
127.0.0.1:6379> strlen str
(integer) 5
4.1.2 應用
4.1.2.1 自增主鍵
商品編號、訂單號采用string的遞增數字特性生成。
定義商品編號key:items:id
192.168.101.3:7003> INCR items:id
(integer) 2
192.168.101.3:7003> INCR items:id
(integer) 3
4.2 Hash類型
4.2.1 使用string的問題
假設有User對象以JSON序列化的形式存儲到Redis中,User對象有id,username、password、age、name等屬性,存儲的過程如下:
保存、更新:
User對象 à json(string) à redis
如果在業務上只是更新age屬性,其他的屬性并不做更新我應該怎么做呢? 如果仍然采用上邊的方法在傳輸、處理時會造成資源浪費,下邊講的hash可以很好的解決這個問題。
4.2.2 redis hash介紹
hash叫散列類型,它提供了字段和字段值的映射。字段值只能是字符串類型,不支持散列類型、集合類型等其它類型。如下:
4.2.3 命令
4.2.3.1 賦值
HSET命令不區分插入和更新操作,當執行插入操作時HSET命令返回1,當執行更新操作時返回0。
? 一次只能設置一個字段值
語法:HSET key field value
127.0.0.1:6379> hset user username zhangsan
(integer) 1
? 一次可以設置多個字段值
語法:HMSET key field value [field value ...]
127.0.0.1:6379> hmset user age 20 username lisi
OK
? 當字段不存在時賦值,類似HSET,區別在于如果字段存在,該命令不執行任何操作
語法:HSETNX key field value
127.0.0.1:6379> hsetnx user age 30 如果user中沒有age字段則設置age值為30,否則不做任何操作
(integer) 0
4.2.3.2 取值
? 一次只能獲取一個字段值
語法:HGET key field
127.0.0.1:6379> hget user username
"zhangsan“
? 一次可以獲取多個字段值
語法:HMGET key field [field ...]
127.0.0.1:6379> hmget user age username
- "20"
- "lisi"
? 獲取所有字段值
語法:HGETALL key
127.0.0.1:6379> hgetall user
- "age"
- "20"
- "username"
- "lisi"
4.2.3.3 刪除字段
可以刪除一個或多個字段,返回值是被刪除的字段個數
語法:HDEL key field [field ...]
127.0.0.1:6379> hdel user age
(integer) 1
127.0.0.1:6379> hdel user age name
(integer) 0
127.0.0.1:6379> hdel user age username
(integer) 1
4.2.3.4 增加數字
語法:HINCRBY key field increment
127.0.0.1:6379> hincrby user age 2 將用戶的年齡加2
(integer) 22
127.0.0.1:6379> hget user age 獲取用戶的年齡
"22“
4.2.3.5 其它命令(自學)
4.2.3.5.1 判斷字段是否存在
語法:HEXISTS key field
127.0.0.1:6379> hexists user age 查看user中是否有age字段
(integer) 1
127.0.0.1:6379> hexists user name 查看user中是否有name字段
(integer) 0
4.2.3.5.2 只獲取字段名或字段值
語法:
HKEYS key
HVALS key
127.0.0.1:6379> hmset user age 20 name lisi
OK
127.0.0.1:6379> hkeys user
- "age"
- "name"
127.0.0.1:6379> hvals user - "20"
- "lisi"
4.2.3.5.3 獲取字段數量
語法:HLEN key
127.0.0.1:6379> hlen user
(integer) 2
4.2.4 應用
4.2.4.1 存儲商品信息
? 商品字段
【商品id、商品名稱、商品描述、商品庫存、商品好評】
? 定義商品信息的key
商品1001的信息在 Redis中的key為:[items:1001]
? 存儲商品信息
192.168.101.3:7003> HMSET items:1001 id 3 name apple price 999.9
OK
? 獲取商品信息
192.168.101.3:7003> HGET items:1001 id
"3"
192.168.101.3:7003> HGETALL items:1001
- "id"
- "3"
- "name"
- "apple"
- "price"
- "999.9"
4.3 List類型
4.3.1 ArrayList與LinkedList的區別
ArrayList使用數組方式存儲數據,所以根據索引查詢數據速度快,而新增或者刪除元素時需要設計到位移操作,所以比較慢。
LinkedList使用雙向鏈表方式存儲數據,每個元素都記錄前后元素的指針,所以插入、刪除數據時只是更改前后元素的指針指向即可,速度非??臁H缓笸ㄟ^下標查詢元素時需要從頭開始索引,所以比較慢,但是如果查詢前幾個元素或后幾個元素速度比較快。
4.3.2 redis list介紹
列表類型(list)可以存儲一個有序的字符串列表,常用的操作是向列表兩端添加元素,或者獲得列表的某一個片段。
列表類型內部是使用雙向鏈表(double linked list)實現的,所以向列表兩端添加元素的時間復雜度為0(1),獲取越接近兩端的元素速度就越快。這意味著即使是一個有幾千萬個元素的列表,獲取頭部或尾部的10條記錄也是極快的。
4.3.3 命令
4.3.3.1 向列表兩端增加元素
? 向列表左邊增加元素
語法:LPUSH key value [value ...]
127.0.0.1:6379> lpush list:1 1 2 3
(integer) 3
? 向列表右邊增加元素
語法:RPUSH key value [value ...]
127.0.0.1:6379> rpush list:1 4 5 6
(integer) 3
4.3.3.2 查看列表
LRANGE命令是列表類型最常用的命令之一,獲取列表中的某一片段,將返回start、stop之間的所有元素(包含兩端的元素),索引從0開始。索引可以是負數,如:“-1”代表最后邊的一個元素。
語法:LRANGE key start stop
127.0.0.1:6379> lrange list:1 0 2
- "2"
- "1"
- "4"
4.3.3.3 從列表兩端彈出元素
LPOP命令從列表左邊彈出一個元素,會分兩步完成:
第一步是將列表左邊的元素從列表中移除
第二步是返回被移除的元素值。
語法:
LPOP key
RPOP key
127.0.0.1:6379> lpop list:1
"3“
127.0.0.1:6379> rpop list:1
"6“
4.3.3.4 獲取列表中元素的個數
語法:LLEN key
127.0.0.1:6379> llen list:1
(integer) 2
4.3.3.5 其它命令(自學)
4.3.3.5.1 刪除列表中指定的值
LREM命令會刪除列表中前count個值為value的元素,返回實際刪除的元素個數。根據count值的不同,該命令的執行方式會有所不同:
? 當count>0時, LREM會從列表左邊開始刪除。
? 當count<0時, LREM會從列表后邊開始刪除。
? 當count=0時, LREM刪除所有值為value的元素。
語法:LREM key count value
4.3.3.5.2 獲得/設置指定索引的元素值
? 獲得指定索引的元素值
語法:LINDEX key index
127.0.0.1:6379> lindex l:list 2
"1"
? 設置指定索引的元素值
語法:LSET key index value
127.0.0.1:6379> lset l:list 2 2
OK
127.0.0.1:6379> lrange l:list 0 -1
- "6"
- "5"
- "2"
- "2"
4.3.3.5.3 只保留列表指定片段
指定范圍和LRANGE一致
語法:LTRIM key start stop
127.0.0.1:6379> lrange l:list 0 -1
- "6"
- "5"
- "0"
- "2"
127.0.0.1:6379> ltrim l:list 0 2
OK
127.0.0.1:6379> lrange l:list 0 -1 - "6"
- "5"
- "0"
4.3.3.5.4 向列表中插入元素
該命令首先會在列表中從左到右查找值為pivot的元素,然后根據第二個參數是BEFORE還是AFTER來決定將value插入到該元素的前面還是后面。
語法:LINSERT key BEFORE|AFTER pivot value
127.0.0.1:6379> lrange list 0 -1
- "3"
- "2"
- "1"
127.0.0.1:6379> linsert list after 3 4
(integer) 4
127.0.0.1:6379> lrange list 0 -1 - "3"
- "4"
- "2"
- "1"
4.3.3.5.5 將元素從一個列表轉移到另一個列表中
語法:RPOPLPUSH source destination
127.0.0.1:6379> rpoplpush list newlist
"1"
127.0.0.1:6379> lrange newlist 0 -1
- "1"
127.0.0.1:6379> lrange list 0 -1 - "3"
- "4"
- "2"
4.3.4 應用
4.3.4.1 商品評論列表
思路:
在Redis中創建商品評論列表
用戶發布商品評論,將評論信息轉成json存儲到list中。
用戶在頁面查詢評論列表,從redis中取出json數據展示到頁面。
定義商品評論列表key:
商品編號為1001的商品評論key【items: comment:1001】
192.168.101.3:7001> LPUSH items:comment:1001 '{"id":1,"name":"商品不錯,很好!!","date":1430295077289}'
4.4 Set類型
4.4.1 redis set介紹
集合中的數據是不重復且沒有順序。
集合類型和列表類型的對比:
集合類型的常用操作是向集合中加入或刪除元素、判斷某個元素是否存在等,由于集合類型的Redis內部是使用值為空的散列表實現,所有這些操作的時間復雜度都為0(1)。
Redis還提供了多個集合之間的交集、并集、差集的運算。
4.4.2 命令
4.4.2.1 增加/刪除元素
語法:SADD key member [member ...]
127.0.0.1:6379> sadd set a b c
(integer) 3
127.0.0.1:6379> sadd set a
(integer) 0
語法:SREM key member [member ...]
127.0.0.1:6379> srem set c d
(integer) 1
4.4.2.2 獲得集合中的所有元素
語法:SMEMBERS key
127.0.0.1:6379> smembers set
- "b"
- "a”
4.4.2.3 判斷元素是否在集合中
語法:SISMEMBER key member
127.0.0.1:6379> sismember set a
(integer) 1
127.0.0.1:6379> sismember set h
(integer) 0
4.4.3 運算命令
4.4.3.1 集合的差集運算 A-B
屬于A并且不屬于B的元素構成的集合。
語法:SDIFF key [key ...]
127.0.0.1:6379> sadd setA 1 2 3
(integer) 3
127.0.0.1:6379> sadd setB 2 3 4
(integer) 3
127.0.0.1:6379> sdiff setA setB
- "1"
127.0.0.1:6379> sdiff setB setA - "4"
4.4.3.2 集合的交集運算 A ∩ B
屬于A且屬于B的元素構成的集合。
語法:SINTER key [key ...]
127.0.0.1:6379> sinter setA setB
- "2"
- "3"
4.4.3.3 集合的并集運算 A ∪ B
屬于A或者屬于B的元素構成的集合
語法:SUNION key [key ...]
127.0.0.1:6379> sunion setA setB
- "1"
- "2"
- "3"
- "4"
4.4.4 其它命令(自學)
4.4.4.1 獲得集合中元素的個數
語法:SCARD key
127.0.0.1:6379> smembers setA
- "1"
- "2"
- "3"
127.0.0.1:6379> scard setA
(integer) 3
4.4.4.2 從集合中彈出一個元素
注意:由于集合是無序的,所有SPOP命令會從集合中隨機選擇一個元素彈出
語法:SPOP key
127.0.0.1:6379> spop setA
"1“
4.5 SortedSet類型zset
4.5.1 redis sorted set介紹
在集合類型的基礎上,有序集合類型為集合中的每個元素都關聯一個分數,這使得我們不僅可以完成插入、刪除和判斷元素是否存在在集合中,還能夠獲得分數最高或最低的前N個元素、獲取指定分數范圍內的元素等與分數有關的操作。
在某些方面有序集合和列表類型有些相似。
1、二者都是有序的。
2、二者都可以獲得某一范圍的元素。
但是,二者有著很大區別:
1、列表類型是通過鏈表實現的,獲取靠近兩端的數據速度極快,而當元素增多后,訪問中間數據的速度會變慢。
2、有序集合類型使用散列表實現,所有即使讀取位于中間部分的數據也很快。
3、列表中不能簡單的調整某個元素的位置,但是有序集合可以(通過更改分數實現)
4、有序集合要比列表類型更耗內存。
4.5.2 命令
4.5.2.1 增加元素
向有序集合中加入一個元素和該元素的分數,如果該元素已經存在則會用新的分數替換原有的分數。返回值是新加入到集合中的元素個數,不包含之前已經存在的元素。
語法:ZADD key score member [score member ...]
127.0.0.1:6379> zadd scoreboard 80 zhangsan 89 lisi 94 wangwu
(integer) 3
127.0.0.1:6379> zadd scoreboard 97 lisi
(integer) 0
4.5.2.2 獲取元素的分數
語法:ZSCORE key member
127.0.0.1:6379> zscore scoreboard lisi
"97"
4.5.2.3 刪除元素
移除有序集key中的一個或多個成員,不存在的成員將被忽略。
當key存在但不是有序集類型時,返回一個錯誤。
語法:ZREM key member [member ...]
127.0.0.1:6379> zrem scoreboard lisi
(integer) 1
4.5.2.4 獲得排名在某個范圍的元素列表
獲得排名在某個范圍的元素列表
? 按照元素分數從小到大的順序返回索引從start到stop之間的所有元素(包含兩端的元素)
語法:ZRANGE key start stop [WITHSCORES]
127.0.0.1:6379> zrange scoreboard 0 2
- "zhangsan"
- "wangwu"
- "lisi“
? 按照元素分數從大到小的順序返回索引從start到stop之間的所有元素(包含兩端的元素)
語法:ZREVRANGE key start stop [WITHSCORES]
127.0.0.1:6379> zrevrange scoreboard 0 2
- " lisi "
- "wangwu"
- " zhangsan “
如果需要獲得元素的分數的可以在命令尾部加上WITHSCORES參數
127.0.0.1:6379> zrange scoreboard 0 1 WITHSCORES
- "zhangsan"
- "80"
- "wangwu"
- "94"
4.5.2.5 其它命令(自學)
4.5.2.5.1 獲得指定分數范圍的元素
語法:ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
127.0.0.1:6379> ZRANGEBYSCORE scoreboard 90 97 WITHSCORES
- "wangwu"
- "94"
- "lisi"
- "97"
127.0.0.1:6379> ZRANGEBYSCORE scoreboard 70 100 limit 1 2 - "wangwu"
- "lisi"
4.5.2.5.2 增加某個元素的分數
返回值是更改后的分數
語法:ZINCRBY key increment member
127.0.0.1:6379> ZINCRBY scoreboard 4 lisi
"101“
4.5.2.5.3 獲得集合中元素的數量
語法:ZCARD key
127.0.0.1:6379> ZCARD scoreboard
(integer) 3
4.5.2.5.4 獲得指定分數范圍內的元素個數
語法:ZCOUNT key min max
127.0.0.1:6379> ZCOUNT scoreboard 80 90
(integer) 1
4.5.2.5.5 按照排名范圍刪除元素
語法:ZREMRANGEBYRANK key start stop
127.0.0.1:6379> ZREMRANGEBYRANK scoreboard 0 1
(integer) 2
127.0.0.1:6379> ZRANGE scoreboard 0 -1
- "lisi"
4.5.2.5.6 按照分數范圍刪除元素
語法:ZREMRANGEBYSCORE key min max
127.0.0.1:6379> zadd scoreboard 84 zhangsan
(integer) 1
127.0.0.1:6379> ZREMRANGEBYSCORE scoreboard 80 100
(integer) 1
4.5.2.5.7 獲取元素的排名
? 從小到大
語法:ZRANK key member
127.0.0.1:6379> ZRANK scoreboard lisi
(integer) 0
? 從大到小
語法:ZREVRANK key member
127.0.0.1:6379> ZREVRANK scoreboard zhangsan
(integer) 1
4.5.3 應用
4.5.3.1 商品銷售排行榜
需求:根據商品銷售量對商品進行排行顯示
思路:定義商品銷售排行榜(sorted set集合),Key為items:sellsort,分數為商品銷售量。
寫入商品銷售量:
? 商品編號1001的銷量是9,商品編號1002的銷量是10
192.168.101.3:7007> ZADD items:sellsort 9 1001 10 1002
? 商品編號1001的銷量加1
192.168.101.3:7001> ZINCRBY items:sellsort 1 1001
? 商品銷量前10名:
192.168.101.3:7001> ZRANGE items:sellsort 0 9 withscores
5 Keys命令(了解)
5.1 設置key的生存時間
Redis在實際使用過程中更多的用作緩存,然而緩存的數據一般都是需要設置生存時間的,即:到期后數據銷毀。
EXPIRE key seconds 設置key的生存時間(單位:秒)key在多少秒后會自動刪除
TTL key 查看key生于的生存時間
PERSIST key 清除生存時間
PEXPIRE key milliseconds 生存時間設置單位為:毫秒
例子:
192.168.101.3:7002> set test 1 設置test的值為1
OK
192.168.101.3:7002> get test 獲取test的值
"1"
192.168.101.3:7002> EXPIRE test 5 設置test的生存時間為5秒
(integer) 1
192.168.101.3:7002> TTL test 查看test的生于生成時間還有1秒刪除
(integer) 1
192.168.101.3:7002> TTL test
(integer) -2
192.168.101.3:7002> get test 獲取test的值,已經刪除
(nil)
5.2 其它命令(自學)
5.2.1 keys
返回滿足給定pattern 的所有key
redis 127.0.0.1:6379> keys mylist*
- "mylist"
- "mylist5"
- "mylist6"
- "mylist7"
- "mylist8"
5.2.2 exists
確認一個key 是否存在
示例:從結果來看,數據庫中不存在HongWan 這個key,但是age 這個key 是存在的
redis 127.0.0.1:6379> exists HongWan
(integer) 0
redis 127.0.0.1:6379> exists age
(integer) 1
redis 127.0.0.1:6379>
5.2.3 del
刪除一個key
redis 127.0.0.1:6379> del age
(integer) 1
redis 127.0.0.1:6379> exists age
(integer) 0
5.2.4 rename
重命名key
示例:age 成功的被我們改名為age_new 了
redis 127.0.0.1:6379[1]> keys *
- "age"
redis 127.0.0.1:6379[1]> rename age age_new
OK
redis 127.0.0.1:6379[1]> keys * - "age_new"
redis 127.0.0.1:6379[1]>
5.2.5 type
返回值的類型
示例:這個方法可以非常簡單的判斷出值的類型
redis 127.0.0.1:6379> type addr
string
redis 127.0.0.1:6379> type myzset2
zset
redis 127.0.0.1:6379> type mylist
list
redis 127.0.0.1:6379>
6 Redis持久化方案
6.1 RDB持久化
RDB方式的持久化是通過快照(snapshotting)完成的,當符合一定條件時Redis會自動將內存中的數據進行快照并持久化到硬盤。
RDB是Redis默認采用的持久化方式。
save 900 1
save 300 10
save 60 10000
6.1.1 持久化條件配置
save 開頭的一行就是持久化配置,可以配置多個條件(每行配置一個條件),每個條件之間是“或”的關系。
“save 900 1”表示15分鐘(900秒鐘)內至少1個鍵被更改則進行快照。
“save 300 10”表示5分鐘(300秒)內至少10個鍵被更改則進行快照。
6.1.2 配置快照文件目錄
配置dir指定rdb快照文件的位置
Note that you must specify a directory here, not a file name.
dir ./
6.1.3 配置快照文件的名稱
設置dbfilename指定rdb快照文件的名稱
The filename where to dump the DB
dbfilename dump.rdb
Redis啟動后會讀取RDB快照文件,將數據從硬盤載入到內存。根據數據量大小與結構和服務器性能不同,這個時間也不同。通常將記錄一千萬個字符串類型鍵、大小為1GB的快照文件載入到內存中需要花費20~30秒鐘。
6.1.4 問題總結
通過RDB方式實現持久化,一旦Redis異常退出,就會丟失最后一次快照以后更改的所有數據。這就需要開發者根據具體的應用場合,通過組合設置自動快照條件的方式來將可能發生的數據損失控制在能夠接受的范圍。
如果數據很重要以至于無法承受任何損失,則可以考慮使用AOF方式進行持久化。
6.2 AOF持久化
默認情況下Redis沒有開啟AOF(append only file)方式的持久化
? 可以通過修改redis.conf配置文件中的appendonly參數開啟
appendonly yes
開啟AOF持久化后每執行一條會更改Redis中的數據的命令,Redis就會將該命令寫入硬
盤中的AOF文件。
? AOF文件的保存位置和RDB文件的位置相同,都是通過dir參數設置的。
dir ./
? 默認的文件名是appendonly.aof,可以通過appendfilename參數修改:
appendfilename appendonly.aof
7 Redis的主從復制
7.1 什么是主從復制
持久化保證了即使redis服務重啟也不會丟失數據,因為redis服務重啟后會將硬盤上持久化的數據恢復到內存中,但是當redis服務器的硬盤損壞了可能會導致數據丟失,如果通過redis的主從復制機制就可以避免這種單點故障,如下圖:
說明:
? 主redis中的數據有兩個副本(replication)即從redis1和從redis2,即使一臺redis服務器宕機其它兩臺redis服務也可以繼續提供服務。
? 主redis中的數據和從redis上的數據保持實時同步,當主redis寫入數據時通過主從復制機制會復制到兩個從redis服務上。
? 只有一個主redis,可以有多個從redis。
? 主從復制不會阻塞master,在同步數據時,master 可以繼續處理client 請求
? 一個redis可以即是主又是從,如下圖:
7.2 主從配置
7.2.1 主redis配置
無需特殊配置。
7.2.2 從redis配置
? 修改從redis服務器上的redis.conf文件
slaveof <masterip> <masterport>
slaveof 127.0.0.1 6379
上邊的配置說明當前該【從redis服務器】所對應的【主redis服務器】的IP是192.168.101.3,端口是6379。
8 Redis集群
8.1 redis-cluster架構圖
架構細節:
(1)所有的redis節點彼此互聯(PING-PONG機制),內部使用二進制協議優化傳輸速度和帶寬.
(2)節點的fail是通過集群中超過半數的節點檢測失效時才生效.
(3)客戶端與redis節點直連,不需要中間proxy層.客戶端不需要連接集群所有節點,連接集群中任何一個可用節點即可
(4)redis-cluster把所有的物理節點映射到[0-16383]slot上,cluster 負責維護node<->slot<->value
Redis 集群中內置了 16384 個哈希槽,當需要在 Redis 集群中放置一個 key-value 時,redis 先對 key 使用 crc16 算法算出一個結果,然后把結果對 16384 求余數,這樣每個 key 都會對應一個編號在 0-16383 之間的哈希槽,redis 會根據節點數量大致均等的將哈希槽映射到不同的節點
示例如下:
8.2 redis-cluster投票:容錯
(1)集群中所有master參與投票,如果半數以上master節點與其中一個master節點通信超過(cluster-node-timeout),認為該master節點掛掉.
(2):什么時候整個集群不可用(cluster_state:fail)?
? 如果集群任意master掛掉,且當前master沒有slave,則集群進入fail狀態。也可以理解成集群的[0-16383]slot映射不完全時進入fail狀態。
? 如果集群超過半數以上master掛掉,無論是否有slave,集群進入fail狀態。
8.3 搭建Ruby環境
redis集群管理工具redis-trib.rb依賴ruby環境,首先需要安裝ruby環境。
? 安裝ruby
[root@redis01 bin]# yum install ruby
[root@redis01 bin]# yum install rubygems
? 使用sftp工具上傳redis-3.0.0.gem至/usr/local下
sftp> put -r "E:\03-teach\03-講課\0707\04-redis\res\ruby和redis接口\redis-3.0.0.gem"
? 安裝ruby和redis的接口程序
[root@linux02 local]# gem install /usr/local/redis-3.0.0.gem
? 將Redis集群搭建腳本文件復制到/usr/local/redis0707目錄下
[root@redis01 /]# cd /root/redis-3.0.0/src/
[root@redis01 src]# ll *.rb
-rwxrwxr-x. 1 root root 48141 4月 1 2015 redis-trib.rb
[root@redis01 src]# cp redis-trib.rb /usr/local/redis0707/ -r
8.4 集群的搭建過程
第一步:創建6個redis實例,需要端口號7001~7006
第二步:修改redis.conf配置文件,打開Cluster-enable yes
第三步:啟動所有的實例
第四步:創建集群
[root@localhost-0723 redis]# ./redis-trib.rb create --replicas 1 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006
Creating cluster
Connecting to node 127.0.0.1:7001: OK
Connecting to node 127.0.0.1:7002: OK
Connecting to node 127.0.0.1:7003: OK
Connecting to node 127.0.0.1:7004: OK
Connecting to node 127.0.0.1:7005: OK
Connecting to node 127.0.0.1:7006: OK
Performing hash slots allocation on 6 nodes...
Using 3 masters:
127.0.0.1:7001
127.0.0.1:7002
127.0.0.1:7003
Adding replica 127.0.0.1:7004 to 127.0.0.1:7001
Adding replica 127.0.0.1:7005 to 127.0.0.1:7002
Adding replica 127.0.0.1:7006 to 127.0.0.1:7003
M: d8f6a0e3192c905f0aad411946f3ef9305350420 127.0.0.1:7001
slots:0-5460 (5461 slots) master
M: 7a12bc730ddc939c84a156f276c446c28acf798c 127.0.0.1:7002
slots:5461-10922 (5462 slots) master
M: 93f73d2424a796657948c660928b71edd3db881f 127.0.0.1:7003
slots:10923-16383 (5461 slots) master
S: f79802d3da6b58ef6f9f30c903db7b2f79664e61 127.0.0.1:7004
replicates d8f6a0e3192c905f0aad411946f3ef9305350420
S: 0bc78702413eb88eb6d7982833a6e040c6af05be 127.0.0.1:7005
replicates 7a12bc730ddc939c84a156f276c446c28acf798c
S: 4170a68ba6b7757e914056e2857bb84c5e10950e 127.0.0.1:7006
replicates 93f73d2424a796657948c660928b71edd3db881f
Can I set the above configuration? (type 'yes' to accept): yes
Nodes configuration updated
Assign a different config epoch to each node
Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join....
Performing Cluster Check (using node 127.0.0.1:7001)
M: d8f6a0e3192c905f0aad411946f3ef9305350420 127.0.0.1:7001
slots:0-5460 (5461 slots) master
M: 7a12bc730ddc939c84a156f276c446c28acf798c 127.0.0.1:7002
Performing hash slots allocation on 6 nodes...
Using 3 masters:
127.0.0.1:7001
127.0.0.1:7002
127.0.0.1:7003
Adding replica 127.0.0.1:7004 to 127.0.0.1:7001
Adding replica 127.0.0.1:7005 to 127.0.0.1:7002
Adding replica 127.0.0.1:7006 to 127.0.0.1:7003
M: d8f6a0e3192c905f0aad411946f3ef9305350420 127.0.0.1:7001
slots:0-5460 (5461 slots) master
M: 7a12bc730ddc939c84a156f276c446c28acf798c 127.0.0.1:7002
slots:5461-10922 (5462 slots) master
M: 93f73d2424a796657948c660928b71edd3db881f 127.0.0.1:7003
slots:10923-16383 (5461 slots) master
S: f79802d3da6b58ef6f9f30c903db7b2f79664e61 127.0.0.1:7004
replicates d8f6a0e3192c905f0aad411946f3ef9305350420
S: 0bc78702413eb88eb6d7982833a6e040c6af05be 127.0.0.1:7005
replicates 7a12bc730ddc939c84a156f276c446c28acf798c
S: 4170a68ba6b7757e914056e2857bb84c5e10950e 127.0.0.1:7006
replicates 93f73d2424a796657948c660928b71edd3db881f
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join....
>>> Performing Cluster Check (using node 127.0.0.1:7001)
M: d8f6a0e3192c905f0aad411946f3ef9305350420 127.0.0.1:7001
slots:0-5460 (5461 slots) master
M: 7a12bc730ddc939c84a156f276c446c28acf798c 127.0.0.1:7002
slots:5461-10922 (5462 slots) master
M: 93f73d2424a796657948c660928b71edd3db881f 127.0.0.1:7003
slots:10923-16383 (5461 slots) master
M: f79802d3da6b58ef6f9f30c903db7b2f79664e61 127.0.0.1:7004
slots: (0 slots) master
replicates d8f6a0e3192c905f0aad411946f3ef9305350420
M: 0bc78702413eb88eb6d7982833a6e040c6af05be 127.0.0.1:7005
slots: (0 slots) master
replicates 7a12bc730ddc939c84a156f276c446c28acf798c
M: 4170a68ba6b7757e914056e2857bb84c5e10950e 127.0.0.1:7006
slots: (0 slots) master
replicates 93f73d2424a796657948c660928b71edd3db881f
[OK] All nodes agree about slots configuration.
Check for open slots...
Check slots coverage...
[OK] All 16384 slots covered.
[root@localhost-0723 redis]#
8.5 連接集群
命令:./redis-cli –h 127.0.0.1 –p 7001 -c
[root@localhost-0723 redis]# ./redis-cli -p 7006 -c
127.0.0.1:7006> set key1 123
-> Redirected to slot [9189] located at 127.0.0.1:7002
OK
127.0.0.1:7002>
8.6 查看集群的命令
? 查看集群狀態
127.0.0.1:7003> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:3
cluster_stats_messages_sent:926
cluster_stats_messages_received:926
? 查看集群中的節點:
127.0.0.1:7003> cluster nodes
7a12bc730ddc939c84a156f276c446c28acf798c 127.0.0.1:7002 master - 0 1443601739754 2 connected 5461-10922
93f73d2424a796657948c660928b71edd3db881f 127.0.0.1:7003 myself,master - 0 0 3 connected 10923-16383
d8f6a0e3192c905f0aad411946f3ef9305350420 127.0.0.1:7001 master - 0 1443601741267 1 connected 0-5460
4170a68ba6b7757e914056e2857bb84c5e10950e 127.0.0.1:7006 slave 93f73d2424a796657948c660928b71edd3db881f 0 1443601739250 6 connected
f79802d3da6b58ef6f9f30c903db7b2f79664e61 127.0.0.1:7004 slave d8f6a0e3192c905f0aad411946f3ef9305350420 0 1443601742277 4 connected
0bc78702413eb88eb6d7982833a6e040c6af05be 127.0.0.1:7005 slave 7a12bc730ddc939c84a156f276c446c28acf798c 0 1443601740259 5 connected
127.0.0.1:7003>
8.7 維護節點(自學)
8.7.1 添加主節點
集群創建成功后可以向集群中添加節點,下面是添加一個master主節點
? 添加7007結點作為新節點
執行命令:./redis-trib.rb add-node 127.0.0.1:7007 127.0.0.1:7001
? 查看集群結點發現7007已添加到集群中
8.7.2 hash槽重新分配
添加完主節點需要對主節點進行hash槽分配,這樣該主節才可以存儲數據。
? 查看集群中槽占用情況
redis集群有16384個槽,集群中的每個結點分配自已槽,通過查看集群結點可以看到槽占用情況。
? 給剛添加的7007結點分配槽
第一步:連接上集群(連接集群中任意一個可用結點都行)
[root@redis01 redis0707]# ./redis-trib.rb reshard 192.168.101.3:7001
第二步:輸入要分配的槽數量
輸入:500,表示要分配500個槽
第三步:輸入接收槽的結點id
輸入:15b809eadae88955e36bcdbb8144f61bbbaf38fb
PS:這里準備給7007分配槽,通過cluster nodes查看7007結點id為:
15b809eadae88955e36bcdbb8144f61bbbaf38fb
第四步:輸入源結點id
輸入:all
第五步:輸入yes開始移動槽到目標結點id
輸入:yes
8.7.3 添加從節點
集群創建成功后可以向集群中添加節點,下面是添加一個slave從節點。
? 添加7008從結點,將7008作為7007的從結點
命令:./redis-trib.rb add-node --slave --master-id 主節點id 新節點的ip和端口 舊節點ip和端口
執行如下命令:
./redis-trib.rb add-node --slave --master-id cad9f7413ec6842c971dbcc2c48b4ca959eb5db4 192.168.101.3:7008 192.168.101.3:7001
cad9f7413ec6842c971dbcc2c48b4ca959eb5db4 是7007結點的id,可通過cluster nodes查看。
注意:如果原來該結點在集群中的配置信息已經生成到cluster-config-file指定的配置文件中(如果cluster-config-file沒有指定則默認為nodes.conf),這時可能會報錯:
[ERR] Node XXXXXX is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0
解決方法是刪除生成的配置文件nodes.conf,刪除后再執行./redis-trib.rb add-node指令
? 查看集群中的結點,剛添加的7008為7007的從節點:
8.7.4 刪除結點
命令:./redis-trib.rb del-node 127.0.0.1:7005 4b45eb75c8b428fbd77ab979b85080146a9bc017
刪除已經占有hash槽的結點會失敗,報錯如下:
[ERR] Node 127.0.0.1:7005 is not empty! Reshard data away and try again.
需要將該結點占用的hash槽分配出去(參考hash槽重新分配章節)。
9 Jedis連接集群
9.1 防火墻配置
[root@localhost-0723 bin]# service iptables stop
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 8080 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 6379 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 6380 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 7001 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 7002 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 7003 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 7004 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 7005 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 7006 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
~
"/etc/sysconfig/iptables" 22L, 1079C 已寫入
[root@localhost-0723 bin]# service iptables restart
iptables:應用防火墻規則: [確定]
[root@localhost-0723 bin]#
9.2 代碼實現
創建JedisCluster類連接redis集群。
@Test
public void testJedisCluster() throws Exception {
//創建一連接,JedisCluster對象,在系統中是單例存在
Set<HostAndPort> nodes = new HashSet<>();
nodes.add(new HostAndPort("127.0.0.1", 7001));
nodes.add(new HostAndPort("127.0.0.1", 7002));
nodes.add(new HostAndPort("127.0.0.1", 7003));
nodes.add(new HostAndPort("127.0.0.1", 7004));
nodes.add(new HostAndPort("127.0.0.1", 7005));
nodes.add(new HostAndPort("127.0.0.1", 7006));
JedisCluster cluster = new JedisCluster(nodes);
//執行JedisCluster對象中的方法,方法和redis一一對應。
cluster.set("cluster-test", "my jedis cluster test");
String result = cluster.get("cluster-test");
System.out.println(result);
//程序結束時需要關閉JedisCluster對象
cluster.close();
}
9.3 使用spring
? 配置applicationContext.xml
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="30" />
<property name="maxIdle" value="10" />
<property name="numTestsPerEvictionRun" value="1024" />
<property name="timeBetweenEvictionRunsMillis" value="30000" />
<property name="minEvictableIdleTimeMillis" value="1800000" />
<property name="softMinEvictableIdleTimeMillis" value="10000" />
<property name="maxWaitMillis" value="1500" />
<property name="testOnBorrow" value="true" />
<property name="testWhileIdle" value="true" />
<property name="blockWhenExhausted" value="false" />
</bean>
<bean id="jedisCluster" class="redis.clients.jedis.JedisCluster">
<constructor-arg index="0">
<set>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="192.168.101.3"></constructor-arg>
<constructor-arg index="1" value="7001"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="192.168.101.3"></constructor-arg>
<constructor-arg index="1" value="7002"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="192.168.101.3"></constructor-arg>
<constructor-arg index="1" value="7003"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="192.168.101.3"></constructor-arg>
<constructor-arg index="1" value="7004"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="192.168.101.3"></constructor-arg>
<constructor-arg index="1" value="7005"></constructor-arg>
</bean>
<bean class="redis.clients.jedis.HostAndPort">
<constructor-arg index="0" value="192.168.101.3"></constructor-arg>
<constructor-arg index="1" value="7006"></constructor-arg>
</bean>
</set>
</constructor-arg>
<constructor-arg index="1" ref="jedisPoolConfig"></constructor-arg>
</bean>
? 測試代碼
private ApplicationContext applicationContext;
@Before
public void init() {
applicationContext = new ClassPathXmlApplicationContext(
"classpath:applicationContext.xml");
}
// redis集群
@Test
public void testJedisCluster() {
JedisCluster jedisCluster = (JedisCluster) applicationContext
.getBean("jedisCluster");
jedisCluster.set("name", "zhangsan");
String value = jedisCluster.get("name");
System.out.println(value);
}