天天看點

Redis使用總結NoSQL介紹Redis簡介Redis安裝Redis用戶端連接配接方式Redis的基本資料類型Java操作RedisRedis主從複制Redis哨兵機制Redis事物Redis持久化Redis釋出訂閱

 Java緩存機制

Java中要用到緩存的地方很多,首當其沖的就是持久層緩存,針對持久層談一下: 

要實作java緩存有很多種方式,最簡單的無非就是static HashMap,這個顯然是基于記憶體緩存,一個map就可以搞定引用對象的緩存,最簡單也最不實用,首要的問題就是儲存對象的有效性以及周期無法控制,這樣很容易就導緻記憶體急劇上升,周期無法控制可以采用SoftReference,WeakReference,PhantomReference這三種對象來執行(看了Ibatis的緩存機制才發現JDK居然還提供了PhantomReference這玩意兒,得惡補基礎啊),這三種都是弱引用,差別在于強度不同,至于弱引用概念個人了解就是對象的生命周期與JVM挂鈎,JVM記憶體不夠了就回收,這樣能很好的控制OutOfMemoryError 異常。 

常用的有Oscache,Ehcache,Jcache,Jbosscache等等很多

OsCache與EhCache差別

Oscache:頁面級緩存(網上強調最多的東西),占用本機的記憶體資源。可 以選擇緩存到硬碟,如存取到硬碟重新開機服務也可重新獲得上次持久化的資源,而如果緩存到記憶體就不行。一般沒必要緩存到硬碟,因為I/O操作也是比較耗資源,和從資料庫取往往優勢很小。Oscache存取資料的作用域分為application和session兩種。

EhCache:Hibernate緩存,DAO緩存,安全性憑證緩存(Acegi),Web緩存,應用持久化和分布式緩存。

NoSQL介紹

NoSQL 是 Not Only SQL 的縮寫,意即"不僅僅是SQL"的意思,泛指非關系型的資料庫。強調Key-Value Stores和文檔資料庫的優點,而不是單純的反對RDBMS。

NoSQL産品是傳統關系型資料庫的功能閹割版本,通過減少用不到或很少用的功能,來大幅度提高産品性能

NoSQL産品 Redis、mongodb Membase、HBase 

Redis 與Memcache差別

Redis支援資料的持久化,可以将資料存放在硬碟上。

Memcache不支援資料的之久存儲。

Redis資料類型豐富,支援set liset等類型

Memcache支援簡單資料類型,需要用戶端自己處理複制對象

Redis簡介

Redis

Redis 是完全開源免費的,遵守BSD協定,是一個高性能的key-value資料庫。

Redis 與其他 key - value 緩存産品有以下三個特點:

Redis支援資料的持久化,可以将記憶體中的資料儲存在磁盤中,重新開機的時候可以再次加載進行使用。

Redis不僅僅支援簡單的key-value類型的資料,同時還提供list,set,zset,hash等資料結構的存儲。

Redis支援資料的備份,即master-slave模式的資料備份。

Redis應用場景

   主要能夠展現 解決資料庫的通路壓力。

   例如:短信驗證碼時間有效期、session共享解決方案

Redis優勢

性能極高 – Redis能讀的速度是110000次/s,寫的速度是81000次/s 。

豐富的資料類型 – Redis支援二進制案例的 Strings,Lists, Hashes, Sets 及 Ordered Sets 資料類型操作。

原子 – Redis的所有操作都是原子性的,同時Redis還支援對幾個操作全并後的原子性執行。

豐富的特性 – Redis還支援 publish/subscribe, 通知, key 過期等等特性。

Redis與其他key-value存儲有什麼不同?

Redis有着更為複雜的資料結構并且提供對他們的原子性操作,這是一個不同于其他資料庫的進化路徑。Redis的資料類型都是基于基本資料結構的同時對程式員透明,無需進行額外的抽象。

Redis運作在記憶體中但是可以持久化到磁盤,是以在對不同資料集進行高速讀寫時需要權衡記憶體,因為資料量不能大于硬體記憶體。在記憶體資料庫方面的另一個優點是,相比在磁盤上相同的複雜的資料結構,在記憶體中操作起來非常簡單,這樣Redis可以做很多内部複雜性很強的事情。同時,在磁盤格式方面他們是緊湊的以追加的方式産生的,因為他們并不需要進行随機通路。

Redis安裝

 windows 安裝redis

  建立start.bat 批處理檔案、内容: redis-server.exe redis.windows.conf

  輕按兩下start.bat啟動

  修改密碼 # requirepass foobared  修改為requirepass 123456

  注意:修改密碼的時候前面不要加空格

 linux 安裝redis

Redis的官方下載下傳網址是:http://redis.io/download  (這裡下載下傳的是Linux版的Redis源碼包)

Redis伺服器端的預設端口是6379。

這裡以虛拟機中的Linux系統如何安裝Redis進行講解。

 在windows系統中下載下傳好Redis的源碼包。

1. 通過WinSCP工具,将Redis的源碼包由windows上傳到Linux系統的這個目錄/opt/redis (即根目錄下的lamp檔案夾)。

2. 解壓縮。       

tar -zxf redis-2.6.17.tar.gz

3. 切換到解壓後的目錄。

cd redis-2.6.17            ( 一般來說,解壓目錄裡的INSTALL檔案或README檔案裡寫有安裝說明,可參考之)

4. 編譯。

make        

(注意,編譯需要C語言編譯器gcc的支援,如果沒有,需要先安裝gcc。可以使用rpm -q gcc檢視gcc是否安裝)

(利用yum線上安裝gcc的指令    yum -y install gcc )

(如果編譯出錯,請使用make clean清除臨時檔案。之後,找到出錯的原因,解決問題後再來重新安裝。 )

