1. 程式人生 > 資料庫 >【不建議收藏】Redis學習筆記

【不建議收藏】Redis學習筆記

這裡寫目錄標題

Redis快取型資料庫基礎

概述

Redis,遠端字典服務。

能幹什麼?

  • 資料持久化:RDB、OF
  • 效率高,快取記憶體
  • 釋出訂閱系統
  • 地圖資訊分析
  • 計時器、瀏覽量

特性

  • 多樣的資料型別
  • 持久化
  • 事務
  • 叢集

學習中需要用的東西

Redis官網:http://redis.io/

Redis中文網:http://www.redis.cn/

Github

Linux

安裝

Redis版本5.0.7

gcc版本4.8

redis解壓目錄:/redis-5.0.7

redis配置檔案目錄 /usr/local/bin/wzconfig/redis.conf

基本常識

redis有13個數據庫

一秒可以寫81000次或者讀110000次

Redis口令

Redis中儲存方式是鍵值對(key-value),所以set key 值為錄入資料,get key為取得資料

連線redis操作:cd /usr/local/bin進入redis安裝目錄,選擇redis配置檔案redis-server wzconfig/redis.conf,連線 redis-cli -p 6379

select 3,切換第4個數據庫

dbsize,當前資料庫大小

set name wz:意思是新增一欄位name,值為wz

get name:取得欄位name的值

keys *:檢視所有鍵名

flushdb:清空當前庫

flushall:清空所有庫

exists name:判斷記憶體中鍵值對是否存在,存在返回1,不存在返回0

MOVE name 1:移動鍵為name的鍵值對到1號資料庫中

EXPIRE name 10:設定鍵為name的鍵值對10秒後自動過期

ttl name:檢視鍵為name的鍵值對過期剩餘時間

type name:檢視鍵name對應值的型別

啟動redis服務

[root@iZwz923i6d0otioytcumi9Z bin]# redis-server wzconfig/redis.conf # 選擇啟動redis的配置檔案
22096:C 07 Dec 2020 16:33:36.518 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
22096:C 07 Dec 2020 16:33:36.518 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=22096, just started
22096:C 07 Dec 2020 16:33:36.518 # Configuration loaded
[root@iZwz923i6d0otioytcumi9Z bin]# redis-cli -p 6379 # 啟動

為什麼Redis是6379?

6379在是手機按鍵上MERZ對應的號碼,而MERZ取自義大利歌女的名字。MERZ長期以來被antirez及其朋友當作愚蠢的代名詞。作者antirez同學在twitter上說將在下一篇博文中向大家解釋為什麼他選擇作為號。而現在這篇博文出爐,在解釋了Redis的LRU機制之後,向大家解釋了採用6379作為預設埠的原因。

Redis讀寫方案

Redis是單執行緒的

Redis是很快的,Redis是基於記憶體操作的,所以Redis是根據機器的記憶體和網路頻寬,而不是CPU。

Redis是C語言寫的,為什麼單執行緒還這麼快?

1、誤區1:高效能的伺服器一定是多執行緒的。

2、誤區2:多執行緒(和CPU排程有關,CPU上下文會切換)一定比單執行緒效率高。

速度比:CPU>記憶體>硬碟

核心:Redis是將所有的資料全部放在記憶體中的,所以使用單執行緒操作效率就是最高的,多執行緒產生的CPU上下文切換導致速度變慢。對於記憶體系統來說,沒有上下文切換,效率就是最高的,多次讀寫都在一個CPU上那麼單執行緒就是最佳方案。

Redis資料型別

Redis是一個開源(BSD許可),記憶體儲存的資料結構伺服器,可用作資料庫,快取記憶體和訊息佇列代理(訊息中介軟體MQ)。它支援、、、、,,等資料型別。內建複製、、LRU收回、以及不同級別磁碟持久化功能,同時通過Redis Sentinel提供高可用,通過Redis Cluster提供自動。

Redis-Key

exists name# 判斷記憶體中鍵值對是否存在,存在返回1,不存在返回0

MOVE name 1# 移動鍵為name的鍵值對到1號資料庫中

EXPIRE name 10# 設定鍵為name的鍵值對10秒後自動過期

ttl name# 檢視鍵為name的鍵值對過期剩餘時間

type name# 檢視鍵name對應值的型別

String

90%的Java程式設計師使用redis只會使用一個String型別

append key1 wz # 在key1後面追加字串wz,如果key1是不存在的,相當於set key1 wz

INCR age# 使age對應的值自增1
INCRBY age 10# 使age對應的值自增10
DECR age# 使age對應的值自減1
DECRBY age 10# 使age對應的值自減5

getrange key1 0 3 #取得key1值的字串中下標為0到3的字元

getrange key1 0 -1# 取得key1值的整個字串

SETRANGE key2 2 q# 替換key2值的下標為2位置的字元

SETEX key3 30 "hello" #如果key3存在,則設定其值為hello,並在30秒還過期,否則建立失敗
SETNX mykey "redis" # 如果mykey不存在,則建立mykey並設定值為redis,否則建立失敗。在分散式鎖中經常使用

mset k1 vi k2 v2 k3 v3 #同時設定多個鍵值對,kl對v1,k2對v2,k3對v3
mget k1 k2 k3 # 使用多個鍵同時取得多個值,輸出結果如下
1) "vi"
2) "v2"
3) "v3" 
msetnx k4 v4# 如果k4不存在,則建立k4並賦值為v4
msetnx k1 v1 k4 v4# 如果k1和k4都不存在,則建立k1和k4並賦值為v1和v4,如果有一個已經存在,則失敗。原子性操作

