Redis

目錄
? ? 1 Redis簡介
? ? 2 數(shù)據(jù)結(jié)構(gòu)和對象
? ? 3 數(shù)據(jù)庫
? ? 4 RDB
? ? 5 AOF
? ? 6 事件
? ? 7 客戶端
? ? 8 復(fù)制
? ? 9 哨兵機制
? ? 10集群
? ? 11 發(fā)布與訂閱
? ? 12 事務(wù)
? ? 13 緩存問題
? ? 14 內(nèi)存淘汰機制
? ? 15 Redis并發(fā)競爭key
? ? 16 緩存與數(shù)據(jù)庫一致性問題
? ? 17 Springboot整合Redis

參考資料
? ? · 《Redis設(shè)計與實現(xiàn)》
? ? · JavaG

1 Redis 簡介

? ? 簡單來說redis就是一個數(shù)據(jù)庫蔚叨,不過與傳統(tǒng)數(shù)據(jù)庫不同的是redis的數(shù)據(jù)是存在內(nèi)存中的,所以讀寫速度非常快已亥,因此redis被廣泛應(yīng)用于緩存方向钱床。另外观堂,redis也經(jīng)常用來做分布式鎖督赤。redis提供了多種數(shù)據(jù)類型來支持不同的業(yè)務(wù)場景懈万。除此之外拴清,redis支持事務(wù)、持久化会通、LUA腳本口予、LRU驅(qū)動事件、多種集群方案涕侈。

2 數(shù)據(jù)結(jié)構(gòu)和對象

? ? redis數(shù)據(jù)庫里面的每個鍵值對都是由對象組成的苹威,其中,

? ? ? ? · 數(shù)據(jù)庫鍵總是一個字符串對象

? ? ? ? · 而數(shù)據(jù)庫鍵的值則可以是字符串對象驾凶、列表對象牙甫、哈希對象集合對象调违、有序集合對象窟哺。

2.1 SDS簡單動態(tài)字符串

2.1.1 SDS定義

圖2-1 SDS結(jié)構(gòu)體定義
圖2-2 SDS示例

? ? 保留空字符“\0”作為字符串的結(jié)尾,兼容C語言技肩,但是空字符的1個字節(jié)不計入SDS的len屬性中且轨。

2.1.2 與C串的區(qū)別

(1)通過常數(shù)復(fù)雜度回去字符串長度,len屬性

(2)字符串拼接虚婿、修改等操作時旋奢,杜絕緩存區(qū)溢出,自動修改大小然痊。

(3)減少修改時內(nèi)存重新分配次數(shù)

? ? ? ? ? ? SDS通過未使用空間(free屬性記錄)解除了字符串長度和底層數(shù)組長度之間的關(guān)聯(lián)至朗。SDS實現(xiàn)了空間預(yù)分配和惰性空間釋放兩種優(yōu)化策略。

????· 空間預(yù)分配:優(yōu)化SDS字符串增長操作剧浸。對象與修改len后锹引,若len小于1MB,則free = len唆香;若len大于等于1MB嫌变,則free = 1MB。故將連續(xù)增長N次字符串所需的內(nèi)存重分配次數(shù)從必定N次降低為最多N次躬它。

? ? · 惰性空間釋放:優(yōu)化SDS字符串縮短操作腾啥。利用free屬性將不適用的數(shù)據(jù)大小記錄下來,等將來使用冯吓。

(4)二進制安全

? ? ? ? 所有的SDS API都會以處理二進制的方式來處理SDS存放的buf數(shù)組里的數(shù)據(jù)倘待,程序不會對其中的數(shù)據(jù)做任何限制、過濾桑谍、或者假設(shè)延柠,數(shù)據(jù)在寫入時是什么樣的,它被讀取時就是什么樣锣披。

2.2 鏈表

2.2.1 定義

圖2-3 list定義
圖2-4 listNode定義
圖2-5 鏈表定義

2.2.2 特性

(1)雙端

(2)無環(huán)

(3)帶有表頭和表尾指針

(4)帶鏈表長度計數(shù)器

(5)多態(tài)贞间,通過dup、free雹仿、match設(shè)置類型特定的函數(shù)

2.3 字典

2.3.1 定義

? ? Redis的字典使用哈希表作為底層實現(xiàn)。

(1)哈希表節(jié)點

圖2-6 哈希表節(jié)點

? ? next指針將多個哈希值相同的鍵值對連接在一起胧辽,以此來解決鍵沖突問題(collision)峻仇。

(2)哈希表

圖2-7 哈希表

(3)字典

圖2-8 字典

? ? ht屬性是一個包含兩個項的數(shù)組,數(shù)組中的每個項都是一個dictht哈希表邑商,一般情況下摄咆,字典只使用ht[0]哈希表凡蚜,ht[1]哈希表只會在對ht[0]哈希表進行rehash時使用。

圖 2-9 dictType
圖 2-10 字典示例

2.3.2 哈希算法

(1)計算hash值吭从,采用MurmurHash2算法計算朝蜘。

(2)計算在哈希表中的位置index = hash & sizemask

2.3.3 解決鍵沖突

(1)使用鏈地址法解決沖突

(2)因為dictEntry節(jié)點組成的鏈表沒有表尾指針,故將新加節(jié)點加到鏈表的表頭位置涩金。

2.3.4 rehash重新散列

? ? 哈希表保存的鍵值對隨著操作會逐漸增多或者減少谱醇,為了讓哈希表的負載因子(load factor)維持在一個合理的范圍之內(nèi),需要重新散列步做。

2.3.4.1 步驟

圖2-11 rehash步驟

2.3.4.2 負載因子

(1)load_factor = ht[0].used / ht[0].size

(2)還要結(jié)合服務(wù)器是否在執(zhí)行BGSAVE或者BGREWRITEAOF指令副渴,在load_factor >= 1(否)或者load_factor >= 5(是)時進行rehash。

2.3.4.3 漸進式rehash

(1)rehash動作分多次全度、漸進式地完成.

(2)漸進式rehash期間煮剧,字典的增刪查改在兩個哈希表上進行。

2.4 skiplist跳躍表

? ? 是一種有序數(shù)據(jù)結(jié)構(gòu)讼载,它通過在每個節(jié)點中維持多個指向其他節(jié)點的指針轿秧,從而達到快速訪問節(jié)點的目的。

2.4.1 定義

(1)zskiplistNode

圖2-12 zskiplistNode

· 層用來加速訪問其他節(jié)點咨堤,一般層的數(shù)量越多菇篡,訪問其他節(jié)點的速度越快

· 層的前進指針:用于從表頭向表尾訪問節(jié)點