5. 進入到src目錄。      

cd src

6. 執行安裝。

make install    

到此就安裝完成。但是,由于安裝redis的時候,我們沒有選擇安裝路徑,故是預設位置安裝。在此,我們可以将可執行檔案和配置檔案移動到習慣的目錄。

cd /usr/local

mkdir -p /usr/local/redis/bin    

mkdir -p /usr/local/redis/etc

cd /lamp/redis-2.6.17

cp ./redis.conf /usr/local/redis/etc

cd src

cp mkreleasehdr.sh redis-benchmark redis-check-aof redis-check-dump redis-cli redis-server redis-sentinel /usr/local/redis/bin

7.開放linux 6379 端口

1.編輯 /etc/sysconfig/iptables 檔案:vi /etc/sysconfig/iptables

加入内容并儲存:-A RH-Firewall-1-INPUT -m state –state NEW -m tcp -p tcp–dport 6379 -j ACCEPT

2.重新開機服務:/etc/init.d/iptables restart

3.檢視端口是否開放:/sbin/iptables -L -n

比較重要的3個可執行檔案:

redis-server:Redis伺服器程式

redis-cli:Redis用戶端程式,它是一個指令行操作工具。也可以使用telnet根據其純文字協定操作。

redis-benchmark:Redis性能測試工具,測試Redis在你的系統及配置下的讀寫性能。

Redis的啟動指令:

/usr/local/redis/bin/redis-server

cd /usr/local/redis/bin

./redis-server /usr/local/redis/etc/redis.conf   為redis-server指定配置文

修改 redis.conf檔案

daemonizeyes --- 修改為yes  背景啟動

requirepass 123456  ----注釋取消掉設定賬号密碼

ps aux |grep '6379'  --- 查詢端口

kill -159886 --- 殺死重置

kill -99886 --- 強制殺死

serviceiptables stop 停止防火牆

redis指令連接配接方式

./redis-cli-h 127.0.0.1 -p 6379 -a "123456" --- redis 使用賬号密碼連接配接

PING 結果表示成功

停止redis

redis-clishutdown  或者 killredis程序的pid

關閉防火牆

Redis用戶端連接配接方式

 使用redisclient-win32.x86.1.5

Redis的基本資料類型

字元串類型(String)

redis 127.0.0.1:6379> SET mykey "redis"

OK

redis 127.0.0.1:6379> GET mykey

"redis"

在上面的例子中,

SET

GET

是redis中的指令,而

mykey

是鍵的名稱。

Redis字元串指令用于管理Redis中的字元串值。以下是使用Redis字元串指令的文法。

redis 127.0.0.1:6379> COMMAND KEY_NAME
           
Shell      

示例

redis 127.0.0.1:6379> SET mykey "redis" 
           
OK 
           
redis 127.0.0.1:6379> GET mykey 
           
"redis"
           
Shell      

在上面的例子中,

SET

GET

是redis中的指令,而

mykey

是鍵的名稱。

Redis字元串指令

下表列出了一些用于在Redis中管理字元串的基本指令。

編号 指令 描述說明
1 SET key value 此指令設定指定鍵的值。
2 GET key 擷取指定鍵的值。
3 GETRANGE key start end 擷取存儲在鍵上的字元串的子字元串。
4 GETSET key value 設定鍵的字元串值并傳回其舊值。
5 GETBIT key offset 傳回在鍵處存儲的字元串值中偏移處的位值。
6 MGET key1 [key2..] 擷取所有給定鍵的值
7 SETBIT key offset value 存儲在鍵上的字元串值中設定或清除偏移處的位
8 SETEX key seconds value 使用鍵和到期時間來設定值
9 SETNX key value 設定鍵的值,僅當鍵不存在時
10 SETRANGE key offset value 在指定偏移處開始的鍵處覆寫字元串的一部分
11 STRLEN key 擷取存儲在鍵中的值的長度
12 MSET key value [key value …] 為多個鍵分别設定它們的值
13 MSETNX key value [key value …] 為多個鍵分别設定它們的值,僅當鍵不存在時
14 PSETEX key milliseconds value 設定鍵的值和到期時間(以毫秒為機關)
15 INCR key 将鍵的整數值增加

1

16 INCRBY key increment 将鍵的整數值按給定的數值增加
17 INCRBYFLOAT key increment 将鍵的浮點值按給定的數值增加
18 DECR key 将鍵的整數值減

1

19 DECRBY key decrement 按給定數值減少鍵的整數值
20 APPEND key value 将指定值附加到鍵

清單類型(List)

Redis清單是簡單的字元串清單,按照插入順序排序。你可以添加一個元素到清單的頭部(左邊)或者尾部(右邊)

一個清單最多可以包含 232 - 1 個元素 (4294967295, 每個清單超過40億個元素)。

redis 127.0.0.1:6379> LPUSH runoobkey redis      
(integer) 1      
redis 127.0.0.1:6379> LPUSH runoobkey mongodb      
(integer) 2      
redis 127.0.0.1:6379> LPUSH runoobkey mysql      
(integer) 3      
redis 127.0.0.1:6379> LRANGE runoobkey 0 10      
1) "mysql"      
2) "mongodb"      
3) "redis"      

Redis 清單指令

下表列出了清單相關的基本指令:

序号 指令及描述
1

BLPOP key1 [key2 ] timeout 

移出并擷取清單的第一個元素,如果清單沒有元素會阻塞清單直到等待逾時或發現可彈出元素為止。

2

BRPOP key1 [key2 ] timeout 

移出并擷取清單的最後一個元素,如果清單沒有元素會阻塞清單直到等待逾時或發現可彈出元素為止。

3

BRPOPLPUSH source destination timeout 

