Redis基礎知識(學習筆記18--主從叢集)

东山絮柳仔發表於2024-07-15

一.主從相關的配置

1.1 masterauth

# 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>
#

因為我們要搭建主從叢集,且每個主機都有可能會是Master,如果設定驗證屬性requirepass。一定要每個主機的密碼都設定為相同的。此時每個配置檔案中都要設定兩個完全相同的屬性:requirepass與masterauth。其中requirepass使用者指定當前主機的訪問密碼,而masterauth用於指定當前slave訪問master時向master提交的訪問密碼,用於讓master驗證請求者身份是否合法。

1.2 repl-disable-tcp-nodelay

# Disable TCP_NODELAY on the replica socket after SYNC?
#
# If you select "yes" Redis will use a smaller number of TCP packets and
# less bandwidth to send data to replicas. But this can add a delay for
# the data to appear on the replica side, up to 40 milliseconds with
# Linux kernels using a default configuration.
#
# If you select "no" the delay for data to appear on the replica side will
# be reduced but more bandwidth will be used for replication.
#
# By default we optimize for low latency, but in very high traffic conditions
# or when the master and replicas are many hops away, turning this to "yes" may
# be a good idea.
repl-disable-tcp-nodelay no

該屬性用於設定是否禁用TCP特性tcp-nodelay。設定為yes則禁用tcp-nodelay,此時master與slave間的通訊會產生延遲,但使用的TCP包數量較少,佔用的網路頻寬會較小。相反,如果設定為no,則網路延遲會變小,但使用的TCP包數量會較多,相應占用的網路頻寬會變大。

知識點補充---tcp-nodelay

為了充分複用網路頻寬,TCP總是希望傳送儘可能大的資料塊。為了達到該目的,TCP中使用了一個名為Nagle的演算法。

Nagle演算法的原理是,網路在接收到要傳送的資料後,並不直接傳送,而是等待著資料量足夠大(由TCP網路特性決定)時再一次性傳送出去。這樣,網路上傳輸的有效資料的比例就等到了大大提升,無效資料的傳輸極大減少,於是就節省了網路頻寬,緩解了網路壓力。

tcp-nodelay 則是TCP協議中Nagle演算法的開關。

1.3 pidfile

# If a pid file is specified, Redis writes it where specified at startup
# and removes it at exit.
#
# When the server runs non daemonized, no pid file is created if none is
# specified in the configuration. When the server is daemonized, the pid file
# is used even if not specified, defaulting to "/var/run/redis.pid".
#
# Creating a pid file is best effort: if Redis is not able to create it
# nothing bad happens, the server will start and run normally.
#
# Note that on modern Linux systems "/run/redis.pid" is more conforming
# and should be used instead.
pidfile /var/run/redis_6379.pid

如果是多例項安裝(一臺機器上安裝多個redis例項),記得要修改這個引數。

當然,另外一些引數配置

埠號(port)、dbfilename、appendfilename、logfile、replica-priority

簡單說下 replica-priority

# The replica priority is an integer number published by Redis in the INFO
# output. It is used by Redis Sentinel in order to select a replica to promote【提升;晉升;】
# into a master if the master is no longer working correctly.
#
# A replica with a low priority number is considered better for promotion, so  ##越小優先順序越高
# for instance if there are three replicas with priority 10, 100, 25 Sentinel
# will pick the one with priority 10, that is the lowest.
#
# However a special priority of 0 marks the replica as not able to perform the ##特殊的優先順序的值為0
# role of master, so a replica with priority of 0 will never be selected by    ##0喪失了稱為master的可能性
# Redis Sentinel for promotion.
#
# By default the priority is 100.
replica-priority 100

1.4 個性化的配置依賴引數include

################################## INCLUDES ###################################

# 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.
#
# Note that 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.
#
# Included paths may contain wildcards. All files matching the wildcards will
# be included in alphabetical order.
# Note that if an include path contains a wildcards but no files match it when
# the server is started, the include statement will be ignored and no error will
# be emitted.  It is safe, therefore, to include wildcard files from empty
# directories.
#
# include /path/to/local.conf
# include /path/to/other.conf
# include /path/to/fragments/*.conf
#

################################## MODULES #####################################

例如我們想獨立出一個配置檔案,但是呢,只想修改幾個或者少部分引數項,這時候,可以include進基本的配置檔案,只把需要修改的引數,重寫下即可。

二. 設定主從關係

2.1 檢視

先檢視下主從關係,檢視指令

> info replication

在主節點上執行,

返回值 role 代表當前節點的角色;

connected_slaves的數值代表 從節點 的個數;

如果有slave節點的話,會以slave0、slave1 呈現出具體的slave資訊(ip:port:state:offset:lag)。

而在從節點上執行的話,返回值是不一樣的:

返回值role 代表叢集角色,其他的返回值還有master_ip、master_port、master_link_status、master_last_io_seconds_age、master_sync_in_process、slave_read_only等等。

