1. 程式人生 > 實用技巧 >Redis詳解

Redis詳解

什麼是Redis?

概述:

Redis(Remote Dictionary Server ),即遠端字典服務,是一個開源的使用ANSI C語言編寫、支援網路、可基於記憶體亦可持久化的日誌型、Key-Value資料庫,並提供多種語言的API。


redis會週期性的把更新的資料寫入磁碟或者把修改操作寫入追加的記錄檔案,並且在此基礎上實現了
master-slave(主從)同步。
免費和開源!是當下最熱門的 NoSQL 技術之一!也被人們稱之為結構化資料庫!

Redis能幹嘛?

  1. 記憶體儲存,持久化,記憶體中是斷電既失,所以持久化很重要(rdb,aof)
  2. 效率高,可以用於快取記憶體
  3. 釋出訂閱系統
  4. 地圖資訊分析
  5. 計時器,計數器(瀏覽量)

Redis特性

  1. 多樣的資料型別
  2. 持久化
  3. 叢集
  4. 事務
  5. ....

Redis安裝

官網:https://redis.io/
中文網:http://www.redis.cn/
下載地址:linux連結

Windows安裝redis

解壓即可使用

Linux安裝redis

將redis上傳至Linux

解壓

tar -zxvf redis-6.0.6.tar.gz

安裝環境

進入redis目錄

yum install gcc-c++

make

make install 

發現出現錯誤

原因版本問題

解決方法

# 檢視gcc版本是否在5.3以上,centos7.6預設安裝4.8.5
gcc -v
# 升級gcc到5.3及以上,如下:
升級到gcc 9.3:
yum -y install centos-release-scl
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
scl enable devtoolset-9 bash
需要注意的是scl命令啟用只是臨時的,退出shell或重啟就會恢復原系統gcc版本。
如果要長期使用gcc 9.3的話:
 
echo "source /opt/rh/devtoolset-9/enable" >>/etc/profile
這樣退出shell重新開啟就是新版的gcc了
以下其他版本同理,修改devtoolset版本號即可。

執行完後再次執行
make
make install

將redis配置檔案。複製到我們當前目錄下

cp /usr/local/redis-6.0.6/redis.conf /usr/local/bin/redisconfig/

redis預設不是後臺啟動的,修改為後臺啟動

daemonize yes

啟動redis

通過指定的配置檔案啟動

redis-server  /usr/local/bin/redisconfig/redis.conf

執行客戶端

redis-cli -p 6379

檢視redis服務是否開啟

ps -ef |grep redis

測試效能

redis-benchmark 是一個壓力測試工具!
官方自帶的效能測試工具!
redis-benchmark 命令引數!

簡單測試

# 測試100個併發 100000個請求
redis-benchmark -h localhost -p 6379 -c 100 -n 100000


官方文件

http://www.redis.cn/commands.html

基礎的知識

redis預設有16個數據庫

預設是第0個數據庫

更換資料庫

select 資料庫 #切換資料庫
select 2

檢視資料庫大小

DBSIZE

檢視資料庫所有的key

keys *

清除當前資料庫

flushdb

清楚所有資料庫

flushall

Redis 是單執行緒的

明白Redis是很快的,官方表示,Redis是基於記憶體操作,CPU不是Redis效能瓶頸,Redis的瓶頸是根據 機器的記憶體和網路頻寬,既然可以使用單執行緒來實現,就使用單執行緒了!所有就使用了單執行緒了!

Redis 是C 語言寫的,官方提供的資料為 100000+ 的QPS,完全不比同樣是使用 key-vale的 Memecache差!

Redis 為什麼單執行緒還這麼快?
1、誤區1:高效能的伺服器一定是多執行緒的?
2、誤區2:多執行緒(CPU上下文會切換!)一定比單執行緒效率高! 先去CPU>記憶體>硬碟的速度要有所瞭解!
核心:redis 是將所有的資料全部放在記憶體中的,所以說使用單執行緒去操作效率就是高的,多執行緒 (CPU上下文會切換:耗時的操作!!!),對於記憶體系統來說,如果沒有上下文切換效率就是高 的!多次讀寫都是在一個CPU上的,在記憶體情況下,這個就是佳的方案!

五大資料型別


全段翻譯:
Redis 是一個開源(BSD許可)的,記憶體中的資料結構儲存系統,它可以用作資料庫、快取和訊息中間 件MQ。 它支援多種型別的資料結構,如 字串(strings), 雜湊(hashes), 列表(lists), 集合 (sets), 有序集合(sorted sets) 與範圍查詢, bitmaps, hyperloglogs 和 地理空間 (geospatial) 索引半徑查詢。 Redis 內建了 複製(replication),LUA指令碼(Lua scripting), LRU 驅動事件(LRU eviction),事務(transactions) 和不同級別的 磁碟持久化(persistence), 並通過 Redis哨兵(Sentinel)和自動 分割槽(Cluster)提供高可用性(high availability)。

我們現在講解的所有命令大家一定要全部記住,後面我們使用SpringBoot。Jedis,所有的方法就是 這些命令!
單點登入

Redis-Key

檢視所有的key

keys *

檢視key是否存在

EXISTS key

移除key

move key num
# num:個數

# 示例
move name 1

設定key的過期時間

EXPIRE key second
#示例: 
EXPIRE name 10
設定name的過期時間 10s

檢視key的過期時間

ttl key

檢視當前key的型別

type key

String字串型別

設定key的值

set key value

獲取key的值

get key

追加key的值

如果key不存在 就相當於 set key

APPEND key value

檢視key的值的長度

STRLEN key

自增自減的功能

#自增
incr key

#自減
decr key

# 自增多少個  num:自增個數
incrby key num
# 自減多少個
decrby key num 

字串範圍 range

GETRANGE key start end

#示例 擷取0-3個字串
GETRANGE key 0 3
# 獲取全部字串
GETRANGE key 0 -1

替換字串

SETRANGE key offset value

設定字串過期

# seconds 秒
setex key seconds value #(設定過期時間)
setnx key value #不存在設定(分散式鎖中常常用到)
#setnx key  如果這個key存在 建立失敗
#setnx key  如果不存在 建立成功 

一次性設定多個值

key 存在就不建立

 mset key value [key value ...]
 #示例
 mset k1 v1 k2 v2 k3 v3

# 設定多個值 要麼同時成功,要麼同時失敗  原子性操作
msetnx key value [key value ...]

設定物件

設定user:1物件 值為json字串來儲存一個物件

# set user:1{name:zhangsan,age:2}
mset user:1:name zhangsan user:1:age 2

先get後set命令

getset key value
#如果不存在,返回nill 設定值
#如果存在值,返回值,更新值


String類似的使用場景:value除了是我們的字串還可以是我們的數字!

  • 計數器
  • 統計多單位的數量
  • 粉絲數
  • 物件快取儲存

list(列表)

基本的資料型別,列表