· 跨度:用來計算排位的,查找某個節(jié)點的過程中一喘,將沿途訪問過的所有層的跨度累計起來驱还,得到的結(jié)果就是目標節(jié)點在條魚表中的排位。

· 后退指針:用于從表尾向表頭方向訪問節(jié)點凸克,每次只能后退至前一個節(jié)點议蟆。

· 分值:跳躍表中的所以節(jié)點按照分值從小到大排序

· 成員對象:指向一個字符串對象SDS,且對象必須唯一

(2)zskiplist

typedef struct zskiplist {

? ? // 表頭節(jié)點和表尾節(jié)點
? ? structz skiplistNode *header, *tail;

? ? // 表中節(jié)點的數(shù)量
? ? unsigned long length;

? ? // 表中層數(shù)最大的節(jié)點的層數(shù)
? ? int level;

} zskiplist;

圖 2-13 跳躍表

2.4.2 應(yīng)用

(1)有序集合鍵

(2)集群節(jié)點中用作內(nèi)部數(shù)據(jù)結(jié)構(gòu)

2.5 intset整數(shù)集合

2.5.1 定義

圖2-14 intset

· encoding屬性決定contents數(shù)組真正的類型可以為INTSET_ENC_INT16(int16_t)萎战,INTSET_ENC_INT32(int32_t)咐容,INTSET_ENC_INT64(int64_t)

· length屬性是contents數(shù)組的長度

· contents數(shù)組是整數(shù)集合的底層實現(xiàn),各個按值大小從小到大有序地排列蚂维,不包含重復(fù)項戳粒。

2.5.2 升級

? ? 當新元素的類型比整數(shù)集合現(xiàn)有所有元素的類型都要長時,整數(shù)集合需要先進行升級虫啥。

(1)步驟

? ? ? ? · 根據(jù)新元素的類型蔚约,擴展整數(shù)集合底層數(shù)組的空間大小

? ? ? ? · 底層數(shù)組現(xiàn)有的所有元素都轉(zhuǎn)換成與新元素相同的類型,并保持數(shù)組的有序性涂籽。

? ? ? ? · 將新元素添加到底層數(shù)組里面

(2)新元素插入的位置

? ? ? ? 要么是最大值要么是最小值苹祟,故只會在表頭和表尾插入。

(3)優(yōu)點

? ? ? ? · 提升整數(shù)集合的靈活性

? ? ? ? · 盡可能地節(jié)約內(nèi)存

2.6 ziplist壓縮列表

2.6.1 定義

(1)ziplist

圖 2-15 ziplist定義
圖 2-16 ziplist說明

(2)節(jié)點entry

圖 2-17 節(jié)點entry

· previous_entry_length:記錄了壓縮列表中前一個節(jié)點的長度。壓縮列表從表尾向表頭遍歷操作就是依賴這個屬性树枫。

· encoding:記錄節(jié)點的content屬性所保存數(shù)據(jù)的類型和長度直焙。

· content 保存節(jié)點的值,可以是一個字節(jié)數(shù)組或者一個整數(shù)砂轻。

2.6.2 連鎖更新

當添加或者刪除節(jié)點的時候箕般,導(dǎo)致previous_entry_length所占字節(jié)空間發(fā)生變化(1字節(jié)或者5字節(jié)),新節(jié)點的后續(xù)節(jié)點都要重新分配空間舔清。

2.7 對象

? ? 包含5中類型的對象∏酰基于引用計數(shù)計數(shù)進行內(nèi)存回收和對象共享機制体谒。

2.7.1 redisObject

(1)結(jié)構(gòu)定義

圖 2-18 redisObject

(2)type

圖 2-19?不同對象的type屬性

(3)encoding

圖 2-20?不同encoding的底層數(shù)據(jù)結(jié)構(gòu)
圖 2-21?不同類型可以使用的編碼常量

2.7.2 字符串對象

(1)可以使用的encoding類型

? ? ? ? REDIS_ENCODING_INT、REDIS_ENCODING_EMBSTR臼婆、REDIS_ENCODING_RAW

(2)編碼轉(zhuǎn)換

? ? ? ? int編碼和embstr編碼的字符串對象在條件滿足的情況下抒痒,被轉(zhuǎn)換為raw對象。

2.7.3 列表對象

(1)可以使用的encoding類型

? ??????REDIS_ENCODING_ZIPLIST颁褂、REDIS_ENCODING_LINKEDLIST

(2)編碼轉(zhuǎn)換

圖 2-22 列表對象編碼轉(zhuǎn)換

2.7.4 哈希對象

(1)可以使用的encoding類型

? ???????REDIS_ENCODING_ZIPLIST故响、REDIS_ENCODING_HT

(2)編碼轉(zhuǎn)換

圖 2-23 哈希對象編碼轉(zhuǎn)換

2.7.5 集合對象

(1)可以使用的encoding類型

? ??????REDIS_ENCODING_INTSET、REDIS_ENCODING_HT

(2)編碼轉(zhuǎn)換

圖 2-24 集合對象編碼轉(zhuǎn)換

2.7.6 有序集合對象

(1)可以使用的encoding類型

? ??????REDIS_ENCODING_ZIPLIST颁独、REDIS_ENCODING_SKIPLIST

(2)底層結(jié)構(gòu)zset

typedef struct zset{

? ? zskiplist *zsl;

? ? dict *dict;

}

· zsl按分值從小到大保存所有集合元素

· dict保存成員到分值的映射彩届,鍵為成員,值為分值誓酒。

這兩種數(shù)據(jù)結(jié)構(gòu)通過指針來共享相同元素的成員和分值樟蠕,不會浪費額外的內(nèi)存。

(3)編碼轉(zhuǎn)換

圖 2-25? 有序集合對象編碼轉(zhuǎn)換

2.7.7 多態(tài)命令

? ? redis除了會根據(jù)值對象的類型來判斷鍵是否能夠執(zhí)行指定命令外靠柑,還會根據(jù)值對象的編碼方式寨辩,選擇正確的命令實現(xiàn)代碼來執(zhí)行命令。

2.7.8 內(nèi)存回收

? ? 引用計數(shù)法:利用redisObject中的refcount屬性歼冰,當計數(shù)值為0時靡狞,回收內(nèi)存。

2.7.9 對象共享

· 將數(shù)據(jù)庫鍵的值指針指向一個向右的值對象

· 將被共享的值對象的引用計數(shù)增1

圖 2-26 對象共享

· 注意:redis只對包含整數(shù)值的字符串對象進行共享隔嫡,其他字符串可能比較值相同較耗CPU甸怕。

2.7.10 空轉(zhuǎn)時長

? ? · redis利用redisObject中的lru屬性,記錄對象最后一次被命令程序訪問的時間畔勤。

