redis實現主從複製

来源:https://www.cnblogs.com/gy001/archive/2022/11/02/16851683.html
-Advertisement-
Play Games

前面說到了redis在單機的模式下是可以數據持久化的,但是不可以解決單點失敗的問題,當單台redis伺服器出現問題時,就可能會造成數據的丟失;想要解決這個問題的話我們可以使用Redis的主從模式這也是Redis集群最簡單的實現方式,這篇文章我就來簡單部署一個Redis主從架構,我準備了3台ubunt ...


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

1、腳本安裝redis

#!/bin/bash
#REDIS_VERSION=redis-7.0.5
#REDIS_VERSION=redis-7.0.3
#REDIS_VERSION=redis-6.2.6
REDIS_VERSION=redis-5.0.14
#REDIS_VERSION=redis-4.0.14
REDIS_URL=http://download.redis.io/releases
PASSWORD=123456
INSTALL_DIR=/apps/redis


CPUS=`lscpu |awk '/^CPU\(s\)/{print $2}'`
. /etc/os-release

color () {
    RES_COL=60
    MOVE_TO_COL="echo -en \\033[${RES_COL}G"
    SETCOLOR_SUCCESS="echo -en \\033[1;32m"
    SETCOLOR_FAILURE="echo -en \\033[1;31m"
    SETCOLOR_WARNING="echo -en \\033[1;33m"
    SETCOLOR_NORMAL="echo -en \E[0m"
    echo -n "$1" && $MOVE_TO_COL
    echo -n "["
    if [ $2 = "success" -o $2 = "0" ] ;then
        ${SETCOLOR_SUCCESS}
        echo -n $"  OK  "
    elif [ $2 = "failure" -o $2 = "1"  ] ;then
        ${SETCOLOR_FAILURE}
        echo -n $"FAILED"
    else
        ${SETCOLOR_WARNING}
        echo -n $"WARNING"
    fi
    ${SETCOLOR_NORMAL}
    echo -n "]"
    echo
}