#物件
set user:1{name:zhangsan,age:3}# 設定一個user:1物件,值為json字串來儲存物件

# 這裡的key是一個巧妙的設計:user:{id}:{filed}
 mset user:1:name zhangsan user:1:age 20
# 即通過key加id加屬性的方式實現工整有序不重複的儲存。可以使用key:{id}:屬性1、key:{id}:屬性2,key:{id}:屬性3等的方式拼出一個完整物件

# 
getset db "redis"# 相當於get db得到原值並輸出後,set db "redis"。如果不存在則返回null並設定新值,如果存在先返回原值再設定新的值

String型別的使用場景:value除了是字串還可以是數字!

  • 計數器
  • 瀏覽量
  • 統計多單位的數量,例:uid:999999:follow 0,設定uid為999999的使用者粉絲數為0
  • 物件快取儲存

List

列表,redis中List可以實現:棧、佇列、阻塞佇列。

所有的list命令都是L開頭的

LPUSH wzlist one #從左側插入,將一個值或者多個值插入到列表的頭部,寫入順是1,2,3儲存順序是3,2,1
LRANGE wzlist 0 -1#取得wzlist列表中所有內容
LRANGE wzlist 0 1#取得wzlist列表中下標為0到下標為1的內容(後進先出,最後進來的下標是0)
RPUSH wzlist right#從右側插入,將一個值或者多個值插入到列表的尾部,寫入順是1,2,3儲存順序就是1,2,3
LPOP wzlist #移除名為wzlist列表的第一個元素
RPOP wzlist#移除名為wzlist列表的最後一個元素
LINDEX wzlist 0#取得wzlist列表中下標為0的值

LLEN wzlist #取得wzlist列表的長度

LREM wzlist 4 3# 從頭部開始移除4個值為3的value

LTRIM wzlist 1 2#刪除列表中除下標為1、2的其他所有元素

RPOPLPUSH mylist myotherlist #移除mylist列表的最後一個元素,將其新增到myotherlist列表中

LSET mylist 0 value0# 修改mylist中下標為0的值修改為value0,如果列表或者下標不存在,則報錯。

LINSERT mylist before "1" "haha" #將haha插入到列表中1的前面
LINSERT mylist after "2" "haha"#將haha插入到列表中2的後面

小結:實際上是一個連結串列,before/Node/after/left/right都可以插入值

如果key不存在,建立新的連結串列

如果key存在,新增內容

如果移除了所以值,只剩key,此連結串列為空連結串列,也不存在

在兩邊插入或者改動值,效率最高,中間元素相對來說效率低。

Set:無序不重複集合

Set中的值是不能重複的,Set指令開頭都是S

127.0.0.1:6379> sadd myset hello# 向set集合myset中新增元素hello
(integer) 1
127.0.0.1:6379> SADD myset world# 向set集合myset中新增元素
(integer) 1
127.0.0.1:6379> SMEMBERS myset# 檢視myset中所有的值
1) "world"
2) "hello"
127.0.0.1:6379> SISMEMBER myset hello# 檢視hello是否在set中
(integer) 1
127.0.0.1:6379> SISMEMBER myset qq# 檢視hello是否在set中
(integer) 0
127.0.0.1:6379> scard myset# 獲取myset集合中有多少個值
(integer) 2
127.0.0.1:6379> SREM myset hello# 移除set中的值為hello的元素
(integer) 1
127.0.0.1:6379> SRANDMEMBER myset 1# 隨機抽取myset集合中的1個元素
"hello"
127.0.0.1:6379> SRANDMEMBER myset 2# 隨機抽取myset集合中的2個元素
"hello"
”world"

##############################
127.0.0.1:6379> SMEMBERS myset
1) "hello"
2) "world"
3) "hello3"
4) "hello2"
127.0.0.1:6379> spop myset 1# 隨機移除myset集合中的1個元素
"hello2"
127.0.0.1:6379> spop myset 2# 隨機移除myset集合中的2個元素
"hello3"
"hello"
127.0.0.1:6379> SMEMBERS myset
1) "world"

##############################
127.0.0.1:6379> SMEMBERS myset
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> SMOVE myset myset2 3# 移動myset中的為3的值到myset2中,如果myset2不存在則先建立後再移動
(integer) 1
127.0.0.1:6379> SMEMBERS myset2
1) "3"

############################
# 交併差
127.0.0.1:6379> sadd key1 a
(integer) 1
127.0.0.1:6379> sadd key2 b
(integer) 1
127.0.0.1:6379> sadd key1 c
(integer) 1
127.0.0.1:6379> sadd key2 c
(integer) 1
127.0.0.1:6379> sadd key2 d
(integer) 1
127.0.0.1:6379> sadd key1 e
(integer) 1
127.0.0.1:6379> SDIFF key1 key2# 取得key1和key2的差集
1) "e"
2) "a"
127.0.0.1:6379> SINTER key1 key2# 取得key1和key2的交集
1) "c"
127.0.0.1:6379> SUNION key1 key2# 取得key1和key2的並集
1) "b"
2) "c"
3) "e"
4) "a"
5) "d"

實際應用:

微博中,A使用者將所有關注的人放在一個set集合中。粉絲也放在一個set中。取得共同關注、共同好友。

六度分割理論。

Hash雜湊表

Map集合,key-value集合

Hash命令以H開頭

