首頁  >  文章  >  資料庫  >  Redis主從架構的建立方式有哪些

Redis主從架構的建立方式有哪些

WBOY
WBOY轉載
2023-05-26 16:23:071117瀏覽

主從環境搭建

redis 的實例在預設的情況下都是主節點,所以我們需要修改一些設定來搭建主從架構,redis 的主從架構搭建還是比較簡單的,redis提供了三種方式來搭建主從架構,在後面我們將就介紹,在介紹之前我們要先了解主從架構的特性:在主從架構中有一個主節點(master)和最少一個從節點(slave ),且資料複製是單向的,只能從主節點複製到從節點,不能由從節點到主節點。

主從架構的建立方式

主從架構的建立有以下三種方式:

  • 在Redis. conf 設定檔中加入slaveof {masterHost} {masterPort} 指令,隨Redis 實例的啟動生效

  • 在redis-server 啟動指令後加入--slaveof {masterHost} {masterPort} 參數

  • 在redis-cli 互動視窗下直接使用指令:slaveof {masterHost} {masterPort}

上面三種方式都可以建構Redis主從架構,我們以第一種方式來演示,其他兩種方式自行嘗試,由於是演示,所以就在本地啟動兩個Redis  實例,並不在多台機器上啟動redis 的實例了,我們準備一個端口6379 的主節點實例,準備一個連接埠6480 從節點的實例,連接埠6480 的redis  實例設定檔取名為6480.conf 並且在裡面新增slaveof 語句,在設定檔最後加入下列語句。

slaveof 127.0.0.1 6379

分別啟動兩個redis 實例,啟動之後他們會自動建立主從關係,關於這背後的原理,我們後面在詳細的聊一聊,先來驗證一下我們的主從架構是否搭建成功,我們先在 6379 master 節點上新增一條資料:

Redis主從架構的建立方式有哪些

#master 節點新增資料

再6480 slave 節點上取得該資料:

Redis主從架構的建立方式有哪些

slave 節點取得資料

可以看出我們在slave 節點上已經成功的取得到了在master 節點新增的值,說明主從架構已經搭建成功了,我們使用info replication  指令來查看兩個節點的訊息,先來看看主節點的資訊。

Redis主從架構的建立方式有哪些

master info replication

可以看出6379 連接埠的實例role 為master,有一個正在連接的實例,還有其他運行的信息,我們再來看看6480 埠的redis  實例資訊。

Redis主從架構的建立方式有哪些

slave info replication

可以觀察到兩個節點之間互相記錄物件訊息,這些資訊將在資料複製時被使用。這裡有一點需要說明一下,預設情況下 slave  節點是唯讀的,並不支援寫入,也不建議開啟寫入,我們可以驗證一下,在 6480 實例上寫入一條資料。

127.0.0.1:6480> set x 3 (error) READONLY You can't write against a read only replica. 127.0.0.1:6480>

提示只讀,不支援寫入操作,當然我們也可以修改該配置,在設定檔中replica-read-only yes  設定項就是用來控制從伺服器只讀的,為什麼只能只讀?因為我們知道複製是單向的,資料只能由master 到slave 節點,如果在salve  節點上開啟寫入的話,那麼修改了slave 節點的數據, master 節點是感知不到的,slave 節點的資料並不能複製到master  節點上,這樣就會造成資料不一致的情況,所以建議slave 節點只讀。

主從架構的斷開

主從架構的斷開同樣是slaveof 指令,在從節點上執行slaveof no one 指令就可以與主節點斷開追隨關係,我們在6480  節點上執行slaveof no one 指令。

127.0.0.1:6480> slaveof no one OK 127.0.0.1:6480> info replication # Replication role:master connected_slaves:0 master_replid:a54f3ba841c67762d6c1e33456c97b94c62f6ac0 master_replid2:e5c1ab2a68064690aebef4bd2bd4f3ddfba9cc27 master_repl_offset:4367 second_repl_offset:4368 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:4367 127.0.0.1:6480>

執行完 slaveof no one 指令之後,6480 節點的角色立刻恢復成了 master ,我們再來看看時候還跟 6379 實例連結在一起,我們在  6379 節點上新增一個 key-value。

127.0.0.1:6379> set y 3 OK

在6480 節點上get y