從清單中彈出一個值,将彈出的元素插入到另外一個清單中并傳回它;如果清單沒有元素會阻塞清單直到等待逾時或發現可彈出元素為止。

4

LINDEX key index 

通過索引擷取清單中的元素

5

LINSERT key BEFORE|AFTER pivot value 

在清單的元素前或者後插入元素

6

LLEN key 

擷取清單長度

7

LPOP key 

移出并擷取清單的第一個元素

8

LPUSH key value1 [value2] 

将一個或多個值插入到清單頭部

9

LPUSHX key value 

将一個值插入到已存在的清單頭部

10

LRANGE key start stop 

擷取清單指定範圍内的元素

11

LREM key count value 

移除清單元素

12

LSET key index value 

通過索引設定清單元素的值

13

LTRIM key start stop 

對一個清單進行修剪(trim),就是說,讓清單隻保留指定區間内的元素,不在指定區間之内的元素都将被删除。

14

RPOP key 

移除并擷取清單最後一個元素

15

RPOPLPUSH source destination 

移除清單的最後一個元素,并将該元素添加到另一個清單并傳回

16

RPUSH key value1 [value2] 

在清單中添加一個或多個值

17

RPUSHX key value 

為已存在的清單添加值

Redis 集合(Set)

Redis的Set是string類型的無序集合。集合成員是唯一的,這就意味着集合中不能出現重複的資料。

Redis 中集合是通過哈希表實作的,是以添加,删除,查找的複雜度都是O(1)。

集合中最大的成員數為 232 - 1 (4294967295, 每個集合可存儲40多億個成員)。

執行個體

redis 127.0.0.1:6379> SADD runoobkey redis      
(integer) 1      
redis 127.0.0.1:6379> SADD runoobkey mongodb      
(integer) 1      
redis 127.0.0.1:6379> SADD runoobkey mysql      
(integer) 1      
redis 127.0.0.1:6379> SADD runoobkey mysql      
(integer) 0      
redis 127.0.0.1:6379> SMEMBERS runoobkey      
1) "mysql"      
2) "mongodb"      
3) "redis"      

在以上執行個體中我們通過 SADD 指令向名為 runoobkey 的集合插入的三個元素。

Redis 集合指令

下表列出了 Redis 集合基本指令:

序号 指令及描述
1

SADD key member1 [member2] 

向集合添加一個或多個成員

2

SCARD key 

擷取集合的成員數

3

SDIFF key1 [key2] 

傳回給定所有集合的差集

4

SDIFFSTORE destination key1 [key2] 

傳回給定所有集合的差集并存儲在 destination 中

5

SINTER key1 [key2] 

傳回給定所有集合的交集

6

SINTERSTORE destination key1 [key2] 

傳回給定所有集合的交集并存儲在 destination 中

7

SISMEMBER key member 

判斷 member 元素是否是集合 key 的成員

8

SMEMBERS key 

傳回集合中的所有成員

9

SMOVE source destination member 

将 member 元素從 source 集合移動到 destination 集合

10

SPOP key 

移除并傳回集合中的一個随機元素

11

SRANDMEMBER key [count] 

傳回集合中一個或多個随機數

12

SREM key member1 [member2] 

移除集合中一個或多個成員

13

SUNION key1 [key2] 

傳回所有給定集合的并集

14

SUNIONSTORE destination key1 [key2] 

所有給定集合的并集存儲在 destination 集合中

15

SSCAN key cursor [MATCH pattern] [COUNT count] 

疊代集合中的元素

Redis 有序集合(sorted set)

Redis 有序集合和集合一樣也是string類型元素的集合,且不允許重複的成員。

不同的是每個元素都會關聯一個double類型的分數。redis正是通過分數來為集合中的成員進行從小到大的排序。

有序集合的成員是唯一的,但分數(score)卻可以重複。

集合是通過哈希表實作的,是以添加,删除,查找的複雜度都是O(1)。集合中最大的成員數為 232 - 1 (4294967295, 每個集合可存儲40多億個成員)。

執行個體

redis 127.0.0.1:6379> ZADD runoobkey 1 redis      
(integer) 1      
redis 127.0.0.1:6379> ZADD runoobkey 2 mongodb      
(integer) 1      
redis 127.0.0.1:6379> ZADD runoobkey 3 mysql      
(integer) 1      
redis 127.0.0.1:6379> ZADD runoobkey 3 mysql      
(integer) 0      
redis 127.0.0.1:6379> ZADD runoobkey 4 mysql      
(integer) 0      
redis 127.0.0.1:6379> ZRANGE runoobkey 0 10 WITHSCORES      
1) "redis"      
2) "1"      
3) "mongodb"      
4) "2"      
5) "mysql"      
6) "4"      

在以上執行個體中我們通過指令 ZADD 向 redis 的有序集合中添加了三個值并關聯上分數。

Redis 有序集合指令

下表列出了 redis 有序集合的基本指令:

序号 指令及描述
1

ZADD key score1 member1 [score2 member2] 

向有序集合添加一個或多個成員,或者更新已存在成員的分數

2

ZCARD key 

擷取有序集合的成員數

3

ZCOUNT key min max 

計算在有序集合中指定區間分數的成員數

4

ZINCRBY key increment member 

有序集合中對指定成員的分數加上增量 increment

5

ZINTERSTORE destination numkeys key [key ...] 

計算給定的一個或多個有序集的交集并将結果集存儲在新的有序集合 key 中

6

ZLEXCOUNT key min max 

在有序集合中計算指定字典區間内成員數量

7

ZRANGE key start stop [WITHSCORES] 

通過索引區間傳回有序集合成指定區間内的成員

8

ZRANGEBYLEX key min max [LIMIT offset count] 

通過字典區間傳回有序集合的成員

