天天看點

Redis主從模式的實作

  前面說到了redis在單機的模式下是可以資料持久化的,但是不可以解決單點失敗的問題,當單台redis伺服器出現問題時,就可能會造成資料的丢失;想要解決這個問題的話我們可以使用Redis的主從模式這也是Redis叢集最簡單的實作方式,這篇文章我就來簡單部署一個Redis主從架構,我準備了3台ubuntu1804的主機,IP位址分别為10.0.0.{100,101,102},主機名分别為redis-master,redis-slave1,redis-slave2。

1、安裝Redis

  這裡我就使用腳本來安裝Redis了。

root@redis-master:~# vim install_redis.sh
#!/bin/bash

SRC_DIR=/usr/local/src
COLOR="echo -e \\033[01;31m"
END='\033[0m'
CPUS=`lscpu | awk '/^CPU\(s\)/{print $2}'`

URL='https://download.redis.io/releases/'
VERSION=redis-6.2.7
PASSWORD=wm521314
INSTALL_DIR=/apps/redis


install() {
    #下載下傳依賴包
    apt -y install make gcc libjemalloc-dev || { ${COLOR}"安裝軟體包失敗,請檢查網絡配置"${END}; exit; }
    
    #開始下載下傳redis源碼包并解壓包
    cd ${SRC_DIR}
    wget ${URL}${VERSION}.tar.gz || { ${COLOR}"Redis源碼下載下傳失敗"${END}; exit; }
    tar xf ${VERSION}.tar.gz
    
    #解壓後的源碼包裡面自帶Makefile檔案,直接編譯安裝即可
    cd ${VERSION}
    make -j ${CPUS} PREFIX=${INSTALL_DIR} install && ${COLOR}"Redis編譯安裝完成"${END} || { ${COLOR}"Redis編譯安裝失敗"${END}; exit; }
    
    #建立軟連結
    ln -s ${INSTALL_DIR}/bin/redis-* /usr/bin/
    
    #建立後期需要的目錄
    mkdir -p ${INSTALL_DIR}/{etc,log,data,run}
    
    #這準備配置檔案并修改預設的配置
    cp redis.conf ${INSTALL_DIR}/etc/
    sed -i -e 's/bind 127.0.0.1.*/bind 0.0.0.0/' -e "/# requirepass/a requirepass ${PASSWORD}" -e "/^dir .*/c dir ${INSTALL_DIR}/data/" -e "/logfile .*/c logfile ${INSTALL_DIR}/log/redis-6379.log" -e "/^pidfile .*/c pidfile ${INSTALL_DIR}/run/redis_6379.pid" ${INSTALL_DIR}/etc/redis.conf

    #判斷是否有redis使用者,沒有就建立一個
    if id redis &> /dev/null ;then
        ${COLOR}"Redis使用者已經存在"${END}
    else
        useradd -r -s /sbin/nologin redis
        ${COLOR}"Redis使用者建立成功"${END}
    fi

    #修改目錄的權限
    chown -R redis.redis ${INSTALL_DIR}
    
    #修改核心參數
    cat >> /etc/sysctl.conf <<-EOF
net.core.somaxconn = 20480
vm.overcommit_memory = 1
EOF

    #準備service檔案
    cat > /lib/systemd/system/redis.service <<-EOF
[Unit]
Description=Redis persistent key-value database
After=network.target

[Service]
ExecStart=${INSTALL_DIR}/bin/redis-server ${INSTALL_DIR}/etc/redis.conf --supervised systemd
ExecStop=/bin/kill -s QUIT \$MAINPID
#Type=notify                                                                                                                                                                                                    
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755

[Install]
WantedBy=multi-user.target
EOF
    
    #重新加載一下服務并設定redis開機自啟動并立即啟動
    systemctl daemon-reload
    systemctl enable --now redis &> /dev/null && ${COLOR}"Redis服務啟動成功,Redis資訊如下:"${END} || { ${COLOR}"Redis服務啟動失敗"${END};exit; }
    sleep 1
    redis-cli -a ${PASSWORD} INFO Server 2> /dev/null
}

install
root@redis-master:~# bash -n install_redis.sh
root@redis-master:~# bash install_redis.sh
           
Redis主從模式的實作

2、Redis主從複制

  Redis的主從模式是可以實作Redis的資料跨主機備份,在配置主從的時候,從節點是需要開啟資料持久化并設定和主節點同樣的連接配接密碼。

Redis主從模式的實作

2.1、預設redis狀态

  在預設的情況下,三台剛安裝的redis主機都是單機模式的master角色。

Redis主從模式的實作
Redis主從模式的實作
Redis主從模式的實作

2.2、實作Redis主從複制

  實作Redis的主從複制是有兩種方式的,一種你可以通過指令行來配置,這樣配置的話是臨時生效,指令行配置的話重新開機Redis服務就沒有用了,但是同步過來的資料還是會保留的;另一種就是修改redis的配置檔案來使其生效,這樣的話即使重新開機redis服務主從的關系還在的。