127.0.0.1:6480> get y (nil) 127.0.0.1:6480>

在6480 節點上取得不到y ,因為6480 節點已經跟6379 節點斷開的聯繫,不存在主從關係了,slaveof  指令不僅能夠斷開連接,還能切換主伺服器,使用指令為slaveof {newMasterIp} {newMasterPort},我們讓6379 成為6480  的從節點, 在6379 節點上執行slaveof 127.0.0.1 6480 指令,我們在來看看6379的info replication。

127.0.0.1:6379> info replication # Replication role:slave master_host:127.0.0.1 master_port:6480 master_link_status:up master_last_io_seconds_ago:2 master_sync_in_progress:0 slave_repl_offset:4367 slave_priority:100 slave_read_only:1 connected_slaves:0 master_replid:99624d4b402b5091552b9cb3dd9a793a3005e2ea master_replid2:0000000000000000000000000000000000000000 master_repl_offset:4367 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:4368 repl_backlog_histlen:0 127.0.0.1:6379>

6379 節點的角色已經是 slave 了,主節點的是 6480 ,我們可以再看 6480 節點的 info replication。

127.0.0.1:6480> info replication # Replication role:master connected_slaves:1 slave0:ip=127.0.0.1,port=6379,state=online,offset=4479,lag=1 master_replid:99624d4b402b5091552b9cb3dd9a793a3005e2ea master_replid2:a54f3ba841c67762d6c1e33456c97b94c62f6ac0 master_repl_offset:4479 second_repl_offset:4368 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:4479 127.0.0.1:6480>

在 6480 節點上有 6379 從節點的訊息,可以看出 slaveof 指令已經幫我們完成了主伺服器的切換。

复制技术的原理

redis 的主从架构好像很简单一样,我们就执行了一条命令就成功搭建了主从架构,并且数据复制也没有问题,使用起来确实简单,但是这背后 redis  还是帮我们做了很多的事情,比如主从服务器之间的数据同步、主从服务器的状态检测等,这背后 redis 是如何实现的呢?接下来我们就一起看看。

数据复制原理

我们执行完 slaveof 命令之后,我们的主从关系就建立好了,在这个过程中, master 服务器与 slave  服务器之间需要经历多个步骤,如下图所示:

Redis主從架構的建立方式有哪些

redis 复制原理

slaveof 命令背后,主从服务器大致经历了七步,其中权限验证这一步不是必须的,为了能够更好的理解这些步骤,就以我们上面搭建的 redis  实例为例来详细聊一聊各步骤。

1、保存主节点信息

在 6480 的客户端向 6480 节点服务器发送 slaveof 127.0.0.1 6379 命令时,我们会立马得到一个 OK。

127.0.0.1:6480> slaveof 127.0.0.1 6379 OK 127.0.0.1:6480>

这时候数据复制工作并没有开始,数据复制工作是在返回 OK 之后才开始执行的,这时候 6480 从节点做的事情是将给定的主服务器 IP 地址  127.0.0.1 以及端口 6379 保存到服务器状态的 masterhost 属性和 masterport 属性里面。

2、建立 socket 连接

在 slaveof 命令执行完之后,从服务器会根据命令设置的 IP 地址和端口,跟主服务器创建套接字连接, 如果从服务器能够跟主服务器成功的建立  socket 连接,那么从服务器将会为这个 socket 关联一个专门用于处理复制工作的文件事件处理器,这个处理器将负责后续的复制工作,比如接受全量复制的  RDB 文件以及服务器传来的写命令。同样主服务器在接受从服务器的 socket 连接之后,将为该 socket  创建一个客户端状态,这时候的从服务器同时具有服务器和客户端两个身份,从服务器可以向主服务器发送命令请求而主服务器则会向从服务器返回命令回复。

3、发送 ping 命令

从服务器与主服务器连接成功后,做的第一件事情就是向主服务器发送一个 ping 命令,发送 ping 命令主要有以下目的:

  • 检测主从之间网络套接字是否可用

  • 检测主节点当前是否可接受处理命令

在发送 ping 命令之后,正常情况下主服务器会返回 pong 命令,接受到主服务器返回的 pong 回复之后就会进行下一步工作,如果没有收到主节点的  pong 回复或者超时,比如网络超时或者主节点正在阻塞无法响应命令,从服务器会断开复制连接,等待下一次定时任务的调度。