? ? · 空轉(zhuǎn)時長蕾各,就是通過將當前時間減去鍵的值對象的lru時間計算得出

? ? · 如服務(wù)器打開maxmemory選項,且回收內(nèi)存算法為volatile-lru或者allkeys-lru庆揪,則當內(nèi)存超過maxmemory時式曲,空轉(zhuǎn)時長較高的部分將優(yōu)先被服務(wù)器釋放,回收內(nèi)存。

3 數(shù)據(jù)庫

3.1 定義

(1)redisServer

struct redisServer{

? ? // 保存服務(wù)器中所有數(shù)據(jù)庫的數(shù)組
????redisDb *db;

? ? // 服務(wù)器數(shù)據(jù)庫數(shù)量
????int dbnum;

? ? // ....

}

圖 3-1 redisServer

? ? dbnum的數(shù)量默認為16.

(2)redisClient

typedef struct redisClient{

? ? // 記錄客戶端當前正在使用的數(shù)據(jù)庫
? ? redisDb *db;

? ? // ....

}

默認使用0號數(shù)據(jù)庫吝羞±忌耍可以通過SELECT命令切換數(shù)據(jù)庫。

(3)redisDb

typedef struct redisDb{

? ? // 數(shù)據(jù)庫鍵空間
? ? dict *dict

? ? // 過期時間
? ? dict *expires;

? ? // ...

}

· dict字典中保存一個數(shù)據(jù)庫中的所有鍵值對钧排。

· 臟鍵敦腔,客戶端使用WATCH命令監(jiān)視的鍵,服務(wù)器每次修改一個鍵之后恨溜,都會對臟鍵計數(shù)器的值加1符衔,計數(shù)器會觸發(fā)服務(wù)器的持久化已經(jīng)復(fù)制操作。

3.2 過期時間

(1)EXPIRE/PEXPIRE命令

? ? ? ? 設(shè)置TTL生存時間糟袁,EXPIRE單位為s判族,PEXPIRE單位為ms。

(2)EXPIREAT/PEXPIREAT命令

? ? ? ? 設(shè)置過期時間项戴,后面跟UNIX時間戳玉掸。

(3)使用 redisDb的expires字典保存過期時間琅坡,鍵為對象,值為過期時間。

(4)redis的過期刪除策略

? ? ? ? · 惰性刪除:在查詢key時篮奄,若過期才刪除

? ? ? ? · 定期刪除:當服務(wù)器周期操作serverCron函數(shù)執(zhí)行時刪除幕帆。每次刪除隨機抽取部分岩榆,并維護一個進度記錄窥翩,知道過期鍵全部清除。

(5)RDB功能和過期鍵

? ? ? ? · 生成RDB文件時氓仲,檢測鍵水慨,過期的鍵不會被保存到文件中。

? ? ? ? · 載入RDB文件時敬扛,主服務(wù)器忽略過期鍵晰洒,從服務(wù)器直接載入(主從同步時會刪除)。

(6)AOF功能和過期鍵

? ? ? ? 過期鍵對AOF無影響啥箭,當過期鍵被刪除式谍珊,AOF文件追加DEL語句。

4 RDB

4.1 概念

(1)RDB持久化是將某個時間點上的數(shù)據(jù)庫狀態(tài)保存到一個RDB文件中急侥。

(2)RDB文件是一個經(jīng)過壓縮的二進制文件砌滞,通過該文件可以還原生成RDB文件時的數(shù)據(jù)庫狀態(tài)。

4.2 創(chuàng)建和載入

4.2.1 創(chuàng)建

(1)SAVE命令

? ? 阻塞Redis服務(wù)器坏怪,直到RDB文件創(chuàng)建完畢為止贝润。

(2)BGSAVE命令

? ? 派生出一個子進程,子進程負責(zé)創(chuàng)建RDB铝宵,服務(wù)器進程繼續(xù)處理命令打掘。

· 注意:如果服務(wù)器開啟了AOF持久化功能华畏,那么服務(wù)器會優(yōu)先使用AOF文件來還原數(shù)據(jù)。當AOF關(guān)閉時尊蚁,才會使用RDB方式亡笑。

4.2.2 載入

? ? 在服務(wù)器啟動時自動執(zhí)行。

4.3 自動間隔性保存

(1)配置

? ? 在redis.windows.conf中横朋,通過save選項設(shè)定服務(wù)器自動執(zhí)行BGSAVE命令的間隔時間仑乌。

圖 4-1 conf文件配置文件
圖 4-2 conf文件配置

· 900秒內(nèi),對數(shù)據(jù)庫修改1次琴锭,創(chuàng)建RDB

· 300秒內(nèi)晰甚,對數(shù)據(jù)庫修改10次,創(chuàng)建RDB

· 60秒內(nèi)决帖,對數(shù)據(jù)庫修改10000次压汪,創(chuàng)建RDB

(2)原理

? ? ? ? · save選項會設(shè)置到redisServer的saveparam屬性中。

? ? ? ? · redisServer的dirty計數(shù)器記錄一次SAVE/BGSAVE后古瓤,數(shù)據(jù)庫修改次數(shù)

? ? ? ? · redisServer的lastsave屬性記錄上一次SAVE/BGSAVE執(zhí)行時間

? ? ? ? · 服務(wù)器周期性操作函數(shù)serverCron默認每個100ms執(zhí)行一次,其中一項工作為檢測save選項條件是否滿足

4.4 RDB文件結(jié)構(gòu)

圖4-3?RDB文件結(jié)構(gòu)

(1)REDIS用來快速檢測所載入的文件是否是RDB文件

(2)db_version長度為4字節(jié)腺阳,記錄RDB文件版本號

(3)databases包含0個或多個數(shù)據(jù)庫落君,以及各數(shù)據(jù)庫中的鍵值對數(shù)據(jù)

(4)EOF長度為1字節(jié),標志RDB文件正文內(nèi)容的結(jié)束

(5)check_sum長度為8字節(jié)無符號整數(shù)亭引,保存一個校驗和绎速,用來檢測RDB文件是否有出錯或者損壞的情況

5 AOF

5.1 概念

????AOF持久化是通過保存Redis服務(wù)器鎖執(zhí)行的寫命令來記錄數(shù)據(jù)庫狀態(tài)的

5.2 創(chuàng)建步驟

5.2.1 命令追加(append)

? ? 服務(wù)器在執(zhí)行完一個寫命令后,會以協(xié)議格式將被執(zhí)行的寫命令追加到redisServer的aof_buf緩沖區(qū)(SDS類型)的末尾焙蚓。

5.2.2 文件寫入與同步