9

ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT] 

通過分數傳回有序集合指定區間内的成員

10

ZRANK key member 

傳回有序集合中指定成員的索引

11

ZREM key member [member ...] 

移除有序集合中的一個或多個成員

12

ZREMRANGEBYLEX key min max 

移除有序集合中給定的字典區間的所有成員

13

ZREMRANGEBYRANK key start stop 

移除有序集合中給定的排名區間的所有成員

14

ZREMRANGEBYSCORE key min max 

移除有序集合中給定的分數區間的所有成員

15

ZREVRANGE key start stop [WITHSCORES] 

傳回有序集中指定區間内的成員,通過索引,分數從高到底

16

ZREVRANGEBYSCORE key max min [WITHSCORES] 

傳回有序集中指定分數區間内的成員,分數從高到低排序

17

ZREVRANK key member 

傳回有序集合中指定成員的排名,有序內建員按分數值遞減(從大到小)排序

18

ZSCORE key member 

傳回有序集中,成員的分數值

19

ZUNIONSTORE destination numkeys key [key ...] 

計算給定的一個或多個有序集的并集,并存儲在新的 key 中

20

ZSCAN key cursor [MATCH pattern] [COUNT count] 

疊代有序集合中的元素(包括元素成員和元素分值)

Redis 哈希(Hash)

Redis hash 是一個string類型的field和value的映射表,hash特别适合用于存儲對象。

Redis 中每個 hash 可以存儲 232 - 1 鍵值對(40多億)。

執行個體

127.0.0.1:6379>  HGETALL runoobkey      
1) "name"      
2) "redis tutorial"      
3) "description"      
4) "redis basic commands for caching"      
5) "likes"      
6) "20"      
7) "visitors"      
8) "23000"      

hset  key mapHey MapValue

在以上執行個體中,我們設定了 redis 的一些描述資訊(name, description, likes,visitors) 到哈希表的 runoobkey 中。

Redis hash 指令

下表列出了 redis hash 基本的相關指令:

序号 指令及描述
1

HDEL key field2 [field2] 

删除一個或多個哈希表字段

2

HEXISTS key field 

檢視哈希表 key 中,指定的字段是否存在。

3

HGET key field 

擷取存儲在哈希表中指定字段的值。

4

HGETALL key 

擷取在哈希表中指定 key 的所有字段和值

5

HINCRBY key field increment 

為哈希表 key 中的指定字段的整數值加上增量 increment 。

6

HINCRBYFLOAT key field increment 

為哈希表 key 中的指定字段的浮點數值加上增量 increment 。

7

HKEYS key 

擷取所有哈希表中的字段

8

HLEN key 

擷取哈希表中字段的數量

9

HMGET key field1 [field2] 

擷取所有給定字段的值

10

HMSET key field1 value1 [field2 value2 ] 

同時将多個 field-value (域-值)對設定到哈希表 key 中。

11

HSET key field value 

将哈希表 key 中的字段 field 的值設為 value 。

12

HSETNX key field value 

隻有在字段 field 不存在時,設定哈希表字段的值。

13

HVALS key 

擷取哈希表中所有值

14

HSCAN key cursor [MATCH pattern] [COUNT count] 

疊代哈希表中的鍵值對。

Java操作Redis

Redis Jedis

  <!-- https://mvnrepository.com/artifact/redis.clients/jedis -->

<dependency>

    <groupId>redis.clients</groupId>

    <artifactId>jedis</artifactId>

    <version>2.9.0</version>

</dependency>