4、身份验证

从服务器在接收到主服务器返回的 pong 回复之后,下一步要做的事情就是根据配置信息决定是否需要身份验证:

  • 如果从服务器设置了 masterauth 参数,则进行身份验证

  • 如果从服务器没有设置 masterauth 参数,则不进行身份验证

在需要身份验证的情况下,从服务器将就向主服务器发送一条 auth 命令,命令参数为从服务器 masterauth  选项的值,举个例子,如果从服务器的配置里将 masterauth 参数设置为:123456,那么从服务器将向主服务器发送 auth 123456  命令,身份验证的过程也不是一帆风顺的,可能会遇到以下几种情况:

  • 从服务器通过 auth 命令发送的密码与主服务器的 requirepass 参数值一致,那么将继续进行后续操作,如果密码不一致,主服务将返回一个  invalid password 错误

  • 如果主服务器没有设置 requirepass 参数,那么主服务器将返回一个 no password is set 错误

所有的错误情况都会令从服务器中止当前的复制工作,并且要从建立 socket 开始重新发起复制流程,直到身份验证通过或者从服务器放弃执行复制为止。

5、發送連接埠資訊

在驗證通過後,從伺服器將執行REPLCONF listening命令,並向主伺服器發送從伺服器的監聽連接埠號,例如在我們的例子中從伺服器監聽的連接埠為 6480,那麼從伺服器將會傳送REPLCONF listening 6480  指令,主伺服器接收到這個指令之後,會將連接埠號碼記錄在從伺服器所對應的客戶端狀態的slave_listening_port 屬性了,也會就是我們在master  伺服器的info replication 裡面看到的port 值。

6、資料複製

資料複製是最複雜的一塊了,由psync 指令來完成,從伺服器會向主伺服器發送一個psync 指令來進行數據同步,在redis 2.8  版本以前使用的是sync 指令,除了指令不同之外,在複製的方式上也有很大的不同,在redis 2.8  版本以前使用的都是全量複製,這對主節點和網路會造成很大的開銷,在redis 2.8 版本以後,資料同步將分為全量同步和部分同步。

  • 全量複製:一般用於初次複製場景,不管是新舊版本的redis  在從伺服器第一次與主服務連接時都將進行一次全量複製,它會把主節點的全部資料一次發給從節點,當資料較大時,會對主節點和網路造成很大的開銷,redis  的早期版本只支援全量複製,這不是一種高效的資料複製方式

  • 部分複製:用於處理在主從複製中因網路閃斷等原因造成的資料遺失場景,當從節點再次連上主節點後,如果條件允許,主節點會補發丟失資料 給從節點。因為補發的數據遠小於全量數據,可以有效避免全量複製的過高開銷,部分複製是對老版複製的重大優化,有效避免了不必要的全量複製操作

redis 之所以能夠支援全量複製和部分複製,主要是對sync 指令的最佳化,在redis 2.8 版本以後使用的是一個全新的psync  指令,指令格式為:psync {runId} {offset},這兩個參數的意義:

  • runId:主節點運行的id

  • #offset:目前從節點複製的資料偏移量

也許你對上面的runid、offset 比較陌生,沒關係,我們先來看看下面三個概念:

1、複製偏移量

參與複製的主從節點都會分別維護自身複製偏移量:主伺服器每次向從伺服器傳播N 個位元組的資料時,就會將自己的偏移量的值加上 N,從伺服器每次接收到主伺服器傳播的N個位元組的資料時,將自己的偏移量值加上 N。透過比較主從伺服器的複製偏移量,就可以知道主從伺服器的資料是否一致,如果主從伺服器的偏移量總是相同,那麼主從資料一致,相反,如果主從伺服器兩個的偏移量並不相同,那麼表示主從伺服器並未處於資料一致的狀態,例如在有多個從伺服器時,在傳輸的過程中某一個伺服器離線了,如下圖所示:

Redis主從架構的建立方式有哪些

#offset 不一致

由於從伺服器A 在資料傳輸時,由於網路原因斷線了,導致偏移量與主伺服器不一致,那麼當從伺服器A 重新啟動並且與主伺服器連線成功後,重新傳送 psync 指令,這時候資料複製應該執行全量複製還是部分複製呢?如果執行部分複製,主伺服器又如何補償從伺服器A  在斷線期間遺失的那部分資料呢?這些問題的答案都在複製積壓緩衝區裡面。