127.0.0.1:6379> hset myhash field1 wangzheng# 為myhash新增一個鍵值對,key:field1,value:wangzheng
(integer) 1
127.0.0.1:6379> HGET myhash field1# 檢視myhash中鍵值對中key為field1的value值
"wangzheng"
127.0.0.1:6379> HMSET myhash field1 hello field2 world# 批量對myhash新增鍵值對,如果包含已存在鍵值對,則覆蓋原有的
OK
127.0.0.1:6379> HMGET myhash field1 field2# 批量查詢myhash中的field1和field2對應的value值
1) "hello"
2) "world"
127.0.0.1:6379> HGETALL myhash# 列出myhash中所有的鍵值對,序號奇數為key,偶數為value
1) "field1"
2) "hello"
3) "field2"
4) "world"

127.0.0.1:6379> HDEL myhash field1# 刪除myhash中鍵名為field1的鍵值對
(integer) 1

127.0.0.1:6379> HLEN myhash# 檢視myhash表長度
(integer) 3

127.0.0.1:6379> HEXISTS myhash field1# 判斷myhash表中是否存在field1欄位
(integer) 1
127.0.0.1:6379> HKEYS myhash# 獲取所有的key
1) "field2"
2) "field1"
3) "field3"

27.0.0.1:6379> HINCRBY myhash field4 1# 自增1
(integer) 2

127.0.0.1:6379> HSETNX myhash field hello# 如果myhash中不存在field欄位則建立並賦值為hello,否則執行失敗。
(integer) 0

實際應用:

和String類似,hash更適合儲存物件。

用於使用者資訊、經常變動的資訊的儲存。

Zset有序集合

在set的基礎上,增加了一個值score用來計數。

127.0.0.1:6379> ZADD myset 1 one# 新增一個值
(integer) 1
127.0.0.1:6379> ZADD myset 2 two 3 three# 新增多個值
(integer) 2
127.0.0.1:6379> ZRANGE myset 0 -1# 查詢所有
1) "one"
2) "two"
3) "three"

127.0.0.1:6379> ZADD salary 2500 xiaohong
(integer) 1
127.0.0.1:6379> ZADD salary 5000 zhangsan
(integer) 1
127.0.0.1:6379> ZADD salary 199999 wangzheng
(integer) 1
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf # 根據score從小到大排列,範圍是負無窮到正無窮(從小到大不可改變)。
1) "xiaohong"
2) "zhangsan"
3) "wangzheng"
127.0.0.1:6379> ZREVRANGE salary 0 -1# 根據score從大到小排列,範圍是所有元素。
1) "wangzheng"
2) "zhangsan"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf 2500 withscores# 根據score從小到大排列,範圍是負無窮到2500(從小到大不可改變),並顯示具體值。
1) "xiaohong"
2) "2500"
127.0.0.1:6379> ZREM salary xiaohong# 移除小紅
(integer) 1
127.0.0.1:6379> ZCARD salary# 獲取集合中元素個數
(integer) 2
127.0.0.1:6379> ZCOUNT myset 0 1# 獲取區間元素個數
(integer) 1

實際應用:

實現優先順序。

排行榜

三種特殊資料型別

geospatial

地理位置

規則:兩極地區無法直接新增,我實際開發中下載城市位置,使用Java一次性匯入。

127.0.0.1:6379>  geoadd china:city 116.4 39.9 beijing# 新增地理位置
(integer) 1
127.0.0.1:6379> GEOPOS china:city beijing# 獲取指定城市的經緯度
1) 1) "116.39999896287918091" #經度
   2) "39.90000009167092543" #緯度
127.0.0.1:6379> GEOPOS china:city beijing shanghai aomen# 獲取多個城市經緯度
1) 1) "116.39999896287918091"
   2) "39.90000009167092543"
2) 1) "121.40000134706497192"
   2) "31.20000061483705878"
3) 1) "113.49999994039535522"
   2) "22.19999914574732003"
127.0.0.1:6379> GEODIST china:city beijing shanghai# beijing和shanghai之間的直線距離
"1067742.3622"# 預設單位米
127.0.0.1:6379> GEODIST china:city beijing shanghai km # beijing和shanghai之間的直線距離,設定單位為千米
"1067.7424"

127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km# 以經緯度110 30為原心,1000km為半徑,尋找在china:city中滿足這個範圍內的城市。
1) "aomen"
2) "xianggang"
3) "shenzhen"
4) "guangzhou"
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km withcoord# 加一個withcoord是顯示詳細經緯度
1) 1) "aomen"
   2) 1) "113.49999994039535522"
      2) "22.19999914574732003"
2) 1) "xianggang"
   2) 1) "114.19999748468399048"
      2) "22.29999896492555678"
3) 1) "shenzhen"
   2) 1) "114.09999936819076538"
      2) "22.50000113800319212"
4) 1) "guangzhou"
   2) 1) "113.29999834299087524"
      2) "23.10000005307264104"
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km withdist# 加一個withdist顯示直線距離
1) 1) "aomen"
   2) "935.1758"
2) 1) "xianggang"
   2) "953.3433"
3) 1) "shenzhen"
   2) "928.8366"
4) 1) "guangzhou"
   2) "834.6077"
127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 10000 km# china:city中beijing的經緯度為中心,10000千米為半徑,尋找在china:city中滿足這個範圍內的城市
1) "aomen"
2) "xianggang"
3) "shenzhen"
4) "guangzhou"
5) "xiangshan"
6) "shanghai"
7) "beijing"
127.0.0.1:6379> GEOHASH china:city beijing shanghai# 將china:city集合中的beijing、shanghai二維的經緯度,轉換成一維的字串
1) "wx4fbxxfke0"
2) "wtw36xbc1j0"