publicclass TestRedis {

    private Jedis jedis;

    @Before

    publicvoid setup() {

        //連接配接redis伺服器,192.168.0.100:6379

        jedis = new Jedis("192.168.0.100", 6379);

        //權限認證

        jedis.auth("admin"); 

    }

    @Test

    publicvoid testString() {

        //-----添加資料---------- 

        jedis.set("name","xinxin");//向key-->name中放入了value-->xinxin 

        System.out.println(jedis.get("name"));//執行結果:xinxin 

        jedis.append("name", " is my lover"); //拼接

        System.out.println(jedis.get("name"));

        jedis.del("name");  //删除某個鍵

        System.out.println(jedis.get("name"));

        //設定多個鍵值對

        jedis.mset("name","liuling","age","23","qq","476777XXX");

        jedis.incr("age"); //進行加1操作

        System.out.println(jedis.get("name") + "-" + jedis.get("age") + "-" + jedis.get("qq"));

    }

    @Test

    publicvoid testMap() {

        //-----添加資料---------- 

        Map<String, String> map = new HashMap<String, String>();

        map.put("name", "xinxin");

        map.put("age", "22");

        map.put("qq", "123456");

        jedis.hmset("user",map);

        //取出user中的name,執行結果:[minxr]-->注意結果是一個泛型的List 

        //第一個參數是存入redis中map對象的key,後面跟的是放入map中的對象的key,後面的key可以跟多個,是可變參數 

        List<String> rsmap = jedis.hmget("user", "name", "age", "qq");

        System.out.println(rsmap); 

        //删除map中的某個鍵值 

        jedis.hdel("user","age");

        System.out.println(jedis.hmget("user", "age")); //因為删除了,是以傳回的是null 

        System.out.println(jedis.hlen("user")); //傳回key為user的鍵中存放的值的個數2

        System.out.println(jedis.exists("user"));//是否存在key為user的記錄傳回true 

        System.out.println(jedis.hkeys("user"));//傳回map對象中的所有key 

        System.out.println(jedis.hvals("user"));//傳回map對象中的所有value

        Iterator<String> iter=jedis.hkeys("user").iterator(); 

        while (iter.hasNext()){ 

            String key = iter.next(); 

            System.out.println(key+":"+jedis.hmget("user",key)); 

        } 

    }

    @Test 

    publicvoid testList(){ 

        //開始前,先移除所有的内容 

        jedis.del("java framework"); 

        System.out.println(jedis.lrange("java framework",0,-1)); 

        //先向key java framework中存放三條資料 

        jedis.lpush("java framework","spring"); 

        jedis.lpush("java framework","struts"); 

        jedis.lpush("java framework","hibernate"); 

        //再取出所有資料jedis.lrange是按範圍取出, 

        // 第一個是key,第二個是起始位置,第三個是結束位置,jedis.llen擷取長度 -1表示取得所有 

        System.out.println(jedis.lrange("java framework",0,-1)); 

        jedis.del("java framework");

        jedis.rpush("java framework","spring"); 

        jedis.rpush("java framework","struts"); 

        jedis.rpush("java framework","hibernate");

        System.out.println(jedis.lrange("java framework",0,-1));

    } 

    @Test 

    publicvoid testSet(){ 

        //添加 

        jedis.sadd("user","liuling"); 

        jedis.sadd("user","xinxin"); 

        jedis.sadd("user","ling"); 

        jedis.sadd("user","zhangxinxin");

        jedis.sadd("user","who"); 

        //移除noname 

        jedis.srem("user","who"); 

        System.out.println(jedis.smembers("user"));//擷取所有加入的value 

        System.out.println(jedis.sismember("user", "who"));//判斷 who 是否是user集合的元素 

        System.out.println(jedis.srandmember("user")); 

        System.out.println(jedis.scard("user"));//傳回集合的元素個數 

    } 

    @Test 

    publicvoid test() throws InterruptedException { 

        //jedis 排序 

        //注意,此處的rpush和lpush是List的操作。是一個雙向連結清單(但從表現來看的) 

        jedis.del("a");//先清除資料,再加入資料進行測試 

        jedis.rpush("a", "1"); 

        jedis.lpush("a","6"); 

        jedis.lpush("a","3"); 

        jedis.lpush("a","9"); 

        System.out.println(jedis.lrange("a",0,-1));// [9, 3, 6, 1] 

        System.out.println(jedis.sort("a")); //[1, 3, 6, 9]  //輸入排序後結果 

        System.out.println(jedis.lrange("a",0,-1)); 

    } 

    @Test

    publicvoid testRedisPool() {

        RedisUtil.getJedis().set("newname", "中文測試");

        System.out.println(RedisUtil.getJedis().get("newname"));

    }

SpringBoot內建Redis

Maven依賴

<parent>

     <groupId>org.springframework.boot</groupId>

     <artifactId>spring-boot-starter-parent</artifactId>

     <version>1.5.3.RELEASE</version>

   </parent>

   <dependencies>

     <dependency>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-data-redis</artifactId>

     </dependency>

     <dependency>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-data-redis</artifactId>

     </dependency>

     <dependency>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-web</artifactId>

     </dependency>

   </dependencies>

新增配置檔案資訊

########################################################

###Redis (RedisConfiguration)

########################################################

spring.redis.database=0

spring.redis.host=127.0.0.1

spring.redis.port=6379

spring.redis.password=123456

spring.redis.pool.max-idle=8

spring.redis.pool.min-idle=0

spring.redis.pool.max-active=8

spring.redis.pool.max-wait=-1

spring.redis.timeout=5000

Java代碼

@Service

publicclass RedisService {

   @Autowired

   private StringRedisTemplate stringRedisTemplate;

   publicvoid setObject(String key, Object value) {

     this.setObject(key, value, null);

   }

   publicvoid setObject(String key, Object value, Long time) {

     if (StringUtils.isEmpty(key) || value == null) {

        return;

     }

     if (valueinstanceof String) {

        // 存放string類型

        String stringValue = (String) value;

        if (time == null) {

           stringRedisTemplate.opsForValue().set(key, stringValue);

        } else {

           stringRedisTemplate.opsForValue().set(key, stringValue, time, TimeUnit.SECONDS);

        }

        return;

     }

     if (valueinstanceof List) {

        // 存放list類型

        List<String> listValue = (List<String>) value;

        for (String string : listValue) {

           stringRedisTemplate.opsForList().leftPush(key, string);

        }

     }

   }

   publicvoid delKey(String key) {

     stringRedisTemplate.delete(key);

   }

   public String getString(String key) {

     returnstringRedisTemplate.opsForValue().get(key);

   }

}

Redis主從複制

  克隆三台linux虛拟機

主從複制配置

redis主從複制

概述

1、redis的複制功能是支援多個資料庫之間的資料同步。一類是主資料庫(master)一類是從資料庫(slave),主資料庫可以進行讀寫操作,當發生寫操作的時候自動将資料同步到從資料庫,而從資料庫一般是隻讀的,并接收主資料庫同步過來的資料,一個主資料庫可以有多個從資料庫,而一個從資料庫隻能有一個主資料庫。

2、通過redis的複制功能可以很好的實作資料庫的讀寫分離,提高伺服器的負載能力。主資料庫主要進行寫操作,而從資料庫負責讀操作。

主從複制過程:見下圖

過程:

1:當一個從資料庫啟動時,會向主資料庫發送sync指令,

2:主資料庫接收到sync指令後會開始在背景儲存快照(執行rdb操作),并将儲存期間接收到的指令緩存起來

3:當快照完成後,redis會将快照檔案和所有緩存的指令發送給從資料庫。

4:從資料庫收到後,會載入快照檔案并執行收到的緩存的指令。

修改redis.conf

修改slave從redis中的redis.conf檔案

slaveof 192.168.33.130 6379  

masterauth 123456--- 主redis伺服器配置了密碼,則需要配置

Redis哨兵機制

什麼是哨兵機制

Redis的哨兵(sentinel) 系統用于管理多個 Redis 伺服器,該系統執行以下三個任務:

·        監控(Monitoring): 哨兵(sentinel) 會不斷地檢查你的Master和Slave是否運作正常。

·        提醒(Notification):當被監控的某個 Redis出現問題時, 哨兵(sentinel) 可以通過 API 向管理者或者其他應用程式發送通知。

·        自動故障遷移(Automatic failover):當一個Master不能正常工作時,哨兵(sentinel) 會開始一次自動故障遷移操作,它會将失效Master的其中一個Slave更新為新的Master, 并讓失效Master的其他Slave改為複制新的Master; 當用戶端試圖連接配接失效的Master時,叢集也會向用戶端傳回新Master的位址,使得叢集可以使用Master代替失效Master。

哨兵(sentinel) 是一個分布式系統,你可以在一個架構中運作多個哨兵(sentinel) 程序,這些程序使用流言協定(gossipprotocols)來接收關于Master是否下線的資訊,并使用投票協定(agreement protocols)來決定是否執行自動故障遷移,以及選擇哪個Slave作為新的Master.

每個哨兵(sentinel) 會向其它哨兵(sentinel)、master、slave定時發送消息,以确認對方是否”活”着,如果發現對方在指定時間(可配置)内未回應,則暫時認為對方已挂(所謂的”主觀認為當機”Subjective Down,簡稱sdown).

若“哨兵群”中的多數sentinel,都報告某一master沒響應,系統才認為該master"徹底死亡"(即:客觀上的真正down機,Objective Down,簡稱odown),通過一定的vote算法,從剩下的slave節點中,選一台提升為master,然後自動修改相關配置.

雖然哨兵(sentinel) 釋出為一個單獨的可執行檔案 redis-sentinel ,但實際上它隻是一個運作在特殊模式下的 Redis 伺服器,你可以在啟動一個普通 Redis 伺服器時通過給定 --sentinel 選項來啟動哨兵(sentinel).

哨兵(sentinel) 的一些設計思路和zookeeper非常類似

單個哨兵(sentinel)

哨兵模式修改配置

實作步驟:

1.拷貝到etc目錄

cp sentinel.conf  /usr/local/redis/etc

2.修改sentinel.conf配置檔案

sentinel monitor mymast  192.168.110.133 6379 1  #主節點 名稱 IP 端口号 選舉次數

sentinel auth-pass mymaster 123456 

3. 修改心跳檢測 5000毫秒

sentinel down-after-milliseconds mymaster 5000

4.sentinel parallel-syncs mymaster 2 --- 做多多少合格節點

5. 啟動哨兵模式

./redis-server/usr/local/redis/etc/sentinel.conf --sentinel &

6. 停止哨兵模式

Redis事物

Redis事物

Redis 事務可以一次執行多個指令,并且帶有以下兩個重要的保證:

事務是一個單獨的隔離操作:事務中的所有指令都會序列化、按順序地執行。事務在執行的過程中,不會被其他用戶端發送來的指令請求所打斷。

事務是一個原子操作:事務中的指令要麼全部被執行,要麼全部都不執行。

一個事務從開始到執行會經曆以下三個階段:

開始事務。

指令入隊。

執行事務。

執行個體

以下是一個事務的例子,它先以 MULTI 開始一個事務,然後将多個指令入隊到事務中,最後由 EXEC 指令觸發事務,一并執行事務中的所有指令:

redis 127.0.0.1:6379> MULTI      
OK      
redis 127.0.0.1:6379> SET book-name "Mastering C++ in 21 days"      
QUEUED      
redis 127.0.0.1:6379> GET book-name      
QUEUED      
redis 127.0.0.1:6379> SADD tag "C++" "Programming" "Mastering Series"      
QUEUED      
redis 127.0.0.1:6379> SMEMBERS tag      
QUEUED      
redis 127.0.0.1:6379> EXEC      
1) OK      
2) "Mastering C++ in 21 days"      
3) (integer) 3      
4) 1) "Mastering Series"      
   2) "C++"      
   3) "Programming"      

