NoSQL 開發中或多或少都會用到,也是面試必問知識點。最近這幾天的面試每一場都問到了。但是感覺回答的並不好,還有很多需要梳理的知識點。這裡通過幾篇 Redis 筆記整個梳理一遍,後面再加上面試題。 Redis 系列: 1. Redis系列(一)Redis入門 2. Redis系列(二)Redi... ...
NoSQL 開發中或多或少都會用到,也是面試必問知識點。最近這幾天的面試每一場都問到了。但是感覺回答的並不好,還有很多需要梳理的知識點。這裡通過幾篇 Redis 筆記整個梳理一遍,後面再加上面試題。
Redis 系列:
- Redis系列(一)Redis入門
- Redis系列(二)Redis的8種數據類型
- Redis系列(三)Redis的事務和Spring Boot整合
- Redis系列(四)Redis配置文件和持久化
- Redis系列(五)發佈訂閱模式、主從複製和哨兵模式
- Redis系列(六)Redis 的緩存穿透、緩存擊穿和緩存雪崩
- Redis命令參考
1、Redis 訂閱發佈
Redis 發佈訂閱(pub/sub)是一種消息通信模式:發送者發(pub)送消息,訂閱者(sub)接收消息。
Redis 客戶端可以訂閱任意數量的頻道。
訂閱 / 發佈消息圖:
下圖展示了頻道 channel1,已經訂閱這個頻道的三個客戶端。
當有新消息通過 publish 命令發送給頻道 channel1 時,這個消息就會被髮送給訂閱它的三個客戶端。
命令
這些命令被廣泛應用於構建即時通訊應用、比如網路聊天室和實時廣播、實時提醒等。
序號 | 命令及描述 |
---|---|
1 | [PSUBSCRIBE pattern pattern ...] 訂閱一個或多個符合給定模式的頻道。 |
2 | [PUBSUB subcommand argument [argument ...]] 查看訂閱與發佈系統狀態。 |
3 | PUBLISH channel message 將信息發送到指定的頻道。 |
4 | [PUNSUBSCRIBE pattern [pattern ...]] 退訂所有給定模式的頻道。 |
5 | [SUBSCRIBE channel channel ...] 訂閱給定的一個或多個頻道的信息。 |
6 | [UNSUBSCRIBE channel [channel ...]] 指退訂給定的頻道。 |
測試
以下實例演示了發佈訂閱是如何工作的。在我們實例中我們創建了訂閱頻道名為 redisChat:
redis 127.0.0.1:6379> SUBSCRIBE redisChat
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "redisChat"
3) (integer) 1
現在,我們先重新開啟個 redis 客戶端,然後在同一個頻道 redisChat 發佈兩次消息,訂閱者就能接收到消息。
redis 127.0.0.1:6379> PUBLISH redisChat "Redis is a great caching technique"
(integer) 1
redis 127.0.0.1:6379> PUBLISH redisChat "Learn redis by runoob.com"
(integer) 1
# 訂閱者的客戶端會顯示如下消息
1) "message"
2) "redisChat"
3) "Redis is a great caching technique"
1) "message"
2) "redisChat"
3) "Learn redis by runoob.com"
原理
Redis 是使用 C 實現的,通過分析 Redis 源碼里的 public.c 文件,瞭解發佈和訂閱機制的底層實現,藉此加深對 Redis 的理解。Redis 通過 public 、subscribe 和 psubscribe 等命令實現發佈和訂閱功能。
微信:
通過 subscribe 命令訂閱某頻道後,redis=server 裡面維護了一個字典,字典的鍵就是一個個頻道!而字典的值則是一個鏈表,鏈表保存了所有訂閱這個 channel 的客戶端。subscribe 命令的關鍵,就是講客戶端添加到給定 channel 的訂閱鏈中。
通過 publish 命令向訂閱者發送消息,redis-server 會使用給定的頻道作為鍵,在它所維護的channel 字典中查找記錄了訂閱這個頻道的所有客戶端的鏈表,遍歷這個鏈表,將消息發佈給所有的訂閱者。
使用場景:
1、實時消息系統
2、實時聊天
3、訂閱、關註系統都可以
稍微複雜的場景更多的使用消息中間件 MQ。
2、主從複製
1、概念
主從複製,是指將一臺 Redis 伺服器的數據,複製到其他的 Redis 伺服器。前者稱之為主節點(master/leader),後者稱之為從節點(slave/flower);數據的複製都是單向的,只能從主節點到從節點。Master 以寫為主,Slave 以讀為主。
預設情況下,每台 Redis 伺服器都是主節點。且一個主節點可以有多個從節點或者沒有從節點,但是一個從節點只能有一個主節點。
2、主從複製的作用
1、數據冗餘:主從複製實現了數據的熱備份,是持久化的之外的一種數據冗餘方式。
2、故障恢復:當主節點出現問題時,可以由從節點提供服務,實現快速的故障恢復。實際也是一種服務的冗餘。
3、負載均衡:在主從複製的基礎上,配合讀寫分離,可以由主節點提供寫服務,由從節點提供讀服務(即寫 Redis 數據時應用連接主節點,讀 Redis 的時候應用連接從節點),分擔伺服器負載;尤其是在寫少讀多的場景下,通過多個節點分擔讀負載,可以大大提高 Redis 伺服器的併發量。
4、高可用(集群)的基石:除了上述作用以外,主從複製還是哨兵模式和集群能夠實施的基礎,因此說主從複製是 Redis 高可用的基礎。
一般來說,要將Redis 運用於工程項目中,只使用一臺 Redis 是萬萬不能的(可能會宕機),原因如下:
1、從結構上,單個 Redis 伺服器會發生單點故障,並且一臺伺服器需要處理所有的請求負載,壓力很大;
2、從容量上,單個 Redis 伺服器記憶體容量有限,就算一臺 Redis 伺服器記憶體容量為 265G, 也不能將所有的記憶體用作 Redis 存儲記憶體,一般來說,單台 Redis最大使用記憶體不應該超過 20G。
電商網站上的商品,一般都是一次上傳,無數次瀏覽的,說專業點就是“多讀少寫”。
對於這種場景,我們可以使用如下這種架構:
主從複製,讀寫分離!80% 的情況下,都是在進行讀操作。這種架構可以減少伺服器壓力,經常使用實際生產環境中,最少是“一主二從”的配置。真實環境中不可能使用單機 Redis。
3、環境配置
只配置從庫,不用配置主庫。
[root@itzhouc bin]# redis-cli -p 6379
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> info replication # 查看當前庫的信息
# Replication
role:master # 角色
connected_slaves:0 # 當前沒有從庫
master_replid:2467dd9bd1c252ce80df280c925187b3417055ad
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>
複製 3 個配置文件,然後修改對應的信息
1、埠
2、pid 名稱
3、log 文件名稱
4、dump.rdb 名稱
port 6381
pidfile /var/run/redis_6381.pid
logfile "6381.log"
dbfilename dump6381.rdb
修改完畢後,啟動我們的 3 個 redis 伺服器,可以通過進程信息查詢。
[root@itzhouc ~]# ps -ef|grep redis
root 426 1 0 16:53 ? 00:00:00 redis-server *:6379
root 446 1 0 16:54 ? 00:00:00 redis-server *:6380
root 457 1 0 16:54 ? 00:00:00 redis-server *:6381
root 464 304 0 16:54 pts/3 00:00:00 grep --color=auto redis
4、一主二從
預設情況下,每台 Redis 伺服器都是主節點,我們一般情況下,只用配置從機就好了。
主機:6379, 從機:6380 和 6381
配置的方式有兩種:一種是直接使用命令配置,這種方式當 Redis 重啟後配置會失效。另一種方式是使用配置文件。這裡使用命令演示一下。
下麵將80 和 81 兩個配置為在從機。
127.0.0.1:6380> SLAVEOF 127.0.0.1 6379 # SLAVEOF host port
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:6
master_sync_in_progress:0
slave_repl_offset:0
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:907bcdf00c69d361ede43f4f6181004e2148efb7
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:0
127.0.0.1:6380>
配置好了之後,看主機:
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2 # 主節點下有兩個從節點
slave0:ip=127.0.0.1,port=6380,state=online,offset=420,lag=1
slave1:ip=127.0.0.1,port=6381,state=online,offset=420,lag=1
master_replid:907bcdf00c69d361ede43f4f6181004e2148efb7
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:420
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:420
127.0.0.1:6379>
真實的主從配置應該是在配置文件中配置,這樣才是永久的。這裡使用命令是暫時的。
配置文件 redis.conf
################################# REPLICATION #################################
# Master-Replica replication. Use replicaof to make a Redis instance a copy of
# another Redis server. A few things to understand ASAP about Redis replication.
#
# +------------------+ +---------------+
# | Master | ---> | Replica |
# | (receive writes) | | (exact copy) |
# +------------------+ +---------------+
#
# 1) Redis replication is asynchronous, but you can configure a master to
# stop accepting writes if it appears to be not connected with at least
# a given number of replicas.
# 2) Redis replicas are able to perform a partial resynchronization with the
# master if the replication link is lost for a relatively small amount of
# time. You may want to configure the replication backlog size (see the next
# sections of this file) with a sensible value depending on your needs.
# 3) Replication is automatic and does not need user intervention. After a
# network partition replicas automatically try to reconnect to masters
# and resynchronize with them.
#
# replicaof <masterip> <masterport> # 這裡配置
# If the master is password protected (using the "requirepass" configuration
# directive below) it is possible to tell the replica to authenticate before
# starting the replication synchronization process, otherwise the master will
# refuse the replica request.
#
# masterauth <master-password>
配置方式也是一樣的。
5、幾個問題
1、主機可以寫,從機不能寫只能讀。主機中的所有信息和數據都會保存在從機中。如果從機嘗試進行寫操作就會報錯。
127.0.0.1:6381> get k1 # k1的值是在主機中寫入的,從機中可以讀取到。
"v1"
127.0.0.1:6381> set k2 v2 # 從機嘗試寫操作,報錯了
(error) READONLY You can't write against a read only replica.
127.0.0.1:6381>
2、如果主機斷開了,從機依然鏈接到主機,可以進行讀操作,但是還是沒有寫操作。這個時候,主機如果恢復了,從機依然可以直接從主機同步信息。
3、使用命令行配置的主從機,如果從機重啟了,就會變回主機。如果再通過命令變回從機的話,立馬就可以從主機中獲取值。這是複製原理決定的。
6、複製原理
Slave 啟動成功連接到 Master 後會發送一個 sync 同步命令。
Master 接收到命令後,啟動後臺的存檔進程,同時收集所有接收到的用於修改數據集的命令,在後臺進程執行完畢後,master 將傳送整個數據文件到 slave ,並完成一次完全同步。
全量複製:Slave 服務在接收到資料庫文件後,將其存檔並載入到記憶體中。
增量複製: Master 繼續將新的所有收集到的修改命令一次傳給 slave,完成同步。
但是只要重新連接 master ,一次完全同步(全量複製)將被自動執行。我們的數據一定可以在從機中看到。
這種模式的原理圖:
第二種模式
這種模式的話,將 6381 的主節點配置為 6380 。主節點 6379 只有一個從機。
如果現在 6379 節點宕機了, 6380 和 6381 節點都是從節點,只能進行讀操作,都不會自動變為主節點。需要手動將其中一個變為主節點,使用如下命令:
SLAVEOF no one
3、哨兵模式
1、概述
主從切換技術的方式是:當主機伺服器宕機之後,需要手動將一臺伺服器切換為主伺服器,這需要人工干預,費時費力,還會造成一段時間內的服務不可用。這不是一種推薦的方式,更多的時候我們優先考慮的的是哨兵模式。Redis 從 2.8 開始正式提供了 Sentinel(哨兵)架構來解決這個問題。
哨兵模式能夠後臺監控主機是否故障,如果故障了根據投票數自動將從庫轉換為主庫。
哨兵模式是一種特殊的模式,首先 Redis 提供了哨兵的命令,哨兵是一個獨立的進程,作為進程,它獨立運行。其原理是哨兵通過發送命令,等待 Redis 伺服器響應,從而監控運行的多個 Redis 實例。
這裡的哨兵有兩個作用
- 通過發送命令,讓 Redis 伺服器返回監控其運行狀態,包括主伺服器和從伺服器
- 當哨兵檢測到 master 宕機,會自動將 slave 切換為 master,然後通過發佈訂閱模式通知其他的從放伺服器,修改配置文件,讓他們切換主機。
然而一個哨兵進程對 Redis 伺服器進行監控,可能會出現問題,為此,我們可以使用多個哨兵進行監控。各個哨兵之間還會進行監控,這樣就形成了多哨兵模式。
假設主伺服器宕機了,哨兵1先檢測到這個結果,系統並不會馬上進行 failover 過程,僅僅是哨兵 1 主觀認為主伺服器不可用,這個現象稱之為主觀下線。當後面的哨兵也檢測到主伺服器不可用,並且數量達到一定值時,那麼哨兵之間就會進行一次投票,投票的結果由一個哨兵發起,進行 failover 【故障轉移】。切換成功後,就會通過發佈訂閱模式,讓各個哨兵把自己監控的從伺服器實現切換主機,這個過程稱之為客觀下線。
2、配置一個一主二從的哨兵模式
1、配置哨兵模式配置文件,新建文件 /usr/local/bin/kconfig/sentinel.conf
。
# sentinel monitor 被監控的名字(隨便寫) host 1
sentinel monitor myredis 127.0.0.1 1
後面的數字1代表主機宕機後,slave投票決定誰成為新的主機,票數最多成為主機。
2、啟動哨兵
[root@itzhouc bin]# ls
6379.log 6381.log dump6380.rdb dump.rdb redis-benchmark redis-check-rdb redis-sentinel
6380.log dump6379.rdb dump6381.rdb kconfig redis-check-aof redis-cli redis-server
[root@itzhouc bin]# redis-sentinel kconfig/sentinel.conf
2421:X 15 May 2020 20:24:06.847 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
2421:X 15 May 2020 20:24:06.847 # Redis version=5.0.5, bits=64, commit=00000000, modified=0, pid=2421, just started
2421:X 15 May 2020 20:24:06.847 # Configuration loaded
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 5.0.5 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in sentinel mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 26379
| `-._ `._ / _.-' | PID: 2421
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
2421:X 15 May 2020 20:24:06.848 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
2421:X 15 May 2020 20:24:06.851 # Sentinel ID is 100430af0018d23bd1ae2fe57e71e0d45f64d9a5
2421:X 15 May 2020 20:24:06.851 # +monitor master myredis 127.0.0.1 6379 quorum 1
2421:X 15 May 2020 20:24:06.852 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379
啟動成功~!
如果現在 Master 節點宕機了,這個時候會從從機中根據投票演算法選擇一個作為主機。
如果原來的主機恢復運行了,只能歸到新的主機下,作為從機, 這就是哨兵模式的規則。
哨兵模式的優點
1、哨兵集群,基於主從複製模式,所有的主從配置優點,它全有
2、主從可以切換,故障可以轉移,系統的可用性就會更好
3、哨兵模式就是主從模式的升級,手動到自動,更加健壯。
哨兵模式的缺點
1、Redis 不方便線上擴容,集群達到一定的上限,線上擴容就會十分麻煩;
2、實現哨兵模式的配置其實也很麻煩,裡面有甚多的配置項。
下一篇筆記將介紹 Redis 的緩存穿透、緩存擊穿和緩存雪崩。