在redis裡面,我們可以把list玩成 ,棧、佇列、阻塞佇列!
所有的list命令都是用l開頭的,Redis不區分大小命令

LPUSH 將一個值或者多個值,插入到列表頭部 (左)

LPUSH key value
127.0.0.1:6379> LPUSH name one
(integer) 1
127.0.0.1:6379> LPUSH name rwo
(integer) 2
127.0.0.1:6379> LPUSH name three # 獲取list中值
(integer) 3
(empty array)
127.0.0.1:6379> LRANGE name 0 3
1) "three"
2) "rwo"
3) "one"
127.0.0.1:6379> 

RPUSH 將一個值或者多個值,插入到列表位部 (右)

RPUSH key value

lpop &rpop 移除list的值

lpop key  #從最左邊移除一個元素
rpop key  #從最右邊移除一個元素

lindex 通過下標獲取list的值

lindex key index  #通過下標獲取list的值

llen 獲取list的長度

llen key

LREM 移除list指定的值

LREM key count element
count:移除幾個
#示例
LREM name 1 one

LTRIM 截斷

LTRIM key start stop

127.0.0.1:6379> lpush name hello1 hello2 hello3
(integer) 3
127.0.0.1:6379> LTRIM name 1 2
OK
127.0.0.1:6379> LRANGE name 0 -1
1) "hello2"
2) "hello1"
127.0.0.1:6379> 

rpoplpush 移動列表元素

rpoplpush source destination
#示例:
#把name列表最左邊的值移到myname最左邊
rpoplpush name myname

EXISTS 判斷列表存不存在

EXISTS key

lset指定列表的下標設定值(更新值)

如果值不存在就報錯

lset key index element

往list指定的元素前面或後面插入值

LINSERT key BEFORE|AFTER pivot element

小結

  • 他實際上是一個連結串列,before Node after , left,
  • right 都可以插入值 如果key 不存在,建立新的連結串列
  • 如果key存在,新增內容

Set(集合)

set中的值是不能重讀的!

新增set集合的值

sadd key member [member ...]

獲取set集合的值

SMEMBERS key

獲取set集合元素個數

SCARD key

移除set的元素

SREM key member [member ...]

隨機獲取set的元素

SRANDMEMBER key [count]

count:指定獲取幾個元素

隨機移除一個元素

spop key

將指定的set集合的元素移到另一個set集合中

smove source destination member

檢視兩個set集合中的不同的元素

SDIFF key [key ...]

key在前檢視誰

127.0.0.1:6379> sadd myset1 a b c 
(integer) 3
127.0.0.1:6379> sadd myset2 c d e 
(integer) 3
127.0.0.1:6379> SDIFF myset1 myset2
1) "a"
2) "b"
127.0.0.1:6379> SDIFF myset2 myset1
1) "e"
2) "d"
127.0.0.1:6379> 

檢視兩個set集合中的交集(共同好友)

SINTER key [key ...]

檢視兩個set集合中的並集

SUNION key [key ...]


微博,A使用者將所有關注的人放在一個set集合中!將它的粉絲也放在一個集合中!
共同關注,共同愛好,二度好友,推薦好友!(六度分割理論)

Hash(雜湊)

Map集合,key-map! 時候這個值是一個map集合! 本質和String型別沒有太大區別,還是一個簡單的 key-vlaue!

新增值

hset key field value [field value ...]

hmset key field value [field value ...]

獲取值

hget key field

hmget key field [field ...]

獲取所有的key

127.0.0.1:6379> HGETALL myhash
1) "user"
2) "joker"
127.0.0.1:6379> 

刪除值

hdel key field [field ...]

獲取hash的欄位熟練

hlen key

判斷hash指定的欄位是否存在

HEXISTS key field

只獲得所有field

hkeys key

只獲得所有value

hvals key

自增自減

HINCRBY key field increment 
#示例
#自增
HINCRBY myhash user 1 
#自減
HINCRBY myhash user -1

設定值如果不存在則可以設定 如果存在則不能設定

 hsetnx key field value

hash變更的資料 user name age,尤其是是使用者資訊之類的,經常變動的資訊! hash 更適合於物件的 儲存,String更加適合字串儲存!

Zset(有序集合)

在set的基礎上,增加了一個值,set k1 v1 zset k1 score1 v1

新增值

zadd key [NX|XX] [CH] [INCR] score member [score member ...]
#################
127.0.0.1:6379> zadd myset 1 one 
(integer) 1
127.0.0.1:6379> zadd myset 2 two 
(integer) 1
127.0.0.1:6379> zadd myset 3 three 
(integer) 1
127.0.0.1:6379> ZRANGE myset 0 -1
1) "one"
2) "two"
3) "three"

從小到大排序

ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]

總大到小排序

zrevrangebyscore key max min [WITHSCORES] [LIMIT offset count]

ZREVRANGE key start stop [WITHSCORES]

移除zset的指定元素

zrem key member [member ...]

獲取有序集合中的個數

zcard key

獲取指定區間的成員數量

zcount key min max


其與的一些API,通過我們的學習嗎,你們剩下的如果工作中有需要,這個時候你可以去查檢視官方文 檔!
案例思路:set 排序 儲存班級成績表,工資表排序!
普通訊息,1, 重要訊息 2,帶權重進行判斷! 排行榜應用實現,取Top N 測試!

三種特殊資料型別

Geospatial 地理位置

朋友的定位,附近的人,打車距離計算?
Redis 的 Geo 在Redis3.2 版本就推出了! 這個功能可以推算地理位置的資訊,兩地之間的距離,方圓 幾裡的人!
可以查詢一些測試資料:http://www.jsons.cn/lngcodeinfo/0706D99C19A781A3/

只有 六個命令:

官方文件:https://www.redis.net.cn/order/3685.html

geoadd 新增地理位置

geoadd key longitude latitude member [longitude latitude member ...]
# getadd 新增地理位置 
# 規則:兩級無法直接新增,我們一般會下載城市資料,直接通過java程式一次性匯入! 
# 有效的經度從-180度到180度。
# 有效的緯度從-85.05112878度到85.05112878度。 
# 當座標位置超出上述指定範圍時,該命令將會返回一個錯誤。    
# 引數 key  值() 
127.0.0.1:6379> geoadd china:city 116.40 39.90 beijing 
(integer) 1 
127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai 
(integer) 1 
127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqi 114.05 22.52 shengzhen 
(integer) 2 
127.0.0.1:6379> geoadd china:city 120.16 30.24 hangzhou 108.96 34.26 xian
(integer) 2

getpos 獲得當前定位

一定是一個座標值

GEOPOS key member [member ...]

GEOPOS china:city beijing

GEODIST 獲取兩個地理位置的距離

兩人之間的距離!
單位:

  • m 表示單位為米。
  • km 表示單位為千米。
  • mi 表示單位為英里。
  • ft 表示單位為英尺。