Redis 事務指令

下表列出了redis 事務的相關指令:

序号 指令及描述
1

DISCARD 

取消事務,放棄執行事務塊内的所有指令。

2

EXEC 

執行所有事務塊内的指令。

3

MULTI 

标記一個事務塊的開始。

4

UNWATCH 

取消 WATCH 指令對所有 key 的監視。

5

WATCH key [key ...] 

監視一個(或多個) key ,如果在事務執行之前這個(或這些) key 被其他指令所改動,那麼事務将被打斷。

Redis持久化

什麼是Redis持久化

什麼是Redis持久化,就是将記憶體資料儲存到硬碟。

Redis 持久化存儲 (AOF 與 RDB 兩種模式)

RDB持久化

RDB 是以二進制檔案,是在某個時間 點将資料寫入一個臨時檔案,持久化結束後,用這個臨時檔案替換上次持久化的檔案,達到資料恢複。

優點:使用單獨子程序來進行持久化,主程序不會進行任何 IO 操作,保證了 redis 的高性能

缺點:RDB 是間隔一段時間進行持久化,如果持久化之間redis 發生故障,會發生資料丢失。是以這種方式更适合資料要求不嚴謹的時候

這裡說的這個執行資料寫入到臨時檔案的時間點是可以通過配置來自己确定的,通過配置redis 在 n 秒内如果超過 m 個 key 被修改這執行一次 RDB 操作。這個操作就類似于在這個時間點來儲存一次 Redis 的所有資料,一次快照資料。所有這個持久化方法也通常叫做 snapshots。

RDB 預設開啟,redis.conf 中的具體配置參數如下;