2.2.1、指令行配置

2.2.1.1、準備測試的資料
Redis主從模式的實作
2.2.1.2、使用指令行啟用主從
Redis主從模式的實作
Redis主從模式的實作
Redis主從模式的實作
2.2.1.3、在master節點檢視主從狀态

  這時回到主節點檢視主從的狀态時,這時會發現自己還是master,但是發現下面多了兩個slave,可以看到兩個slave的相關資訊。

Redis主從模式的實作
2.2.1.4、檢視相關日志資訊
Redis主從模式的實作
Redis主從模式的實作
2.2.1.5、檢視連接配接狀态
Redis主從模式的實作
Redis主從模式的實作
Redis主從模式的實作

這時候你在master節點上寫入資料時,兩個slave節點是可以把資料同步過來的。

Redis主從模式的實作
Redis主從模式的實作
Redis主從模式的實作

這是在從節點測試一下是否可以寫入資料,從下圖可以看出是沒有寫入key的操作的,隻能進行讀的操作。

Redis主從模式的實作
2.2.1.6、取消主從同步

  我們是可以通過從節點執行replicaof no one指令即可取消主從複制,修改完後角色會變成master,并且之前同步的資料是不會丢的。

Redis主從模式的實作

  由于是通過指令行來實作的主從複制,當從節點重新開機Redis服務後就會失效了,這和使用指令行取消主從是一樣的,不過之前的資料還是在的。

Redis主從模式的實作

2.2.2、修改配置檔案

  我們在前面使用了指令行實作了主從複制,指令行配置是有缺陷的,當從節點的redis服務重新開機後就失效了;為了解決這個缺陷我們可以将指令行配置的内容加到配置檔案中,在重新開機一下redis服務讓其讀取配置檔案。

Redis主從模式的實作
Redis主從模式的實作

添加資料檢視是否同步可以參考前面使用指令行配置那個的步驟是一樣的,這裡我就不示範了。

3、主從複制故障與恢複

3.1、從節點故障與恢複

  當從節點出現故障時,隻需将Redis用戶端指向其他的從節點就可以了,并不會對整體的架構的讀操作進行太大的影響,即使所有的從節點出現故障,也可以直接通路主節點進行讀的操作;不過一般從節點出現故障後,除了一些特殊情況一般都會盡快的修複好,進而減輕其他節點的工作負載。

Redis主從模式的實作

3.2、主節點故障與恢複

3.2.1、主節點故障

Redis主從模式的實作
Redis主從模式的實作

3.2.2、提升新的主節點

  當我們的主節點故障時,我們可以将一個從節點提升為新的主節點,在将另一個從節點指向到新的主節點,這裡我就直接使用指令行修改配置了。

Redis主從模式的實作
Redis主從模式的實作

3.2.3、原主節點恢複正常

  當原來的主節點修複好了後,把Redis服務起來後會發現恢複到了單機的狀态,并且隻有之前的資料。

Redis主從模式的實作

  如果現在想要将原的主節點變成現有的主從架構的從節點,這樣的話就可以将新的主節點(slave1)的資料同步過來了;但是想要保持之前的原節點不變的話,就需要将現在的主從架構中的節點都指向原節點,并且剛剛新增的key也就會丢失;這裡我們可以保持原先的master節點為主節點為例,這裡可以把slave2設定成原master節點的從節點,我們也是可以直接把現在新主節點(slave1)設定成原master節點的從節點,這樣的話就形成了級聯複制,這樣的話slave可以不用修改配置,這樣的話slave2是從slave1來同步資料,而slave1從master節點同步資料。

Redis主從模式的實作
Redis主從模式的實作

4、主從複制的優化

4.1、主從複制過程

  Redis主從複制可以分為全量同步和增量同步。

4.1.1、全量複制的過程

Redis主從模式的實作

  第一次都是需要主從同步是全量同步的,主從同步可以讓從節點到主節點進行同步資料,而且從節點也可以有從節點,也就是前面示範的級聯複制的架構;

  Redis的主從同步是非阻塞的,master節點收到從伺服器的psync(在2.8版本之前是SYNC)指令,會fork一個子程序在背景執行bgsave指令,并将新寫入的資料先寫入到一個緩沖區中,bgsave執行完成之後,再将生成的RDB檔案發送給slave節點,然後master節點再将緩沖區的内容以redis協定格式再全部發送給slave節點,slave節點先删除舊資料,slave節點将收到後的RDB檔案載入自己的記憶體,再加載所有收到緩沖區的内容,進而這樣一次完整的資料同步。

  Redis全量複制一般發生在Slave首次初始化階段,這時Slave需要将Master上的所有資料都複制一份。

4.1.2、增量複制的過程