GEO中命名的實現原理是Zset,所以我們可以使用Zset操作GEO,如下

127.0.0.1:6379> ZRANGE china:city 0 -1# 使用Zset來查詢所有地理資訊
1) "aomen"
2) "xianggang"
3) "shenzhen"
4) "guangzhou"
5) "xiangshan"
6) "shanghai"
7) "beijing"
127.0.0.1:6379> ZREM china:city xianggang# 刪除指定地理位置
(integer) 1
127.0.0.1:6379> ZRANGE china:city 0 -1
1) "aomen"
2) "shenzhen"
3) "guangzhou"
4) "xiangshan"
5) "shanghai"
6) "beijing"

Hyperloglog資料結構

用於基數統計的演算法

基數,多個數據集中不重複的元素,可以接受誤差。

一個人訪問同一網站多次還是算作一個人。

**傳統方式:**使用set儲存使用者id,set不允許重複,用set的元素數量來作為判斷標準。

**題:**如果儲存大量使用者id,導致記憶體佔用嚴重。

Hyperloglog的優點

佔用記憶體是固定的,即使儲存2^64個不同元素的基數,只需要12KB記憶體,如果要從記憶體角度來比較的話,Hyperloglog是首選。

但是有0.81%的錯誤率。統計使用者訪問量(UV)資料可以忽略不計。

127.0.0.1:6379> PFADD mykey a b c d e f g h i j k l m n# 建立第一組元素
(integer) 1
127.0.0.1:6379> PFCOUNT mykey# 顯示資料量
(integer) 14
127.0.0.1:6379> PFADD mykey2 o p q r s t u v w x y z# 建立第二組元素
(integer) 1
127.0.0.1:6379> PFCOUNT mykey2# 顯示資料量
(integer) 12
127.0.0.1:6379> PFMERGE mykey3 mykey mykey2# 將mykey3賦值為mykey和mykey2的不重複並集,如果出現重複,則只保留一個其餘的均忽略
OK
127.0.0.1:6379> PFCOUNT mykey32# 顯示資料量
(integer) 25

Bitmaps點陣圖

位儲存

統計使用者資訊、統計疫情資訊

都是操作二進位制位來進行記錄,就只有1和0兩個狀態。

如打卡每天打一次卡,365天就是365bit,1位元組等於8bit,儲存365天約46位元組即可。

# 情景再現:員工打卡系統,sign代表打卡者,0代表星期一,1代表星期二,以此類推,記錄為1代表打卡成功,記錄為0代表打卡失敗
# 錄入
127.0.0.1:6379> setbit sign 0 1# 下標為0,記錄為1,打卡
(integer) 0
127.0.0.1:6379> setbit sign 1 0# 下標為1,記錄為0,未打卡
(integer) 0

# 查詢
127.0.0.1:6379> getbit sign 3# 檢視星期四是否打卡
(integer) 0 # 否
127.0.0.1:6379> getbit sign 0# 檢視星期一是否打卡
(integer) 1 # 是

# 統計
127.0.0.1:6379> BITCOUNT sign# 統計sign所有資料中為1的資料的總數,即統計sign本週打卡成功的情況
(integer) 3

事務回顧

事務的四個基本特徵:
Atomic(原子性):事務中包含的操作被看做一個邏輯單元,這個邏輯單元中的操作要麼全部成 功,要麼全部失敗。

Consistency(一致性):事務完成時,資料必須處於一致狀態,資料的完整性約束沒有被破壞,事務在執行過程中發生錯誤,會被回滾(Rollback)到事務開始前的狀態,就像這個事務從來沒 有執行過一樣。

Isolation(隔離性):事務允許多個使用者對同一個資料進行併發訪問,而不破壞資料的正確性 和完整性。同時,並行事務的修改必須與其他並行事務的修改相互獨立。

Durability(永續性):事務結束後,事務處理的結果必須能夠得到固化。


Redis事務

Redis事務和普通事務的區別:

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

Redis事務沒有隔離性,沒有隔離級別的概念。

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

Redis事務本質:一組命令的集合。

一次性:Redis中命令集合按照順序排列在一個佇列中一次執行完畢。

順序性:一個事務中所有的命令都會被序列化,在事務執行過程中,會按照順序執行。

排他性:事務執行中不允許其他干擾。

Redis事務步驟:

  • 開啟事務
  • 命令入隊
  • 執行事務

鎖:Redis實現樂觀鎖

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> set k3 v3# 語句入隊
QUEUED
127.0.0.1:6379> exec# 執行事務// 注意在執行完exec語句後,再需要使用事務需要再次multi開啟
1) OK
2) OK
3) OK

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> set k4 v4# 語句入隊
QUEUED
127.0.0.1:6379> DISCARD# 取消事務// 注意在執行完DISCARD語句後,再需要使用事務需要再次multi開啟
OK
127.0.0.1:6379> get k4# k4存入失敗,事務取消成功
(nil)

# 如果語句出現問題,那麼整個事務不執行。比如下面入隊一個不存在的語句getset
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v3
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> getset k3
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> set k5 v5
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> 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> get k2
QUEUED
127.0.0.1:6379> exec
1) (error) ERR value is not an integer or out of range
2) OK
3) "v2"