#dbfilename:持久化資料存儲在本地的檔案

dbfilename dump.rdb

#dir:持久化資料存儲在本地的路徑,如果是在/redis/redis-3.0.6/src下啟動的redis-cli,則資料會存儲在目前src目錄下

dir ./

##snapshot觸發的時機,save   

##如下為900秒後,至少有一個變更操作,才會snapshot 

##對于此值的設定,需要謹慎,評估系統的變更操作密集程度 

##可以通過“save “””來關閉snapshot功能 

#save時間,以下分别表示更改了1個key時間隔900s進行持久化存儲;更改了10個key300s進行存儲;更改10000個key60s進行存儲。

save 9001

save 30010

save 6010000

##當snapshot時出現錯誤無法繼續時,是否阻塞用戶端“變更操作”,“錯誤”可能因為磁盤已滿/磁盤故障/OS級别異常等 

stop-writes-on-bgsave-erroryes 

##是否啟用rdb檔案壓縮,預設為“yes”,壓縮往往意味着“額外的cpu消耗”,同時也意味這較小的檔案尺寸以及較短的網絡傳輸時間 

rdbcompression yes 

AOF持久化

Append-only file,将“操作 + 資料”以格式化指令的方式追加到記錄檔檔案的尾部,在 append 操作傳回後(已經寫入到檔案或者即将寫入),才進行實際的資料變更,“日志檔案”儲存了曆史所有的操作過程;當 server 需要資料恢複時,可以直接 replay 此日志檔案,即可還原所有的操作過程。AOF 相對可靠,它和 mysql 中bin.log、apache.log、zookeeper 中 txn-log 簡直異曲同工。AOF 檔案内容是字元串,非常容易閱讀和解析。

優點:可以保持更高的資料完整性,如果設定追加 file 的時間是 1s,如果 redis 發生故障,最多會丢失 1s 的資料;且如果日志寫入不完整支援 redis-check-aof 來進行日志修複;AOF 檔案沒被 rewrite 之前(檔案過大時會對指令進行合并重寫),可以删除其中的某些指令(比如誤操作的 flushall)。

缺點:AOF 檔案比 RDB 檔案大,且恢複速度慢。

我們可以簡單的認為 AOF 就是日志檔案,此檔案隻會記錄“變更操作”(例如:set/del 等),如果 server 中持續的大量變更操作,将會導緻 AOF 檔案非常的龐大,意味着 server 失效後,資料恢複的過程将會很長;事實上,一條資料經過多次變更,将會産生多條 AOF 記錄,其實隻要儲存目前的狀态,曆史的操作記錄是可以抛棄的;因為 AOF 持久化模式還伴生了“AOF rewrite”。

AOF 的特性決定了它相對比較安全,如果你期望資料更少的丢失,那麼可以采用 AOF 模式。如果 AOF 檔案正在被寫入時突然 server 失效,有可能導緻檔案的最後一次記錄是不完整,你可以通過手工或者程式的方式去檢測并修正不完整的記錄,以便通過 aof 檔案恢複能夠正常;同時需要提醒,如果你的 redis 持久化手段中有 aof,那麼在 server 故障失效後再次啟動前,需要檢測 aof 檔案的完整性。

AOF 預設關閉,開啟方法,修改配置檔案 reds.conf:appendonly yes

##此選項為aof功能的開關,預設為“no”,可以通過“yes”來開啟aof功能 

##隻有在“yes”下,aof重寫/檔案同步等特性才會生效 

appendonlyyes 

##指定aof檔案名稱 

appendfilename appendonly.aof 

##指定aof操作中檔案同步政策,有三個合法值:always everysec no,預設為everysec 

appendfsync everysec 

##在aof-rewrite期間,appendfsync是否暫緩檔案同步,"no"表示“不暫緩”,“yes”表示“暫緩”,預設為“no” 

no-appendfsync-on-rewrite no 

##aof檔案rewrite觸發的最小檔案尺寸(mb,gb),隻有大于此aof檔案大于此尺寸是才會觸發rewrite,預設“64mb”,建議“512mb” 

auto-aof-rewrite-min-size 64mb 

##相對于“上一次”rewrite,本次rewrite觸發時aof檔案應該增長的百分比。 

##每一次rewrite之後,redis都會記錄下此時“新aof”檔案的大小(例如A),那麼當aof檔案增長到A*(1 + p)之後 

##觸發下一次rewrite,每一次aof記錄的添加,都會檢測目前aof檔案的尺寸。 

auto-aof-rewrite-percentage 100 

AOF 是檔案操作,對于變更操作比較密集的 server,那麼必将造成磁盤 IO 的負荷加重;此外 linux 對檔案操作采取了“延遲寫入”手段,即并非每次 write操作都會觸發實際磁盤操作,而是進入了 buffer 中,當buffer 資料達到閥值時觸發實際寫入(也有其他時機),這是 linux 對檔案系統的優化,但是這卻有可能帶來隐患,如果 buffer 沒有重新整理到磁盤,此時實體機器失效(比如斷電),那麼有可能導緻最後一條或者多條 aof 記錄的丢失。通過上述配置檔案,可以得知 redis 提供了 3 中 aof 記錄同步選項:

always:每一條 aof 記錄都立即同步到檔案,這是最安全的方式,也以為更多的磁盤操作和阻塞延遲,是 IO 開支較大。

everysec:每秒同步一次,性能和安全都比較中庸的方式,也是redis 推薦的方式。如果遇到實體伺服器故障,有可能導緻最近一秒内 aof 記錄丢失(可能為部分丢失)。

no:redis 并不直接調用檔案同步,而是交給作業系統來處理,作業系統可以根據 buffer 填充情況 / 通道空閑時間等擇機觸發同步;這是一種普通的檔案操作方式。性能較好,在實體伺服器故障時,資料丢失量會因 OS 配置有關。