GEODIST china:city beijing shanghai km  # 檢視上海到北京的直線距離 
GEODIST china:city beijing chongqi km   # 檢視重慶到北京的直線距離 

georadius (附近的人)

以給定的經緯度為中心, 找出某一半徑內的元素

我附近的人? (獲得所有附近的人的地址,定位!)通過半徑來查詢!
獲得指定數量的人,200 所有資料應該都錄入:china:city ,才會讓結果更加請求!

GEORADIUS china:city 110 30 1000 km  # 以110,30 這個經緯度為中心,尋 找方圓1000km內的城市

GEORADIUS china:city 110 30 500 km withdist  # 顯示到中間距離的位置 
GEORADIUS china:city 110 30 500 km withcoord  # 顯示他人的定位資訊 

GEORADIUS china:city 110 30 500 km withdist withcoord count 1  # 篩選出指定的結果! 

GEORADIUSBYMEMBER 找出位於指定元素周圍的其他元素

GEORADIUSBYMEMBER china:city beijing 1000 km 
GEORADIUSBYMEMBER china:city shanghai 400 km 

GEOHASH 命令 - 返回一個或多個位置元素的 Geohash 表示

該命令將返回11個字元的Geohash字串!

# 將二維的經緯度轉換為一維的字串,如果兩個字串越接近,那麼則距離越近! 
geohash china:city beijing chongqi

GEO 底層的實現原理其實就是 Zset!我們可以使用Zset命令來操作geo

 ZRANGE china:city 0 -1  # 檢視地圖中全部的元素 
 zrem china:city beijing  # 移除指定元素!

Hyperloglog

什麼是基數?

A {1,3,5,7,8,7} B{1,3,5,7,8}
基數(不重複的元素) = 5,可以接受誤差!

簡介

Redis 2.8.9 版本就更新了 Hyperloglog 資料結構! Redis Hyperloglog 基數統計的演算法!

優點:佔用的記憶體是固定,2^64 不同的元素的技術,只需要廢 12KB記憶體!如果要從記憶體角度來比較的 話 Hyperloglog 首選!

網頁的 UV (一個人訪問一個網站多次,但是還是算作一個人!)

傳統的方式, set 儲存使用者的id,然後就可以統計 set 中的元素數量作為標準判斷 ! 這個方式如果儲存大量的使用者id,就會比較麻煩!我們的目的是為了計數,而不是儲存使用者id;
0.81% 錯誤率! 統計UV任務,可以忽略不計的!

測試使用

127.0.0.1:6379> PFadd mykey a b c d e f g h i j   # 建立第一組元素 mykey 
(integer) 1
127.0.0.1:6379> PFCOUNT mykey  # 統計 mykey 元素的基數數量 
(integer) 10 
 127.0.0.1:6379> PFadd mykey2 i j z x c v b n m   # 建立第二組元素 mykey2 
(integer) 1 
 127.0.0.1:6379> PFCOUNT mykey2 
(integer) 9 
127.0.0.1:6379> PFMERGE mykey3 mykey mykey2  # 合併兩組 mykey mykey2 => mykey3 並集 
OK 
127.0.0.1:6379> PFCOUNT mykey3  # 看並集的數量! 
(integer) 15 

如果允許容錯,那麼一定可以使用 Hyperloglog ! 如果不允許容錯,就使用 set 或者自己的資料型別即可!

Bitmaps

位儲存

統計使用者資訊,活躍,不活躍! 登入 、 未登入! 打卡,365打卡! 兩個狀態的,都可以使用 Bitmaps!
Bitmap 點陣圖,資料結構! 都是操作二進位制位來進行記錄,就只有0 和 1 兩個狀態! 365 天 = 365 bit 1位元組 = 8bit 46 個位元組左右!

使用bitmap 來記錄 週一到週日的打卡!
週一:1 週二:0 週三:0 週四:1 ......

setbit key offset value

setbit key 周幾 是否打卡(1:打卡,0未打卡)

127.0.0.1:6379> setbit sign 0 1
(integer) 0
127.0.0.1:6379> setbit sign 1 0
(integer) 0
127.0.0.1:6379> setbit sign 2 1
(integer) 0
127.0.0.1:6379> setbit sign 3 1
(integer) 0
127.0.0.1:6379> setbit sign 4 1
(integer) 0
127.0.0.1:6379> setbit sign 5 0
(integer) 0
127.0.0.1:6379> setbit sign 6 0
(integer) 0
127.0.0.1:6379

檢視某天是否打卡

127.0.0.1:6379>  getbit sign 6
(integer) 0
127.0.0.1:6379>  getbit sign 2
(integer) 1
127.0.0.1:6379> 

統計打卡多少天

127.0.0.1:6379> bitcount sign
(integer) 4
127.0.0.1:6379>

事務

Redis 事務本質:一組命令的集合! 一個事務中的所有命令都會被序列化,在事務執行過程的中,會按 照順序執行!

一次性、順序性、排他性!執行一些列的命令!

------ 佇列 set set set 執行-----

Redis事務沒有沒有隔離級別的概念!

所有的命令在事務中,並沒有直接被執行!只有發起執行命令的時候才會執行!Exec

Redis單條命令式儲存原子性的,但是事務不保證原子性!

redis的事務:

  • 開啟事務(multi)
  • 命令入隊(......)
  • 執行事務(exec)
multi  #開啟事務
exec  # 執行事務 
DISCARD   # 取消事務 

正常執行事務

127.0.0.1:6379> multi #開啟事務
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> exec #執行事務
1) OK
2) OK
3) "v1"
127.0.0.1:6379> 

放棄事務

127.0.0.1:6379> multi #開啟事務
OK
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> discard  #放棄事務
OK
127.0.0.1:6379> get k3
(nil)
127.0.0.1:6379> 

編譯型異常(程式碼有問題! 命令有錯!) ,事務中所有的命令都不會被執行!

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> setk2 v2
(error) ERR unknown command `setk2`, with args beginning with: `v2`, 
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k3 
(nil)
127.0.0.1:6379> 

執行時異常(1/0), 如果事務佇列中存在語法性,那麼執行命令的時候,其他命令是可以正常執行 的,錯誤命令丟擲異常

127.0.0.1:6379> set k1 "v1" 
OK 
127.0.0.1:6379> multi 
OK 
127.0.0.1:6379> incr k1  # 會執行的時候失敗! 
QUEUED 
127.0.0.1:6379> set k2 v2 
QUEUED 
127.0.0.1:6379> set k3 v3 
QUEUED 
127.0.0.1:6379> get k3 
QUEUED 
127.0.0.1:6379> exec 
1) (error) ERR value is not an integer or out of range  # 雖然第一條命令報錯了,但是 依舊正常執行成功了! 
2) OK 
3) OK 
4) "v3" 
127.0.0.1:6379> get k2 
"v2" 
127.0.0.1:6379> get k3 
"v3"

Redis watch 監控

Redis樂觀鎖