? ? 服務(wù)器在每個事件處理結(jié)束時纹冤,調(diào)用flushAppendOnlyFile函數(shù)將aof_buf緩沖區(qū)中的內(nèi)容寫入和保存到AOF文件里面。flushAppendOnlyFile函數(shù)的appendfsync參數(shù)決定同步(何時將操作系統(tǒng)內(nèi)存緩存區(qū)的內(nèi)容寫入磁盤)方式:

圖 5-1?AOF同步的三種設(shè)置

everysec為默認設(shè)置购公。

5.3 載入

步驟:

(1)創(chuàng)建一個不帶網(wǎng)絡(luò)連接的偽客戶端

(2)從AOF文件中分析并讀取一條寫命令(包括新增萌京,修改,刪除)

(3)使用偽客戶端執(zhí)行寫命令

(4)一直執(zhí)行(2)和(3)直到所有命令被處理完宏浩。

5.4 AOF重寫

(1)原因:為了解決長時間后AOF文件體積膨脹的問題(主要由于Redis的內(nèi)存淘汰機制知残,一定時間后,大量數(shù)據(jù)被淘汰比庄,使得原本的AOF存在大量之前的寫記錄求妹,變得冗長)

(2)實現(xiàn):創(chuàng)建一個新的AOF文件代替現(xiàn)有AOF文件。新舊兩個AOF文件保存的數(shù)據(jù)庫狀態(tài)相同佳窑,但新AOF文件不包含任何浪費空間的冗命令制恍。

(3)原理:從數(shù)據(jù)庫讀取鍵現(xiàn)在的值,用一條命令去記錄鍵值對神凑,代替之前記錄這個鍵值對的多條命令净神。

(4)后臺重寫:創(chuàng)建子進程執(zhí)行AOF重寫程序(因為Reids采用單線程模式工作)。

6 事件

? ? Redis服務(wù)器是一個事件驅(qū)動程序

6.1 文件事件

6.1.1 構(gòu)成

圖 6-1 文件事件處理器

(1)套接字 socket

? ? ? ? Redis服務(wù)器通過套接字與客戶端連接。

(2)I/O多路復(fù)用

圖 6-2 IO多路復(fù)用

? ? ? ? 將所有產(chǎn)生的套接字都放在一個隊列里面强挫,然后通過這個隊列岔霸,以有序、同步俯渤、每次一個套接字的方式向文件事件分派器傳送套接字呆细。

? ? ? ? Redis以單線程模式運行。

(3)文件事件分派器

? ? ? ? 根據(jù)IO復(fù)用器傳過來的套接字產(chǎn)生的事件類型八匠,調(diào)用相應(yīng)的事件處理器

(4)事件處理器

? ? ? ? · 命令請求處理器

? ? ? ? · 命令回復(fù)處理器

? ? ? ? · 連接應(yīng)答處理器

? ? ? ? · 絮爷。。梨树。

6.1.2 事件類型

(1)AE_READABLE

? ? ? ? 套接字可讀坑夯。即客戶端對套接字執(zhí)行write操作,或者close操作抡四,或者有新的可應(yīng)答套接字出現(xiàn)柜蜈。

(2)AE_WRITABLE

? ? ? ? 套接字可寫,即客戶端對套接字執(zhí)行read操作指巡。

? ? 當兩種事件同時發(fā)生時淑履,文件事件分派器優(yōu)先處理AR_READABLE事件。

6.2 時間事件

? ? 分為定時事件和周期性事件兩類藻雪。

6.2.1 分類

(1)定時事件:讓一段程序在指定的時間后執(zhí)行一次秘噪。事件處理器返回AE_NOMORE

(2)周期性事件:讓程序每隔指定時間就執(zhí)行一次。事件處理器返回非AE_NOMORE整數(shù)值勉耀。

????目前版本Redis只使用周期性事件指煎。

6.2.2 時間事件的屬性

? ? · id 服務(wù)器為時間事件創(chuàng)建的全局唯一ID

? ? · when 毫秒精度的UNIX時間戳,記錄時間事件的到達時間

? ? · timeProc 時間時間處理器便斥,當時間事件到達時至壤,服務(wù)器會調(diào)用相應(yīng)的處理器來處理事件

6.2.3 實現(xiàn)

????服務(wù)器將所有時間事件放在一個無序鏈表中,每當時間事件執(zhí)行器運行時枢纠,它就遍歷整個鏈表崇渗,查找所有已到達的時間事件,并調(diào)用相應(yīng)的事件處理器京郑。

圖 6-3 鏈表實現(xiàn)

? ? · 新的時間事件總是插入到鏈表的表頭宅广。

? ? · 正常模式下的Redis服務(wù)器只使用serverCron一個時間事件,故無序鏈表并不影響事件執(zhí)行性能些举。

6.2.4 serverCron函數(shù)

(1)Redis需要定期對自身的資源和狀態(tài)進行檢查和調(diào)整

(2)主要工作:

? ? ? ? · 更新服務(wù)器的各類統(tǒng)計信息跟狱,如時間、內(nèi)存占用等

? ? ? ? · 清理數(shù)據(jù)庫中的過期鍵值對

? ? ? ? · 關(guān)閉和清理連接失效的客戶端

? ? ? ? · 嘗試進行AOF或RDB持久化操作

? ? ? ? · 如果服務(wù)器是主服務(wù)器户魏,對從服務(wù)器進行定期同步

? ? ? ? · 如果處于集群模式驶臊,對集群進行定期同步和連接測試

(3)默認serverCron平均每間隔100ms運行一次(Redis2.6)挪挤,Redis2.8開始,用戶通過修改redis.windos.conf的hz選項來調(diào)整每秒執(zhí)行次數(shù)关翎。

6.3 事件的執(zhí)行原則

(1)一次文件事件之后扛门,仍然沒有時間事件到達,那么服務(wù)器將再次等待并處理文件事件纵寝。

(2)事件的處理都是同步论寨、有序、原子地執(zhí)行的爽茴。

(3)時間事件在文件事件之后執(zhí)行葬凳,通常執(zhí)行時間會比時間事件設(shè)定的到達時間稍晚一些。

7 客戶端

7.1 redisClient

struct redisServer {

? ? // ...

? ? // 一個鏈表室奏,保存了所有客戶端狀態(tài)
? ? list *client

? ? // 套接字描述符
? ? int fd;

? ? //...

}

7.2 客戶端分類

(1)普通客戶端

? ? ? ? · fd > -1的整數(shù)火焰,來源于網(wǎng)絡(luò)

? ? ? ? · 創(chuàng)建時,添加到鏈表表尾

(2)偽客戶端

? ? ? ? · fd = -1胧沫,不是來源于網(wǎng)絡(luò)

? ? ? ? · AOF在載入AOF文件時創(chuàng)建昌简。在載入完成后,偽客戶端關(guān)閉绒怨。

