Redis详解
什么是Redis?
概述:
Redis(Remote Dictionary Server ),即遠程字典服務,是一個開源的使用ANSI C語言編寫、支持網絡、可基于內存亦可持久化的日志型、Key-Value數據庫,并提供多種語言的API。
redis會周期性的把更新的數據寫入磁盤或者把修改操作寫入追加的記錄文件,并且在此基礎上實現了
master-slave(主從)同步。
免費和開源!是當下最熱門的 NoSQL 技術之一!也被人們稱之為結構化數據庫!
Redis能干嘛?
內存存儲,持久化,內存中是斷電既失,所以持久化很重要(rdb,aof)
效率高,可以用于高速緩存
發布訂閱系統
地圖信息分析
計時器,計數器(瀏覽量)
Redis特性
多樣的數據類型
持久化
集群
事務
....
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項目
導入依賴
<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>
開啟本地客戶端
連接遠程需要開啟防火墻端口
創建連接
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、執行 ?ushall 命令,也會觸發我們的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[故障轉移]操作。 切換成功后,就會通過發布訂閱模式,讓各個哨兵把自己監控的從服務器實現切換主機,這個過程稱為 客觀下線。
測試!
我們目前的狀態是 一主二從!
配置哨兵
配置哨兵配置文件 sentinel.conf
新建配置文件sentinel.conf
# sentinel monitor 被監控的名稱 host port 1
sentinel monitor myredis 127.0.0.1 6379 1
后面的這個數字1,代表主機掛了,slave投票看讓誰接替成為主機,票數多的,就會成為主機!
啟動哨兵!
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,設置不同的過期時間,讓 緩存失效的時間點盡量均勻.
推薦課程:鏈接
總結
- 上一篇: 可口的披萨,美味的披萨怎么拍照
- 下一篇: 两个视频怎么合成一个视频