悲觀鎖:

  • 很悲觀,認為什麼時候都會出問題,無論做什麼都會加鎖

樂觀鎖:

  • 很樂觀,認為什麼時候都不會出問題,所以不會上鎖! 更新資料的時候去判斷一下,在此期間是否 有人修改過這個資料,
  • 獲取version
  • 更新的時候比較 version

Redis測監視測試

正常執行成功!

127.0.0.1:6379> set money 100 
OK 
127.0.0.1:6379> set out 0 
OK 
127.0.0.1:6379> watch money   # 監視 money 物件 
OK 
127.0.0.1:6379> multi     # 事務正常結束,資料期間沒有發生變動,這個時候就正常執行成功! 
OK 
127.0.0.1:6379> DECRBY money 20 
QUEUED 
127.0.0.1:6379> INCRBY out 20
QUEUED 
 127.0.0.1:6379> exec 
 1) (integer) 80 
 2) (integer) 20 

測試多執行緒修改值 , 使用watch 可以當做redis的樂觀鎖操作!

127.0.0.1:6379> watch money   # 監視  money 
OK 
127.0.0.1:6379> multi 
OK 
127.0.0.1:6379> DECRBY money 10 
QUEUED 
127.0.0.1:6379> INCRBY out 10
QUEUED 
127.0.0.1:6379> exec  # 執行之前,另外一個執行緒,修改了我們的值,這個時候,就會導致事務執行失敗!
(nil)

解鎖

Jedis

什麼是Jedis 是 Redis 官方推薦的 java連線開發工具! 使用Java 操作Redis 中介軟體!如果你要使用 java操作redis,那麼一定要對Jedis 十分的熟悉!

測試

建立maven專案

  1. 匯入依賴
<dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>3.2.0</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.28</version>
    </dependency>
  1. 開啟本地客戶端
    連線遠端需要開啟防火牆埠
  2. 建立連線
 public static void main(String[] args) {
        //1. new Jedis物件
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        System.out.println(jedis.ping());
    }


String
list
hash
set
zset
命令redis一樣

事務

public static void main(String[] args) {
        Jedis jedis = new Jedis("127.0.0.7", 6379);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("hello","word");
        jsonObject.put("name","joker");
        Transaction multi = jedis.multi();
        String result = jsonObject.toJSONString();
        try {
            multi.set("user1",result);
            multi.set("user2",result);
            multi.exec();//執行事務
        }catch (Exception e){
            multi.discard();//放棄事務
        }finally {
            System.out.println(jedis.get("user1"));
            System.out.println(jedis.get("user2"));
        }
    }

SpringBoot整合

SpringBoot 操作資料:spring-data jpa jdbc mongodb redis!
SpringData 也是和 SpringBoot 齊名的專案!

說明: 在 SpringBoot2.x 之後,原來使用的jedis 被替換為了 lettuce? jedis : 採用的直連,多個執行緒操作的話,是不安全的,如果想要避免不安全的,使用 jedis pool 連線池! 更像 BIO 模式 lettuce : 採用netty,例項可以再多個執行緒中進行共享,不存線上程不安全的情況!可以減少執行緒資料 了,更像 NIO 模式

建立SpringBoot專案
1、勾選依賴



2、配置application.properties

spring.redis.host=127.0.0.1
spring.redis.port=6379

3、測試

@SpringBootTest
class SpringbootRedisApplicationTests {
    @Autowired
    private RedisTemplate redisTemplate;
    @Test
    void contextLoads() {
        //opsForValue() 類似於String
        //opsForList() 類似於list
        //opsForHash() 類似於hash
        //ZSet() 類似於 zset
        RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
        connection.flushDb();
        redisTemplate.opsForHash().put("","","");
    }

}

自定義RedisTemplate

@Configuration
public class RedisConfig {
    // 這是我給大家寫好的一個固定模板,大家在企業中,拿去就可以直接使用!    
    // 自己定義了一個 RedisTemplate
    @Bean
    @SuppressWarnings("all")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        // 我們為了自己開發方便,一般直接使用 <String, Object>
         RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
         template.setConnectionFactory(factory);
          // Json序列化配置
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // String 的序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key採用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也採用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式採用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式採用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}

Redis.conf詳解

啟動的時候,就通過配置檔案來啟動!
工作中,一些小小的配置,可以讓你脫穎而出!
行家有沒有,出手就知道

單位

1、配置檔案 unit單位 對大小寫不敏感!

包含


就是好比我們學習Spring、Improt, include

網路

bind 127.0.0.1    # 繫結的ip 
protected-mode yes # 保護模式 
port 6379  # 埠設定

通用 GENERAL

daemonize yes   # 以守護程序的方式執行,預設是 no,我們需要自己開啟為yes!
pidfile /var/run/redis_6379.pid  # 如果以後臺的方式執行,我們就需要指定一個 pid 檔案!
# 日誌 
# Specify the server verbosity level.
 # This can be one of:
# debug (a lot of information, useful for development/testing)   
# verbose (many rarely useful info, but not a mess like the debug level) 
# notice (moderately verbose, what you want in production probably) 生產環境 
# warning (only very important / critical messages are logged)
loglevel notice 
logfile "" # 日誌的檔案位置名
databases 16  # 資料庫的數量,預設是 16 個數據庫 
always-show-logo yes  # 是否總是顯示LOGO

快照

持久化, 在規定的時間內,執行了多少次操作,則會持久化到檔案 .rdb. aof
redis 是記憶體資料庫,如果沒有持久化,那麼資料斷電及失!

# 如果900s內,如果至少有一個1 key進行了修改,我們及進行持久化操作 
save 900 1 
# 如果300s內,如果至少10 key進行了修改,我們及進行持久化操作 
save 300 10
# 如果60s內,如果至少10000 key進行了修改,我們及進行持久化操作
save 60 10000 
# 我們之後學習持久化,會自己定義這個測試!
stop-writes-on-bgsave-error yes   # 持久化如果出錯,是否還需要繼續工作!
rdbcompression yes # 是否壓縮 rdb 檔案,需要消耗一些cpu資源!
rdbchecksum yes # 儲存rdb檔案的時候,進行錯誤的檢查校驗!
dir ./  # rdb 檔案儲存的目錄!

REPLICATION 複製,我們後面講解主從複製的,時候再進行講解

SECURITY 安全

設定redis的密碼

127.0.0.1:6379> ping 
PONG 
127.0.0.1:6379> config get requirepass   # 獲取redis的密碼 
1) "requirepass" 
2) "" 
127.0.0.1:6379> config set requirepass "123456"   # 設定redis的密碼 
OK 
127.0.0.1:6379> config get requirepass   # 發現所有的命令都沒有許可權了 
(error) NOAUTH Authentication required. 
127.0.0.1:6379> ping 
(error) NOAUTH Authentication required. 
127.0.0.1:6379> auth 123456  # 使用密碼進行登入! 
OK 
127.0.0.1:6379> config get requirepass 
1) "requirepass" 
2) "123456