Redis主從模式的實作

  在全量同步之後再次需要同步時,從伺服器隻要發送目前的offset位置(等同于MySQL的binlog的位置)給主伺服器,然後主伺服器根據相應的位置将之後的資料(包括寫在緩沖區的積壓資料)發送給從伺服器,再次将其儲存到從節點記憶體即可。

4.1.3、主從同步完整過程

  1. 從伺服器連接配接主伺服器,發送PSYNC指令。
  2. 當主伺服器接收到PSYNC指令後,開始執行BGSAVE指令生成RDB快照檔案并使用緩沖區記錄此後執行的所有寫指令。
  3. 當主伺服器BGSAVE執行完後,向所有從伺服器發送RDB快照檔案,并在發送期間繼續記錄被執行的寫指令。
  4. 從伺服器收到快照檔案後丢棄所有舊資料,載入收到的快照至記憶體。
  5. 主伺服器快照發送完畢後,開始向從伺服器發送緩沖區中的寫指令。
  6. 從伺服器完成對快照的載入,開始接收指令請求,并執行來自主伺服器緩沖區的寫指令。
  7. 後期同步會先發送自己slave_repl_offset位置,隻同步新增加的資料,不再全量同步。
Redis主從模式的實作

4.2、主從複制的主要事項

4.2.1、避免全量複制

  • 第一次的全量複制是沒法避免的,後續的全量複制是可以利用小主節點(記憶體小),盡量在業務低峰時進行全量複制;
  • 在主節點重新開機後會發現運作的ID發生了變化,可能會觸發全量複制,可以利用故障轉移,例如哨兵或者叢集的方式,而從節點重新開機的話是不會導緻全量複制的;
  • 當複制積壓緩沖區不足時,主節點生成的新資料大與緩沖區的大小,從節點恢複和主節點連接配接後,這樣會導緻全量複制,這個是可以修改repl-backlog-size的值來解決,将其值調大。

4.2.2、避免複制的風暴

  單主節點複制的風暴:當主節點重新開機後,多個從節點會同時從主節點複制資料,這樣的話是會帶來複制風暴,解決方式可以更換複制的架構,比如可以使用級聯複制的架構。

Redis主從模式的實作

  單機器多執行個體的複制風暴:當伺服器出現當機時,後面有修複了,這樣的話就會進行大量的全量複制,并引發複制風暴,解決的方法是主節點分散多機器。

Redis主從模式的實作

4.3、主從複制優化配置

repl-diskless-sync no # 是否使用無盤同步RDB檔案,預設為no,no為不使用無盤,需要将RDB檔案儲存到磁盤後再發送給slave,yes為支援無盤,支援無盤就是RDB檔案不需要儲存至本地磁盤,而且直接通過socket檔案發送給slave

repl-diskless-sync-delay 5 #diskless時複制的伺服器等待的延遲時間

repl-ping-slave-period 10 #slave端向server端發送ping的時間間隔,預設為10秒

repl-timeout 60 #設定主從ping連接配接逾時時間,超過此值無法連接配接,master_link_status顯示為down,并記錄錯誤日志

repl-disable-tcp-nodelay no #是否啟用TCP_NODELAY,如設定成yes,則redis會合并小的TCP包進而節省帶寬, 但會增加同步延遲(40ms),造成master與slave資料不一緻,假如設定成no,則redis master會立即發送同步資料,沒有延遲,yes關注網絡性能,no關注redis服務中的資料一緻性

repl-backlog-size 1mb #master的寫入資料緩沖區,用于記錄自上一次同步後到下一次同步過程中間的寫入指令,計算公式:repl-backlog-size = 允許從節點最大中斷時長 * 主執行個體offset每秒寫入量,比如master每秒最大寫入64mb,最大允許60秒,那麼就要設定為64mb*60秒=3840MB(3.8G),建議此值是設定的足夠大

repl-backlog-ttl 3600 #如果一段時間後沒有slave連接配接到master,則backlog size的記憶體将會被釋放。如果值為0則 表示永遠不釋放這部份記憶體。

slave-priority 100 #slave端的優先級設定,值是一個整數,數字越小表示優先級越高。當master故障時将會按照優先級來選擇slave端進行恢複,如果值設定為0,則表示該slave永遠不會被選擇。

min-replicas-to-write 1 #設定一個master的可用slave不能少于多少個,否則master無法執行寫

min-slaves-max-lag 20 #設定至少有上面數量的slave延遲時間都大于多少秒時,master不接收寫操作(拒絕寫入)
           

5、常見主從複制故障

5.1、master密碼不對

5.2、redis版本不一緻

5.3、無法遠端連接配接

5.4、配置不一緻

  1. 當主從節點的maxmemory不一緻,主節點的記憶體大雨從節點的記憶體時,這樣就可能會出現主從複制丢失資料的情況。
  2. 主從節點的rename-command指令不一緻,例如在主節點定義了flushall,flushdb,而在從節點上沒有定義,這樣的話在主節點執行flushall或者flushdb的話,在從節點的資料是沒有同步的。

繼續閱讀