其實,我們可以選擇的太少,everysec 是最佳的選擇。如果你非常在意每個資料都極其可靠,建議你選擇一款“關系性資料庫”吧。

AOF 檔案會不斷增大,它的大小直接影響“故障恢複”的時間, 而且 AOF 檔案中曆史操作是可以丢棄的。AOF rewrite 操作就是“壓縮”AOF檔案的過程,當然 redis 并沒有采用“基于原 aof 檔案”來重寫的方式,而是采取了類似 snapshot 的方式:基于 copy-on-write,全量周遊記憶體中資料,然後逐個序列到 aof 檔案中。是以 AOF rewrite 能夠正确反應目前記憶體資料的狀态,這正是我們所需要的;*rewrite 過程中,對于新的變更操作将仍然被寫入到原 AOF 檔案中,同時這些新的變更操作也會被 redis 收集起來(buffer,copy-on-write方式下,最極端的可能是所有的 key 都在此期間被修改,将會耗費 2 倍記憶體),當記憶體資料被全部寫入到新的 aof 檔案之後,收集的新的變更操作也将會一并追加到新的 aof 檔案中,此後将會重命名新的 aof 檔案為 appendonly.aof, 此後所有的操作都将被寫入新的 aof 檔案。如果在 rewrite 過程中,出現故障,将不會影響原 AOF 檔案的正常工作,隻有當 rewrite 完成之後才會切換檔案,因為 rewrite 過程是比較可靠的。*

觸發rewrite 的時機可以通過配置檔案來聲明,同時 redis 中可以通過 bgrewriteaof 指令人工幹預。

redis-cli -h ip -p port bgrewriteaof

因為rewrite 操作 /aof 記錄同步 /snapshot 都消耗磁盤 IO,redis 采取了“schedule”政策:無論是“人工幹預”還是系統觸發,snapshot和 rewrite 需要逐個被執行。

AOF rewrite 過程并不阻塞用戶端請求。系統會開啟一個子程序來完成。

AOF與RDB差別

AOF 和 RDB 各有優缺點,這是有它們各自的特點所決定:

RDB

RDB是在某個時間點将資料寫入一個臨時檔案,持久化結束後,用這個臨時檔案替換上次持久化的檔案,達到資料恢複。 

優點:使用單獨子程序來進行持久化,主程序不會進行任何IO操作,保證了redis的高性能 

缺點:RDB是間隔一段時間進行持久化,如果持久化之間redis發生故障,會發生資料丢失。是以這種方式更适合資料要求不嚴謹的時候

AOF

Append-only file,将“操作 + 資料”以格式化指令的方式追加到記錄檔檔案的尾部,在append操作傳回後(已經寫入到檔案或者即将寫入),才進行實際的資料變更,“日志檔案”儲存了曆史所有的操作過程;當server需要資料恢複時,可以直接replay此日志檔案,即可還原所有的操作過程。AOF相對可靠,它和mysql中bin.log、apache.log、zookeeper中txn-log簡直異曲同工。AOF檔案内容是字元串,非常容易閱讀和解析。 

優點:可以保持更高的資料完整性,如果設定追加file的時間是1s,如果redis發生故障,最多會丢失1s的資料;且如果日志寫入不完整支援redis-check-aof來進行日志修複;AOF檔案沒被rewrite之前(檔案過大時會對指令進行合并重寫),可以删除其中的某些指令(比如誤操作的flushall)。 

缺點:AOF檔案比RDB檔案大,且恢複速度慢。

Redis釋出訂閱

Redis 釋出訂閱(pub/sub)是一種消息通信模式:發送者(pub)發送消息,訂閱者(sub)接收消息。

Redis 用戶端可以訂閱任意數量的頻道。

下圖展示了頻道 channel1 , 以及訂閱這個頻道的三個用戶端 —— client2 、 client5 和 client1 之間的關系:

當有新消息通過 PUBLISH 指令發送給頻道 channel1 時, 這個消息就會被發送給訂閱它的三個用戶端:

執行個體

以下執行個體示範了釋出訂閱是如何工作的。在我們執行個體中我們建立了訂閱頻道名為 redisChat:

redis 127.0.0.1:6379> SUBSCRIBE redisChat      
Reading messages... (press Ctrl-C to quit)      
1) "subscribe"      
2) "redisChat"      
3) (integer) 1      

現在,我們先重新開啟個 redis 用戶端,然後在同一個頻道 redisChat 釋出兩次消息,訂閱者就能接收到消息。

redis 127.0.0.1:6379> PUBLISH redisChat "Redis is a great caching technique"      
(integer) 1      
redis 127.0.0.1:6379> PUBLISH redisChat "Learn redis by runoob.com"      
(integer) 1      
# 訂閱者的用戶端會顯示如下消息      
1) "message"      
2) "redisChat"      
3) "Redis is a great caching technique"      
1) "message"      
2) "redisChat"      
3) "Learn redis by runoob.com"      

釋出訂閱指令

下表列出了 redis 釋出訂閱常用指令:

序号 指令及描述
1

PSUBSCRIBE pattern [pattern ...] 

訂閱一個或多個符合給定模式的頻道。

2

PUBSUB subcommand [argument [argument ...]] 

檢視訂閱與釋出系統狀态。

3

PUBLISH channel message 

将資訊發送到指定的頻道。

4

PUNSUBSCRIBE [pattern [pattern ...]] 

退訂所有給定模式的頻道。

5

SUBSCRIBE channel [channel ...] 

訂閱給定的一個或多個頻道的資訊。

6

UNSUBSCRIBE [channel [channel ...]] 

指退訂給定的頻道。

繼續閱讀