redis安裝、集群搭建等

1 Redis介紹
1.1 什么是NoSql
為了解決高并發(fā)、高可擴展、高可用、大數(shù)據(jù)存儲問題而產(chǎn)生的數(shù)據(jù)庫解決方案,就是NoSql數(shù)據(jù)庫。

NoSQL,泛指非關系型的數(shù)據(jù)庫,NoSQL即Not-Only SQL,它可以作為關系型數(shù)據(jù)庫的良好補充。
1.2 Nosql數(shù)據(jù)庫分類
? 鍵值(Key-Value)存儲數(shù)據(jù)庫
相關產(chǎn)品: Tokyo Cabinet/Tyrant、Redis、Voldemort、Berkeley DB
典型應用: 內容緩存,主要用于處理大量數(shù)據(jù)的高訪問負載。
數(shù)據(jù)模型: 一系列鍵值對
優(yōu)勢: 快速查詢
劣勢: 存儲的數(shù)據(jù)缺少結構化

? 列存儲數(shù)據(jù)庫
相關產(chǎn)品:Cassandra, HBase, Riak
典型應用:分布式的文件系統(tǒng)
數(shù)據(jù)模型:以列簇式存儲,將同一列數(shù)據(jù)存在一起
優(yōu)勢:查找速度快,可擴展性強,更容易進行分布式擴展
劣勢:功能相對局限
? 文檔型數(shù)據(jù)庫
相關產(chǎn)品:CouchDB、MongoDB
典型應用:Web應用(與Key-Value類似,Value是結構化的)
數(shù)據(jù)模型: 一系列鍵值對
優(yōu)勢:數(shù)據(jù)結構要求不嚴格
劣勢: 查詢性能不高,而且缺乏統(tǒng)一的查詢語法
? 圖形(Graph)數(shù)據(jù)庫
相關數(shù)據(jù)庫:Neo4J、InfoGrid、Infinite Graph
典型應用:社交網(wǎng)絡
數(shù)據(jù)模型:圖結構
優(yōu)勢:利用圖結構相關算法。
劣勢:需要對整個圖做計算才能得出結果,不容易做分布式的集群方案。

1.3 什么是Redis
Redis是用C語言開發(fā)的一個開源的高性能鍵值對(key-value)數(shù)據(jù)庫。它通過提供多種鍵值數(shù)據(jù)類型來適應不同場景下的存儲需求,目前為止Redis支持的鍵值數(shù)據(jù)類型如
下:

字符串類型
散列類型
列表類型
集合類型
有序集合類型。
1.4 redis歷史發(fā)展
2008年,意大利的一家創(chuàng)業(yè)公司Merzia推出了一款基于MySQL的網(wǎng)站實時統(tǒng)計系統(tǒng)LLOOGG,然而沒過多久該公司的創(chuàng)始人 Salvatore Sanfilippo便 對MySQL的性能感到失望,于是他決定親自為LLOOGG量身定做一個數(shù)據(jù)庫,并于2009年開發(fā)完成,這個數(shù)據(jù)庫就是Redis。 不過Salvatore Sanfilippo并不滿足只將Redis用于LLOOGG這一款產(chǎn)品,而是希望更多的人使用它,于是在同一年Salvatore Sanfilippo將Redis開源發(fā)布,并開始和Redis的另一名主要的代碼貢獻者Pieter Noordhuis一起繼續(xù)著Redis的開發(fā),直到今天。
Salvatore Sanfilippo自己也沒有想到,短短的幾年時間,Redis就擁有了龐大的用戶群體。Hacker News在2012年發(fā)布了一份數(shù)據(jù)庫的使用情況調查,結果顯示有近12%的公司在使用Redis。國內如新浪微博、街旁網(wǎng)、知乎網(wǎng),國外如GitHub、Stack Overflow、Flickr等都是Redis的用戶。
VMware公司從2010年開始贊助Redis的開發(fā), Salvatore Sanfilippo和Pieter Noordhuis也分別在3月和5月加入VMware,全職開發(fā)Redis。

1.5 redis的應用場景
緩存(數(shù)據(jù)查詢、短連接、新聞內容、商品內容等等)。(最多使用)
分布式集群架構中的session分離。
聊天室的在線好友列表。
任務隊列。(秒殺、搶購、12306等等)
應用排行榜。
網(wǎng)站訪問統(tǒng)計。
數(shù)據(jù)過期處理(可以精確到毫秒)