需要注意的是從節點是不可以執行寫命令的,否則報錯

(error)READONLY You can't write against a read only replica.

2.2 設定命令

在從節點上執行命令,如下

> slaveof host(主節點ip) port(主節點的埠號)

只執行上面的命令,如果從節點重啟的話,主從關係就會失效,即丟失已設定的主從關係。

2.3. 分級管理

若redis主從叢集中的slave較多時,他們的資料同步過程會對master形成較大的效能壓力。此時,可以對這些slave進行分級管理。

設定方式很簡單,只需要讓低階別slave指定其slaveof的主機為上一級slave即可。不過,上一級slave的狀態仍為slave,只不過,其是更上一級的slave。

調整主從關係,不需要關閉已有關係,再重建,而是直接執行 slaveof host port 進行調整即可。

2.4 容災冷處理

在master/slave的redis叢集中,若master出現了當機怎麼辦?有兩種處理方式,一種是透過手工角色調整,使slave晉升為master的冷處理;一種是使用哨兵模式,實現redis叢集的高可用HA,即熱處理。

無論master是否當機,slave都可以透過下面的命令,將自己提升為master。

> slaveof no one

如果其原本就有下一級的slave,那麼,其就直接變為了這些slave的真正的master了。而原來的master就會失去了這個原來的slave。

三. 主從複製原理

3.1 主從複製過程

當一個redis節點(slave)接收到類似slaveof 127.0..1 6379 的指令後直至其可以從master持續複製資料,大體經歷瞭如下幾個過程:

(1)儲存master地址

當slave接收到slaveof <master_ip> <master_port>指令後,slave會立即將新的master的地址儲存下來。

(2)建立連線

slave中維護著一個定時任務,該定時任務會嘗試著與該master建立socker連線。

(3)slave傳送ping命令

連線成功後,slave會傳送ping命令,進行首次通訊。如果slave沒有收到master的回覆,則slave就會主動斷開連線,下次的定時任務會重新嘗試連線。

(4)對slave身份驗證

master 在接收到slave的ping命令後,並不會立即對其進行回覆,而是先對Salve進行身份驗證。如果驗證不透過,則會傳送訊息拒絕連線;。驗證透過,master 向slave傳送連線成功響應。

(5)master持久化

slave在成功接收到master的響應後,slave向master發出資料同步請求。master在接收到資料同步請求後,fork出一個子程序,讓子程序以非同步方式立即進行資料持久化。

(6)資料傳送

持久化完畢後,master再fork出一個子程序,讓子程序以非同步方式將資料傳送給slave。slave會將接收到的資料不斷寫入到本地的持久化檔案中。

在slave資料同步過程中,master的主程序仍在不斷地接受著客戶端的寫操作,且不僅將新的資料寫入到master記憶體,同時也寫入到了同步快取。當master的持久化檔案中的資料傳送完畢後,master會再將同步快取中新的資料傳送給slave,由slave將其寫入到本地持久化檔案中。資料同步完成。

(7)slave恢復記憶體資料

資料同步完畢後,slave就會讀取本地持久化檔案,將其恢復到本地記憶體資料,然後就可以對外提供服務了。

(8)持續增量複製

對外服務中master持續接收到寫操作,會以增量方式傳送給slave,以保證主從資料的一致性。

流程概況如下

考慮到資料傳送過程中,仍由資料進來,補充如下:

3.2 資料同步演變過程

(1)sync 同步

redis 2.8 版本之前,首次通訊成功後,slave會向master傳送sync資料同步請求,然後master就會將其所有資料全部傳送給slave,由slave儲存到其本地的持久化檔案中。這個過程稱為全量複製。

但這裡存在一個問題:在全量複製過程中可能會出現網路抖動而導致複製過程中斷。當網路恢復後,slave與master重新連線成功,此時slave會重新傳送sync請求,然後會從頭開始全量複製。

由於全量複製過程非常耗時,所以期間出現網路抖動的機率很高。而中斷後的從頭開始不僅需要消耗大量的系統資源、網路頻寬,而且可能會出現長時間無法完成全量複製的情況。

(2)psync

redis 2.8 版本之後,全量複製採用了psync(Partial Sync,不完全同步)同步策略。當全量複製過程出現由於網路抖動而導致複製過程中斷時,當重新連線成功後,複製過程可以“斷點續傳”。即從斷點位置開始繼續複製,而不用從頭再來。這樣大大提升了效能。

為了實現psync,整個系統做了三個大的變化:

A. 複製偏移量

系統為每個需要傳送資料進行了編號,該編號從0開始,每個位元組一個編號。該編號稱為複製偏移量。參與複製的主從節點都會維護該複製偏移量。

可以透過 命令info replication 的返回結果中的 slave_repl_offset (從節點)或 master_repl_offset(主節點 代表已傳送出去的資料)值檢視。