面試常問:Redis監控(Watch)和實現樂觀鎖

悲觀鎖:

  • 認為所有時候都會出問題,無論做什麼都加鎖。

樂觀鎖:

  • 認為所有時候都不會出現問題,所以不會上鎖。
  • 在更新資料的時候去判斷一下,在此期間是否有人修改這個資料,使用version來判斷。
  • 更新時候比較和上次的version是否一致。

Redis監視測試

# 情景再現:持有100元money,使用20元out
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物件,一旦事務執行成功,監控就會自己取消掉,如果事務沒有執行成功,則需要使用unwatch語句手動解鎖。
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

如果出現第一個執行緒還未進行修改money時,第二個執行緒搶先一步修改了money.

使用watch可以當做redis的樂觀鎖操作。

測試:

# 執行緒1開啟監視,並啟動事務,命令入隊。
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

# 執行緒2突然出現,修改了money的值,此時執行緒1的事務還沒有執行,但是指令已經入隊
127.0.0.1:6379> set money 1000# 修改money值
OK

 # 執行緒1,執行事務失敗,返回空
127.0.0.1:6379> exec# 執行事務
(nil)

# 此時想要繼續完成操作,需要解開監視,加監視,啟動事務,命令入隊,完成執行。
127.0.0.1:6379> unwatch# 解開監視
OK
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# 比對監視的值是否發生變化,如果沒有變化,執行成功。否則執行失敗
1) (integer) 990
2) (integer) 30

Jedis

使用Java來操作Redis,Jedis是Redis推薦的Java連線開發工具,是Java操作Redis的中介軟體。

匯入Jedis包:

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.2.0</version>
        </dependency>

編碼測試:

  • 連線資料庫

  • public class TestPing {
        public static void main(String[] args) {
            // 1、 new一個Jedis物件
            Jedis jedis = new Jedis("127.0.0.1",6379);
            // Jedis所有的命令就是Redis命令
            System.out.println(jedis.ping());
            //連線成功輸出PONG
        }
    }
    
  • 操作命令

  • 結束測試

常用API

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-wWrM7wL2-1607850961471)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201207085155607.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-Turhs59W-1607850961474)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201207085219477.png)]

String

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-3Zmz0H6o-1607850961475)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201207085743192.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-3LyQzrSY-1607850961478)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201207085832484.png)]

List

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-n5X853Su-1607850961480)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201207090025696.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-htwtLRTg-1607850961481)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201207090119141.png)]

Set

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-HeGE292y-1607850961482)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201207090216934.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-eYevspQe-1607850961482)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201207090223805.png)]

Hash

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-EaDrO0qI-1607850961483)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201207090341102.png)]

Zset

三種特殊型別

Jedis事務

public class TestTX {
    public static void main(String[] args) {
        //連線
        Jedis jedis = new Jedis("127.0.0.1", 6379);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("hello","world");
        jsonObject.put("name","wz");

        //開啟事務
        Transaction multi = jedis.multi();
        String res = jsonObject.toJSONString();
//        jedis.watch(res);
        try {
            multi.set("user1",res);
            multi.set("user2",res);

            int i = 1/0;// 異常模擬

            multi.exec();// 執行事務

        }catch (Exception e){
            multi.discard();// 如果出現異常,就放棄事務。
            e.printStackTrace();
        }finally {
            System.out.println(jedis.get("user1"));
            System.out.println(jedis.get("user2"));
            jedis.flushDB();
            jedis.close(); //關閉連線
        }
    }
}

Springj整合Redis

SpringBoot相關的資料操作都被封裝到SpringData中,如JDBC、JPA、MongoDB、Redis等等。

MyBatis是主動迎合的Spring,釋出了MyBatis-Spring,所以MyBatis不在SpringData中。

SpringBoot2.x之後底層由Jedis替換為了lettuce

Jedis:採用的直連,多個執行緒操作是不安全的,如果想要避免不安全,就需要使用Jedis pool連線池,導致效能較低。BIO模式

lettuce:底層採用netty,例項可以在多個執行緒中進行共享,不存線上程不安全的情況。可以減少執行緒資料。NIO模式。

SpringRedis原始碼分析

public class RedisAutoConfiguration {
    public RedisAutoConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean(name = {"redisTemplate"}) // 如果不存在此方法,就實現此方法,意思就是可以自己手動實現來替代此方法。
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        //預設的RedisTemplate沒有過多的設定,Redis物件都是需要序列化(即按照順序儲存)
        //兩個泛型是<Object, Object>型別,我們後使用需要強制型別轉換<String, Object>
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean // 由於String是redis中最常使用的型別,所以說單獨提出來了一個bean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

整合測試

匯入依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

配置連線

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

測試

值的序列化配置,預設的序列化方式是jdk序列化

private boolean initialized = false;
private boolean enableDefaultSerializer = true;
@Nullable
private RedisSerializer<?> defaultSerializer;
@Nullable
private ClassLoader classLoader;
@Nullable
private RedisSerializer keySerializer = null;
@Nullable
private RedisSerializer valueSerializer = null;
@Nullable
private RedisSerializer hashKeySerializer = null;
@Nullable
private RedisSerializer hashValueSerializer = null;
private RedisSerializer<String> stringSerializer = RedisSerializer.string();
@Nullable
private ScriptExecutor<K> scriptExecutor;

編寫自己的RedisTemplate配置,固定模板,企業中可以直接使用。

作用是替代JDK序列化,解決控制檯中輸出英文或者中文是亂碼的問題。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-7RSnhQjq-1607850961484)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201207131414271.png)]