prepare(){
    if [ $ID = "centos" -o $ID = "rocky" ];then
        yum  -y install gcc make jemalloc-devel systemd-devel
    else
        apt update
        apt -y install  gcc make libjemalloc-dev libsystemd-dev
    fi
    if [ $? -eq 0 ];then
        color "安裝軟體包成功"  0
    else
        color "安裝軟體包失敗,請檢查網路配置" 1
        exit
    fi
}
install() {
    if [ ! -f ${REDIS_VERSION}.tar.gz ];then
        wget ${REDIS_URL}/${REDIS_VERSION}.tar.gz || { color "Redis 源碼下載失敗" 1 ; exit; }
    fi
    tar xf ${REDIS_VERSION}.tar.gz -C /usr/local/src
    cd /usr/local/src/${REDIS_VERSION}
    make -j $CUPS USE_SYSTEMD=yes PREFIX=${INSTALL_DIR} install && color "Redis 編譯安裝完成" 0 || { color "Redis 編譯安裝失敗" 1 ;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


    if id redis &> /dev/null ;then
         color "Redis 用戶已存在" 1
    else
         useradd -r -s /sbin/nologin redis
         color "Redis 用戶創建成功" 0
    fi

    chown -R redis.redis ${INSTALL_DIR}

    cat >> /etc/sysctl.conf <<EOF
net.core.somaxconn = 1024
vm.overcommit_memory = 1
EOF
    sysctl -p
    if [ $ID = "centos" -o $ID = "rocky" ];then
        echo 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' >> /etc/rc.d/rc.local
        chmod +x /etc/rc.d/rc.local
        /etc/rc.d/rc.local
    else
        echo -e '#!/bin/bash\necho never > /sys/kernel/mm/transparent_hugepage/enabled' >> /etc/rc.local
        chmod +x /etc/rc.local
        /etc/rc.local
    fi


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
LimitNOFILE=1000000

[Install]
WantedBy=multi-user.target

EOF
     systemctl daemon-reload
     systemctl enable --now  redis &> /dev/null
     if [ $? -eq 0 ];then
         color "Redis 服務啟動成功,Redis信息如下:"  0
     else
         color "Redis 啟動失敗" 1
         exit
     fi
     sleep 2
     redis-cli -a $PASSWORD INFO Server 2> /dev/null
}

prepare

install

#查看redis是否啟用

[root@slave2 ~]#systemctl status redis.service
● redis.service - Redis persistent key-value database
Loaded: loaded (/lib/systemd/system/redis.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2022-11-02 15:14:08 CST; 10min ago
Main PID: 12529 (redis-server)
Tasks: 4 (limit: 2236)
Memory: 1.7M
CGroup: /system.slice/redis.service
└─12529 /apps/redis/bin/redis-server 0.0.0.0:6379

11月 02 15:14:08 ubuntu2004 systemd[1]: Starting Redis persistent key-value database...
11月 02 15:14:08 ubuntu2004 systemd[1]: Started Redis persistent key-value database.

2、Redis主從複製

 

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

 

 

 

 2.1、預設redis狀態

剛安裝好後的redis三台機器都是master狀態,可以進到客戶端查詢一下

 

 

 

 

 2.2、實現Redis主從複製

 實現Redis的主從複製是有兩種方式的,一種你可以通過命令行來配置,這樣配置的話是臨時生效,命令行配置的話重啟Redis服務就沒有用了,但是同步過來的數據還是會保留的;另一種就是修改redis的配置文件來使其生效,這樣的話即使重啟redis服務主從的關係還在的。

2.2.1客戶端命令行配置

準備點數據

[root@master ~]#redis-cli -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> mset k1 v1 k2 v1 k3 v3
OK
127.0.0.1:6379> dbsize
(integer) 3

使用命令行啟用主從

127.0.0.1:6379> replicaof 10.0.0.101 6379
OK
127.0.0.1:6379> INFO replication
# Replication
role:slave   #角色已經變成了slave,但是狀態還是down,這時需要設置下主節點的連接密碼才能變成up
master_host:10.0.0.101
master_port:6379
master_link_status:down
master_last_io_seconds_ago:-1
master_sync_in_progress:0
slave_repl_offset:1
master_link_down_since_seconds:1667376380
slave_priority:100
slave_read_only:1
connected_slaves:0

slave2節點同樣操作

 

 

 在master節點查看主從狀態

 

 

 

 查看連接狀態

 

 

 複製測試,發現之前的數據已經同步過來了

 

 

 

 

 

 取消主從同步

我們是可以通過從節點執行replicaof no one命令即可取消主從複製,修改完後角色會變成master,並且之前同步的數據是不會丟的。

 

 

 2.2.2修改配置文件

我們在前面使用了命令行實現了主從複製,命令行配置是有缺陷的,當從節點的redis服務重啟後就失效了;為瞭解決這個缺陷我們可以將命令行配置的內容加到配置文件中,在重啟一下redis服務讓其讀取配置文件。

[root@slave2 ~]#echo -e "replicaof 10.0.0.101 6379\nmasterauth 123456" >> /apps/redis/etc/redis.conf
[root@slave2 ~]#tail -2 /apps/redis/etc/redis.conf
replicaof 10.0.0.101 6379
masterauth 123456
[root@slave2 ~]#systemctl restart redis.service

登錄上去查看主從關係

 

 

 3、主從複製故障與恢復

3.1、從節點故障與恢復

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

 

3.2、主節點故障與恢復

當我們的主節點故障時,我們可以將一個從節點提升為新的主節點,在將另一個從節點指向到新的主節點,當原來的主節點修複好了後,把Redis服務起來後會發現恢復到了單機的狀態,並且只有之前的數據。過程和之前一樣我就不做演示了。

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

4、主從複製的優化

 4.1、主從複製過程

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

4.1.1、全量複製的過程

第一次都是需要主從同步是全量同步的,主從同步可以讓從節點到主節點進行同步數據,而且從節點也可以有從節點,也就是前面演示的級聯複製的架構;
  Redis的主從同步是非阻塞的,master節點收到從伺服器的psync(在2.8版本之前是SYNC)命令,會fork一個子進程在後臺執行bgsave命令,並將新寫入的數據先寫入到一個緩衝區中,bgsave執行完成之後,再將生成的RDB文件發送給slave節點,然後master節點再將緩衝區的內容以redis協議格式再全部發送給slave節點,slave節點先刪除舊數據,slave節點將收到後的RDB文件載入自己的記憶體,再載入所有收到緩衝區的內容,從而這樣一次完整的數據同步。
  Redis全量複製一般發生在Slave首次初始化階段,這時Slave需要將Master上的所有數據都複製一份。

4.1.2、增量複製的過程

 

 

 在全量同步之後再次需要同步時,從伺服器只要發送當前的offset位置(等同於MySQL的binlog的位置)給主伺服器,然後主伺服器根據相應的位置將之後的數據(包括寫在緩衝區的積壓數據)發送給從伺服器,再次將其保存到從節點記憶體即可。

 4.1.3、主從同步完整過程

  1. 從伺服器連接主伺服器,發送PSYNC命令。
  2. 當主伺服器接收到PSYNC命令後,開始執行BGSAVE命令生成RDB快照文件並使用緩衝區記錄此後執行的所有寫命令。
  3. 當主伺服器BGSAVE執行完後,向所有從伺服器發送RDB快照文件,併在發送期間繼續記錄被執行的寫命令。
  4. 從伺服器收到快照文件後丟棄所有舊數據,載入收到的快照至記憶體。
  5. 主伺服器快照發送完畢後,開始向從伺服器發送緩衝區中的寫命令。
  6. 從伺服器完成對快照的載入,開始接收命令請求,並執行來自主伺服器緩衝區的寫命令。
  7. 後期同步會先發送自己slave_repl_offset位置,只同步新增加的數據,不再全量同步。

 

4.2、主從複製的主要事項

4.2.1、避免全量複製

 

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

4.2.2、避免複製的風暴

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

 

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

 

 

 

 

 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密碼不對  

即主節點在Redis配置文件中設置的requirepass部分,從節點在執行主從同步命令時或者修改配置文件時未添加正確,則會導致無法建立主從同步關係。

5.2、redis版本不一致  

不同的redis大版本之間是會存在相容性的問題的,例如大版本3和大版本4之間,大版本4和大版本5之間,因此各master節點和slave節點之間必須保持版本的一致。

5.3、無法遠程連接  

當在開啟了安全模式的情況下,沒有設置bind地址或者密碼的話,外部是訪問不了的,也就是沒辦法遠程連接。

5.4、配置不一致

  • 當主從節點的maxmemory不一致,主節點的記憶體大雨從節點的記憶體時,這樣就可能會出現主從複製丟失數據的情況。
  • 主從節點的rename-command命令不一致,例如在主節點定義了flushall,flushdb,而在從節點上沒有定義,這樣的話在主節點執行flushall或者flushdb的話,在從節點的數據是沒有同步的。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 背景 2008 年前後的 Midori 項目試圖構建一個以 .NET 為用戶態基礎的操作系統,在這個項目中有很多讓 CLR 以及 C# 的類型系統向著適合系統編程的方向改進的探索,雖然項目最終沒有面世,但是積累了很多的成果。近些年由於 .NET 團隊在高性能和零開銷設施上的需要,從 2017 年開始 ...
  • 自己寫了一種,速度不是很快,但是能夠實現 var findpic = new FindPic(); var rec = findpic.FindPicture(@"C:\Users\zaranet\Desktop\xiao.png", @"C:\Users\zaranet\Desktop\da.pn ...
  • ###前言 剛接觸XAF的小伙伴可能會有一個疑惑,XAF中有Model(BusinessObject)、View、Controller,感覺明顯是一個MVC的設計模式,但當你用MVC的設計模式與其對應時,又會發現有一些不一樣,可能這時有小伙伴會想會不會是MVC的變體,因為MVC只是一個設計模式,不同 ...
  • 長連接與短連接 所謂長連接,指在一個TCP連接上可以連續發送多個數據包,在TCP連接保持期間,如果沒有數據包發送,需要雙方發檢測包以維持此連接,一般需要自己做線上維持。 短連接是指通信雙方有數據交互時,就建立一個TCP連接,數據發送完成後,則斷開此TCP連接,一般銀行都使用短連接。 比如http的, ...
  • <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-web ...
  • lsof -i tcp:埠號 要殺死進程的話,即:kill -9 pid ...
  • 前言 上一篇博客給大家介紹了LabVIEW開放神經網路交互工具包【ONNX】,今天我們就一起來看一下如何使用LabVIEW開放神經網路交互工具包實現TensorRT加速YOLOv5。 以下是YOLOv5的相關筆記總結,希望對大家有所幫助。 內容地址鏈接 【YOLOv5】LabVIEW+OpenVIN ...
  • GreatSQL社區原創內容未經授權不得隨意使用,轉載請聯繫小編並註明來源。 GreatSQL是MySQL的國產分支版本,使用上與MySQL一致。 前文回顧 實現一個簡單的Database1(譯文) 實現一個簡單的Database2(譯文) 實現一個簡單的Database3(譯文) 實現一個簡單的D ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...