限制 CLIENTS

maxclients 10000   # 設定能連線上redis的大客戶端的數量
maxmemory <bytes>  # redis 配置大的記憶體容量
maxmemory-policy noeviction  # 記憶體到達上限之後的處理策略 

 1、volatile-lru:只對設定了過期時間的key進行LRU(預設值)     
 2、allkeys-lru : 刪除lru演算法的key       
 3、volatile-random:隨機刪除即將過期key       
 4、allkeys-random:隨機刪除       
 5、volatile-ttl : 刪除即將過期的       
 6、noeviction : 永不過期,返回錯誤

APPEND ONLY 模式 aof配置

appendonly no    # 預設是不開啟aof模式的,預設是使用rdb方式持久化的,在大部分所有的情況下, rdb完全夠用!
appendfilename "appendonly.aof"  # 持久化的檔案的名字
# appendfsync always   # 每次修改都會 sync。消耗效能 
appendfsync everysec   # 每秒執行一次 sync,可能會丟失這1s的資料! 
# appendfsync no       # 不執行 sync,這個時候作業系統自己同步資料,速度快! 

Redis持久化

面試和工作,持久化都是重點!
Redis 是記憶體資料庫,如果不將記憶體中的資料庫狀態儲存到磁碟,那麼一旦伺服器程序退出,伺服器中 的資料庫狀態也會消失。所以 Redis 提供了持久化功能!

RDB(Redis DataBase)

什麼是RDB

在主從複製中,rdb就是備用了!從機上面!

在指定的時間間隔內將記憶體中的資料集快照寫入磁碟,也就是行話講的Snapshot快照,它恢復時是將快 照檔案直接讀到記憶體裡。

Redis會單獨建立(fork)一個子程序來進行持久化,會先將資料寫入到一個臨時檔案中,待持久化過程 都結束了,再用這個臨時檔案替換上次持久化好的檔案。整個過程中,主程序是不進行任何IO操作的。 這就確保了極高的效能。如果需要進行大規模資料的恢復,且對於資料恢復的完整性不是非常敏感,那 RDB方式要比AOF方式更加的高效。RDB的缺點是後一次持久化後的資料可能丟失。我們預設的就是 RDB,一般情況下不需要修改這個配置

有時候在生產環境我們會將這個檔案進行備份!

rdb儲存的檔案是dump.rdb 都是在我們的配置檔案中快照中進行配置的!

觸發機制
1、save的規則滿足的情況下,會自動觸發rdb規則
2、執行 flushall 命令,也會觸發我們的rdb規則!
3、退出redis,也會產生 rdb 檔案! 備份就自動生成一個 dump.rdb

如果恢復rdb檔案!

1、只需要將rdb檔案放在我們redis啟動目錄就可以,redis啟動的時候會自動檢查dump.rdb 恢復其中 的資料!
2、檢視需要存在的位置

127.0.0.1:6379> config get dir
1) "dir"
2) "/usr/local/bin"
127.0.0.1:6379> 

幾乎就他自己預設的配置就夠用了,但是我們還是需要去學習!

優點:
1、適合大規模的資料恢復!
2、對資料的完整性要不高!
缺點:
1、需要一定的時間間隔程序操作!如果redis意外宕機了,這個後一次修改資料就沒有的了!
2、fork程序的時候,會佔用一定的內容空間!!

AOF(Append Only File)

將我們的所有命令都記錄下來,history,恢復的時候就把這個檔案全部在執行一遍!

以日誌的形式來記錄每個寫操作,將Redis執行過的所有指令記錄下來(讀操作不記錄),只許追加檔案 但不可以改寫檔案,redis啟動之初會讀取該檔案重新構建資料,換言之,redis重啟的話就根據日誌檔案 的內容將寫指令從前到後執行一次以完成資料的恢復工作

Aof儲存的是 appendonly.aof 檔案

append


預設是不開啟的,我們需要手動進行配置!我們只需要將 appendonly 改為yes就開啟了 aof! 重啟,redis 就可以生效了!

如果這個 aof 檔案有錯位,這時候 redis 是啟動不起來的嗎,我們需要修復這個aof檔案
redis 給我們提供了一個工具 redis-check-aof --fix

重寫規則說明

aof 預設就是檔案的無限追加,檔案會越來越大!

優點和缺點

appendonly no    # 預設是不開啟aof模式的,預設是使用rdb方式持久化的,在大部分所有的情況下, rdb完全夠用! 
appendfilename "appendonly.aof"  # 持久化的檔案的名字
# appendfsync always   # 每次修改都會 sync。消耗效能 
appendfsync everysec   # 每秒執行一次 sync,可能會丟失這1s的資料!
# appendfsync no       # 不執行 sync,這個時候作業系統自己同步資料,速度快!
# rewrite  重寫, 

優點:
1、每一次修改都同步,檔案的完整會更加好!
2、每秒同步一次,可能會丟失一秒的資料 3、從不同步,效率高的!
缺點:
1、相對於資料檔案來說,aof遠遠大於 rdb,修復的速度也比 rdb慢! 2、Aof 執行效率也要比 rdb 慢,所以我們redis預設的配置就是rdb持久化

擴充套件:
1、RDB 持久化方式能夠在指定的時間間隔內對你的資料進行快照儲存

2、AOF 持久化方式記錄每次對伺服器寫的操作,當伺服器重啟的時候會重新執行這些命令來恢復原始 的資料,AOF命令以Redis 協議追加儲存每次寫的操作到檔案末尾,Redis還能對AOF檔案進行後臺重 寫,使得AOF檔案的體積不至於過大。

3、只做快取,如果你只希望你的資料在伺服器執行的時候存在,你也可以不使用任何持久化

4、同時開啟兩種持久化方式

  • 在這種情況下,當redis重啟的時候會優先載入AOF檔案來恢復原始的資料,因為在通常情況下AOF 檔案儲存的資料集要比RDB檔案儲存的資料集要完整。
  • RDB 的資料不實時,同時使用兩者時伺服器重啟也只會找AOF檔案,那要不要只使用AOF呢?作者 建議不要,因為RDB更適合用於備份資料庫(AOF在不斷變化不好備份),快速重啟,而且不會有 AOF可能潛在的Bug,留著作為一個萬一的手段。

5、效能建議

  • 因為RDB檔案只用作後備用途,建議只在Slave上持久化RDB檔案,而且只要15分鐘備份一次就夠 了,只保留 save 900 1 這條規則
  • 如果Enable AOF ,好處是在惡劣情況下也只會丟失不超過兩秒資料,啟動指令碼較簡單隻load自 己的AOF檔案就可以了,代價一是帶來了持續的IO,二是AOF rewrite 的後將 rewrite 過程中產 生的新資料寫到新檔案造成的阻塞幾乎是不可避免的。只要硬碟許可,應該儘量減少AOF rewrite 的頻率,AOF重寫的基礎大小預設值64M太小了,可以設到5G以上,預設超過原大小100%大小重 寫可以改到適當的數值。
  • 如果不Enable AOF ,僅靠 Master-Slave Repllcation 實現高可用性也可以,能省掉一大筆IO,也 減少了rewrite時帶來的系統波動。代價是如果Master/Slave 同時倒掉,會丟失十幾分鐘的資料, 啟動指令碼也要比較兩個 Master/Slave 中的 RDB檔案,載入較新的那個,微博就是這種架構。