2、複製積壓緩衝區

複製積壓緩衝區是保存在主節點上的一個固定長度的佇列,預設大小為1MB,當主節點有連接的從節點(slave)時被創建,這時主節點(master)  響應寫入指令時,不但會把指令傳送給從節點,還會寫入複製積壓緩衝區,如下圖所示:

Redis主從架構的建立方式有哪些

複製積壓緩衝區

因此,主伺服器的複製積壓緩衝區裡面會保存著一部分最近傳播的寫入命令,複製積壓緩衝區會為佇列中的每個位元組記錄對應的複製偏移量。所以當從伺服器重新連接主伺服器時,從伺服器透過 psync 指令將自己的複製偏移量offset 傳送給主伺服器,主伺服器會根據這個複製偏移量來決定對從伺服器執行何種資料同步作業:

  • 如果從伺服器的複製偏移量之後的資料仍然存在於複製積壓緩衝區裡面,那麼主伺服器將對從伺服器執行部分複製操作

  • 如果从服务器的复制偏移量之后的数据不存在于复制积压缓冲区里面,那么主服务器将对从服务器执行全量复制操作

3、服务器运行ID

每个 Redis 节点启动后都会动态分配一个 40 位的十六进制字符串作为运行 ID,运行 ID 的主要作用是用来唯一识别 Redis 节点,我们可以使用  info server 命令来查看

127.0.0.1:6379> info server # Server redis_version:5.0.5 redis_git_sha1:00000000 redis_git_dirty:0 redis_build_id:2ef1d58592147923 redis_mode:standalone os:Linux 3.10.0-957.27.2.el7.x86_64 x86_64 arch_bits:64 multiplexing_api:epoll atomicvar_api:atomic-builtin gcc_version:4.8.5 process_id:25214 run_id:7b987673dfb4dfc10dd8d65b9a198e239d20d2b1 tcp_port:6379 uptime_in_seconds:14382 uptime_in_days:0 hz:10 configured_hz:10 lru_clock:14554933 executable:/usr/local/redis-5.0.5/src/./redis-server config_file:/usr/local/redis-5.0.5/redis.conf 127.0.0.1:6379>

这里面有一个run_id 字段就是服务器运行的ID

在熟悉这几个概念之后,我们可以一起探讨 psync 命令的运行流程,具体如下图所示:

Redis主從架構的建立方式有哪些

psync 运行流程

psync 命令的逻辑比较简单,整个流程分为两步:

1、从节点发送 psync 命令给主节点,参数 runId  是当前从节点保存的主节点运行ID,参数offset是当前从节点保存的复制偏移量,如果是第一次参与复制则默认值为 -1。

2、主节点接收到 psync 命令之后,会向从服务器返回以下三种回复中的一种:

  • 回复 +FULLRESYNC {runId} {offset}:表示主服务器将与从服务器执行一次全量复制操作,其中 runid 是这个主服务器的运行  id,从服务器会保存这个id,在下一次发送 psync 命令时使用,而 offset  则是主服务器当前的复制偏移量,从服务器会将这个值作为自己的初始化偏移量

  • 回复 +CONTINUE:那么表示主服务器与从服务器将执行部分复制操作,从服务器只要等着主服务器将自己缺少的那部分数据发送过来就可以了

  • 回复 +ERR:那么表示主服务器的版本低于 redis 2.8,它识别不了 psync 命令,从服务器将向主服务器发送 sync  命令,并与主服务器执行全量复制

7、命令持续复制

当主节点把当前的数据同步给从节点后,便完成了复制的建立流程。主从服务器之间的连接不会中断,因为主节点会持续发送写命令到从节点,以确保主从数据的一致性。

经过上面 7 步就完成了主从服务器之间的数据同步,由于这篇文章的篇幅比较长,关于全量复制和部分复制的细节就不介绍了,全量复制就是将主节点的当前的数据生产  RDB  文件,发送给从服务器,从服务器再从本地磁盘加载,这样当文件过大时就需要特别大的网络开销,不然由于数据传输比较慢会导致主从数据延时较大,部分复制就是主服务器将复制积压缓冲区的写命令直接发送给从服务器。