2 Redis安裝配置
2.1 Redis下載
官網(wǎng)地址:http://redis.io/
下載地址:http://download.redis.io/releases/redis-3.0.0.tar.gz

2.2 Redis安裝
Redis是C語言開發(fā),建議在linux上運行,本教程使用Centos6.4作為安裝環(huán)境。
第一步:在VMware中安裝CentOS(參考Linux教程中的安裝虛擬機)
第二步:在Linux下安裝gcc環(huán)境(該步驟可以省略,CentOS中默認自帶C環(huán)境)
[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

第三步:執(zhí)行命令
[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:清除防火墻規(guī)則: [確定]
iptables:將鏈設置為政策 ACCEPT:filter [確定]
iptables:正在卸載模塊: [確定]
iptables:應用防火墻規(guī)則: [確定]
[root@localhost-0723 redis-3.0.0]#

注意:
默認一共是16個數(shù)據(jù)庫,每個數(shù)據(jù)庫之間是相互隔離。數(shù)據(jù)庫的數(shù)量是在redis.conf中配置的。

切換數(shù)據(jù)庫使用命令:select 數(shù)據(jù)庫編號
例如:select 1

3.3 Java客戶端Jedis
3.3.1 jedis介紹
Redis不僅是使用命令來操作,現(xiàn)在基本上主流的語言都有客戶端支持,比如java、C、C#、C++、php、Node.js、Go等。
在官方網(wǎng)站里列一些Java的客戶端,有Jedis、Redisson、Jredis、JDBC-Redis、等其中官方推薦使用Jedis和Redisson。 在企業(yè)中用的最多的就是Jedis,下面我們就重點學習下Jedis。
Jedis同樣也是托管在github上,地址:https://github.com/xetorthio/jedis

3.3.2 添加jar包

3.3.3 單實例連接
@Test
public void testJedis() {
//創(chuàng)建一個Jedis的連接
Jedis jedis = new Jedis("127.0.0.1", 6379);
//執(zhí)行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() {
//創(chuàng)建一連接池對象
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">
    <!-- 最大連接數(shù) -->
    <property name="maxTotal" value="30" />
    <!-- 最大空閑連接數(shù) -->
    <property name="maxIdle" value="10" />
    <!-- 每次釋放連接的最大數(shù)目 -->
    <property name="numTestsPerEvictionRun" value="1024" />
    <!-- 釋放連接的掃描間隔(毫秒) -->
    <property name="timeBetweenEvictionRunsMillis" value="30000" />
    <!-- 連接最小空閑時間 -->
    <property name="minEvictableIdleTimeMillis" value="1800000" />
    <!-- 連接空閑多久后釋放, 當空閑時間>該值 且 空閑連接>最大空閑連接數(shù) 時直接釋放 -->
    <property name="softMinEvictableIdleTimeMillis" value="10000" />
    <!-- 獲取連接時的最大等待毫秒數(shù),小于零:阻塞不確定的時間,默認-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數(shù)據(jù)類型
Redis中存儲數(shù)據(jù)是通過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

  1. "v1"
  2. "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 數(shù)值增減
? 遞增數(shù)字
當存儲的字符串是整數(shù)時,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

? 增加指定的整數(shù)
語法: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

? 遞減數(shù)值
語法:DECR key
127.0.0.1:6379> decr num
(integer) 9
127.0.0.1:6379> decr num
(integer) 8

? 減少指定的整數(shù)
語法: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的遞增數(shù)字特性生成。

定義商品編號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
如果在業(yè)務上只是更新age屬性,其他的屬性并不做更新我應該怎么做呢? 如果仍然采用上邊的方法在傳輸、處理時會造成資源浪費,下邊講的hash可以很好的解決這個問題。

4.2.2 redis hash介紹
hash叫散列類型,它提供了字段和字段值的映射。字段值只能是字符串類型,不支持散列類型、集合類型等其它類型。如下:

4.2.3 命令
4.2.3.1 賦值
HSET命令不區(qū)分插入和更新操作,當執(zhí)行插入操作時HSET命令返回1,當執(zhí)行更新操作時返回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,區(qū)別在于如果字段存在,該命令不執(zhí)行任何操作
語法: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

  1. "20"
  2. "lisi"

? 獲取所有字段值
語法:HGETALL key
127.0.0.1:6379> hgetall user

  1. "age"
  2. "20"
  3. "username"
  4. "lisi"

4.2.3.3 刪除字段
可以刪除一個或多個字段,返回值是被刪除的字段個數(shù)

語法: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 增加數(shù)字
語法: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

  1. "age"
  2. "name"
    127.0.0.1:6379> hvals user
  3. "20"
  4. "lisi"

4.2.3.5.3 獲取字段數(shù)量
語法: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

  1. "id"
  2. "3"
  3. "name"
  4. "apple"
  5. "price"
  6. "999.9"

4.3 List類型
4.3.1 ArrayList與LinkedList的區(qū)別
ArrayList使用數(shù)組方式存儲數(shù)據(jù),所以根據(jù)索引查詢數(shù)據(jù)速度快,而新增或者刪除元素時需要設計到位移操作,所以比較慢。
LinkedList使用雙向鏈表方式存儲數(shù)據(jù),每個元素都記錄前后元素的指針,所以插入、刪除數(shù)據(jù)時只是更改前后元素的指針指向即可,速度非???。然后通過下標查詢元素時需要從頭開始索引,所以比較慢,但是如果查詢前幾個元素或后幾個元素速度比較快。

4.3.2 redis list介紹
列表類型(list)可以存儲一個有序的字符串列表,常用的操作是向列表兩端添加元素,或者獲得列表的某一個片段。
列表類型內部是使用雙向鏈表(double linked list)實現(xiàn)的,所以向列表兩端添加元素的時間復雜度為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開始。索引可以是負數(shù),如:“-1”代表最后邊的一個元素。

語法:LRANGE key start stop
127.0.0.1:6379> lrange list:1 0 2

  1. "2"
  2. "1"
  3. "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 獲取列表中元素的個數(shù)
語法:LLEN key
127.0.0.1:6379> llen list:1
(integer) 2

4.3.3.5 其它命令(自學)
4.3.3.5.1 刪除列表中指定的值
LREM命令會刪除列表中前count個值為value的元素,返回實際刪除的元素個數(shù)。根據(jù)count值的不同,該命令的執(zhí)行方式會有所不同:
? 當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

  1. "6"
  2. "5"
  3. "2"
  4. "2"

4.3.3.5.3 只保留列表指定片段
指定范圍和LRANGE一致

語法:LTRIM key start stop
127.0.0.1:6379> lrange l:list 0 -1

  1. "6"
  2. "5"
  3. "0"
  4. "2"
    127.0.0.1:6379> ltrim l:list 0 2
    OK
    127.0.0.1:6379> lrange l:list 0 -1
  5. "6"
  6. "5"
  7. "0"

4.3.3.5.4 向列表中插入元素
該命令首先會在列表中從左到右查找值為pivot的元素,然后根據(jù)第二個參數(shù)是BEFORE還是AFTER來決定將value插入到該元素的前面還是后面。

語法:LINSERT key BEFORE|AFTER pivot value
127.0.0.1:6379> lrange list 0 -1

  1. "3"
  2. "2"
  3. "1"
    127.0.0.1:6379> linsert list after 3 4
    (integer) 4
    127.0.0.1:6379> lrange list 0 -1
  4. "3"
  5. "4"
  6. "2"
  7. "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. "1"
    127.0.0.1:6379> lrange list 0 -1
  2. "3"
  3. "4"
  4. "2"

4.3.4 應用
4.3.4.1 商品評論列表
思路:
在Redis中創(chuàng)建商品評論列表
用戶發(fā)布商品評論,將評論信息轉成json存儲到list中。
用戶在頁面查詢評論列表,從redis中取出json數(shù)據(jù)展示到頁面。

定義商品評論列表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介紹
集合中的數(shù)據(jù)是不重復且沒有順序。

集合類型和列表類型的對比:

集合類型的常用操作是向集合中加入或刪除元素、判斷某個元素是否存在等,由于集合類型的Redis內部是使用值為空的散列表實現(xiàn),所有這些操作的時間復雜度都為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

  1. "b"
  2. "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. "1"
    127.0.0.1:6379> sdiff setB setA
  2. "4"

4.4.3.2 集合的交集運算 A ∩ B
屬于A且屬于B的元素構成的集合。

語法:SINTER key [key ...]
127.0.0.1:6379> sinter setA setB

  1. "2"
  2. "3"

4.4.3.3 集合的并集運算 A ∪ B
屬于A或者屬于B的元素構成的集合

語法:SUNION key [key ...]
127.0.0.1:6379> sunion setA setB

  1. "1"
  2. "2"
  3. "3"
  4. "4"

4.4.4 其它命令(自學)
4.4.4.1 獲得集合中元素的個數(shù)
語法:SCARD key
127.0.0.1:6379> smembers setA

  1. "1"
  2. "2"
  3. "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介紹
在集合類型的基礎上,有序集合類型為集合中的每個元素都關聯(lián)一個分數(shù),這使得我們不僅可以完成插入、刪除和判斷元素是否存在在集合中,還能夠獲得分數(shù)最高或最低的前N個元素、獲取指定分數(shù)范圍內的元素等與分數(shù)有關的操作。

在某些方面有序集合和列表類型有些相似。
1、二者都是有序的。
2、二者都可以獲得某一范圍的元素。
但是,二者有著很大區(qū)別:
1、列表類型是通過鏈表實現(xiàn)的,獲取靠近兩端的數(shù)據(jù)速度極快,而當元素增多后,訪問中間數(shù)據(jù)的速度會變慢。
2、有序集合類型使用散列表實現(xiàn),所有即使讀取位于中間部分的數(shù)據(jù)也很快。
3、列表中不能簡單的調整某個元素的位置,但是有序集合可以(通過更改分數(shù)實現(xiàn))
4、有序集合要比列表類型更耗內存。

4.5.2 命令
4.5.2.1 增加元素
向有序集合中加入一個元素和該元素的分數(shù),如果該元素已經(jīng)存在則會用新的分數(shù)替換原有的分數(shù)。返回值是新加入到集合中的元素個數(shù),不包含之前已經(jīng)存在的元素。

語法: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 獲取元素的分數(shù)
語法: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 獲得排名在某個范圍的元素列表
獲得排名在某個范圍的元素列表
? 按照元素分數(shù)從小到大的順序返回索引從start到stop之間的所有元素(包含兩端的元素)

語法:ZRANGE key start stop [WITHSCORES]
127.0.0.1:6379> zrange scoreboard 0 2

  1. "zhangsan"
  2. "wangwu"
  3. "lisi“

? 按照元素分數(shù)從大到小的順序返回索引從start到stop之間的所有元素(包含兩端的元素)

語法:ZREVRANGE key start stop [WITHSCORES]
127.0.0.1:6379> zrevrange scoreboard 0 2

  1. " lisi "
  2. "wangwu"
  3. " zhangsan “

如果需要獲得元素的分數(shù)的可以在命令尾部加上WITHSCORES參數(shù)
127.0.0.1:6379> zrange scoreboard 0 1 WITHSCORES

  1. "zhangsan"
  2. "80"
  3. "wangwu"
  4. "94"

4.5.2.5 其它命令(自學)
4.5.2.5.1 獲得指定分數(shù)范圍的元素
語法:ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
127.0.0.1:6379> ZRANGEBYSCORE scoreboard 90 97 WITHSCORES

  1. "wangwu"
  2. "94"
  3. "lisi"
  4. "97"
    127.0.0.1:6379> ZRANGEBYSCORE scoreboard 70 100 limit 1 2
  5. "wangwu"
  6. "lisi"

4.5.2.5.2 增加某個元素的分數(shù)
返回值是更改后的分數(shù)

語法:ZINCRBY key increment member
127.0.0.1:6379> ZINCRBY scoreboard 4 lisi
"101“

4.5.2.5.3 獲得集合中元素的數(shù)量
語法:ZCARD key
127.0.0.1:6379> ZCARD scoreboard
(integer) 3

4.5.2.5.4 獲得指定分數(shù)范圍內的元素個數(shù)
語法: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

  1. "lisi"
    4.5.2.5.6 按照分數(shù)范圍刪除元素
    語法: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 商品銷售排行榜
需求:根據(jù)商品銷售量對商品進行排行顯示
思路:定義商品銷售排行榜(sorted set集合),Key為items:sellsort,分數(shù)為商品銷售量。

寫入商品銷售量:
? 商品編號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在實際使用過程中更多的用作緩存,然而緩存的數(shù)據(jù)一般都是需要設置生存時間的,即:到期后數(shù)據(jù)銷毀。

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的值,已經(jīng)刪除
(nil)

5.2 其它命令(自學)

5.2.1 keys
返回滿足給定pattern 的所有key
redis 127.0.0.1:6379> keys mylist*

  1. "mylist"
  2. "mylist5"
  3. "mylist6"
  4. "mylist7"
  5. "mylist8"

5.2.2 exists
確認一個key 是否存在
示例:從結果來看,數(shù)據(jù)庫中不存在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 *

  1. "age"
    redis 127.0.0.1:6379[1]> rename age age_new
    OK
    redis 127.0.0.1:6379[1]> keys *
  2. "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會自動將內存中的數(shù)據(jù)進行快照并持久化到硬盤。

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快照文件,將數(shù)據(jù)從硬盤載入到內存。根據(jù)數(shù)據(jù)量大小與結構和服務器性能不同,這個時間也不同。通常將記錄一千萬個字符串類型鍵、大小為1GB的快照文件載入到內存中需要花費20~30秒鐘。

6.1.4 問題總結
通過RDB方式實現(xiàn)持久化,一旦Redis異常退出,就會丟失最后一次快照以后更改的所有數(shù)據(jù)。這就需要開發(fā)者根據(jù)具體的應用場合,通過組合設置自動快照條件的方式來將可能發(fā)生的數(shù)據(jù)損失控制在能夠接受的范圍。
如果數(shù)據(jù)很重要以至于無法承受任何損失,則可以考慮使用AOF方式進行持久化。

6.2 AOF持久化
默認情況下Redis沒有開啟AOF(append only file)方式的持久化

? 可以通過修改redis.conf配置文件中的appendonly參數(shù)開啟
appendonly yes

開啟AOF持久化后每執(zhí)行一條會更改Redis中的數(shù)據(jù)的命令,Redis就會將該命令寫入硬
盤中的AOF文件。
? AOF文件的保存位置和RDB文件的位置相同,都是通過dir參數(shù)設置的。
dir ./

? 默認的文件名是appendonly.aof,可以通過appendfilename參數(shù)修改:
appendfilename appendonly.aof

7 Redis的主從復制
7.1 什么是主從復制

持久化保證了即使redis服務重啟也不會丟失數(shù)據(jù),因為redis服務重啟后會將硬盤上持久化的數(shù)據(jù)恢復到內存中,但是當redis服務器的硬盤損壞了可能會導致數(shù)據(jù)丟失,如果通過redis的主從復制機制就可以避免這種單點故障,如下圖:

說明:
? 主redis中的數(shù)據(jù)有兩個副本(replication)即從redis1和從redis2,即使一臺redis服務器宕機其它兩臺redis服務也可以繼續(xù)提供服務。
? 主redis中的數(shù)據(jù)和從redis上的數(shù)據(jù)保持實時同步,當主redis寫入數(shù)據(jù)時通過主從復制機制會復制到兩個從redis服務上。
? 只有一個主redis,可以有多個從redis。
? 主從復制不會阻塞master,在同步數(shù)據(jù)時,master 可以繼續(xù)處理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架構圖

架構細節(jié):
(1)所有的redis節(jié)點彼此互聯(lián)(PING-PONG機制),內部使用二進制協(xié)議優(yōu)化傳輸速度和帶寬.
(2)節(jié)點的fail是通過集群中超過半數(shù)的節(jié)點檢測失效時才生效.
(3)客戶端與redis節(jié)點直連,不需要中間proxy層.客戶端不需要連接集群所有節(jié)點,連接集群中任何一個可用節(jié)點即可
(4)redis-cluster把所有的物理節(jié)點映射到[0-16383]slot上,cluster 負責維護node<->slot<->value
Redis 集群中內置了 16384 個哈希槽,當需要在 Redis 集群中放置一個 key-value 時,redis 先對 key 使用 crc16 算法算出一個結果,然后把結果對 16384 求余數(shù),這樣每個 key 都會對應一個編號在 0-16383 之間的哈希槽,redis 會根據(jù)節(jié)點數(shù)量大致均等的將哈希槽映射到不同的節(jié)點

示例如下:

8.2 redis-cluster投票:容錯

(1)集群中所有master參與投票,如果半數(shù)以上master節(jié)點與其中一個master節(jié)點通信超過(cluster-node-timeout),認為該master節(jié)點掛掉.
(2):什么時候整個集群不可用(cluster_state:fail)?
? 如果集群任意master掛掉,且當前master沒有slave,則集群進入fail狀態(tài)。也可以理解成集群的[0-16383]slot映射不完全時進入fail狀態(tài)。
? 如果集群超過半數(shù)以上master掛掉,無論是否有slave,集群進入fail狀態(tài)。

8.3 搭建Ruby環(huán)境
redis集群管理工具redis-trib.rb依賴ruby環(huán)境,首先需要安裝ruby環(huán)境。

? 安裝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 集群的搭建過程
第一步:創(chuàng)建6個redis實例,需要端口號7001~7006

第二步:修改redis.conf配置文件,打開Cluster-enable yes

第三步:啟動所有的實例

第四步:創(chuàng)建集群
[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 查看集群的命令
? 查看集群狀態(tài)
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

? 查看集群中的節(jié)點:

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 維護節(jié)點(自學)
8.7.1 添加主節(jié)點
集群創(chuàng)建成功后可以向集群中添加節(jié)點,下面是添加一個master主節(jié)點
? 添加7007結點作為新節(jié)點
執(zhí)行命令:./redis-trib.rb add-node 127.0.0.1:7007 127.0.0.1:7001

? 查看集群結點發(fā)現(xiàn)7007已添加到集群中

8.7.2 hash槽重新分配
添加完主節(jié)點需要對主節(jié)點進行hash槽分配,這樣該主節(jié)才可以存儲數(shù)據(jù)。

? 查看集群中槽占用情況

redis集群有16384個槽,集群中的每個結點分配自已槽,通過查看集群結點可以看到槽占用情況。

? 給剛添加的7007結點分配槽
第一步:連接上集群(連接集群中任意一個可用結點都行)
[root@redis01 redis0707]# ./redis-trib.rb reshard 192.168.101.3:7001

第二步:輸入要分配的槽數(shù)量

輸入:500,表示要分配500個槽

第三步:輸入接收槽的結點id

輸入:15b809eadae88955e36bcdbb8144f61bbbaf38fb
PS:這里準備給7007分配槽,通過cluster nodes查看7007結點id為:
15b809eadae88955e36bcdbb8144f61bbbaf38fb

第四步:輸入源結點id

輸入:all

第五步:輸入yes開始移動槽到目標結點id

輸入:yes

8.7.3 添加從節(jié)點

集群創(chuàng)建成功后可以向集群中添加節(jié)點,下面是添加一個slave從節(jié)點。
? 添加7008從結點,將7008作為7007的從結點

命令:./redis-trib.rb add-node --slave --master-id 主節(jié)點id 新節(jié)點的ip和端口 舊節(jié)點ip和端口

執(zhí)行如下命令:
./redis-trib.rb add-node --slave --master-id cad9f7413ec6842c971dbcc2c48b4ca959eb5db4 192.168.101.3:7008 192.168.101.3:7001

cad9f7413ec6842c971dbcc2c48b4ca959eb5db4 是7007結點的id,可通過cluster nodes查看。

注意:如果原來該結點在集群中的配置信息已經(jīng)生成到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,刪除后再執(zhí)行./redis-trib.rb add-node指令

? 查看集群中的結點,剛添加的7008為7007的從節(jié)點:

8.7.4 刪除結點
命令:./redis-trib.rb del-node 127.0.0.1:7005 4b45eb75c8b428fbd77ab979b85080146a9bc017

刪除已經(jīng)占有hash槽的結點會失敗,報錯如下:
[ERR] Node 127.0.0.1:7005 is not empty! Reshard data away and try again.

需要將該結點占用的hash槽分配出去(參考hash槽重新分配章節(jié))。
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:應用防火墻規(guī)則: [確定]
[root@localhost-0723 bin]#

9.2 代碼實現(xiàn)
創(chuàng)建JedisCluster類連接redis集群。

@Test
public void testJedisCluster() throws Exception {
//創(chuàng)建一連接,JedisCluster對象,在系統(tǒng)中是單例存在
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);
//執(zhí)行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);
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容