? ? ? ? · Lua腳本執(zhí)行時創(chuàng)建江场。在服務(wù)器關(guān)閉時,偽客戶端關(guān)閉窖逗。

8 復(fù)制

8.1 概念

(1)"SLAVEOF ip port"命令或者配置文件中的slaveof選項

(2)主從服務(wù)器的數(shù)據(jù)庫將保存相同的數(shù)據(jù)

8.2 舊版(Redis2.8之前)

? ? 分為兩個步驟進行,同步和命令傳播餐蔬。

8.2.1 同步

圖 8-1 同步過程

(1)從服務(wù)器向主服務(wù)器發(fā)送SYNC命令

(2)收到SYNC命令的主服務(wù)器執(zhí)行BGSAVE命令碎紊。在后臺生成一個RDB文件,并使用一個緩沖區(qū)記錄從現(xiàn)在開始執(zhí)行的所有寫命令

(3)主服務(wù)器將RDB文件發(fā)送給從服務(wù)器樊诺,從服務(wù)器收入并載入RDB文件仗考。

(4)主服務(wù)器將記錄在緩沖區(qū)里面的所有寫命令發(fā)送給從服務(wù)器。

8.2.2 命令傳播

? ? 同步之后词爬,每次將主服務(wù)器的寫命令發(fā)送給從服務(wù)器秃嗜。

8.3 新版

? ? 為了解決舊版復(fù)制功能在處理斷線重復(fù)制情況時的低效問題。

8.3.1 實現(xiàn)

????使用PSYNC命令顿膨,具有完整重同步和部分重同步兩種模式

(1)完整重同步锅锨,用于初次復(fù)制情況

? ? ? ? 和SYNC命令類似,傳送RDB文件和寫命令緩沖區(qū)恋沃。

(2)部分重同步必搞,用于處理斷線后重復(fù)制情況

? ? ? ? 主服務(wù)器將主從服務(wù)器連接斷開期間執(zhí)行的寫命令發(fā)送給從服務(wù)器。

8.4 心跳檢測

(1)在命令傳播階段囊咏,從服務(wù)器默認會以每秒一次的頻率恕洲,向主服務(wù)器發(fā)送命令:

????????REPLCONF ACK <replication_offset>

(2)作用:

? ? ? ? · 檢測主從服務(wù)器的網(wǎng)絡(luò)連接狀態(tài)

? ? ? ? · 輔助實現(xiàn)min-slaves選項

? ? ? ? · 檢測命令丟失

9 哨兵機制

9.1 意義

? ? sentinel是Redis的高可用性解決方案塔橡。監(jiān)視的主服務(wù)器進入下線狀態(tài)時,自動將下線主服務(wù)器屬下的某個從服務(wù)器升級為新的主服務(wù)器霜第。

? ? 若之前的主服務(wù)器重新上線葛家,則自動成為現(xiàn)存主服務(wù)器的從服務(wù)器。

圖 9-1 sentinel

9.2 啟動sentinel

(1)初始化服務(wù)器

? ? ? ? · Sentinel本質(zhì)上是一個運行在特殊模式下的Redis服務(wù)器

? ? ? ? · Sentinel不適用數(shù)據(jù)庫泌类,不會載入RDB或者AOF文件

(2)將普通Redis服務(wù)器使用的代碼替換為sentinel專用代碼

(3)初始化sentinel狀態(tài)

(4)根據(jù)配置文件癞谒,初始化Sentinel的監(jiān)視主服務(wù)器列表

(5)創(chuàng)建連向主服務(wù)器的網(wǎng)絡(luò)連接

? ? ? ? · 命令連接:向服務(wù)器發(fā)送命令和接收命令回復(fù)

? ? ? ? · 訂閱連接:訂閱服務(wù)器的_sentinel_:hello頻道

9.3 獲取服務(wù)器信息

(1)Sentinel默認以十秒一次的頻率,通過命令連接向被監(jiān)視的主服務(wù)器發(fā)送INFO命令末誓。

? ? 可以獲取以下消息:

? ? ? ? · 主服務(wù)器本身的信息

? ? ? ? · 所有從服務(wù)器的信息

(2)Sentinel默認以十秒一次的頻率扯俱,通過命令連接向被監(jiān)視的從服務(wù)器發(fā)送INFO命令。

9.4 發(fā)送和接收

(1)sentinel每兩秒一次發(fā)送命令給監(jiān)視的主從服務(wù)器的_sentinel_:hello頻道

(2)訂閱連接建立之后喇澡,通過_sentinel_hello頻道獲取信息迅栅。

9.5 檢測是否下線

(1)主觀下線

????????Sentinel默認每次一秒的頻率向建立了命令連接的Redis實例發(fā)送PING命令。若在down-after-milliseconds選項配置的時間內(nèi)沒有有效回復(fù)晴玖,認為為主觀下線狀態(tài)读存。

(2)客觀下線

? ? ? ? 當Sentinel將一個主服務(wù)器判斷為主觀下線后,為了確認是否真的下線了呕屎,會向同樣監(jiān)視這一主服務(wù)器的其他Sentinel進行詢問让簿,若其他Sentinel也認為為下線狀態(tài),在接收到足夠數(shù)量的下線判斷后秀睛,Sentinel認為主服務(wù)器為客觀下線尔当,并進行故障轉(zhuǎn)移操作。

9.6 選舉領(lǐng)頭Sentinel

? ? 當一個主服務(wù)器為客觀下線時蹂安,監(jiān)視這個主服務(wù)器的所有Sentinel選舉一個領(lǐng)頭Sentinel對主服務(wù)器執(zhí)行故障轉(zhuǎn)移操作椭迎。

主要步驟如下:

(1)在一個配置紀元(計數(shù)器)里面,所有Sentinel有一次將某個Sentinel設(shè)置為局部領(lǐng)頭Sentinel的機會田盈,并且局部領(lǐng)頭一旦設(shè)置畜号,在這個配置紀元里面就不能再更改。

(2)Sentinel向另一個Sentinel發(fā)送帶有自己運行ID的命令允瞧,讓其設(shè)置自己為局部領(lǐng)頭Sentinel(相當于搶票)简软。

(3)局部領(lǐng)頭Sentinel規(guī)則:先到先得。已經(jīng)設(shè)置為別人為Sentinel的Sentinel述暂,拒絕后續(xù)收到的設(shè)置

(4)如果某個Sentinel被半數(shù)以上的Sentinel設(shè)置成了局部領(lǐng)頭Sentinel痹升,那么這個Sentinel成為領(lǐng)頭Sentinel。

9.7 故障轉(zhuǎn)移