// 在企業開發中,我們80%不會使用原生的序列化操作,即原生的redis。
// 在真實的開發中,都會看到一個公司自己封裝的RedisUtils或者RedisTools,自己實現的Redis操作。企業級開發大部分不使用原生的。

基礎總結

在實際開發中:

讀請求:

不要求強一致性的讀請求,走Redis,要求強一致性的直接從MySQL讀取。

寫請求:

資料首先都寫到MySQL資料庫,之後更新Redis(先寫redis再寫MySQL的話,如果寫入失敗MySQL事務回滾,又因為Redis事務的性質特殊,會造成Redis中存在上一次操作的髒資料)。

MySQL和Redis處理不同的資料型別

  • MySQL處理實時性資料,例如金融資料、交易資料。
  • Redis處理實時性要求不高的資料,例如網站最熱貼排行榜,好友列表等。

在併發不高的情況下,讀操作優先讀取redis,不存在的話就去訪問MySQL,並把讀到的資料寫回Redis中;寫操作的話,直接寫MySQL,成功後再寫入Redis(可以在MySQL端定義CRUD觸發器,在觸發CRUD操作後寫資料到Redis,也可以在Redis端解析binlog,再做相應的操作)

在併發高的情況下,讀操作和上面一樣,寫操作是非同步寫,寫入Redis後直接返回,然後定期寫入MySQL

需要頻繁呼叫且不經常變動的資料使用redis操作get到轉換為JSON返回給前端,就不再回到底層查詢MySQL資料庫,效率提升。






Redis進階導論

Redis.conf詳解

啟動時通過配置檔案啟動的。

單位

# Redis configuration file example.
#
# Note that in order to read the configuration file, Redis must be
# started with the file path as first argument:
#
# ./redis-server /path/to/redis.conf

# Note on units: when memory size is needed, it is possible to specify
# it in the usual form of 1k 5GB 4M and so forth:
#
# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes
#
# units are case insensitive so 1GB 1Gb 1gB are all the same.
大小寫不敏感

配置檔案unit單位對大小寫不敏感。

包含

# Include one or more other config files here.  This is useful if you
# have a standard template that goes to all Redis servers but also need
# to customize a few per-server settings.  Include files can include
# other files, so use this wisely.
#
# Notice option "include" won't be rewritten by command "CONFIG REWRITE"
# from admin or Redis Sentinel. Since Redis always uses the last processed
# line as value of a configuration directive, you'd better put includes
# at the beginning of this file to avoid overwriting config change at runtime.
#
# If instead you are interested in using includes to override configuration
# options, it is better to use include as the last line.
#
# include /path/to/local.conf
# include /path/to/other.conf

好比學習Spring中可以把多個配置檔案配置過來。

網路

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

通用

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是記憶體資料庫,沒有持久化資料斷電即失去。

save 900 1 # 如果900秒(15分鐘)內至少有1個key進行了修改,則進行持久化操作
save 300 10# 如果300秒(5分鐘)內至少有10個key進行了修改,則進行持久化操作
save 60 10000# 如果60秒(1分鐘)內至少有10000個key進行了修改,則進行持久化操作
# 我們之後會自己定義

stop-writes-on-bgsave-error yes# 持久化如果出錯是否還需要繼續工作,預設開啟,一般情況下開啟
rdbcompression yes #是否壓縮rdb檔案,需要消耗一些CPU資源
rdbchecksum yes# 儲存rdb檔案時是否去錯誤校驗rdb檔案
dir ./ # rdb檔案的儲存目錄

安全

設定redis密碼,預設是沒有密碼的

127.0.0.1:6379> config get requirepass #檢視密碼
1) "requirepass"
2) ""
127.0.0.1:6379> config set requirepass root123# 設定密碼
OK
127.0.0.1:6379> config get requirepass# 沒有登入無法使用功能
(error) NOAUTH Authentication required.
127.0.0.1:6379> pings# 沒有登入無法使用功能
(error) NOAUTH Authentication required.
127.0.0.1:6379> auth root123 # 登入
OK
127.0.0.1:6379> config get requirepass# 登入後可以使用
1) "requirepass"
2) "root123"

限制

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

maxmemory-policy 六種策略

**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# 每1秒執行一次sync,可能會丟失者1秒的資料
# appendfsync no #不執行sync,這個時候作業系統自己同步資料,速度最快

具體配置在Redis持久化中進行學習。

Redis持久化

面試和工作持久化都是重點

RDB

資料存入,再次啟動時讀出。

什麼時候使用?在主從複製中,rdb就是備用的,從機上面使用。

什麼是RDB

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-a7SZNEUU-1607850961484)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201207152005468.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-uYTNf1uF-1607850961485)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201207152015171.png)]

rdb儲存的檔案是dump.rdb,關於如何觸發建立dump.rdb都是在redis.conf配置的快照中進行配置的。

只要dump.rdb檔案生成,即使關機失去記憶體,也能在下一次啟動時成功讀取到持久化的資訊。

rdb觸發機制

1、save的規則滿足的情況下會自動觸發.rdb檔案的建立

2、執行了flushdb或者flushall也會生成 .rdb檔案

3、退出redis,也會產生rdb檔案

備份就會自動生成dump.rdb

只要dump.rdb檔案生成,即使關機失去記憶體,也能在下一次啟動時成功讀取到持久化的資訊。

如何恢復rdb檔案