Redis釋出訂閱

Redis 釋出訂閱(pub/sub)是一種訊息通訊模式:傳送者(pub)傳送訊息,訂閱者(sub)接收訊息。微信、 微博、關注系統!

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

訂閱/釋出訊息圖:
第一個:訊息傳送者, 第二個:頻道 第三個:訊息訂閱者!

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

當有新訊息通過 PUBLISH 命令傳送給頻道 channel1 時, 這個訊息就會被髮送給訂閱它的三個客戶 端:

命令

這些命令被廣泛用於構建即時通訊應用,比如網路聊天室(chatroom)和實時廣播、實時提醒等

測試

訂閱端:

127.0.0.1:6379> SUBSCRIBE joker #訂閱一個頻道 joker
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "joker"
3) (integer) 1

傳送端

127.0.0.1:6379> PUBLISH joker joker_dj #發信息給joker頻道傳送一個joker_dj資訊
(integer) 1
127.0.0.1:6379>

訂閱端:

原理

Redis是使用C實現的,通過分析 Redis 原始碼裡的 pubsub.c 檔案,瞭解釋出和訂閱機制的底層實現,籍 此加深對 Redis 的理解。

Redis 通過 PUBLISH 、SUBSCRIBE 和 PSUBSCRIBE 等命令實現釋出和訂閱功能。
微信:
通過 SUBSCRIBE 命令訂閱某頻道後,redis-server 裡維護了一個字典,字典的鍵就是一個個 頻道!, 而字典的值則是一個連結串列,連結串列中儲存了所有訂閱這個 channel 的客戶端。SUBSCRIBE 命令的關鍵, 就是將客戶端新增到給定 channel 的訂閱連結串列中。

通過 PUBLISH 命令向訂閱者傳送訊息,redis-server 會使用給定的頻道作為鍵,在它所維護的 channel 字典中查詢記錄了訂閱這個頻道的所有客戶端的連結串列,遍歷這個連結串列,將訊息釋出給所有訂閱者。

Pub/Sub 從字面上理解就是釋出(Publish)與訂閱(Subscribe),在Redis中,你可以設定對某一個 key值進行訊息釋出及訊息訂閱,當一個key值上進行了訊息釋出後,所有訂閱它的客戶端都會收到相應 的訊息。這一功能明顯的用法就是用作實時訊息系統,比如普通的即時聊天,群聊等功能。

使用場景:
1、實時訊息系統!
2、事實聊天!(頻道當做聊天室,將資訊回顯給所有人即可!) 3、訂閱,關注系統都是可以的! 稍微複雜的場景我們就會使用 訊息中介軟體 MQ ()

Redis主從複製

概念

主從複製,是指將一臺Redis伺服器的資料,複製到其他的Redis伺服器。前者稱為主節點 (master/leader),後者稱為從節點(slave/follower);資料的複製是單向的,只能由主節點到從節點。 Master以寫為主,Slave 以讀為主。

預設情況下,每臺Redis伺服器都是主節點;

且一個主節點可以有多個從節點(或沒有從節點),但一個從節點只能有一個主節點。

主從複製的作用主要包括:

1、資料冗餘:主從複製實現了資料的熱備份,是持久化之外的一種資料冗餘方式。

2、故障恢復:當主節點出現問題時,可以由從節點提供服務,實現快速的故障恢復;實際上是一種服務 的冗餘。

3、負載均衡:在主從複製的基礎上,配合讀寫分離,可以由主節點提供寫服務,由從節點提供讀服務 (即寫Redis資料時應用連線主節點,讀Redis資料時應用連線從節點),分擔伺服器負載;尤其是在寫 少讀多的場景下,通過多個從節點分擔讀負載,可以大大提高Redis伺服器的併發量。

4、高可用(叢集)基石:除了上述作用以外,主從複製還是哨兵和叢集能夠實施的基礎,因此說主從復 制是Redis高可用的基礎。

一般來說,要將Redis運用於工程專案中,只使用一臺Redis是萬萬不能的(宕機),原因如下:

1、從結構上,單個Redis伺服器會發生單點故障,並且一臺伺服器需要處理所有的請求負載,壓力較 大;

2、從容量上,單個Redis伺服器記憶體容量有限,就算一臺Redis伺服器記憶體容量為256G,也不能將所有 記憶體用作Redis儲存記憶體,一般來說,單臺Redis大使用記憶體不應該超過20G。

電商網站上的商品,一般都是一次上傳,無數次瀏覽的,說專業點也就是"多讀少寫"。
對於這種場景,我們可以使如下這種架構:


主從複製,讀寫分離! 80% 的情況下都是在進行讀操作!減緩伺服器的壓力!架構中經常使用! 一主 二從!

只要在公司中,主從複製就是必須要使用的,因為在真實的專案中不可能單機使用Redis

環境配置

只配置從庫,不用配置主庫!

127.0.0.1:6379>  info replication
# Replication
role:master
connected_slaves:0
master_replid:bccb48dfc6e76f5d785fc4571c6f0e482893238f
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6379>

建立三個連線

複製三個redis.conf檔案

[root@iZbp13uh1twnfutkq5x60iZ redisconfig]# cp redis.conf redis79.conf
[root@iZbp13uh1twnfutkq5x60iZ redisconfig]# cp redis.conf redis80.conf
[root@iZbp13uh1twnfutkq5x60iZ redisconfig]# cp redis.conf redis81.conf


修改對應的配置檔案
1、埠 6379 6380 6381

2、pid 名字

redis_6379.pid redis_6380.pid redis_6381.pid
3、log檔名字

logfile "6379.log"
logfile "6380.log"
logfile "6381.log"
4、dump.rdb 名字
dbfilename dump6379.rdb
dbfilename dump6380.rdb
dbfilename dump6381.rdb

啟動三臺redis

一主二從

預設情況下,每臺Redis伺服器都是主節點; 我們一般情況下只用配置從機就好了!
認老大! 一主 (79)二從(80,81)

命令列配置

SLAVEOF host port #  SLAVEOF host 6379   找誰當自己的老大! 

127.0.0.1:6380> SLAVEOF 127.0.0.1 6379
OK
127.0.0.1:6381> SLAVEOF 127.0.0.1 6379
OK

如果兩個都配置完了,就是有兩個從機


配置檔案配置

真實的從主配置應該在配置檔案中配置,這樣的話是永久的,我們這裡使用的是命令,暫時的