B.主節點複製ID

當master啟動後,就會動態生成一個長度為40位的16進位制字串作為當前master的複製ID,該ID是在進行資料同步時slave識別master使用的。透過 info replication 的master_replid屬性可檢視到該ID。

特別注意:master redis 重啟,動態生成的複製ID就會變化。

C.複製積壓緩衝區

當master有連線的slave時,在master中就會建立並維護一個佇列backlog,預設大小為1MB,該佇列稱為複製積壓緩衝區。master接收到了寫操作,資料不僅會寫入到了master主存,寫入到了master中為每個slave配置的傳送快取,而且還會寫入到複製積壓緩衝區。其作用就是用於儲存最近操作的資料,以備“斷點續傳”時做資料補償,防止資料丟失。

D. psync 同步過程

psync是一個由slave提交的命令,其格式為psync <master_replid> <repl_offset> ,表示當前slave要從指定中的repl_offset+1處開始複製。 repl_offset表示當前slave已經完成複製的資料的offset。該命令保證了“斷點續傳”的實現。

在第一次開始複製時,slave並不直到master的動態ID,並且一定時從頭開始複製,所以其提交的psync命令為PSYNC ? -1。即master_replid 為問號(?),repl_offset為-1。

如果複製過程中斷後,slave與master成功連線,則save再次提交psync命令。此時psync命令的repl_offset引數為其前面已經完成複製的資料的偏移量。

其實,並不是slave提交psync命令後就可以立即從master處開始複製,而是需要master給出響應結果後,根據響應結果來執行。master根據slave提交的請求及master自身情況會給出不同的響應結果。響應結果有三種可能:

  • FULLRESYNC <master_replid> <repl_offset>:告知slave當前master的動態ID及可以開始全量複製了,這裡的repl_offset一般為0。
  • CONTINUE:告知slave可以按照你提交的repl_offset後面位置開始“續傳”了。
  • ERR:告知slave,當前master的版本低於redis 2.8 ,不支援psync,你可以開始全量複製。

psync過程概況如下

E. psync存在的問題

  • 在psync資料同步過程中,若slave重啟,在slave記憶體中儲存的master的動態ID與續傳需要的offset都會消失,“斷點續傳”將無法進行,從而只能進行全量複製,導致資源浪費。
  • 在psync資料同步過程中,master當機後slave會發生“易主”,從而導致slave需要從新master進行全量複製,形成資源浪費。

(3)psync 同步的改進

Redis 4.0 對psync進行了改進,提出了“同源增量同步”策略。

A. 解決slave重啟問題

針對“slave重啟時master動態ID丟失問題”,改進後的psync將master的動態ID直接寫入到了slave的持久化檔案中。

slave重啟後直接從本地持久化檔案中讀取master的動態ID,然後向master提交獲取複製偏移量的請求。master會根據提交請求的slave地址,查詢到儲存在master中的複製偏移量,然後向slave回覆FULLRESYNC <master_replid> <repl_offset>,以告知slave其馬上要開始傳送的位置。然後master開始“斷點續傳”。

B. 解決slave易主問題

slave易主後需要和新master進行全量複製,本質原因是新master不認識slave提交的psync請求中的“原master的動態ID”。如果slave傳送psync <原master_replid> <repl_offset> 命令,新的master能夠識別出該slave要從原master複製資料,而自己的資料都是從該master複製來的。那麼新master就會明白,其與該slave"師出同門",應該接收其“斷點續傳”同步請求。

而新master中恰好儲存的有“原master的動態ID”。由於改進後的psync中每個slave都在本地儲存了當前的master的動態ID,所以當slave晉升為新的master後,其本地仍儲存有之前master的動態ID。而這一點也恰恰為解決“slave易主”問題提供了條件。透過master的info replication 中master_replid2 可以檢視到。如果尚未傳送易主,則該值為40個0。

(4) 無盤操作

Redis 6.0 對同步過程又進行了改進,提出了“無盤全量同步”與“無盤載入”策略,避免了耗時的IO操作。

  • 無盤全量同步:master的主程序fork出的子程序直接將記憶體中的資料傳送給slave,無需經過磁碟。
  • 無盤載入:slave在接收到master傳送來的資料後不需要將其寫入到磁碟檔案,而是直接寫入到記憶體,這樣slave就可快速完成資料恢復。

(5) 共享複製積壓緩衝區

Redis 7.0 版本對複製積壓緩衝區進行了改進,讓各個slave的傳送緩衝區共享複製積壓緩衝區。這使得複製積壓緩衝區的作用,除了可以保障資料的安全性外,還作為所有slave的傳送緩衝區,充分利用了複製積壓緩衝區。

學習參閱特別宣告

【Redis影片從入門到高階】

【https://www.bilibili.com/video/BV1U24y1y7jF?p=11&vd_source=0e347fbc6c2b049143afaa5a15abfc1c】

相關文章