只需要將rdb檔案放在redis啟動目錄下即可,redis啟動時會自動檢查dump.rdb檔案恢復其中的資料到記憶體中。

127.0.0.1:6379> config get dir
1) "dir"
2) "/usr/local/bin" # 如果在此目錄下存在dump.rdb檔案,redis啟動就會自動恢復dump.rdb中的內容到記憶體中。

幾乎預設的配置已經夠用了,但是我們還是要去學習。

優點:

1、適合打大規模的資料恢復。應用情景:伺服器宕機後,redis啟動目錄中的dump.rdb檔案將資料恢復到宕機前的模樣。

2、對資料完整性要求不高。如果設定60秒內10000次訪問才觸發生成dump.rdb,那麼在

AOF

幾乎不使用

將所有命令都記錄下來,有一個歷史檔案,恢復時候將此檔案全部再執行一遍。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-rrKUVAij-1607850961485)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201207162342519.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-FxSNMB14-1607850961486)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201207161940712.png)]

AOF儲存的是appendonly.aof,也是在配置檔案redis.conf中配置。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-F7T83vPw-1607850961486)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201207162320811.png)]

預設是不開啟aof的,我們需要主動進行配置

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-BUEFZNvQ-1607850961487)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201207162702453.png)]

no改為yes

重啟redis就可以生效了

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-7oEQxsbP-1607850961488)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201207163543616.png)]

appendonly.aof建立成功

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-6JMtjxH1-1607850961488)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201207163908956.png)]

如果aof檔案有錯誤,此時redis是啟動不起來的,我們需要修復aof這個檔案。

重寫規則說明

redis會記錄上一次aof檔案的大小,如果aof檔案大於64MB,將fork一個新的程序來將為aof檔案進行重寫。

aof預設的是檔案的無限追加,所以這個檔案只會越來越大。

優點和缺點

優點:

1、每一次修改都同步,檔案的完整性比較好。

appendonly no # 預設是不開啟aof模式的,預設使用rdb方式持久化,在大部分情況下,rdb完全夠用
appendfilename "appendonly.aof #持久化檔案的名字

# appendfsync always #每次都會修改sync,消耗效能
appendfsync everysec# 每1秒執行一次sync,可能會丟失者1秒的資料
# appendfsync no #不執行sync,這個時候作業系統自己同步資料,速度最快

2、每秒同步一次,可能會丟失一秒的資料。

3、從不同步,效率最高。

缺點:

1、相對於資料檔案來說,即aof檔案遠遠大於rdb,修復速度也比rdb慢。

2、aop檔案的讀寫效率慢,所以redis預設是rdb而不是aof

RDB和AOF的擴充套件

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-CfrGuXQh-1607850961489)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201207174918785.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-h4ZQEmB2-1607850961490)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201207175652075.png)]

Redis釋出訂閱

Redis釋出訂閱是一種訊息模式:傳送者傳送訊息,訂閱者接受訊息。舉例:微信、微博、關注系統。

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

三個角色:訊息傳送者、頻道、訊息訂閱者

訂閱並不是Redis特有的,只是Redis也可以實現。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-ayOuzTzs-1607850961490)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201208102943383.png)]

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

img

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

img

Redis 釋出訂閱命令

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

channel頻道,message訊息

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-AJTLxdGv-1607850961492)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201208103503766.png)]

測試

訂閱端:

# 訂閱者對頻道wz發起訂閱
127.0.0.1:6379> SUBSCRIBE wz
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "wz"
3) (integer) 1

釋出端:

# 釋出者向頻道wz發起訊息
127.0.0.1:6379> PUBLISH wz "hello"
(integer) 1

訂閱端得到釋出端推送的資訊展示

# 訂閱者收到訊息後實時更新
127.0.0.1:6379> SUBSCRIBE wz
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "wz"
3) (integer) 1
1) "message" # 訊息
2) "wz" # 頻道
3) "hello" # 訊息內容

Redis訂閱釋出原理

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-nAnyRwuK-1607850961493)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201208105250782.png)]

實際應用:

1、實時訊息系統。在註冊完網頁後,自動訂閱網站官方這個頻道,從而實現官方向使用者的推送。

2、實時聊天。將資訊回顯即可。

訂閱、關注系統。

稍微複雜的場景我們就會使用專門的訊息中介軟體來做,例如MQ、Kafka

Redis主從複製

主從複製,是指將一臺Redis伺服器的資料,複製到其他的Redis伺服器。前者稱為主節點(master/leader),後者稱為從節點(slave/follower);資料的複製是單向的,只能由主節點到從節點。預設情況下,每臺Redis伺服器都是主節點;且一個主節點可以有多個從節點(或沒有從節點),但一個從節點只能有一個主節點。
image.png

  1. 一個master可以有多個slave(最少是一主二從)
  2. 一個slave只能有一個master
  3. 資料流向是單向的,master到slave(主節點到從節點,主節點寫,從節點寫。)
  4. 主從複製,讀寫分離。80%情況下都是在讀。所以將寫的請求放在主節點,讀的請求放在從節點,減緩伺服器壓力。

主從複製的作用

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-JWUxc9B2-1607850961493)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201208122659357.png)]

ps:高可用一般指叢集。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-Oig7Tovz-1607850961494)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201208122837612.png)]

只要在公司中,主從複製就是必須使用的,因為在真實開發中不可能單機使用redis,因為會有效能瓶頸。

環境配置

只配置從機,不配置主機,因為每臺redis伺服器本身就預設是主節點。