心跳检测

心跳检测是发生在主从节点在建立复制后,它们之间维护着长连接并彼此发送心跳命令,便以后续持续发送写命令,主从心跳检测如下图所示:

Redis主從架構的建立方式有哪些

主从心跳检测

主从节点彼此都有心跳检测机制,各自模拟成对方的客户端进行通信,主从心跳检测的规则如下:

  • 默认情况下,主节点会每隔 10 秒向从节点发送 ping 命令,以检测从节点的连接状态和是否存活。可通过修改 redis.conf 配置文件里面的  repl-ping-replica-period 参数来控制发送频率

  • 从节点在主线程中每隔 1 秒发送 replconf ack {offset} 命令,给主节点  上报自身当前的复制偏移量,这条命令除了检测主从节点网络之外,还通过发送复制偏移量来保证主从的数据一致

主节点根据 replconf 命令判断从节点超时时间,体现在 info replication 统 计中的 lag 信息中,我们在主服务器上执行 info  replication 命令:

127.0.0.1:6379> info replication # Replication role:master connected_slaves:1 slave0:ip=127.0.0.1,port=6480,state=online,offset=25774,lag=0 master_replid:c62b6621e3acac55d122556a94f92d8679d93ea0 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:25774 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:25774 127.0.0.1:6379>

可以看出 slave0 字段的值最后面有一个 lag,lag 表示与从节点最后一次通信延迟的秒数,正常延迟应该在 0 和 1 之间。如果超过  repl-timeout 配置的值(默认60秒),则判定从节点下线并断开复制客户端连接,如果从节点重新恢复,心跳检测会继续进行。

主从拓扑架构

Redis 的主从拓扑结构可以支持单层或多层复制关系,根据拓扑复杂性可以分为以下三种:一主一从、一主多从、树状主从架构。

一主一从结构

一主一从结构是最简单的复制拓扑结构,我们前面搭建的就是一主一从的架构,架构如图所示:

Redis主從架構的建立方式有哪些

一主一从架构

一主一從架構

用於主節點出現宕機時從節點提供故障轉移支持,當應用寫入命令並發量較高且需要持久化時,可以只在從節點上開啟 AOF,這樣既確保資料安全性同時也避免了持久化對主節點的效能幹擾。但這裡有一個坑,需要你注意,就是當主節點關閉持久化功能時,  如果主節點離線要避免自動重新啟動操作。因為主節點之前沒有開啟持久化功能自動重啟後資料集為空,這時從節點如果繼續複製主節點會導致從節點資料也被清空的情況,喪失了持久化的意義。安全的做法是在從節點上執行  slaveof no one 斷開與主節點的複製關係,再重啟主節點從而避免此問題。

一主多從架構一主多從架構又稱為星狀拓樸結構,一主多從架構如下圖:

Redis主從架構的建立方式有哪些

一主多從架構

一主多從架構可以實現讀寫分離來減輕主伺服器的壓力,對於讀佔比較大的場景,可以把讀指令送到 從節點來分擔主節點壓力。同時在日常開發中如果需要執行一些比較耗時的讀取命令,如:keys、sort等,可以在其中一台從節點上執行,防止慢查詢對主節點造成阻塞從而影響線上服務的穩定性。對於寫入並發量較高的場景,多個從節點會導致主節點寫命令的多次發送從而過度消耗網路頻寬,同時也加重了主節點的負載影響服務穩定性。

樹狀主從架構

樹狀主從架構又稱為樹狀拓樸架構,樹狀主從架構如下圖所示:

Redis主從架構的建立方式有哪些

樹狀主從架構

樹狀主從架構使得從節點不但可以複製主節數據,同時可以作為其他從節點的主節點繼續向下層複製。解決了一主多從架構中的不足,透過引入複製中  間層,可以有效降低主節點負載和需要傳送給從節點的資料量。如架構圖中,資料寫入節點A 後會同步到 B 和 C節點,B節點再把資料同步到 D 和  E節點,資料實作了一層一層的向下複製。為避免對主節點效能的干擾,主節點在需要掛載多個從節點時可以採用樹狀主從結構,以降低其負載壓力。

以上是Redis主從架構的建立方式有哪些的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除