# replicaof 主機ip 主機埠
replicaof <masterip> <masterport>
# masterauth 主機密碼
masterauth <master-password>

細節

主機可以寫,從機不能寫只能讀!主機中的所有資訊和資料,都會自動被從機儲存!

主機寫:

從機讀:

從機不能寫:

測試:主機斷開連線,從機依舊連線到主機的,但是沒有寫操作,這個時候,主機如果回來了,從機依舊可以直接獲取到主機寫的資訊!

如果是使用命令列,來配置的主從,這個時候如果重啟了,就會變回主機!只要變為從機,立馬就會從主機中獲取值!

複製原理

Slave 啟動成功連線到 master 後會傳送一個sync同步命令

Master 接到命令,啟動後臺的存檔程序,同時收集所有接收到的用於修改資料集命令,在後臺程序執行 完畢之後,master將傳送整個資料檔案到slave,並完成一次完全同步。

全量複製:而slave服務在接收到資料庫檔案資料後,將其存檔並載入到記憶體中。

增量複製:Master 繼續將新的所有收集到的修改命令依次傳給slave,完成同步

但是隻要是重新連線master,一次完全同步(全量複製)將被自動執行! 我們的資料一定可以在從機中 看到!

層層鏈路

上一個M連結下一個 S!

這時候也可以完成我們的主從複製!

如果沒有老大了,這個時候能不能選擇一個老大出來呢? 手動!

謀朝篡位

如果主機斷開了連線,我們可以使用 SLAVEOF no one 讓自己變成主機!其他的節點就可以手動連 接到新的這個主節點(手動)!如果這個時候老大修復了,那就要重新連線!

哨兵模式

(自動選舉老大的模式)

概述

主從切換技術的方法是:當主伺服器宕機後,需要手動把一臺從伺服器切換為主伺服器,這就需要人工 干預,費事費力,還會造成一段時間內服務不可用。這不是一種推薦的方式,更多時候,我們優先考慮 哨兵模式。Redis從2.8開始正式提供了Sentinel(哨兵) 架構來解決這個問題。

謀朝篡位的自動版,能夠後臺監控主機是否故障,如果故障了根據投票數自動將從庫轉換為主庫。

哨兵模式是一種特殊的模式,首先Redis提供了哨兵的命令,哨兵是一個獨立的程序,作為程序,它會獨 立執行。其原理是哨兵通過傳送命令,等待Redis伺服器響應,從而監控執行的多個Redis例項。


這裡的哨兵有兩個作用

  • 通過傳送命令,讓Redis伺服器返回監控其執行狀態,包括主伺服器和從伺服器。
  • 當哨兵監測到master宕機,會自動將slave切換成master,然後通過釋出訂閱模式通知其他的從服 務器,修改配置檔案,讓它們切換主機。

然而一個哨兵程序對Redis伺服器進行監控,可能會出現問題,為此,我們可以使用多個哨兵進行監控。 各個哨兵之間還會進行監控,這樣就形成了多哨兵模式。


假設主伺服器宕機,哨兵1先檢測到這個結果,系統並不會馬上進行failover過程,僅僅是哨兵1主觀的認 為主伺服器不可用,這個現象成為主觀下線。當後面的哨兵也檢測到主伺服器不可用,並且數量達到一 定值時,那麼哨兵之間就會進行一次投票,投票的結果由一個哨兵發起,進行failover[故障轉移]操作。 切換成功後,就會通過釋出訂閱模式,讓各個哨兵把自己監控的從伺服器實現切換主機,這個過程稱為 客觀下線。

測試!

我們目前的狀態是 一主二從!

配置哨兵

  1. 配置哨兵配置檔案 sentinel.conf
    新建配置檔案sentinel.conf
# sentinel monitor 被監控的名稱 host  port  1 
sentinel monitor myredis 127.0.0.1 6379 1


後面的這個數字1,代表主機掛了,slave投票看讓誰接替成為主機,票數多的,就會成為主機!

  1. 啟動哨兵!
redis-sentinel redisconfig/sentinel.conf


如果把主機宕機,哨兵會把某個從機升級為主機

如果主機此時回來了,只能歸併到新的主機下,當做從機,這就是哨兵模式的規則

哨兵模式

優點:
1、哨兵叢集,基於主從複製模式,所有的主從配置優點,它全有
2、 主從可以切換,故障可以轉移,系統的可用性就會更好
3、哨兵模式就是主從模式的升級,手動到自動,更加健壯

缺點:
1、Redis 不好啊線上擴容的,叢集容量一旦到達上限,線上擴容就十分麻煩!
2、實現哨兵模式的配置其實是很麻煩的,裡面有很多選擇!

哨兵模式的全部配置!

# Example sentinel.conf
# 哨兵sentinel例項執行的埠 預設26379 
port 26379

# 哨兵sentinel的工作目錄 
dir /tmp
# 哨兵sentinel監控的redis主節點的 ip port 
# master-name  可以自己命名的主節點名字 只能由字母A-z、數字0-9 、這三個字元".-_"組成。 
# quorum 配置多少個sentinel哨兵統一認為master主節點失聯 那麼這時客觀上認為主節點失聯了 
# sentinel monitor <master-name> <ip> <redis-port> <quorum>
sentinel monitor mymaster 127.0.0.1 6379 2

# 當在Redis例項中開啟了requirepass foobared 授權密碼 這樣所有連線Redis例項的客戶端都要提供 密碼 
# 設定哨兵sentinel 連線主從的密碼 注意必須為主從設定一樣的驗證密碼 
# sentinel auth-pass <master-name> <password>
sentinel auth-pass mymaster MySUPER--secret-0123passw0rd

# 指定多少毫秒之後 主節點沒有應答哨兵sentinel 此時 哨兵主觀上認為主節點下線 預設30秒 
# sentinel down-after-milliseconds <master-name> <milliseconds> 
sentinel down-after-milliseconds mymaster 30000

# 這個配置項指定了在發生failover主備切換時多可以有多少個slave同時對新的master進行 同步, 這個數字越小,完成failover所需的時間就越長,但是如果這個數字越大,就意味著越 多的slave因為replication而不可用。 可以通過將這個值設為 1 來保證每次只有一個slave 處於不能處理命令請求的狀態。 
# sentinel parallel-syncs <master-name> <numslaves> 
sentinel parallel-syncs mymaster 1

# 故障轉移的超時時間 failover-timeout 可以用在以下這些方面: 
#1. 同一個sentinel對同一個master兩次failover之間的間隔時間。 
#2. 當一個slave從一個錯誤的master那裡同步資料開始計算時間。直到slave被糾正為向正確的master那 裡同步資料時。 
#3.當想要取消一個正在進行的failover所需要的時間。   
#4.當進行failover時,配置所有slaves指向新的master所需的大時間。不過,即使過了這個超時, slaves依然會被正確配置為指向master,但是就不按parallel-syncs所配置的規則來了 