(1)在已下線主服務(wù)器屬下的所有從服務(wù)器中畦韭,挑選出一個從服務(wù)器视卢,將其轉(zhuǎn)換為主服務(wù)器。

? ? ? ? 領(lǐng)頭Sentinel按照從服務(wù)器的優(yōu)先級廊驼,對列表中剩余的從服務(wù)器進行排序据过,并選出其中優(yōu)先級最高的從服務(wù)器

(2)讓已下線主服務(wù)器屬下的所以從服務(wù)器改為復(fù)制新的主服務(wù)器惋砂。

(3)將已下線主服務(wù)器設(shè)置為新的主服務(wù)器的從服務(wù)器,當這個舊的主服務(wù)器重新上線時绳锅,它就會成為新的主服務(wù)器的從服務(wù)器西饵。

10集群

? ? Redis集群是Redis提供的分布式數(shù)據(jù)庫方案,集群通過分片進行數(shù)據(jù)共享鳞芙,并提供復(fù)制和故障轉(zhuǎn)移功能眷柔。

10.1 節(jié)點

(1)CLUSTER MEET命令

? ? ? ? · 格式 CLUSTER MEET <ip> <port>

? ? ? ? · 向另一個節(jié)點發(fā)送命令,進行握手原朝,握手成功后加入所在集群驯嘱。

(2)啟動節(jié)點

圖 10-1 啟動集群節(jié)點

(3)集群數(shù)據(jù)結(jié)構(gòu)

? ? · clusterNode 每個節(jié)點使用其記錄自己的狀態(tài),并為集群中其他節(jié)點創(chuàng)建一個相應(yīng)的clusterNode結(jié)構(gòu)

圖 10-2 clusterNode

? ? · clusterLink 保存了連接節(jié)點所需的有關(guān)信息

圖 10-3 clusterLink

? ? · clusterState 記錄在當前節(jié)點的視角下喳坠,集群目前所處狀態(tài)

圖 10-4 clusterState

(4)節(jié)點握手

圖 10-5 節(jié)點握手

10.2 槽指派

(1)概念

? ? ? ? Redis集群通過分片的方式來保存數(shù)據(jù)庫中的鍵值對:集群的整個數(shù)據(jù)庫被分為16384割槽(slot)鞠评,數(shù)據(jù)庫中的每個鍵都屬于整個16384個槽的其中一個,集群中的每個節(jié)點可以處理0~16384個槽壕鹉。

(2)數(shù)據(jù)結(jié)構(gòu)

struct clusterNode{

? ? //....

? ? unsigned char slots[16384/8];

? ? int numslots;

? ? // ....

}

? ? · 二進制數(shù)組中索引上的二進制位為1必怜,則表示節(jié)點負責(zé)處理該槽

? ? · numslots表示該節(jié)點負責(zé)的槽數(shù)量

(3)相關(guān)命令

? ? CLUSTER ADDSLOTS 指派槽

(4)注意點

? ? 節(jié)點數(shù)據(jù)庫只能使用0號數(shù)據(jù)庫抬闯,這和單機服務(wù)器的數(shù)據(jù)庫不同芙扎。

10.3 復(fù)制和故障轉(zhuǎn)移

10.3.1 復(fù)制

圖10-6 集群復(fù)制

? ? 主節(jié)點(master)用于處理槽榜田,從節(jié)點用于復(fù)制某個主節(jié)點,在其主節(jié)點下線時可以代替主節(jié)點繼續(xù)處理命令請求脊凰。

10.3.2 故障轉(zhuǎn)移

(1)在從節(jié)點中選一個成為新的主節(jié)點

? ? ? ? 新主節(jié)點的選取抖棘,類似于sentinel領(lǐng)頭的選取,算法都是基于Raft算法實現(xiàn)的狸涌。

(2)新的主節(jié)點撤銷對已下線主節(jié)點的槽指派切省,并將這些槽指派給自己

(3)新的主節(jié)點廣播PONG消息,讓其他節(jié)點知道自己成為新的主節(jié)點

(4)接收和處理自己的槽相關(guān)的請求杈抢,故障轉(zhuǎn)移完成。

11 發(fā)布與訂閱

11.1 概述

(1)由PUBLISH(發(fā)送消息)仑性、SUBSCRIBE(訂閱頻道)惶楼、PSUBSCRIBE(訂閱模式)等命令組成

(2)通過執(zhí)行SUBSCRIBE命令,客戶端可以訂閱一個或多個頻道诊杆,每當有其他客戶端向被訂閱的頻道發(fā)送消息時歼捐,頻道的所有訂閱者都會受到這條消息。

(3)通過執(zhí)行PSUBSCRIBE命令訂閱一個或多個模式晨汹,每當有其他客戶端向某個頻道發(fā)送消息時豹储,消息會被發(fā)送給與這個頻道相匹配的模式的訂閱者。

圖 11-1 頻道和模式

11.2 頻道

11.2.1 數(shù)據(jù)結(jié)構(gòu)

struct redisServer{

? ? // ...

? ? // 保存所有頻道的訂閱關(guān)系
? ? dict *pubsub_channels;

? ? // ...

}

? ? · 字典的鍵是某個被訂閱的頻道

? ? · 字典的值是一個鏈表淘这,記錄所有訂閱該頻道的客戶端

圖 11-2 頻道結(jié)構(gòu)

11.2.2 訂閱和退訂

(1)訂閱:使用SUBSCRIBE命令剥扣,在鏈表的尾部添加

(2)退訂:使用UNSUBSCRIBE命令巩剖,從鏈表中刪除客戶端。當出現(xiàn)鍵對應(yīng)空鏈表钠怯,要從字典中刪除鍵

11.3 模式

11.3.1 數(shù)據(jù)結(jié)構(gòu)

struct redisServer{

????// ...

????// 保存所有頻道的訂閱關(guān)系
????dict *pubsub_patterns;

????// ...

}

11.3.2 訂閱和退訂

? ? 類似頻道佳魔。

11.4 發(fā)送消息

? ? PUBLISH命令:在pubsub_channels字典里找到頻道channel的訂閱者名單(一個鏈表),然后將消息發(fā)送給名單上的所有客戶端晦炊。

12 事務(wù)

12.1 概述

? ? 使用MULTI(事務(wù)開始)鞠鲜、EXEC(提交事務(wù))、WATCH等命令來實現(xiàn)事務(wù)断国。

? ? 事務(wù)提供了一種多個命令請求打包贤姆,然后一次性、按順序地執(zhí)行多個命令的機制稳衬,并且在事務(wù)執(zhí)行期間霞捡,服務(wù)器不會中斷事務(wù)而改去執(zhí)行其他客戶端的命令請求。

12.2 事務(wù)的實現(xiàn)