127.0.0.1:6379> info replication #檢視當前庫的角色
# Replication
role:master
connected_slaves:0
master_replid:fb1c53140ad7f8cacaf39d7e39fd64b8014deeea
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

一主二從偽叢集模式搭建:

複製三個配置檔案,修改對應的配置資訊。

1、修改埠號

2、pid名字

3、日誌名

4、備份檔案dump.rdb檔名

修改完畢後啟動三個redis服務

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-YBk2vg8r-1607850961495)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201208124422579.png)]

啟動成功驗證:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-Vtf67dVg-1607850961495)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201208124252046.png)]

配置從機:

從機1

127.0.0.1:6380> SLAVEOF 127.0.0.1 6379
OK
127.0.0.1:6380> info replication
# Replication
role:slave# 身份是從機
master_host:127.0.0.1
master_port:6379 # 主機埠號
master_link_status:up
master_last_io_seconds_ago:9
master_sync_in_progress:0
slave_repl_offset:14
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:38d163d200d5c9b7c6e88773fe8564802f0e67a6
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:14
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:14

從機2

127.0.0.1:6381> SLAVEOF 127.0.0.1 6379
OK
127.0.0.1:6381> info replication
# Replication
role:slave # 身份是從機
master_host:127.0.0.1
master_port:6379# 主機埠號
master_link_status:up
master_last_io_seconds_ago:7
master_sync_in_progress:0
slave_repl_offset:42
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:38d163d200d5c9b7c6e88773fe8564802f0e67a6
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:42
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:43
repl_backlog_histlen:0

檢視主機資訊:

127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2 # 從機數
slave0:ip=127.0.0.1,port=6380,state=online,offset=84,lag=1# 從機1
slave1:ip=127.0.0.1,port=6381,state=online,offset=84,lag=1# 從機2
master_replid:38d163d200d5c9b7c6e88773fe8564802f0e67a6
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:84
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:84

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

細節

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

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-Ush2yP34-1607850961496)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201208132619528.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-vNQxWjR3-1607850961496)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201208132642304.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-ELLVnW2b-1607850961497)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201208132608873.png)]

測試:

主機斷開連線:

主機斷開連線,從機依舊是連線到主機的,只是沒有寫操作了,從機依舊可以獲得主機寫入過的資訊,如果此時主機重新連線了,此時可以重新獲取到主機寫的資訊。

從機斷開連線:

前提是使用命令方式設定主從複製,而不是使用配置檔案實現主從複製的情況下,從機斷開連線後,重新連線後此從機自動變回主機,不再能獲得原來是從機身份時主機中的內容,如果此時重新變回從機,就會重新獲得主機的內容。

主從複製原理

  • 全量複製
  • 增量複製

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-hYwjNP9J-1607850961497)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201208140409724.png)]

崩星咆哮炮主從複製模型搭建(”我是火車王“模型)

主機A下掛載一個從機B,從機B下掛載從機C。

此時從機B的主機是A,從機C的主機是B,A中寫入資料,B讀取A成功後,C也能從B中讀取到A的資料。

A——>B——>C

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-Nk6gsFsk-1607850961498)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201208141724018.png)]

如果此時主機崩潰,如何才能從從機中選出一個當作新主機?

127.0.0.1:6381> SLAVEOF no one # 表明已經無主機可用,將自己作為主機。
OK
127.0.0.1:6381> INFO replication # 檢查主從複製配置
# Replication
role:master # 已經變為主機
connected_slaves:0
master_replid:b5b46f59a09000b5a85bd610dc24ffa564cccc74
master_replid2:38d163d200d5c9b7c6e88773fe8564802f0e67a6
master_repl_offset:7473
second_repl_offset:7474
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:43
repl_backlog_histlen:7431

如果此時主機恢復了,就只能重新配置。

Redis主從複製哨兵模式(工作中用)

自動選取主機的模式。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-uleXT0lV-1607850961498)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201208144624716.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-DZL4IQ6K-1607850961499)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201208144749087.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-yo2mKNro-1607850961499)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201208144909750.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-ew1AzUwG-1607850961500)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20201208144942034.png)]

測試

1、建立哨兵配置檔案sentinel.conf,固定名稱,不能拼錯。

2、在哨兵配置檔案中寫入

sentinel monitor myredis 127.0.0.1 6379 1# 自定義監控名稱myredis,監控目標127.0.0.1下的6379埠,1的意思是如果主機掛了就自動去已掛主機下的從機中票選一個票數最多的從機,成為新的主機。

3、啟動哨兵

[root@iZwz923i6d0otioytcumi9Z bin]# redis-sentinel wzconfig/sentinel.conf # 哨兵模式啟動,配置檔案是sentinel.conf
23516:X 08 Dec 2020 15:13:37.984 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
23516:X 08 Dec 2020 15:13:37.984 # Redis version=5.0.7, bits=64, commit=00000000, modified=0, pid=23516, just started
23516:X 08 Dec 2020 15:13:37.984 # Configuration loaded
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 5.0.7 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in sentinel mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 26379
 |    `-._   `._    /     _.-'    |     PID: 23516
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

23516:X 08 Dec 2020 15:13:37.985 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
23516:X 08 Dec 2020 15:13:37.987 # Sentinel ID is 334f503724eb834cfbbb2498f75fc2847e6b9496
23516:X 08 Dec 2020 15:13:37.987 # +monitor master myredis 127.0.0.1 6379 quorum 1

此時斷開6379主機連線,哨兵模式替換開始運作