# 預設三分鐘 
# sentinel failover-timeout <master-name> <milliseconds>

sentinel failover-timeout mymaster 180000

# SCRIPTS EXECUTION

#配置當某一事件發生時所需要執行的指令碼,可以通過指令碼來通知管理員,例如當系統執行不正常時發郵件通知 相關人員。 
#對於指令碼的執行結果有以下規則: 
#若指令碼執行後返回1,那麼該指令碼稍後將會被再次執行,重複次數目前預設為10 
#若指令碼執行後返回2,或者比2更高的一個返回值,指令碼將不會重複執行。 
#如果指令碼在執行過程中由於收到系統中斷訊號被終止了,則同返回值為1時的行為相同。 
#一個指令碼的大執行時間為60s,如果超過這個時間,指令碼將會被一個SIGKILL訊號終止,之後重新執行。

#通知型指令碼:當sentinel有任何警告級別的事件發生時(比如說redis例項的主觀失效和客觀失效等等), 將會去呼叫這個指令碼,這時這個指令碼應該通過郵件,SMS等方式去通知系統管理員關於系統不正常執行的信 息。呼叫該指令碼時,將傳給指令碼兩個引數,一個是事件的型別,一個是事件的描述。如果sentinel.conf配 置檔案中配置了這個指令碼路徑,那麼必須保證這個指令碼存在於這個路徑,並且是可執行的,否則sentinel無 法正常啟動成功。 

#通知指令碼 # shell程式設計 # sentinel notification-script <master-name> <script-path>
sentinel notification-script mymaster /var/redis/notify.sh

# 客戶端重新配置主節點引數指令碼 
# 當一個master由於failover而發生改變時,這個指令碼將會被呼叫,通知相關的客戶端關於master地址已 經發生改變的資訊。 
# 以下引數將會在呼叫指令碼時傳給指令碼:  
# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port> 
# 目前<state>總是“failover”, 
# <role>是“leader”或者“observer”中的一個。 
# 引數 from-ip, from-port, to-ip, to-port是用來和舊的master和新的master(即舊的slave)通 信的 
# 這個指令碼應該是通用的,能被多次呼叫,不是針對性的。 
# sentinel client-reconfig-script <master-name> <script-path> 
sentinel client-reconfig-script mymaster /var/redis/reconfig.sh # 一般都是由運維來配 置! 

Redis快取穿透和雪崩

服務的高可用問題!

在這裡我們不會詳細的區分析解決方案的底層!

Redis快取的使用,極大的提升了應用程式的效能和效率,特別是資料查詢方面。但同時,它也帶來了一 些問題。其中,要害的問題,就是資料的一致性問題,從嚴格意義上講,這個問題無解。如果對資料 的一致性要求很高,那麼就不能使用快取。

另外的一些典型問題就是,快取穿透、快取雪崩和快取擊穿。目前,業界也都有比較流行的解決方案。

快取穿透(查不到)

概念

快取穿透的概念很簡單,使用者想要查詢一個數據,發現redis記憶體資料庫沒有,也就是快取沒有命中,於 是向持久層資料庫查詢。發現也沒有,於是本次查詢失敗。當用戶很多的時候,快取都沒有命中(秒 殺!),於是都去請求了持久層資料庫。這會給持久層資料庫造成很大的壓力,這時候就相當於出現了 快取穿透。

解決方案

布隆過濾器
布隆過濾器是一種資料結構,對所有可能查詢的引數以hash形式儲存,在控制層先進行校驗,不符合則 丟棄,從而避免了對底層儲存系統的查詢壓力;


快取空物件
當儲存層不命中後,即使返回的空物件也將其快取起來,同時會設定一個過期時間,之後再訪問這個數 據將會從快取中獲取,保護了後端資料來源;

但是這種方法會存在兩個問題:

1、如果空值能夠被快取起來,這就意味著快取需要更多的空間儲存更多的鍵,因為這當中可能會有很多 的空值的鍵;

2、即使對空值設定了過期時間,還是會存在快取層和儲存層的資料會有一段時間視窗的不一致,這對於 需要保持一致性的業務會有影響。

快取擊穿(量太大,快取過期!)

概述

這裡需要注意和快取擊穿的區別,快取擊穿,是指一個key非常熱點,在不停的扛著大併發,大併發集中 對這一個點進行訪問,當這個key在失效的瞬間,持續的大併發就穿破快取,直接請求資料庫,就像在一 個屏障上鑿開了一個洞

當某個key在過期的瞬間,有大量的請求併發訪問,這類資料一般是熱點資料,由於快取過期,會同時訪 問資料庫來查詢新資料,並且回寫快取,會導使資料庫瞬間壓力過大。

解決方案

設定熱點資料永不過期
從快取層面來看,沒有設定過期時間,所以不會出現熱點 key 過期後產生的問題。

分散式鎖:使用分散式鎖,保證對於每個key同時只有一個執行緒去查詢後端服務,其他執行緒沒有獲得分佈 式鎖的許可權,因此只需要等待即可。這種方式將高併發的壓力轉移到了分散式鎖,因此對分散式鎖的考 驗很大。

快取雪崩

概念

快取雪崩,是指在某一個時間段,快取集中過期失效。Redis 宕機

產生雪崩的原因之一,比如在寫本文的時候,馬上就要到雙十二零點,很快就會迎來一波搶購,這波商 品時間比較集中的放入了快取,假設快取一個小時。那麼到了凌晨一點鐘的時候,這批商品的快取就都 過期了。而對這批商品的訪問查詢,都落到了資料庫上,對於資料庫而言,就會產生週期性的壓力波 峰。於是所有的請求都會達到儲存層,儲存層的呼叫量會暴增,造成儲存層也會掛掉的情況。

其實集中過期,倒不是非常致命,比較致命的快取雪崩,是快取伺服器某個節點宕機或斷網。因為自然 形成的快取雪崩,一定是在某個時間段集中建立快取,這個時候,資料庫也是可以頂住壓力的。無非就 是對資料庫產生週期性的壓力而已。而快取服務節點的宕機,對資料庫伺服器造成的壓力是不可預知 的,很有可能瞬間就把資料庫壓垮。

解決方案

redis高可用
這個思想的含義是,既然redis有可能掛掉,那我多增設幾臺redis,這樣一臺掛掉之後其他的還可以繼續 工作,其實就是搭建的叢集。(異地多活!)

限流降級
這個解決方案的思想是,在快取失效後,通過加鎖或者佇列來控制讀資料庫寫快取的執行緒數量。比如對 某個key只允許一個執行緒查詢資料和寫快取,其他執行緒等待。

資料預熱
資料加熱的含義就是在正式部署之前,我先把可能的資料先預先訪問一遍,這樣部分可能大量訪問的數 據就會載入到快取中。在即將發生大併發訪問前手動觸發載入快取不同的key,設定不同的過期時間,讓 快取失效的時間點儘量均勻.

推薦課程:連結