(1)事務(wù)開始

? ? ? ? · MULTI命令將客戶端切換至事務(wù)狀態(tài)宋彼。

? ? ? ? · 原理:在客戶端狀態(tài)的flags屬性中打開REDIS_MULTI標識弄砍。

(2)命令入隊

? ? ? ? · 如果是EXEC、DISCARD输涕、WATCH音婶、MULTI四個命令,立即執(zhí)行

? ? ? ? · 其他命令放入事務(wù)隊列莱坎,然后客戶端返回QUEUED回復(fù)

(3)事務(wù)執(zhí)行

? ? ? ? 遍歷客戶端的事務(wù)隊列衣式,執(zhí)行隊列中保存的所有命令。

12.3 WATCH命令

(1)作用

? ? ? ? 是一個樂觀鎖檐什,在執(zhí)行EXEC命令前碴卧,監(jiān)視任意數(shù)量的數(shù)據(jù)庫鍵。在EXEC命令執(zhí)行時乃正,若監(jiān)視的鍵是否至少有一個已經(jīng)被修改過了住册,如果是的話,服務(wù)器拒絕執(zhí)行事務(wù)瓮具,向客戶端返回空回復(fù)荧飞。

圖12-1 WATCH命令的使用

(2)數(shù)據(jù)結(jié)構(gòu)

typedef struct redisDb{

? ? // ...

? ? // 正在被WATCH命令監(jiān)視的鍵
? ? dict *watched_keys;

? ? // ...

}

? ? 每個數(shù)據(jù)庫都保存一個字典,鍵為WATCH命令監(jiān)視的數(shù)據(jù)庫鍵名党。值為一個鏈表叹阔,記錄所有監(jiān)視相應(yīng)數(shù)據(jù)庫鍵的客戶端。

(3)當被監(jiān)視的鍵被修改传睹,則客戶端的REDIS_DITRY_CAS標識打開耳幢。

13 緩存問題

13.1 緩存雪崩

(1)原因

????????緩存同一時間大面積的失效,大量的請求直接落到數(shù)據(jù)庫上欧啤,造成數(shù)據(jù)庫短時間內(nèi)承受大量請求而崩掉睛藻。

(2)解決辦法

圖 13-1 緩存雪崩解決辦法

· 事前:盡量保證整個Redis集群的高可用性启上,發(fā)現(xiàn)機器宕機幾塊補上,選擇合適的內(nèi)存淘汰策略修档。

· 事中: 本地ehcache緩存+hystrix限流&降級碧绞,避免MySQL崩掉

· 事后:利用redis持久化機制保存的數(shù)據(jù)盡快恢復(fù)緩存

13.2 緩存穿透

13.2.1 原因

? ? ? ? 大量請求的key根本不在緩存中,導(dǎo)致請求直接到了數(shù)據(jù)庫上吱窝。

? ? ? ? 一般MySQL的最大連接數(shù)在150左右讥邻,最大連接數(shù)還只是一個指標,cpu院峡,內(nèi)存兴使,自盤,網(wǎng)絡(luò)等

圖13-2 緩存穿透

13.2.2 解決辦法

13.2.2.1 無效key的時間減短

????黑客每次構(gòu)建不同的請求Key照激,會導(dǎo)致redis中緩存大量無效的key发魄,故可以將無效key的過期時間設(shè)置短一點。

13.2.2.2 布隆過濾器

圖13-3 布隆過濾器的使用

(1)布隆過濾器的概念

????布隆過濾器(Bloom Filter)可以看作由二進制向量(或者說位數(shù)組)和一系列隨機映射函數(shù)(哈希函數(shù))兩部分組成的數(shù)據(jù)結(jié)構(gòu)俩垃。相比于我們平時常用的的 List励幼、Map 、Set 等數(shù)據(jù)結(jié)構(gòu)口柳,它占用空間更少并且效率更高苹粟,但是缺點是其返回的結(jié)果是概率性的,而不是非常準確的跃闹。理論情況下添加到集合中的元素越多嵌削,誤報的可能性就越大。并且望艺,存放在布隆過濾器的數(shù)據(jù)不容易刪除苛秕。

圖13-4 布隆過濾器的bit數(shù)組

????位數(shù)組中的每個元素都只占用 1 bit ,并且每個元素只能是 0 或者 1找默。這樣申請一個 100w 個元素的位數(shù)組只占用 1000000Bit / 8 = 125000 Byte = 125000/1024 kb ≈ 122kb 的空間艇劫。

總結(jié):一個名叫 Bloom 的人提出了一種來檢索元素是否在給定大集合中的數(shù)據(jù)結(jié)構(gòu),這種數(shù)據(jù)結(jié)構(gòu)是高效且性能很好的惩激,但缺點是具有一定的錯誤識別率和刪除難度店煞。并且,理論情況下咧欣,添加到集合中的元素越多浅缸,誤報的可能性就越大轨帜。

(2)布隆過濾器的原理介紹

· 當一個元素加入布隆過濾器中的時候魄咕,會進行如下操作:

????????使用布隆過濾器中的哈希函數(shù)對元素值進行計算,得到哈希值(有幾個哈希函數(shù)得到幾個哈希值)

????????根據(jù)得到的哈希值蚌父,在位數(shù)組中把對應(yīng)下標的值置為 1

· 當我們需要判斷一個元素是否存在于布隆過濾器的時候哮兰,會進行如下操作:

????????對給定元素再次進行相同的哈希計算

????????得到值之后判斷位數(shù)組中的每個元素是否都為 1毛萌,如果值都為 1,那么說明這個值在布隆過濾器中喝滞,如果存在一個值不為 1阁将,說明該元素不在布隆過濾器中

舉個簡單的例子:

圖 13-5 eg1

? ??不同的字符串可能哈希出來的位置相同,這種情況我們可以適當增加位數(shù)組大小或者調(diào)整我們的哈希函數(shù)右遭。

綜上做盅,我們可以得出:布隆過濾器說某個元素存在,小概率會誤判窘哈。布隆過濾器說某個元素不在吹榴,那么這個元素一定不在。

? ? 在Redis中具體工作機制如下:

14 內(nèi)存淘汰機制

? ? 保證Redis中的數(shù)據(jù)為熱點數(shù)據(jù)滚婉。

(1)volatile-lru:從已設(shè)置過期時間的數(shù)據(jù)集中挑選最近最少使用的數(shù)據(jù)淘汰

(2)volatile-ttl:從已設(shè)置過期時間的數(shù)據(jù)集中挑選將要過期的數(shù)據(jù)淘汰

(3)volatile-random:從已設(shè)置過期時間的數(shù)據(jù)集中挑選任意數(shù)據(jù)淘汰

