Redis学习笔记·
目錄
?
第一章 nosql概述(not only sql)
?1.1為什么需要nosql
1.2 nosql數(shù)據(jù)庫(kù)的四大分類
NoSQL數(shù)據(jù)庫(kù)的四大分類表格分析
第二章 redis概述
2.1概述:
2.2 redis特性:
第三章?API
redis中文網(wǎng):Redis命令中心(Redis commands) -- Redis中國(guó)用戶組(CRUG)
3.1全局命令
3.2字符串
3.3?hash:
3.4?列表list
3.5集合set
3.6有序集合zset
3.7?位圖(bit)
3.8?GEO
3.9?Pub/Sub?發(fā)布訂閱
3.10?Stream
第四章 redis管理器
4.1?全局命令
4.2.1.鍵的遷移:把部分?jǐn)?shù)據(jù)遷移到另一臺(tái)redis服務(wù)器
4.3.1?redis數(shù)據(jù)庫(kù)管理
第五章 redis持久化
第六章?redis主從復(fù)制
6.1方式:
6.2相關(guān)命令:
6.3注意事項(xiàng):
6.4Redis主從拓?fù)?#xff1a;
6.5復(fù)制原理:
6.6數(shù)據(jù)同步:
6.7 主從的缺點(diǎn):
6.8?主從故障如何故障轉(zhuǎn)移
第七章?部署模式
7.1單節(jié)點(diǎn)模式
7.2主從模式
7.3集群模式
7.4讀寫分離?
7.5哨兵機(jī)制(sentinel)的高可用
第八章?redis集群高可用
8.1?分區(qū)規(guī)則
9.總結(jié)
10. 布隆過(guò)濾器
11. 策略?
11.1. 過(guò)期策略:?
11.2. 內(nèi)存回收
11.3. LRU(最近最少使用)
11.4.?LFU(最近最不常用)
12.多路復(fù)用
第一章 nosql概述(not only sql)
非關(guān)系型數(shù)據(jù)庫(kù)
?1.1為什么需要nosql
????????? ? High Performance-高并發(fā)讀寫
? ? ? ? ? ? ? Huge Storage - 海量數(shù)據(jù)的高效率存儲(chǔ)和訪問(wèn)
? ? ? ? ? ? ? High Scalability && High Availabitiy - 高可擴(kuò)展性和高可用性
?NoSQL數(shù)據(jù)庫(kù)在以下的這幾種情況下比較適用:
????????????1?、數(shù)據(jù)模型比較簡(jiǎn)單;
????????????2、需要靈活性更強(qiáng)的IT系統(tǒng);
????????????3、對(duì)數(shù)據(jù)庫(kù)性能要求較高;
????????????4、不需要高度的數(shù)據(jù)一致性;
????????????5、對(duì)于給定key,比較容易映射復(fù)雜值的環(huán)境
nosql存在的一些問(wèn)題
1.2 nosql數(shù)據(jù)庫(kù)的四大分類
- 鍵值對(duì)(Key-Value)存儲(chǔ) redis
????這一類數(shù)據(jù)庫(kù)主要會(huì)使用到一個(gè)哈希表,這個(gè)表中有一個(gè)特定的鍵和一個(gè)指針指向特定的數(shù)據(jù)。Key/value模型對(duì)于IT系統(tǒng)來(lái)說(shuō)的優(yōu)勢(shì)在于簡(jiǎn)單、易部署。但是如果DBA只對(duì)部分值進(jìn)行查詢或更新的時(shí)候,Key/value就顯得效率低下了。舉例如:Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB.
- ?列存儲(chǔ):
???????這部分?jǐn)?shù)據(jù)庫(kù)通常是用來(lái)應(yīng)對(duì)分布式存儲(chǔ)的海量數(shù)據(jù)。鍵仍然存在,但是它們的特點(diǎn)是指向了多個(gè)列。這些列是由列家族來(lái)安排的。如:Cassandra, HBase, Riak.
- 文檔數(shù)據(jù)庫(kù):mongodb
??????文檔型數(shù)據(jù)庫(kù)的靈感是來(lái)自于Lotus Notes辦公軟件的,而且它同第一種鍵值存儲(chǔ)相類似。該類型的數(shù)據(jù)模型是版本化的文檔,半結(jié)構(gòu)化的文檔以特定的格式存儲(chǔ),比如JSON。文檔型數(shù)據(jù)庫(kù)可 以看作是鍵值數(shù)據(jù)庫(kù)的升級(jí)版,允許之間嵌套鍵值。而且文檔型數(shù)據(jù)庫(kù)比鍵值數(shù)據(jù)庫(kù)的查詢效率更高。如:CouchDB, MongoDb. 國(guó)內(nèi)也有文檔型數(shù)據(jù)庫(kù)SequoiaDB,已經(jīng)開源。
- 圖形數(shù)據(jù)庫(kù)(多用于社交網(wǎng)絡(luò))InfoGrid
??????圖形結(jié)構(gòu)的數(shù)據(jù)庫(kù)同其他行列以及剛性結(jié)構(gòu)的SQL數(shù)據(jù)庫(kù)不同,它是使用靈活的圖形模型,并且能夠擴(kuò)展到多個(gè)服務(wù)器上。NoSQL數(shù)據(jù)庫(kù)沒(méi)有標(biāo)準(zhǔn)的查詢語(yǔ)言(SQL),因此進(jìn)行數(shù)據(jù)庫(kù)查詢需要制定數(shù)據(jù)模型。許多NoSQL數(shù)據(jù)庫(kù)都有REST式的數(shù)據(jù)接口或者查詢API。如:Neo4J, InfoGrid, Infinite Graph.
NoSQL數(shù)據(jù)庫(kù)的四大分類表格分析
??
| 鍵值(key-value) | Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB | 內(nèi)容緩存,主要用于處理大量數(shù)據(jù)的高訪問(wèn)負(fù)載,也用于一些日志系統(tǒng)等等。 | Key 指向 Value 的鍵值對(duì),通常用hash table來(lái)實(shí)現(xiàn) | 查找速度快 | 數(shù)據(jù)無(wú)結(jié)構(gòu)化,通常只被當(dāng)作字符串或者二進(jìn)制數(shù)據(jù) |
| 列存儲(chǔ)數(shù)據(jù)庫(kù) | Cassandra, HBase, Riak | 分布式的文件系統(tǒng) | 以列簇式存儲(chǔ),將同一列數(shù)據(jù)存在一起 | 查找速度快,可擴(kuò)展性強(qiáng),更容易進(jìn)行分布式擴(kuò)展 | 功能相對(duì)局限 |
| 文檔型數(shù)據(jù)庫(kù) | CouchDB, MongoDb | Web應(yīng)用(與Key-Value類似,Value是結(jié)構(gòu)化的,不同的是數(shù)據(jù)庫(kù)能夠了解Value的內(nèi)容) | Key-Value對(duì)應(yīng)的鍵值對(duì),Value為結(jié)構(gòu)化數(shù)據(jù) | 數(shù)據(jù)結(jié)構(gòu)要求不嚴(yán)格,表結(jié)構(gòu)可變,不需要像關(guān)系型數(shù)據(jù)庫(kù)一樣需要預(yù)先定義表結(jié)構(gòu) | 查詢性能不高,而且缺乏統(tǒng)一的查詢語(yǔ)法。 |
| 圖形(Graph)數(shù)據(jù)庫(kù) | Neo4J, InfoGrid, Infinite Graph | 社交網(wǎng)絡(luò),推薦系統(tǒng)等。專注于構(gòu)建關(guān)系圖譜 | 圖結(jié)構(gòu) | 利用圖結(jié)構(gòu)相關(guān)算法。比如最短路徑尋址,N度關(guān)系查找等 | 需要對(duì)整個(gè)圖做計(jì)算才能得出需要的信息,而且這種結(jié)構(gòu)不太好做分布式的集群方案。 |
第二章 redis概述
2.1概述:
用C語(yǔ)言開發(fā)的一個(gè)開源的、高性能的鍵值對(duì)(key-value)數(shù)據(jù)庫(kù),通過(guò)提供多種鍵值數(shù)據(jù)類型來(lái)適應(yīng)不同場(chǎng)景的數(shù)據(jù)需求。高性能鍵值對(duì)數(shù)據(jù)庫(kù)。其中value可以為string、hash、list、set、zset等多種數(shù)據(jù)結(jié)構(gòu),可以滿足很多應(yīng)用場(chǎng)景。還提供了鍵過(guò)期,發(fā)布訂閱,事務(wù),流水線,等附加功能,
流水線: Redis 的流水線功能允許客戶端一次將多個(gè)命令請(qǐng)求發(fā)送給服務(wù)器, 并將被執(zhí)行的多個(gè)命令請(qǐng)求的結(jié)果在一個(gè)命令回復(fù)中全部返回給客戶端, 使用這個(gè)功能可以有效地減少客戶端在執(zhí)行多個(gè)命令時(shí)需要與服務(wù)器進(jìn)行通信的次數(shù)。
2.2 redis特性:
1〉速度快,數(shù)據(jù)放在內(nèi)存中,官方給出的讀寫性能10萬(wàn)/S,與機(jī)器性能也有關(guān)
? ? ? ? a,數(shù)據(jù)放內(nèi)存中是速度快的主要原因
? ? ? ? b,C語(yǔ)言實(shí)現(xiàn),與操作系統(tǒng)距離近
? ? ? ? c,使用了單線程架構(gòu),預(yù)防多線程可能產(chǎn)生的競(jìng)爭(zhēng)問(wèn)題
2〉鍵值對(duì)的數(shù)據(jù)結(jié)構(gòu)服務(wù)器
3〉簡(jiǎn)單穩(wěn)定:單線程
4〉持久化:發(fā)生斷電或機(jī)器故障,數(shù)據(jù)可能會(huì)丟失,持久化到硬盤
?????? 6〉主從復(fù)制:實(shí)現(xiàn)多個(gè)相同數(shù)據(jù)的redis副本
?????? 8〉高可用和分布式:哨兵機(jī)制實(shí)現(xiàn)高可用,保證redis節(jié)點(diǎn)故障發(fā)現(xiàn)和自動(dòng)轉(zhuǎn)移
?????? 9〉客戶端語(yǔ)言多:java php python c c++ nodejs等
redis支持的鍵值數(shù)據(jù)類型
- 字符串類型
- 列表類型
- 有序集合類型
- 散列類型
- 集合類型
應(yīng)用場(chǎng)景
- 緩存:合理使用緩存加快數(shù)據(jù)訪問(wèn)速度,降低后端數(shù)據(jù)源壓力
- 任務(wù)隊(duì)列(不推薦使用)
- 數(shù)據(jù)過(guò)期處理(精確到毫秒)
- 分布式集群架構(gòu)中的session分離
- 社交網(wǎng)絡(luò):贊、踩、粉絲、下拉刷新
- 計(jì)數(shù)器
- 排行榜:按照熱度排名,按照發(fā)布時(shí)間排行,主要用到列表和有序集合
redis的優(yōu)點(diǎn)
非常快速:每一秒鐘可執(zhí)行大約110000次的set操作,81000次的get操作。并發(fā)大概十萬(wàn)。
支持多種數(shù)據(jù)類型:字符串,列表,有序/三列集合,集合等等類型。
操作具有原子性:原子性保證了并發(fā)情況下,服務(wù)器能接收更新的值。
注:單線程。
單線程架構(gòu)
?? 列舉例子:三個(gè)客戶端同時(shí)執(zhí)行命令
???????? 客戶端1:set name test
???????? 客戶端2:incr num
???????? 客戶端3:incr num
執(zhí)行過(guò)程:發(fā)送指令-〉執(zhí)行命令-〉返回結(jié)果
執(zhí)行命令:單線程執(zhí)行,所有命令進(jìn)入隊(duì)列,按順序執(zhí)行,使用I/O多路復(fù)用解決I/O問(wèn)題,后面有介紹(由于讀寫操作等待用戶輸入或輸出都是阻塞的,所以 I/O 操作在一般情況下往往不能直接返回,這會(huì)導(dǎo)致某一文件的 I/O 阻塞導(dǎo)致整個(gè)進(jìn)程無(wú)法對(duì)其它客戶提供服務(wù)?,IO多路復(fù)用模型是建立在內(nèi)核提供的多路分離函數(shù)select基礎(chǔ)之上的,使用select函數(shù)可以避免同步非阻塞IO模型中輪詢等待的問(wèn)題)
單線程快原因:純內(nèi)存訪問(wèn), 非阻塞I/O(使用多路復(fù)用),單線程避免線程切換和競(jìng)爭(zhēng)產(chǎn)生資源消耗
問(wèn)題:如果某個(gè)命令執(zhí)行,會(huì)造成其它命令的阻塞
第三章?API
redis中文網(wǎng):Redis命令中心(Redis commands) -- Redis中國(guó)用戶組(CRUG)
3.1全局命令
切換數(shù)據(jù)庫(kù):select 2
| 命令 | 描述 |
| keys * | 查看所有鍵,如果存在大量鍵,線上禁止使用此指令 |
| dbsize | 鍵總數(shù) |
| exists key??? | 檢查鍵是否存在,存在返回1,不存在返回0 |
| expire key seconds? | 鍵過(guò)期 |
| ttl?key | ?查看剩余的過(guò)期時(shí)間 |
| type key? | 鍵的數(shù)據(jù)結(jié)構(gòu)類型,鍵不存在返回none |
| flushall | 清空所有數(shù)據(jù)庫(kù)節(jié)點(diǎn),redis默認(rèn)16個(gè)節(jié)點(diǎn) |
| flushdb | 清空當(dāng)前數(shù)據(jù)庫(kù)節(jié)點(diǎn)(0) |
| select datanode | 切換節(jié)點(diǎn),總共16個(gè)節(jié)點(diǎn),默認(rèn)是0節(jié)點(diǎn)。 |
3.2字符串
? ? ?3.2.1字符串類型:字符串(xml,json),數(shù)字(整形,浮點(diǎn)數(shù)),二進(jìn)制(圖片,音、視頻)最大不能超過(guò)512MB。
? ? ?3.2.2?API:
| set | |
| set key value?? | 設(shè)值 |
| set key value? ex 10 | // ex表示過(guò)期,單位是秒; |
| setnx?key?value | 不存在key時(shí)才能插入,存在key返回0失敗,不存在key返回1成功;注:setnx可用做分布式鎖 |
| mset?key1?value1?key2?value2....... | 批量操作設(shè)值 |
| get | |
| ?get?key? | 獲取值 |
| mget key1 key2..... | 批量獲取 |
| 運(yùn)算 | |
| incr?key | 自增,必須為整數(shù)自加1,非整數(shù)返回錯(cuò)誤,無(wú)key鍵從0自增返回1 |
| decr?key | 遞減整數(shù) |
| incrby key value | 加法,整數(shù)值+value |
| incrbyfloat? key?1.1 | 浮點(diǎn)數(shù)?加法 |
| ?decrby?key?value? | 減法整數(shù) |
| 其它 | |
| append?key?value | 追加值 |
| strlen?key | 獲取字符串長(zhǎng)度 |
| getrange?key?index1,index2 | 截取字符串,返回下標(biāo)第index1個(gè)到?第index2個(gè),下標(biāo)從0開始。 |
| object encoding?key | 內(nèi)部編碼 int :8個(gè)字長(zhǎng);embstr:小于等于39字節(jié)字符串;raw大于39字節(jié)的字符串 |
3.3?hash:
是一個(gè)string類型的field和value和value的映射表,hash特別適合用于存儲(chǔ)對(duì)象;
| hset?key?field?value | 設(shè)值,field?value類似于map中的key?value |
| hget?key?field | 取值 |
| hdel?key?field | 刪值 |
| hlen?key | 長(zhǎng)度 |
| hmset?key field1 value1 field2 value2....? | 批量設(shè)值 |
| hmget?key?field1?field2... | 批量取值 |
| hkeys key | 獲取所有field |
| hvals key | 獲取所有value |
| hgetall?key | 獲取所有field?value |
| hincrby key field value hincrbyfloat key field value | 加法 |
| hdecrby?key?field value? | 減法 |
內(nèi)部編碼:ziplist<壓縮列表>和hashtable<哈希表>
?當(dāng)field個(gè)數(shù)少且沒(méi)有大的value時(shí),內(nèi)部編碼為ziplist
?當(dāng)value大于64字節(jié),內(nèi)部編碼由ziplist變成hashtable
1.字符串:
優(yōu)點(diǎn):簡(jiǎn)單直觀,每個(gè)鍵對(duì)應(yīng)一個(gè)值
缺點(diǎn):鍵數(shù)過(guò)多,占用內(nèi)存多,用戶信息過(guò)于分散,不用于生產(chǎn)環(huán)境
HASH類型是稀疏,每個(gè)鍵可以有不同的filed, 若用redis模擬做關(guān)系復(fù)雜查詢開發(fā)因難,維護(hù)成本高
2.將對(duì)象序列化存入reids:set user:1 serialize(userInfo);
優(yōu)點(diǎn):編程簡(jiǎn)單,若使用序列化合理內(nèi)存使用率高
缺點(diǎn):序列化與反序列化有一定開銷,更新屬性時(shí)需要把userInfo全取出來(lái)進(jìn)行反序列化,更新后再序列化到redis
3.使用hash類型:?hmset user:1 name james age 23 sex boy
優(yōu)點(diǎn):簡(jiǎn)單直觀,使用合理可減少內(nèi)存空間消耗
缺點(diǎn):要控制ziplist與hashtable兩種編碼轉(zhuǎn)換,且hashtable會(huì)消耗更多內(nèi)存
總結(jié):對(duì)于更新不多的情況下,可以使用序列化,對(duì)于VALUE值不大于64字節(jié)可以使用hash類型
3.4?列表list
用來(lái)存儲(chǔ)多個(gè)有序的字符串,一個(gè)列表最多可存2的32次方減1個(gè)元素
因?yàn)橛行?#xff0c;可以通過(guò)索引下標(biāo)獲取元素或某個(gè)范圍內(nèi)元素列表,列表元素可以重復(fù)
| rpush key val1 val2 val3 | 從右向左添加val1 val2 val3 |
| lpush?key?val1?val2?val3 | 從左向右添加 |
| linsert?key before val1 val2 | 在val1之前插入val2 ,after為之后 |
| lrange?key 0 -1 | 從左到右獲取列表的所有元素 |
| lindex?key?index | index下標(biāo),正數(shù)從左到右,負(fù)數(shù)-1表示最末尾 |
| llen?key | 返回當(dāng)前列表長(zhǎng)度 |
| lpop?key | 把最左邊的第一個(gè)元素刪除?返回刪除的值 |
| rpop?key | 刪除最右邊的元素,返回刪除的值 |
| lrem?key?count?valu | 刪除指定元素value,刪除count個(gè) |
| ltrim?key?index1 index2 | 只保留從第index1到index2的元素,其它全部刪除,下標(biāo)從0開始 |
| set?key?index?value | 把下標(biāo)為index的值改成value。 |
內(nèi)部編碼:
object encoding?key
1,ziplist:當(dāng)元素個(gè)數(shù)少且沒(méi)大元素,編碼為ziplist,減少內(nèi)存的使用
2,linkedlist:當(dāng)元素超過(guò)512個(gè),或元素超過(guò)64字節(jié),內(nèi)部編碼變成linkedlist鏈表;
3.5集合set
保存多元素,與列表不一樣的是不允許有重復(fù)元素,且集合是無(wú)序,一個(gè)集合最多可存2的32次方減1個(gè)元素,除了支持增刪改查,還支持集合交集、并集、差集;
| sadd?key?v1 v2 v3 | 當(dāng)插入相同的元素,則重復(fù)無(wú)效,返回0, |
| smember? key | 獲取key集合的所有元素,返回結(jié)果無(wú)序 |
| srem? key?value | 刪除指定value |
| scard?key | 計(jì)算元素個(gè)數(shù) |
| sismember? key?value | 判斷元素value在key集合中是否存在,存在返回1,不存在返回0 |
| srandmember?key?count | 隨機(jī)返回count個(gè)元素 |
| spop?key?count | 隨機(jī)獲取count個(gè)元素,并刪除 |
| sinter?key1?key2? key3..... | 求多個(gè)結(jié)合的交集 |
| sunion? key1 key2 key3...... | 求并集? |
| sdiff key1 key2..... | 差集 |
| sinterstore? key? key1 key2... | 將key1 key2...交集保存到key |
| sunionstore key? key1 key2.. | 將key1 key2...合集保存到key |
| sdiffstore key? key1 key2... | 將key1 key2...差集保存到key |
內(nèi)部編碼:??object encoding?key
1.intset:當(dāng)元素個(gè)數(shù)少(小于512個(gè))且都為整數(shù),redis使用intset減少內(nèi)存的使用
2.hashtable:當(dāng)超過(guò)512個(gè)或不為整數(shù)(比如a b)時(shí),編碼為hashtable
使用場(chǎng)景:
? 標(biāo)簽,社交,查詢有共同興趣愛好的人,智能推薦
3.6有序集合zset
有序集合,可排序的,但是唯一。
| zadd key score member [score member......] | 如果該元素已經(jīng)存在則會(huì)用新的分?jǐn)?shù)替換原有的分?jǐn)?shù)。返回值是新加入到集合中的元素個(gè)數(shù),不包含之前已經(jīng)存在的元素。? |
| zadd?key?value?member? | 點(diǎn)贊數(shù)1, 返回操作成功的條數(shù)1 |
| ?zadd?key?nx?value?member? | 添加的必須不存在,主用于添加 |
| ?zadd?key?xx incr?value?member? | 必須存在,主用于修改 |
| zadd? key xx ch incr?value?member | ? |
| zscore key member | 獲取元素的分?jǐn)?shù)? |
| zrem key member [member …] | 移除有序集key中的一個(gè)或多個(gè)成員,不存在的成員將被忽略。當(dāng)key存在但不是有序集類型時(shí),返回一個(gè)錯(cuò)誤。 |
| zrange key start stop [withscores] | 按照元素分?jǐn)?shù)從小到大的順序返回索引從start到stop之間的所有元素(包含兩端的元素)? |
| zrevrange key start stop [withscores] | 按照元素分?jǐn)?shù)從大到小的順序返回索引從start到stop之間的所有元素(包含兩端的元素)? |
| zrange scoreboard 0 1 withscores | 如果需要獲得元素的分?jǐn)?shù)的可以在命令尾部加上WITHSCORES參數(shù) |
| zrange key member | 獲取元素的排名,從小到大 |
| zrevrange key member | 獲取元素的排名,從大到小 |
| zrangebyscore key min max [withscores] [LIMIT offset count] | 獲得指定分?jǐn)?shù)范圍的元素? |
| zincrby key increment member | 增加某個(gè)元素的分?jǐn)?shù)? |
| zcard key | 獲得集合中元素的數(shù)量? |
| zcount key min max | 獲得指定分?jǐn)?shù)范圍內(nèi)的元素個(gè)數(shù)? |
| ZREMRANGEBYRANK key start stop | 按照排名范圍刪除元素? |
| ZREMRANGEBYSCORE key min max | 按照分?jǐn)?shù)范圍刪除元素? |
| zinterstore destination numkeys key ... [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX] | 有序集合交集 ?destination:交集產(chǎn)生新的元素存儲(chǔ)鍵名稱 ???????? numkeys:? 要做交集計(jì)算的鍵個(gè)數(shù) ???????? key :元素鍵值 ????? ???weights:每個(gè)被選中的鍵對(duì)應(yīng)值乘weight, 默認(rèn)為1 |
| zunionstore destination numkeys key ... [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX] | 有序集合并集(合并去重): ?destination:交集產(chǎn)生新的元素存儲(chǔ)鍵名稱 ???????? numkeys:? 要做交集計(jì)算的鍵個(gè)數(shù) ???????? key :元素鍵值 ???????? weights:每個(gè)被選中的鍵對(duì)應(yīng)值乘weight, 默認(rèn)為1 |
有序集合內(nèi)部編碼 object encoding?key?
1.ziplist:當(dāng)元素個(gè)數(shù)少(小于128個(gè)),元素值小于64字節(jié)時(shí),使用ziplist編碼,可有效減少內(nèi)存的使用
2.skiplist:? ?大于128個(gè)元素或元素值大于64字節(jié)時(shí)為skiplist編碼與LIST SET 對(duì)比:
| 列表 | 是 | 是 | 索引下標(biāo) | 時(shí)間軸,消息隊(duì)列 |
| 集合 | 否 | 否 | 無(wú) | 標(biāo)簽,社交 |
| 有序結(jié)合 | 否 | 是 | 分值 | 排行榜,點(diǎn)贊數(shù) |
3.7?位圖(bit)
3.8?GEO
? ? ? ? GEO 3.2版本開始對(duì)GEO(地理位置)的支持| 命令 | 描述 |
| GEOADD | 增加地理位置的坐標(biāo),可以批量添加地理位置 |
| GEODIST | 獲取兩個(gè)地理位置的距離 |
| GEOHASH | 獲取某個(gè)地理位置的geohash值 |
| GEOPOS | 獲取指定位置的坐標(biāo),可以批量獲取多個(gè)地理位置的坐標(biāo) |
| GEORADIUS | 根據(jù)給定地理位置坐標(biāo)獲取指定范圍內(nèi)的地理位置集合 (注意:該命令的中心點(diǎn)由輸入的經(jīng)度和緯度決定) |
| GEORADIUSBYMEMBER | 根據(jù)給定成員的位置獲取指定范圍內(nèi)的位置信息集合 (注意:該命令的中心點(diǎn)是由給定的位置元素決定) |
3.9?Pub/Sub?發(fā)布訂閱
生產(chǎn)者發(fā)布消息到頻道
消費(fèi)者訂閱頻道,從頻道接收消息
生產(chǎn)者、消費(fèi)者彼此相互不了解
3.10?Stream
類似kafka
第四章 redis管理器
4.1?全局命令
?4.1.1?鍵重命名 rename oldKey newkey??? //格式
???????????? rename oldKey newKey???? //若oldKey之前存在則被覆蓋
???????????? set name james ;set name1 mike //數(shù)據(jù)初始化
???????????? renamenx name name1 //重命名失敗,只有當(dāng)name1不存在才能改名
?4.1.2? 返回隨機(jī)鍵? dbsize? //redis有16個(gè)庫(kù),查看當(dāng)前庫(kù)的鍵值對(duì)總數(shù)
?????????????? randomkey? //返回隨機(jī)鍵
?4.1.3 鍵過(guò)期:expire name:03 20? //鍵name:03 在10秒后過(guò)期
?????????? ttl name:03??????? //查看過(guò)期按秒到計(jì)時(shí),當(dāng)返回-2說(shuō)明已刪除
?????????? pttl name:03?????? //查看過(guò)期按毫秒到時(shí)計(jì)
?????????? set name:05 james? //初始化數(shù)據(jù)
?????????? pexpire name:05 20000? //20000毫秒(20S)后過(guò)期
?????????? expire name:06 -2? //直接過(guò)期,和del一樣
?????????
?expireat name:04 1516971599? //設(shè)置在2018/01/26 20:59:59過(guò)期
????????? 時(shí)間轉(zhuǎn)時(shí)間戳:網(wǎng)址http://tool.chinaz.com/Tools/unixtime.aspx?
???????? ?persist? key? ? ? ?//去掉過(guò)期?
????????? 注意:對(duì)于字符串重設(shè)值后,expire無(wú)效,
????????? set name james
????????? expire name 50
????????? ttl name
????????? set name james1 //此時(shí)expire取消
????????? ttl name?? //返回-1, 長(zhǎng)期有效
4.2.1.鍵的遷移:把部分?jǐn)?shù)據(jù)遷移到另一臺(tái)redis服務(wù)器
? 1, move key db? //reids有16個(gè)庫(kù), 編號(hào)為0-15
這種模式不建議在生產(chǎn)環(huán)境使用,在同一個(gè)reids里可以玩
?2, dump key;
?restore key ttl value//實(shí)現(xiàn)不同redis實(shí)例的鍵遷移,ttl=0代表沒(méi)有過(guò)期時(shí)間
3,migrate指令遷移到其它實(shí)例redis,在1.111服務(wù)器上將test移到118
4.2.2 鍵的遍歷:
? redis提供了兩個(gè)命令來(lái)遍歷所有的鍵
?1,鍵全量遍歷:
mset country china city bj name james? //設(shè)置3個(gè)字符串鍵值對(duì)
keys? * //返回所有的鍵, *匹配任意字符多個(gè)字符
keys *y //以結(jié)尾的鍵,
keys n*e //以n開頭以e結(jié)尾,返回name
keys n?me? //? ?問(wèn)號(hào)代表只匹配一個(gè)字符? 返回name,全局匹配
keys n?m*?? //返回name
keys [j,l]*? //返回以j l開頭的所有鍵? keys [j]ames 全量匹配james
考慮到是單線程, 在生產(chǎn)環(huán)境不建議使用,如果鍵多可能會(huì)阻塞
如果鍵少,可以
2,漸進(jìn)式遍歷
mset? a a b b c c d d e e f f g g h h i i j j k k l l m m n n o o p p q q r r s s t t u u v v w w x x y y z z??? //初始化26個(gè)字母鍵值對(duì)
字符串類型:
?scan 0 match n* count 20 //匹配以n開頭的鍵,取20條,第一次scan 0開始
第二次從游標(biāo)4096開始取20個(gè)以n開頭的鍵,相當(dāng)于一頁(yè)一頁(yè)的取
當(dāng)最后返回0時(shí),鍵被取完
比如將old:user開頭的元素全刪掉
注:可有效地解決keys命令可能產(chǎn)生的阻塞問(wèn)題
- 除scan字符串外:還有以下
- SCAN?命令用于迭代當(dāng)前數(shù)據(jù)庫(kù)中的數(shù)據(jù)庫(kù)鍵。
- SSCAN?命令用于迭代集合鍵中的元素。
- HSCAN?命令用于迭代哈希鍵中的鍵值對(duì)。
- ZSCAN?命令用于迭代有序集合中的元素(包括元素成員和元素分值)。
用法和scan一樣
4.3.1?redis數(shù)據(jù)庫(kù)管理
select 0?? //共16個(gè)庫(kù), 0 --15, select切換數(shù)據(jù)庫(kù)
set name james
select 1
get name? //隔離了,取不到,和mysql不同庫(kù)一樣
其中redis3.0以后的版本慢慢弱化了這個(gè)功能,如在redis cluster中只允許0數(shù)據(jù)庫(kù)
?????? 原因:1,redis單線程,如果用多個(gè)庫(kù),這些庫(kù)使用同一個(gè)CPU,彼此會(huì)有影響
2,多數(shù)據(jù)庫(kù),調(diào)試與運(yùn)維麻煩,若有一個(gè)慢查詢,會(huì)影響其它庫(kù)查詢速度
3,來(lái)回切換,容易混亂
?????? flushdb: 只清空當(dāng)前數(shù)據(jù)庫(kù)的鍵值對(duì)? dbsiz? 0
?????? flushall:? 清空所有庫(kù)的鍵值對(duì)? (這兩個(gè)指令慎用!!!!)
4.4 redis功能細(xì)解
4.4.1?慢查詢?cè)蚍治?與mysql一樣:當(dāng)執(zhí)行時(shí)間超過(guò)閥值,會(huì)將發(fā)生時(shí)間 耗時(shí) 命令記錄
?redis命令生命周期:發(fā)送 排隊(duì) 執(zhí)行 返回
????? 慢查詢只統(tǒng)計(jì)第3個(gè)執(zhí)行步驟的時(shí)間
??
????? 預(yù)設(shè)閥值:兩種方式,默認(rèn)為10毫秒
?? 使用config set完后,若想將配置持久化保存到redis.conf,要執(zhí)行config rewrite
???????? 2,redis.conf修改:找到slowlog-log-slower-than 10000 ,修改保存即可
????? 注意:slowlog-log-slower-than =0記錄所有命令 -1命令都不記錄
????? 原理:慢查詢記錄也是存在隊(duì)列里的,slow-max-len 存放的記錄最大條數(shù),比如設(shè)置的slow-max-len=10,當(dāng)有第11條慢查詢命令插入時(shí),隊(duì)列的第一條命令就會(huì)出列,第11條入列到慢查詢隊(duì)列中, 可以config set動(dòng)態(tài)設(shè)置,也可以修改redis.conf完成配置。
?獲取隊(duì)列里慢查詢的命令:slowlog get???? 查詢返回的結(jié)構(gòu)如下
?獲取慢查詢列表當(dāng)前的長(zhǎng)度:slowlog len? //以上只有1條慢查詢,返回1
? 對(duì)慢查詢列表清理(重置):slowlog reset //再查slowlog len 此時(shí)返回0 清空
? 對(duì)于線上slow-max-len配置的建議:線上可加大slow-max-len的值,記錄慢查詢存長(zhǎng)命令時(shí)redis會(huì)做截?cái)?#xff0c;不會(huì)占用大量?jī)?nèi)存,線上可設(shè)置1000以上
? 對(duì)于線上slowlog-log-slower-than配置的建議:默認(rèn)為10毫秒,根據(jù)redis并發(fā)量來(lái)調(diào)整,對(duì)于高并發(fā)比建議為1毫秒
? 注意:1,慢查詢只記錄命令在redis的執(zhí)行時(shí)間,不包括排隊(duì)、網(wǎng)絡(luò)傳輸時(shí)間
4.5?redis-cli詳解
? ./redis-cli -r 3 -h 192.168.1.111 -a 12345678 ping //返回pong表示127.0.0.1:6379能通,r代表次數(shù)
./redis-cli -r 100 -i 1 info |grep used_memory_human //每秒輸出內(nèi)存使用量,輸100次,i代表執(zhí)行的時(shí)間間隔
./redis-cli -p 6379? -h 192.168.1.111 -a 12345678?
第五章 redis持久化
redis支持RDB和AOF兩種持久化機(jī)制,持久化可以避免因進(jìn)程退出而造成數(shù)據(jù)丟失;
????? 5.1RDB持久化把當(dāng)前進(jìn)程數(shù)據(jù)生成快照(.rdb)文件保存到硬盤的過(guò)程,有手動(dòng)觸發(fā)和自動(dòng)觸發(fā)
??????? 手動(dòng)觸發(fā)有save和bgsave兩命令
???????? save命令:阻塞當(dāng)前Redis,直到RDB持久化過(guò)程完成為止,若內(nèi)存實(shí)例比較大會(huì)造成長(zhǎng)時(shí)間阻塞,線上環(huán)境不建議用它
???????? bgsave命令:redis進(jìn)程執(zhí)行fork操作創(chuàng)建子線程,由子線程完成持久化,阻塞時(shí)間很短(微秒級(jí)),是save的優(yōu)化,在執(zhí)行redis-cli shutdown關(guān)閉redis服務(wù)時(shí),如果沒(méi)有開啟AOF持久化,自動(dòng)執(zhí)行bgsave;
???????? 顯然bgsave是對(duì)save的優(yōu)化。
5.2RDB文件的操作
?? 命令:config set dir /usr/local? //設(shè)置rdb文件保存路徑
?? 備份:bgsave? //將dump.rdb保存到usr/local下
?? 恢復(fù):將dump.rdb放到redis安裝目錄與redis.conf同級(jí)目錄,重啟redis即可
?? 優(yōu)點(diǎn):1,壓縮后的二進(jìn)制文,適用于備份、全量復(fù)制,用于災(zāi)難恢復(fù)
???????? 2,加載RDB恢復(fù)數(shù)據(jù)遠(yuǎn)快于AOF方式
?? 缺點(diǎn):1,無(wú)法做到實(shí)時(shí)持久化,每次都要?jiǎng)?chuàng)建子進(jìn)程,頻繁操作成本過(guò)高
???????? 2,保存后的二進(jìn)制文件,存在老版本不兼容新版本rdb文件的問(wèn)題?????????
5.3AOF持久化
? 針對(duì)RDB不適合實(shí)時(shí)持久化,redis提供了AOF持久化方式來(lái)解決
? 開啟:redis.conf設(shè)置:appendonly yes? (默認(rèn)不開啟,為no)
? 默認(rèn)文件名:appendfilename "appendonly.aof"??
????? 流程說(shuō)明:1,所有的寫入命令(set hset)會(huì)append追加到aof_buf緩沖區(qū)中
???????? 2,AOF緩沖區(qū)向硬盤做sync同步
???????? 3,隨著AOF文件越來(lái)越大,需定期對(duì)AOF文件rewrite重寫,達(dá)到壓縮
??? ?????4,當(dāng)redis服務(wù)重啟,可load加載AOF文件進(jìn)行恢復(fù)
AOF持久化流程:命令寫入(append),文件同步(sync),文件重寫(rewrite),重啟加載(load)
redis的AOF配置詳解:
appendonly yes???? //啟用aof持久化方式
# appendfsync always //每收到寫命令就立即強(qiáng)制寫入磁盤,最慢的,但是保證完全的持久化,不推薦使用
appendfsync everysec //每秒強(qiáng)制寫入磁盤一次,性能和持久化方面做了折中,推薦
# appendfsync no??? //完全依賴os,性能最好,持久化沒(méi)保證(操作系統(tǒng)自身的同步)
no-appendfsync-on-rewrite? yes? //正在導(dǎo)出rdb快照的過(guò)程中,要不要停止同步aof
auto-aof-rewrite-percentage 100? //aof文件大小比起上次重寫時(shí)的大小,增長(zhǎng)率100%時(shí),重寫
auto-aof-rewrite-min-size 64mb?? //aof文件,至少超過(guò)64M時(shí),重寫
如何從AOF恢復(fù)?
1. 設(shè)置appendonly yes;
2. 將appendonly.aof放到dir參數(shù)指定的目錄;
3. 啟動(dòng)Redis,Redis會(huì)自動(dòng)加載appendonly.aof文件。
redis重啟時(shí)恢復(fù)加載AOF與RDB順序及流程:
1,當(dāng)AOF和RDB文件同時(shí)存在時(shí),優(yōu)先加載
2,若關(guān)閉了AOF,加載RDB文件
3,加載AOF/RDB成功,redis重啟成功
4,AOF/RDB存在錯(cuò)誤,redis啟動(dòng)失敗并打印錯(cuò)誤信息
5.4 Redis 4.0 混合持久化
重啟 Redis 時(shí)不使用 rdb 來(lái)恢復(fù)內(nèi)存狀態(tài),就會(huì)丟失大量數(shù)據(jù)。
使用 AOF 日志重放相對(duì)rdb要慢很多,redis重啟就會(huì)非常慢
Redis 4.0 帶來(lái)了一個(gè)新的持久化選項(xiàng)——混合持久化。將 rdb 文件的內(nèi)容和增量的 AOF 日志文件存在一起。這里的 AOF 日志不再是全量的日志,而是自持久化開始到持久化結(jié)束的這段時(shí)間發(fā)生的增量 AOF 日志,通常這部分 AOF 日志很小。
?Redis 重啟的時(shí)先加載 rdb ,再重放增量 AOF 日志。比起以前的?AOF 全量文件重放,重啟效率因此得到大幅提升。
第六章?redis主從復(fù)制
6.1方式:
- 1.新增redis6380.conf, 加入? slaveof 192.168.1.111 6379,? 在6379啟動(dòng)完后再啟6380,完成配置;
- 2.redis-server --slaveof 192.168.1.111 6379
6.2相關(guān)命令:
- 查看狀態(tài):info replication
- 斷開主從復(fù)制:在slave節(jié)點(diǎn),執(zhí)行6380:>slaveof no one
- 斷開后再變成主從復(fù)制:6380:> slaveof 127.0.0.1 6379
- 數(shù)據(jù)較重要的節(jié)點(diǎn),主從復(fù)制時(shí)使用密碼驗(yàn)證: requirepass
- 從節(jié)點(diǎn)建議用只讀模式slave-read-only=yes, 若從節(jié)點(diǎn)修改數(shù)據(jù),主從數(shù)據(jù)不一致??????
- 傳輸延遲:主從一般部署在不同機(jī)器上,復(fù)制時(shí)存在網(wǎng)絡(luò)延時(shí)問(wèn)題,redis提供repl-disable-tcp-nodelay參數(shù)決定是否關(guān)閉TCP_NODELAY,默認(rèn)為關(guān)閉
6.3注意事項(xiàng):
參數(shù)關(guān)閉時(shí):
???? 無(wú)論大小都會(huì)及時(shí)發(fā)布到從節(jié)點(diǎn),占帶寬,適用于主從網(wǎng)絡(luò)好的場(chǎng)景,
參數(shù)啟用時(shí):
???? 主節(jié)點(diǎn)合并所有數(shù)據(jù)成TCP包節(jié)省帶寬,默認(rèn)為40毫秒發(fā)一次,取決于內(nèi)核,主從的同步延遲40毫秒,適用于網(wǎng)絡(luò)環(huán)境復(fù)雜或帶寬緊張,如跨機(jī)房
6.4Redis主從拓?fù)?#xff1a;
一主一從:用于主節(jié)點(diǎn)故障轉(zhuǎn)移從節(jié)點(diǎn),當(dāng)主節(jié)點(diǎn)的“寫”命令并發(fā)高且需要持久化,可以只在從節(jié)點(diǎn)開啟AOF(主節(jié)點(diǎn)不需要)
一主多從:針對(duì)“讀”較多的場(chǎng)景,“讀”由多個(gè)從節(jié)點(diǎn)來(lái)分擔(dān),但節(jié)點(diǎn)越多,主節(jié)點(diǎn)同步到多節(jié)點(diǎn)的次數(shù)也越多,影響帶寬,也加重主節(jié)點(diǎn)的穩(wěn)定
樹狀主從:一主多從的缺點(diǎn)(主節(jié)點(diǎn)推送次數(shù)多壓力大)可用些方案解決,
????????? 主節(jié)點(diǎn)只推送一次數(shù)據(jù)到從節(jié)點(diǎn)1,再由從節(jié)點(diǎn)2推送到11,減輕主節(jié)點(diǎn)推送的壓力
6.5復(fù)制原理:
執(zhí)行slave master port后,
與主節(jié)點(diǎn)連接,同步主節(jié)點(diǎn)的數(shù)據(jù),6380:>info replication:查看主從及同步信息
6.6數(shù)據(jù)同步:
redis 2.8版本以上使用psync命令完成同步,過(guò)程分“全量”與“部分”復(fù)制
全量復(fù)制:
???? 一般用于初次復(fù)制場(chǎng)景(第一次建立SLAVE后全量)
部分復(fù)制:
??? 網(wǎng)絡(luò)出現(xiàn)問(wèn)題,從節(jié)占再次連主時(shí),主節(jié)點(diǎn)補(bǔ)發(fā)缺少的數(shù)據(jù),每次數(shù)據(jù)增加同步
心跳:
???? 主從有長(zhǎng)連接心跳,主節(jié)點(diǎn)默認(rèn)每10S向從節(jié)點(diǎn)發(fā)ping命令,repl-ping-slave-period控制發(fā)送頻率
6.7 主從的缺點(diǎn):
1,主從復(fù)制,若主節(jié)點(diǎn)出現(xiàn)問(wèn)題,則不能提供服務(wù),需要人工修改配置將從變主
2,主從復(fù)制主節(jié)點(diǎn)的寫能力單機(jī),能力有限
3,單機(jī)節(jié)點(diǎn)的存儲(chǔ)能力也有限
6.8?主從故障如何故障轉(zhuǎn)移
??? A,主節(jié)點(diǎn)(master)故障,從節(jié)點(diǎn)slave-1端執(zhí)行 slaveof no one后變成新主節(jié)點(diǎn);
??? B,其它的節(jié)點(diǎn)成為新主節(jié)點(diǎn)的從節(jié)點(diǎn),并從新節(jié)點(diǎn)復(fù)制數(shù)據(jù);
??? C,需要人工干預(yù),無(wú)法實(shí)現(xiàn)高可用。
第七章?部署模式
7.1單節(jié)點(diǎn)模式
7.2主從模式
提供高性能的緩存服務(wù)和數(shù)據(jù)高可靠。
主從架構(gòu)-雙副本:
? 主節(jié)點(diǎn)提供日常服務(wù)訪問(wèn),從節(jié)點(diǎn)提供HA高可用,當(dāng)主節(jié)點(diǎn)發(fā)生故障,系統(tǒng)會(huì)自動(dòng)在30秒內(nèi)切換至從節(jié)點(diǎn),保證業(yè)務(wù)平穩(wěn)運(yùn)行。
可靠性
-
主從節(jié)點(diǎn)位于不同物理機(jī)。主節(jié)點(diǎn)對(duì)外提供寫入訪問(wèn)。當(dāng)主節(jié)點(diǎn)出現(xiàn)故障,HA系統(tǒng)會(huì)自動(dòng)進(jìn)行主從切換,保證業(yè)務(wù)平穩(wěn)運(yùn)行。
-
默認(rèn)開啟數(shù)據(jù)持久化功能。支持?jǐn)?shù)據(jù)備份功能,用戶可以針對(duì)備份集回滾實(shí)例或者克隆實(shí)例,有效地解決數(shù)據(jù)誤操作等問(wèn)題。
使用場(chǎng)景
-
Redis作為持久化數(shù)據(jù)存儲(chǔ)使用的業(yè)務(wù)標(biāo)準(zhǔn)版提供持久化機(jī)制及備份恢復(fù)機(jī)制,極大地保證數(shù)據(jù)可靠性。
-
單個(gè)Redis性能壓力可控的業(yè)務(wù)由于Redis原生采用單線程機(jī)制,性能在10萬(wàn)QPS以下的業(yè)務(wù)建議使用。如果需要更高的性能要求,請(qǐng)選用集群版本。
-
Redis命令相對(duì)簡(jiǎn)單,排序、計(jì)算類命令較少的業(yè)務(wù)由于Redis的單線程機(jī)制,CPU會(huì)成為主要瓶頸。如排序、計(jì)算類較多的業(yè)務(wù)建議選用集群版配置。
主從架構(gòu)-單副本:
可以在沒(méi)有數(shù)據(jù)可靠性要求的純緩存場(chǎng)景充分發(fā)揮性能優(yōu)勢(shì)。
使用場(chǎng)景
-
純緩存類業(yè)務(wù)場(chǎng)景
單副本版本只有一個(gè)數(shù)據(jù)庫(kù)節(jié)點(diǎn),節(jié)點(diǎn)出現(xiàn)故障時(shí),系統(tǒng)會(huì)重新拉起一個(gè)Redis進(jìn)程(沒(méi)有數(shù)據(jù)),當(dāng)節(jié)點(diǎn)故障業(yè)務(wù)自動(dòng)切換完成后,應(yīng)用程序需要將數(shù)據(jù)重新預(yù)熱,以免對(duì)后端數(shù)據(jù)庫(kù)產(chǎn)生訪問(wèn)壓力沖擊。單副本架構(gòu)不能提供數(shù)據(jù)可靠性,如果發(fā)生節(jié)點(diǎn)故障,您需要重新對(duì)業(yè)務(wù)進(jìn)行預(yù)熱,因此,在對(duì)數(shù)據(jù)可靠性要求較高的敏感性業(yè)務(wù)中,建議選用雙副本架構(gòu)。
-
單個(gè)Redis性能壓力可控
由于Redis原生采用單線程機(jī)制,CPU為單核能力,性能在8萬(wàn)QPS的業(yè)務(wù)建議使用。如果需要更高的性能要求,請(qǐng)選用集群版配置。
-
Redis命令相對(duì)簡(jiǎn)單,排序、計(jì)算類命令較少
由于Redis的單線程機(jī)制,CPU為主要瓶頸。如排序、計(jì)算類較多的業(yè)務(wù)建議選用集群版配置。
7.3集群模式
? ? ? ?突破了redis自身單線程瓶頸,滿足大容量、高性能的業(yè)務(wù)需求。
集群版-雙副本:
7.4讀寫分離?
? ? ?提供高可用,高性能,靈活度高,解決熱點(diǎn)數(shù)據(jù)集中及高并發(fā)讀取的業(yè)務(wù)需求。節(jié)約用戶運(yùn)維成本。
? ? ? 針對(duì)讀多寫少的業(yè)務(wù)場(chǎng)景,提供高可用、高性能、靈活的讀寫分離服務(wù),滿足熱點(diǎn)數(shù)據(jù)集中及高并發(fā)讀取的業(yè)務(wù)需求,最大化地節(jié)約運(yùn)維成本。讀寫分離版主要由主備節(jié)點(diǎn)、只讀節(jié)點(diǎn)、Proxy(代理)節(jié)點(diǎn)和高可用系統(tǒng)組成。
7.5哨兵機(jī)制(sentinel)的高可用
原理:當(dāng)主節(jié)點(diǎn)出現(xiàn)故障時(shí),由Redis Sentinel自動(dòng)完成故障發(fā)現(xiàn)和轉(zhuǎn)移,并通知應(yīng)用方,實(shí)現(xiàn)高可用性。
哨兵機(jī)制-故障轉(zhuǎn)移流程A
A,由Sentinel節(jié)點(diǎn)定期監(jiān)控發(fā)現(xiàn)主節(jié)點(diǎn)是否出現(xiàn)了故障
sentinel會(huì)向master發(fā)送心跳PING來(lái)確認(rèn)master是否存活,如果master在“一定時(shí)間范圍”內(nèi)不回應(yīng)PONG 或者是回復(fù)了一個(gè)錯(cuò)誤消息,那么這個(gè)sentinel會(huì)主觀地(單方面地)認(rèn)為這個(gè)master已經(jīng)不可用了
B,當(dāng)主節(jié)點(diǎn)出現(xiàn)故障,此時(shí)假設(shè)3個(gè)Sentinel節(jié)點(diǎn)共同選舉了Sentinel3節(jié)點(diǎn)為領(lǐng)導(dǎo)者sentinel,負(fù)載處理主節(jié)點(diǎn)的故障轉(zhuǎn)移
C,由Sentinel3領(lǐng)導(dǎo)者節(jié)點(diǎn)執(zhí)行故障轉(zhuǎn)移,過(guò)程和主從復(fù)制一樣,但是自動(dòng)執(zhí)行
RedisSentinel如何安裝與部署
我們以3個(gè)Sentinel節(jié)點(diǎn)、2個(gè)從節(jié)點(diǎn)、1個(gè)主節(jié)點(diǎn)為例進(jìn)行安裝部署
安裝與部署1(先搭主從)
前提:
先搭建好一主兩從redis的主從復(fù)制,和之前復(fù)制的搭建一樣,搭建方式如下:
A主節(jié)點(diǎn)6379節(jié)點(diǎn)(/usr/local/bin/conf/redis6379.conf):
????? 修改 requirepass 12345678,注釋掉#bind 127.0.0.1
B從節(jié)點(diǎn)redis6380.conf和redis6381.conf:
????? 修改 requirepass 12345678 ,注釋掉#bind 127.0.0.1,
????? 加上masterauth 12345678 ,加上slaveof 127.0.0.1 6379
注意:當(dāng)主從起來(lái)后,主節(jié)點(diǎn)可讀寫,從節(jié)點(diǎn)只可讀不可寫
哨兵機(jī)制核心配置
redis sentinel哨兵機(jī)制配置(也是3個(gè)節(jié)點(diǎn)):
?? /usr/local/bin/conf/sentinel_26379.conf?
?? /usr/local/bin/conf/sentinel_26380.conf
?? /usr/local/bin/conf/sentinel_26381.conf
將三個(gè)文件的端口改成: 26379?? 26380?? 26381
sentinel monitor mymaster 192.168.1.111 6379 2? //監(jiān)聽主節(jié)點(diǎn)6379
sentinel auth-pass mymaster 12345678???? //連接主節(jié)點(diǎn)時(shí)的密碼
三個(gè)配置除端口外,其它一樣
配完此腳本,哨兵機(jī)制可正常啟動(dòng)運(yùn)行。
哨兵其它配置
sentinel monitor mymaster 192.168.1.111 6379 2? //監(jiān)控主節(jié)點(diǎn)的IP地址端口
sentinel auth-pass mymaster 12345678? //sentinel連主節(jié)點(diǎn)的密碼
sentinel config-epoch mymaster 2????? //執(zhí)行故障轉(zhuǎn)移時(shí), 最多可以有多少個(gè)從節(jié)點(diǎn)同時(shí)對(duì)新的主節(jié)點(diǎn)進(jìn)行數(shù)據(jù)同步
sentinel leader-epoch mymaster 2
sentinel failover-timeout mymaster 180000 //故障轉(zhuǎn)移超時(shí)時(shí)間180s,???????????????????????????
??? a,如果轉(zhuǎn)移超時(shí)失敗,下次轉(zhuǎn)移時(shí)時(shí)間為之前的2倍;
??? b,從節(jié)點(diǎn)變主節(jié)點(diǎn)時(shí),從節(jié)點(diǎn)執(zhí)行slaveof no one命令一直失敗的話,當(dāng)時(shí)間超過(guò)180S時(shí),則故障轉(zhuǎn)移失敗
??? c,從節(jié)點(diǎn)復(fù)制新主節(jié)點(diǎn)時(shí)間超過(guò)180S轉(zhuǎn)移失敗
sentinel down-after-milliseconds mymaster 300000//sentinel節(jié)點(diǎn)定期向主節(jié)點(diǎn)ping命令
哨兵機(jī)制啟動(dòng)
?????? 啟動(dòng)sentinel服務(wù):
??????????? ./redis-sentinel conf/sentinel_26379.conf &
??????????? ./redis-sentinel conf/sentinel_26380.conf &
??????????? ./redis-sentinel conf/sentinel_26381.conf &
RedisSentinel節(jié)點(diǎn)測(cè)試
測(cè)試:kill -9 6379? 殺掉6379的redis服務(wù)
看日志是分配6380 還是6381做為主節(jié)點(diǎn),當(dāng)6379服務(wù)再啟動(dòng)時(shí),已變成從節(jié)點(diǎn)
假設(shè)6380升級(jí)為主節(jié)點(diǎn):
進(jìn)入6380>info replication????
???????? role:master
打開sentinel_26379.conf等三個(gè)配置,
???? sentinel monitor mymaster 192.168.1.111 6380 2 //有2個(gè)sentinel認(rèn)為master下線
打開redis6379.conf等三個(gè)配置, slaveof 127.0.0.1 6380,也變成了6380
注意:生產(chǎn)環(huán)境建議讓redis Sentinel部署到不同的物理機(jī)上。
坑點(diǎn):sentinel monitor mymaster 192.168.1.111 6379 2
???? //切記將IP不要寫成127.0.0.1
不然使用JedisSentinelPool取jedis連接的時(shí)候會(huì)變成取127.0.0.1 6379的錯(cuò)誤地址
RedisSentinel如何監(jiān)控2個(gè)redis主節(jié)點(diǎn)呢?
我們以3個(gè)Sentinel節(jié)點(diǎn)、2個(gè)從節(jié)點(diǎn)、1個(gè)主節(jié)點(diǎn)為例進(jìn)行安裝部署
原配置加上一句:sentinel monitor mymasterB 192.168.1.112 6379 2
?部署建議
a,sentinel節(jié)點(diǎn)應(yīng)部署在多臺(tái)物理機(jī)(線上環(huán)境)
b,至少三個(gè)且奇數(shù)個(gè)sentinel節(jié)點(diǎn)
c,3個(gè)sentinel可同時(shí)監(jiān)控一個(gè)主節(jié)點(diǎn)或多個(gè)主節(jié)點(diǎn),當(dāng)監(jiān)聽N個(gè)主節(jié)點(diǎn)較多時(shí),如果sentinel出現(xiàn)異常,會(huì)對(duì)多個(gè)主節(jié)點(diǎn)有影響,同時(shí)還會(huì)造成sentinel節(jié)點(diǎn)產(chǎn)生過(guò)多的網(wǎng)絡(luò)連接,一般線上建議還是, 3個(gè)sentinel監(jiān)聽一個(gè)主節(jié)點(diǎn)
哨兵的API
?命令:redis-cli -p 26379? //進(jìn)入哨兵的命令模式,使用redis-cli進(jìn)入
? 26379> sentinel masters或sentinel master mymaster
? 26379> sentinel slaves mymaster
? 26379> sentinel sentinels mymaster //查sentinel節(jié)點(diǎn)集合(不包括當(dāng)前26379)
? 26379> sentinel failover mymaster //對(duì)主節(jié)點(diǎn)強(qiáng)制故障轉(zhuǎn)移,沒(méi)和其它節(jié)點(diǎn)協(xié)商
./redis-cli -p 26380 shutdown //關(guān)閉
?客戶端連接(redis-sentinel例子工程)
遠(yuǎn)程客戶端連接時(shí),要打開protected-mode no
?????
在使用工程redis-sentinel,調(diào)用jedis查詢的流程如下:
???? 1,將三個(gè)sentinel的IP和端口 加入JedisSentinelPool
???? 2,根據(jù)IP和地址創(chuàng)建JedisSentinelPool池對(duì)象
???? 3,在這個(gè)對(duì)象創(chuàng)建完后,此時(shí)該對(duì)象已把redis的主節(jié)點(diǎn)
第八章?redis集群高可用
RedisCluster是Redis的分布式解決方案,在3.0版本后推出的方案,有效地解決了Redis分布式的需求,當(dāng)遇到單機(jī)內(nèi)存、并發(fā)等瓶頸時(shí),可使用此方案來(lái)解決這些問(wèn)題
8.1?分區(qū)規(guī)則
常見的分區(qū):
- 規(guī)則哈希分區(qū)
- 順序分區(qū),
redis集群使用了哈希分區(qū),順序分區(qū)暫用不到,不做具體說(shuō)明;
?RedisCluster采用了哈希分區(qū)的“虛擬槽分區(qū)”方式(哈希分區(qū)分節(jié)點(diǎn)取余、一致性哈希分區(qū)和虛擬槽分區(qū))。
根據(jù)hash值取模,對(duì)應(yīng)到虛擬槽上(范圍)。比如:server1:[1-n1],server2:[n1-n2],server3:[n2-n3]
插槽:集群內(nèi)部會(huì)將所有的key映射到16384個(gè)插槽中,集群中的每個(gè)數(shù)據(jù)庫(kù)實(shí)例負(fù)責(zé)其中部分的插槽的讀寫。
鍵與插槽的關(guān)系:
Redis會(huì)將key的有效部分,使用CRC16算法計(jì)算出散列值,然后對(duì)16384取余數(shù),從
而把key分配到插槽中。鍵名的有效部分規(guī)則是:
1:如果鍵名包含{},那么有效部分就是{}中的值
2:否則就是取整個(gè)鍵名
移動(dòng)已分配的插槽:
獲取插槽對(duì)應(yīng)的節(jié)點(diǎn):
9.總結(jié)
Redis要達(dá)到高性能需要做到:
1.Value盡可能的小。當(dāng)value太大時(shí),比如json數(shù),幾十kb,或者上mb的數(shù)據(jù)。大的數(shù)據(jù)量在帶寬的限制下直接的效果就是QPS驟降,跌到幾百都毫不意外。而且,redis單線程這一點(diǎn),導(dǎo)致某個(gè)大的value訪問(wèn)會(huì)阻塞所有其他的操作。
2.使用Pipeline或Lua Script。Redis一般被用做網(wǎng)絡(luò)服務(wù)。所有的請(qǐng)求都是跨網(wǎng)絡(luò)進(jìn)行的。所以TCP Round Trip的長(zhǎng)短對(duì)Redis的性能表現(xiàn)很重要。盡量減少Round Trip可以有效的提高吞吐。所以,通常的優(yōu)化方法是使用Pipeline,使得客戶端可以一次性把一組Redis命令發(fā)給Redis Server;或者預(yù)先在Redis Server中定義Lua Script,使用時(shí)直接調(diào)用。但無(wú)論是Pipeline還是Lua Script,都會(huì)受到業(yè)務(wù)需求的制約——不是所有業(yè)務(wù)都適合用Pipeline/Lua Script的。
3.網(wǎng)路一定要快。redis性能一般情況都會(huì)被網(wǎng)絡(luò)影響。
4.不開啟RDB或者AOF。開啟任何一種持久化方案都會(huì)影響Redis的性能表現(xiàn)。因?yàn)殚_啟持久化會(huì)有同步磁盤的操作。
注意:
1.redis適合一些不太在乎數(shù)據(jù)丟失的場(chǎng)景,如果針對(duì)的數(shù)據(jù)是絕對(duì)不能有失的,那么還是要使用ACID的數(shù)據(jù)庫(kù)。
2.隊(duì)列在redis5.0版本之前最好不要使用,因?yàn)檫€不夠完善,即使是5.0版本的Stream Date Type。實(shí)現(xiàn)了類似于Kafka的append only數(shù)據(jù)結(jié)構(gòu)和API。不過(guò)很可能要到5.2才能在生產(chǎn)中使用(2019年年底),而且目前redis的隊(duì)列還沒(méi)有經(jīng)過(guò)市場(chǎng)的檢驗(yàn)。
3.在?事務(wù)這一塊,redis沒(méi)有ACID事務(wù),他的原子性只針對(duì)于服務(wù)端,對(duì)于使用redis的客戶端則需要其他的處理來(lái)保證線程安全,redis持久化沒(méi)有提供相互節(jié)點(diǎn)同步數(shù)據(jù)的方式。
所以redis適合的場(chǎng)景:
- 共享Cache ,不怕丟數(shù)據(jù),丟了可以從DB中reload;
- 共享Session ,不怕丟數(shù)據(jù),丟了可以重新登錄;
- batch job的中間結(jié)果。不怕丟數(shù)據(jù),丟了重新跑job就可以了;
- 一些簡(jiǎn)單數(shù)據(jù)的存儲(chǔ),低頻改動(dòng),但是會(huì)被頻繁讀取。比如首頁(yè)推薦的產(chǎn)品列表。但此時(shí)必須增加HA的防護(hù),sentinel、cluster或者自定義的機(jī)制都可以;
- 一些更加復(fù)雜存儲(chǔ)的building block,比如分布式鎖,此時(shí)需要多節(jié)點(diǎn)來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的quorum
10. 布隆過(guò)濾器
? 描述:不怎么精確的set,特點(diǎn)是高效地插入和查詢,可以用來(lái)告訴你 “某樣?xùn)|西一定不存在或者可能存在”。相比于傳統(tǒng)的 List、Set、Map 等數(shù)據(jù)結(jié)構(gòu),它更高效、占用空間更少,但是缺點(diǎn)是其返回的結(jié)果是概率性的,而不是確切的,可能誤判。
? 用處:進(jìn)行精度控制。比如緩存穿透,使用布隆過(guò)濾器。
? 原理:?本質(zhì)是一個(gè)bit數(shù)組,通過(guò)多次hash產(chǎn)生復(fù)數(shù)個(gè)下標(biāo),然后把bit數(shù)組中的對(duì)應(yīng)下標(biāo)的值從0變?yōu)?。
提高精度方法:1.擴(kuò)容bit數(shù)組的長(zhǎng)度,2.增加hash函數(shù),這樣可以有更多的下標(biāo)。
redisBloom: redis的module插件。
11. 策略?
11.1. 過(guò)期策略:?
將一個(gè)過(guò)期的鍵刪除的三種策略:
- 1.定時(shí)刪除(默認(rèn)會(huì)每秒進(jìn)行十次過(guò)期掃描(100ms一次))
????????為每個(gè)鍵設(shè)置一個(gè)定時(shí)器,一旦過(guò)期時(shí)間到了,則將鍵刪除。這種策略對(duì)內(nèi)存很友好,但是對(duì) CPU 不友好,因?yàn)槊總€(gè)定時(shí)器都會(huì)占用一定的 CPU 資源。設(shè)置了過(guò)期時(shí)間的key會(huì)放在過(guò)期字典中。通過(guò)貪心策略來(lái)獲取過(guò)期字典中的key。
? ? ? ? ?1.從過(guò)期字典中隨機(jī) n?個(gè) key;
? ? ? ? ?2.刪除這 n個(gè) key 中已經(jīng)過(guò)期的 key;
? ? ? ? 3.如果過(guò)期的 key 比率超過(guò) 1/4,那就重復(fù)步驟 1;
- ?2.惰性刪除(獲取key時(shí)檢查,如果過(guò)期就刪除)
??????????不管鍵有沒(méi)有過(guò)期都不主動(dòng)刪除,等到每次去獲取鍵時(shí)再判斷是否過(guò)期,如果過(guò)期就刪除該鍵,否則返回鍵對(duì)應(yīng)的值。這種策略對(duì)內(nèi)存不夠友好,可能會(huì)浪費(fèi)很多內(nèi)存。
- 3.定期掃描:
????????系統(tǒng)每隔一段時(shí)間就定期掃描一次,發(fā)現(xiàn)過(guò)期的鍵就進(jìn)行刪除。這種策略相對(duì)來(lái)說(shuō)是上面兩種策略的折中方案。需要注意的是這個(gè)定期的頻率要結(jié)合實(shí)際情況掌控好,使用這種方案有一個(gè)缺陷就是可能會(huì)出現(xiàn)已經(jīng)過(guò)期的鍵也被返回。
在 Redis 當(dāng)中,其選擇的是策略 2 和策略 3 的綜合使用。不過(guò) Redis 的定期掃描只會(huì)掃描設(shè)置了過(guò)期時(shí)間的鍵,因?yàn)樵O(shè)置了過(guò)期時(shí)間的鍵 Redis 會(huì)單獨(dú)存在,所以不會(huì)出現(xiàn)掃描所有鍵的情況:
typedef struct redisDb {dict *dict; //所有的鍵值對(duì)dict *expires; //設(shè)置了過(guò)期時(shí)間的鍵值對(duì)dict *blocking_keys; //被阻塞的 key,如客戶端執(zhí)行 BLPOP 等阻塞指令時(shí)dict *watched_keys; //WATCHED keysint id; //Database ID//... 省略了其他屬性} redisDb;11.2. 內(nèi)存回收
????????使用redis服務(wù)時(shí),很多情況下某些key對(duì)只會(huì)在特定的時(shí)間內(nèi)有效,為了防止這種類型的數(shù)據(jù)局一直占用內(nèi)存,可以給key設(shè)置有效期。
redis中可以通過(guò)4個(gè)獨(dú)立的命令來(lái)給一個(gè)key設(shè)置過(guò)期時(shí)間:
- expire key ttl:將 key 值的過(guò)期時(shí)間設(shè)置為 ttl 秒。
- pexpire key ttl:將 key 值的過(guò)期時(shí)間設(shè)置為 ttl 毫秒。
- expireat key timestamp:將 key 值的過(guò)期時(shí)間設(shè)置為指定的 timestamp 秒數(shù)。
- pexpireat key timestamp:將 key 值的過(guò)期時(shí)間設(shè)置為指定的 timestamp 毫秒數(shù)。 PS:不管使用哪一個(gè)命令,最終 Redis 底層都是使用 pexpireat 命令來(lái)實(shí)現(xiàn)的。
另外,set 等命令也可以設(shè)置 key 的同時(shí)加上過(guò)期時(shí)間,這樣可以保證設(shè)值和設(shè)過(guò)期時(shí)間的原子性。
設(shè)置了有效期后,可以通過(guò) ttl 和 pttl 兩個(gè)命令來(lái)查詢剩余過(guò)期時(shí)間(如果未設(shè)置過(guò)期時(shí)間則下面兩個(gè)命令返回 -1,
如果設(shè)置了一個(gè)非法的過(guò)期時(shí)間,則都返回 -2):
- ttl key 返回 key 剩余過(guò)期秒數(shù)。
- pttl key 返回 key 剩余過(guò)期的毫秒數(shù)。
當(dāng) Redis 當(dāng)中所有的鍵都沒(méi)有過(guò)期,而且此時(shí)內(nèi)存滿了,那么客戶端繼續(xù)執(zhí)行 set 等命令時(shí),?Redis 當(dāng)中提供了不同的淘汰策略來(lái)處理這種場(chǎng)景。
首先 Redis 提供了一個(gè)參數(shù) maxmemory 來(lái)配置 Redis 最大使用內(nèi)存:
maxmemory <bytes>或者也可以通過(guò)命令 config set maxmemory 1GB 來(lái)動(dòng)態(tài)修改。
如果沒(méi)有設(shè)置該參數(shù),那么在 32 位的操作系統(tǒng)中 Redis 最多使用 3GB 內(nèi)存,而在 64 位的操作系統(tǒng)中則不作限制。
Redis 中提供了 8 種淘汰策略,可以通過(guò)參數(shù) maxmemory-policy 進(jìn)行配置:
8種內(nèi)存淘汰策略:
- noeviction(默認(rèn)):當(dāng)內(nèi)存使用超過(guò)配置的時(shí)候會(huì)返回錯(cuò)誤,不會(huì)驅(qū)逐任何鍵,讀操作命令可以正常執(zhí)行;不做任何處理,直接報(bào)錯(cuò)。
- volatile-lru:對(duì)設(shè)置了過(guò)期時(shí)間的記錄,驅(qū)逐最久沒(méi)有使用的鍵;
- volatile-ttl:對(duì)設(shè)置了過(guò)期時(shí)間的記錄,驅(qū)逐馬上就要過(guò)期的鍵 ;
- volatile-lfu:對(duì)設(shè)置了過(guò)期時(shí)間的記錄,驅(qū)逐使用頻率最少的鍵;
- volatile-random:對(duì)設(shè)置了過(guò)期時(shí)間的記錄,隨機(jī)刪除設(shè)置了過(guò)期時(shí)間的key;
- allkeys-lfu:對(duì)于所有記錄,驅(qū)逐使用頻率最少的鍵;
- allkeys-lru:對(duì)于所有記錄,所有key使用LRU算法淘汰,驅(qū)逐最久沒(méi)有使用的鍵;
- allkeys-random:對(duì)于所有記錄,所有key隨機(jī)刪除;
根據(jù)以上算法刪除設(shè)置了過(guò)期時(shí)間的key,直到騰出可用空間。如果沒(méi)有可刪除的key,且內(nèi)存還是不夠用時(shí),則報(bào)錯(cuò)。
PS:淘汰策略也可以直接使用命令 config set maxmemory-policy <策略> 來(lái)
11.3. LRU(最近最少使用)
最長(zhǎng)時(shí)間未被使用。使用雙向鏈表。
LinkedHashMap模擬LRU算法。
removeEldestEntry(Map.Entry<K,V> eldest)方法,可以刪除最久未訪問(wèn)的結(jié)點(diǎn)。
當(dāng)accessOrder為false時(shí)(默認(rèn)情況),linkedHashMap只會(huì)按插入順序維護(hù)雙向鏈表。而開啟了accessOrder之后,linkedHashMap就會(huì)把每一次對(duì)結(jié)點(diǎn)的訪問(wèn)也作為標(biāo)準(zhǔn)來(lái)進(jìn)行排序。也就是說(shuō),在每次插入結(jié)點(diǎn)/訪問(wèn)結(jié)點(diǎn)的時(shí)候,都會(huì)將相應(yīng)結(jié)點(diǎn)移動(dòng)到雙向鏈表的尾部,從而達(dá)到按訪問(wèn)順序進(jìn)行排序的目的。
LRU 全稱為:Least Recently Used。即:最近最長(zhǎng)時(shí)間未被使用。這個(gè)主要針對(duì)的是使用時(shí)間。
Redis 改進(jìn)后的 LRU 算法 在 Redis 當(dāng)中,并沒(méi)有采用傳統(tǒng)的 LRU 算法,因?yàn)閭鹘y(tǒng)的 LRU 算法存在 2 個(gè)問(wèn)題:
- 需要額外的空間進(jìn)行存儲(chǔ)。
- 可能存在某些 key 值使用很頻繁,但是最近沒(méi)被使用,從而被 LRU 算法刪除。
為了避免以上 2 個(gè)問(wèn)題,Redis 當(dāng)中對(duì)傳統(tǒng)的 LRU 算法進(jìn)行了改造,通過(guò)抽樣的方式進(jìn)行刪除。
配置文件中提供了一個(gè)屬性 maxmemory_samples 5,默認(rèn)值就是 5,表示隨機(jī)抽取 5 個(gè) key 值,然后對(duì)這 5 個(gè) key 值按照 LRU 算法進(jìn)行刪除,
所以很明顯,key 值越大,刪除的準(zhǔn)確度越高。
對(duì)抽樣 LRU 算法和傳統(tǒng)的 LRU 算法,Redis 官網(wǎng)當(dāng)中有一個(gè)對(duì)比圖:
- 淺灰色帶是被刪除的對(duì)象。
- 灰色帶是未被刪除的對(duì)象。
- 綠色是添加的對(duì)象。
左上角第一幅圖代表的是傳統(tǒng) LRU 算法,可以看到,當(dāng)抽樣數(shù)達(dá)到 10 個(gè)(右上角),已經(jīng)和傳統(tǒng)的 LRU 算法非常接近了。
Redis 如何管理熱度數(shù)據(jù)
前面我們講述字符串對(duì)象時(shí),提到了 redisObject 對(duì)象中存在一個(gè) lru 屬性:
typedef struct redisObject {unsigned type:4;//對(duì)象類型(4 位=0.5 字節(jié))unsigned encoding:4;//編碼(4 位=0.5 字節(jié))unsigned lru:LRU_BITS;//記錄對(duì)象最后一次被應(yīng)用程序訪問(wèn)的時(shí)間(24 位=3 字節(jié))int refcount;//引用計(jì)數(shù)。等于 0 時(shí)表示可以被垃圾回收(32 位=4 字節(jié))void *ptr;//指向底層實(shí)際的數(shù)據(jù)存儲(chǔ)結(jié)構(gòu),如:SDS 等(8 字節(jié)) } robj;????????lru 屬性是創(chuàng)建對(duì)象的時(shí)候?qū)懭?#xff0c;對(duì)象被訪問(wèn)到時(shí)也會(huì)進(jìn)行更新。正常人的思路就是最后決定要不要?jiǎng)h除某一個(gè)鍵肯定是用當(dāng)前時(shí)間戳減去 lru,差值最大的就優(yōu)先被刪除。但是 Redis 里面并不是這么做的,Redis 中維護(hù)了一個(gè)全局屬性 lru_clock,這個(gè)屬性是通過(guò)一個(gè)全局函數(shù) serverCron
每隔 100 毫秒執(zhí)行一次來(lái)更新的,記錄的是當(dāng)前 unix 時(shí)間戳。
最后決定刪除的數(shù)據(jù)是通過(guò) lru_clock 減去對(duì)象的 lru 屬性而得出的。那么為什么 Redis 要這么做呢?直接取全局時(shí)間不是更準(zhǔn)確嗎?
這是因?yàn)檫@么做可以避免每次更新對(duì)象的 lru 屬性的時(shí)候可以直接取全局屬性,而不需要去調(diào)用系統(tǒng)函數(shù)來(lái)獲取系統(tǒng)時(shí)間,
從而提升效率(Redis 當(dāng)中有很多這種細(xì)節(jié)考慮來(lái)提升性能,可以說(shuō)是對(duì)性能盡可能的優(yōu)化到極致)。
不過(guò)這里還有一個(gè)問(wèn)題,我們看到,redisObject 對(duì)象中的 lru 屬性只有 24 位,24 位只能存儲(chǔ) 194 天的時(shí)間戳大小,一旦超過(guò) 194 天之后就會(huì)重新從 0 開始計(jì)算,所以這時(shí)候就可能會(huì)出現(xiàn),redisObject 對(duì)象中的 lru 屬性大于全局的 lru_clock 屬性的情況。
正因?yàn)槿绱?#xff0c;所以計(jì)算的時(shí)候也需要分為 2 種情況:
- 當(dāng)全局 lruclock > lru,則使用 lruclock - lru 得到空閑時(shí)間。
- 當(dāng)全局 lruclock < lru,則使用 lruclock_max(即 194 天) - lru + lruclock 得到空閑時(shí)間。
需要注意的是,這種計(jì)算方式并不能保證抽樣的數(shù)據(jù)中一定能刪除空閑時(shí)間最長(zhǎng)的。這是因?yàn)槭紫瘸^(guò) 194 天還不被使用的情況很少,
再次有 lruclock 第 2 輪繼續(xù)超過(guò) lru 屬性時(shí),計(jì)算才會(huì)出問(wèn)題。
比如對(duì)象 A 記錄的 lru 是 1 天,而 lruclock 第二輪都到 10 天了,這時(shí)候就會(huì)導(dǎo)致計(jì)算結(jié)果只有 10-1=9 天,實(shí)際上應(yīng)該是 194+10-1=203 天。
但是這種情況可以說(shuō)又是更少發(fā)生,所以說(shuō)這種處理方式是可能存在刪除不準(zhǔn)確的情況,但是本身這種算法就是一種近似的算法,所以并不會(huì)有太大影響。
11.4.?LFU(最近最不常用)
一定時(shí)間內(nèi),訪問(wèn)次數(shù)最少的。
?LFU 全稱為:Least Frequently Used。即:最近最少頻率使用,這個(gè)主要針對(duì)的是使用頻率。這個(gè)屬性也是記錄在 redisObject 中的 lru 屬性內(nèi)。
????????當(dāng)我們采用 LFU 回收策略時(shí),lru 屬性的高 16 位用來(lái)記錄訪問(wèn)時(shí)間(last decrement time:ldt,單位為分鐘),低 8 位用來(lái)記錄訪問(wèn)頻率(logistic counter:logc),簡(jiǎn)稱 counter。
????????訪問(wèn)頻次遞增 LFU 計(jì)數(shù)器每個(gè)鍵只有 8 位,它能表示的最大值是 255,所以 Redis 使用的是一種基于概率的對(duì)數(shù)器來(lái)實(shí)現(xiàn) counter 的遞增。
?給定一個(gè)舊的訪問(wèn)頻次,當(dāng)一個(gè)鍵被訪問(wèn)時(shí),counter 按以下方式遞增:
- 提取 0 和 1 之間的隨機(jī)數(shù) R。
- counter - 初始值(默認(rèn)為 5),得到一個(gè)基礎(chǔ)差值,如果這個(gè)差值小于 0,則直接取 0,為了方便計(jì)算,把這個(gè)差值記為 baseval。
- 概率 P 計(jì)算公式為:1/(baseval * lfu_log_factor + 1)。
- 如果 R < P 時(shí),頻次進(jìn)行遞增(counter++)。
公式中的 lfu_log_factor 稱之為對(duì)數(shù)因子,默認(rèn)是 10 ,可以通過(guò)參數(shù)來(lái)進(jìn)行控制:
lfu_log_factor 10 下圖就是對(duì)數(shù)因子 lfu_log_factor 和頻次 counter 增長(zhǎng)的關(guān)系圖:
????????可以看到,當(dāng)對(duì)數(shù)因子 lfu_log_factor 為 100 時(shí),大概是 10M(1000 萬(wàn)) 次訪問(wèn)才會(huì)將訪問(wèn) counter 增長(zhǎng)到 255,而默認(rèn)的 10 也能支持到 1M(100 萬(wàn))次訪問(wèn) counter 才能達(dá)到 255 上限,這在大部分場(chǎng)景都是足夠滿足需求的。
訪問(wèn)頻次遞減
如果訪問(wèn)頻次 counter 只是一直在遞增,那么遲早會(huì)全部都到 255,也就是說(shuō) counter 一直遞增不能完全反應(yīng)一個(gè) key 的熱度的,
所以當(dāng)某一個(gè) key 一段時(shí)間不被訪問(wèn)之后,counter 也需要對(duì)應(yīng)減少。
counter 的減少速度由參數(shù) lfu-decay-time 進(jìn)行控制,默認(rèn)是 1,單位是分鐘。默認(rèn)值 1 表示:N 分鐘內(nèi)沒(méi)有訪問(wèn),counter 就要減 N。
lfu-decay-time 1 具體算法如下:
看起來(lái)這么復(fù)雜,其實(shí)計(jì)算公式就是一句話:取出當(dāng)前的時(shí)間戳和對(duì)象中的 lru 屬性進(jìn)行對(duì)比,計(jì)算出當(dāng)前多久沒(méi)有被訪問(wèn)到,比如計(jì)算得到的結(jié)果是 100 分鐘沒(méi)有被訪問(wèn),然后再去除配置參數(shù) lfu_decay_time,如果這個(gè)配置默認(rèn)為 1 也即是 100/1=100,代表 100 分鐘沒(méi)訪問(wèn),所以 counter 就減少 100。
12.多路復(fù)用
cpu 處理相比于 IO 可以忽略
每個(gè)客戶端建立連接時(shí),都需要服務(wù)端為其 創(chuàng)建 socket 套接字,建立連接
然后該客戶端的每個(gè)請(qǐng)求都要經(jīng)歷以下幾步:
(1)等待請(qǐng)求數(shù)據(jù)數(shù)據(jù)從客戶端發(fā)送過(guò)來(lái)
(2)將請(qǐng)求數(shù)據(jù)從內(nèi)核復(fù)制到用戶進(jìn)程的緩沖區(qū)(buffer)
(3)對(duì)請(qǐng)求數(shù)據(jù)進(jìn)行處理(對(duì)于 redis 而言,一般就是簡(jiǎn)單的 get/set)
由于操作簡(jiǎn)單+只涉及內(nèi)存,所以第(3)步的處理很簡(jiǎn)單、很快,主要時(shí)間耗在(1)步
? ? ?
總結(jié)
以上是生活随笔為你收集整理的Redis学习笔记·的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 电脑上个别按键失灵可能原因
- 下一篇: 更改MySQL密码并验证,及使用SQLy