(4)allkeys-lru:內(nèi)存不足時图筹,在鍵空間中移除最近最少使用的key(最常用)

(5)allkeys-random:從數(shù)據(jù)集中任意選擇數(shù)據(jù)淘汰

(6)no-eviction:禁止驅(qū)逐數(shù)據(jù)

redis4.0后新增

(7)volatile-lfu:從已設(shè)置過期時間的數(shù)據(jù)集中挑選最不經(jīng)常使用的數(shù)據(jù)淘汰

(8)allkeys-lfu:內(nèi)存不足時,在鍵空間中移除最不經(jīng)常使用的key

15 Redis并發(fā)競爭key

? ? 分布式鎖一般有三種方式實現(xiàn):數(shù)據(jù)庫樂觀鎖让腹,基于Redis的分布式鎖远剩,基于zookeeper的分布式鎖

<dependency>

? ? <groupId>redis.clients</groupId>

? ? <artifactId>jedis</artifactId>

? ? <version>2.9.0</version>

</dependency>

public class RedisTool {

? ? private static final String LOCK_SUCCESS = "OK";

? ? private static final String SET_IF_NOT_EXIST = "NX";

? ? private static final String SET_WITH_EXPIRE_TIME = "PX";

? ? /**

? ? * 嘗試獲取分布式鎖

? ? * @param jedis Redis客戶端

? ? * @param lockKey 鎖

? ? * @param requestId 請求標識

? ? * @param expireTime 超期時間

? ? * @return 是否獲取成功

? ? */

? ? public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {

? ? ? ? String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);

? ? ? ? if (LOCK_SUCCESS.equals(result)) {

? ? ? ? ? ? return true;

? ? ? ? }

? ? ? ? return false;

? ? }

}

這個set()方法一共有五個形參:

? ? · 第一個為key骇窍,我們使用key來當鎖瓜晤,因為key是唯一的像鸡。

? ? · 第二個為value锌云,我們傳的是requestId,很多童鞋可能不明白,有key作為鎖不就夠了嗎,為什么還要用到value遥皂?原因就是我們在上面講到可靠性時,分布式鎖要滿足第四個條件解鈴還須系鈴人爬凑,通過給value賦值為requestId潘靖,我們就知道這把鎖是哪個請求加的了吐辙,在解鎖的時候就可以有依據(jù)昵时。requestId可以使用UUID.randomUUID().toString()方法生成。

? ? · 第三個為nxxx椒丧,這個參數(shù)我們填的是NX,意思是SET IF NOT EXIST救巷,即當key不存在時壶熏,我們進行set操作;若key已經(jīng)存在浦译,則不做任何操作棒假;

? ? · 第四個為expx,這個參數(shù)我們傳的是PX精盅,意思是我們要給這個key加一個過期的設(shè)置帽哑,具體時間由第五個參數(shù)決定。

? ? · 第五個為time叹俏,與第四個參數(shù)相呼應(yīng)妻枕,代表key的過期時間。

? ? 方法底層主要使用Redis的Setnx 命令實現(xiàn)粘驰。

????總的來說屡谐,執(zhí)行上面的set()方法就只會導(dǎo)致兩種結(jié)果:1. 當前沒有鎖(key不存在),那么就進行加鎖操作蝌数,并對鎖設(shè)置個有效期愕掏,同時value表示加鎖的客戶端。2. 已有鎖存在顶伞,不做任何操作饵撑。

16 緩存與數(shù)據(jù)庫一致性問題

????最經(jīng)典的緩存+數(shù)據(jù)庫讀寫的模式,就是 Cache Aside Pattern唆貌。

? ? · 讀的時候滑潘,先讀緩存,緩存沒有的話锨咙,就讀數(shù)據(jù)庫众羡,然后取出數(shù)據(jù)后放入緩存,同時返回響應(yīng)蓖租。

? ? · 更新的時候粱侣,先刪除緩存,然后再更新數(shù)據(jù)庫蓖宦。

17 Springboot整合Redis

17.1 依賴

<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>

</dependencies>

17.2 配置文件

spring:

#redis

? redis:

? ? ? host: localhost

? ? ? password: 123456

? ? ? port: 6379

? ? ? pool:

? ? ? ? max-idle: 100

? ? ? ? min-idle: 1

? ? ? ? max-active: 1000

? ? ? ? max-wait: -1

17.3 Service層代碼

@Service

public?class?RedisService {

????@Autowired
????private?StringRedisTemplate stringRedisTemplate;

????public?void?setStr(String key, String value) {

????????setStr(key, value, null);

????}

????public?void?setStr(String key, String value, Long time) {

????????stringRedisTemplate.opsForValue().set(key, value);

????????if?(time?!= null)

????????????stringRedisTemplate.expire(key, time, TimeUnit.SECONDS);

????}

????public?Object getKey(String key) {

????????return?stringRedisTemplate.opsForValue().get(key);

????}

????public?void?delKey(String key) {

????????stringRedisTemplate.delete(key);

????}

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末齐婴,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子稠茂,更是在濱河造成了極大的恐慌柠偶,老刑警劉巖情妖,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異诱担,居然都是意外死亡毡证,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門蔫仙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來料睛,“玉大人,你說我怎么就攤上這事摇邦⌒羯罚” “怎么了?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵施籍,是天一觀的道長居扒。 經(jīng)常有香客問我,道長丑慎,這世上最難降的妖魔是什么喜喂? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮竿裂,結(jié)果婚禮上夜惭,老公的妹妹穿的比我還像新娘。我一直安慰自己铛绰,他們只是感情好诈茧,可當我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著捂掰,像睡著了一般敢会。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上这嚣,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天鸥昏,我揣著相機與錄音,去河邊找鬼姐帚。 笑死吏垮,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的罐旗。 我是一名探鬼主播膳汪,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼九秀!你這毒婦竟也來了遗嗽?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤鼓蜒,失蹤者是張志新(化名)和其女友劉穎痹换,沒想到半個月后征字,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡娇豫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年匙姜,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片冯痢。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡氮昧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出系羞,到底是詐尸還是另有隱情,我是刑警寧澤霸琴,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布椒振,位于F島的核電站,受9級特大地震影響梧乘,放射性物質(zhì)發(fā)生泄漏澎迎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一选调、第九天 我趴在偏房一處隱蔽的房頂上張望夹供。 院中可真熱鬧,春花似錦仁堪、人聲如沸哮洽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽运授。三九已至旦签,卻和暖如春缺猛,著一層夾襖步出監(jiān)牢的瞬間垒棋,已是汗流浹背蔑赘。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工蹬叭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留捺檬,地道東北人再层。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像堡纬,于是被迫代替她去往敵國和親聂受。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容