多實(shí)例Redis主從集群搭建與運(yùn)維實(shí)戰(zhàn)指南)
1. 項(xiàng)目概述單機(jī)多實(shí)例Redis主從集群的實(shí)戰(zhàn)價(jià)值在真實(shí)的運(yùn)維場(chǎng)景里我們常常會(huì)遇到一種“尷尬”的預(yù)算或測(cè)試環(huán)境手頭只有一臺(tái)性能還不錯(cuò)的Linux服務(wù)器但業(yè)務(wù)上又需要驗(yàn)證Redis的高可用架構(gòu)或者為開(kāi)發(fā)測(cè)試提供一個(gè)具備主從復(fù)制能力的緩存環(huán)境。直接上物理或虛擬機(jī)集群成本太高用Docker雖然方便但有時(shí)又希望更貼近原生部署便于理解底層機(jī)制。這時(shí)候“一臺(tái)主機(jī)多個(gè)端口”的Redis主從復(fù)制集群方案就成了一個(gè)極具性價(jià)比的練手和過(guò)渡選擇。這個(gè)方案的核心就是在同一臺(tái)物理機(jī)或虛擬機(jī)上啟動(dòng)多個(gè)Redis服務(wù)進(jìn)程每個(gè)進(jìn)程監(jiān)聽(tīng)不同的端口例如6379, 6380, 6381并將它們配置成主從關(guān)系。它解決的痛點(diǎn)非常明確用最低的硬件成本模擬出生產(chǎn)級(jí)Redis主從復(fù)制的核心行為包括數(shù)據(jù)同步、讀寫(xiě)分離、故障感知等。無(wú)論是用來(lái)學(xué)習(xí)Redis復(fù)制原理還是為小型項(xiàng)目搭建一個(gè)具備基本數(shù)據(jù)冗余的緩存層這個(gè)方案都足夠輕量、直接。我從業(yè)十多年從早期手動(dòng)配置到后來(lái)用自動(dòng)化工具管理這種單機(jī)多實(shí)例的模式在測(cè)試、預(yù)發(fā)布環(huán)境甚至某些對(duì)延遲極其敏感的小型生產(chǎn)服務(wù)中依然有它的用武之地。它讓你能聚焦于Redis本身的配置、監(jiān)控和故障處理而不被復(fù)雜的網(wǎng)絡(luò)和機(jī)器管理分散精力。接下來(lái)我就帶你從零開(kāi)始拆解如何穩(wěn)健地搭建這樣一個(gè)環(huán)境并分享那些只有踩過(guò)坑才知道的細(xì)節(jié)。2. 整體架構(gòu)設(shè)計(jì)與核心思路拆解2.1 為什么選擇單機(jī)多端口模式在深入實(shí)操之前我們必須先理清選擇這種架構(gòu)背后的考量這決定了后續(xù)每一步配置的合理性。首先成本與效率的平衡。對(duì)于學(xué)習(xí)、功能驗(yàn)證、性能壓測(cè)或開(kāi)發(fā)聯(lián)調(diào)環(huán)境申請(qǐng)多臺(tái)服務(wù)器資源周期長(zhǎng)、成本高。單機(jī)多實(shí)例方案能在幾分鐘內(nèi)快速搭建一個(gè)“麻雀雖小五臟俱全”的復(fù)制集所有數(shù)據(jù)交互都在本機(jī)回環(huán)地址127.0.0.1上進(jìn)行網(wǎng)絡(luò)延遲幾乎為零這非常利于觀察純粹的數(shù)據(jù)同步性能。其次理解原理的最佳路徑。Redis的主從復(fù)制其核心流程——全量同步RDB文件傳輸、增量同步Replication Buffer、長(zhǎng)連接維護(hù)等——在單機(jī)環(huán)境下與跨機(jī)器環(huán)境完全一致。通過(guò)在一臺(tái)機(jī)器上操作你可以更專注地使用INFO replication、MONITOR等命令觀察狀態(tài)變化而不受網(wǎng)絡(luò)抖動(dòng)等外部因素干擾。然而必須清醒認(rèn)識(shí)到它的局限性。最明顯的就是缺乏真正的高可用性。既然所有實(shí)例都在同一臺(tái)宿主機(jī)上那么宿主機(jī)的硬件故障、內(nèi)核崩潰或機(jī)房斷電將導(dǎo)致整個(gè)“集群”徹底宕機(jī)從節(jié)點(diǎn)起不到災(zāi)備作用。因此這個(gè)架構(gòu)的定位是“數(shù)據(jù)冗余與讀寫(xiě)分離”而非“服務(wù)高可用”。它保證了數(shù)據(jù)有多份拷貝也允許你將讀請(qǐng)求分散到從節(jié)點(diǎn)但無(wú)法解決主機(jī)級(jí)別的單點(diǎn)故障。2.2 核心組件與關(guān)系規(guī)劃一個(gè)典型的一主二從最小集群規(guī)劃如下這也是我們本文實(shí)操的藍(lán)本主節(jié)點(diǎn) (Master): 承擔(dān)所有寫(xiě)操作并將數(shù)據(jù)變更同步給從節(jié)點(diǎn)。我們將其綁定在127.0.0.1:6379。從節(jié)點(diǎn)1 (Slave-1): 復(fù)制主節(jié)點(diǎn)數(shù)據(jù)可處理讀請(qǐng)求。綁定在127.0.0.1:6380。從節(jié)點(diǎn)2 (Slave-2): 復(fù)制主節(jié)點(diǎn)數(shù)據(jù)可處理讀請(qǐng)求。綁定在127.0.0.1:6381。配置文件: 每個(gè)實(shí)例需要一個(gè)獨(dú)立的配置文件。這是管理多實(shí)例的關(guān)鍵避免配置混雜。數(shù)據(jù)目錄: 每個(gè)實(shí)例應(yīng)有獨(dú)立的數(shù)據(jù)目錄dir用于存放RDB持久化文件、AOF文件如果開(kāi)啟以及節(jié)點(diǎn)自身的運(yùn)行元數(shù)據(jù)。日志文件: 每個(gè)實(shí)例應(yīng)有獨(dú)立的日志文件便于排查問(wèn)題。它們之間的關(guān)系是星型拓?fù)鋬蓚€(gè)從節(jié)點(diǎn)直接連接主節(jié)點(diǎn)。從節(jié)點(diǎn)之間彼此獨(dú)立。你也可以配置鏈?zhǔn)綇?fù)制Slave of Slave但在單機(jī)環(huán)境下意義不大且會(huì)增加復(fù)雜度。3. 環(huán)境準(zhǔn)備與配置文件詳解3.1 系統(tǒng)與Redis安裝基礎(chǔ)假設(shè)我們使用的是一臺(tái)干凈的CentOS 7或Ubuntu 20.04服務(wù)器。首先確保系統(tǒng)基礎(chǔ)環(huán)境。# 更新系統(tǒng)包以CentOS為例 sudo yum update -y # 安裝編譯依賴 sudo yum install -y gcc tcl systemd-devel wget接下來(lái)我們編譯安裝Redis。選擇較新的穩(wěn)定版本如6.2.x系列它在內(nèi)存和復(fù)制方面有諸多優(yōu)化。# 下載源碼包 wget https://download.redis.io/releases/redis-6.2.13.tar.gz tar -xzf redis-6.2.13.tar.gz cd redis-6.2.13 # 編譯安裝指定安裝目錄為 /usr/local/redis make BUILD_TLSyes USE_SYSTEMDyes sudo make PREFIX/usr/local/redis installUSE_SYSTEMDyes參數(shù)是為了后續(xù)方便用systemd管理多個(gè)實(shí)例。安裝完成后二進(jìn)制文件redis-server,redis-cli會(huì)在/usr/local/redis/bin/目錄下。3.2 多實(shí)例目錄結(jié)構(gòu)與配置生成這是避免混亂的關(guān)鍵一步。我們不修改Redis默認(rèn)的redis.conf而是為每個(gè)實(shí)例創(chuàng)建專屬的配置和數(shù)據(jù)空間。# 創(chuàng)建總的管理目錄 sudo mkdir -p /redis-cluster cd /redis-cluster # 為三個(gè)實(shí)例創(chuàng)建子目錄分別存放配置、數(shù)據(jù)、日志 for port in 6379 6380 6381; do sudo mkdir -p node-${port}/{conf,data,log} sudo chown -R whoami:whoami node-${port} # 根據(jù)實(shí)際情況調(diào)整所屬用戶 done # 從源碼包中復(fù)制一份原始的配置文件作為模板 cp /path/to/redis-6.2.13/redis.conf /redis-cluster/redis.conf.template現(xiàn)在我們來(lái)生成三個(gè)不同的配置文件。重點(diǎn)修改以下參數(shù)我將逐一解釋原因主節(jié)點(diǎn)配置 (node-6379/conf/redis.conf):port 6379 bind 127.0.0.1 daemonize yes pidfile /redis-cluster/node-6379/redis_6379.pid logfile /redis-cluster/node-6379/log/redis.log dir /redis-cluster/node-6379/data dbfilename dump-6379.rdb # 主節(jié)點(diǎn)無(wú)需配置 replicaof # 但可以設(shè)置密碼如果設(shè)置從節(jié)點(diǎn)需要配置 masterauth # requirepass yourMasterPassword從節(jié)點(diǎn)配置 (node-6380/conf/redis.conf):(6381類似修改對(duì)應(yīng)端口和路徑)port 6380 bind 127.0.0.1 daemonize yes pidfile /redis-cluster/node-6380/redis_6380.pid logfile /redis-cluster/node-6380/log/redis.log dir /redis-cluster/node-6380/data dbfilename dump-6380.rdb # 核心指定主節(jié)點(diǎn)。格式為 replicaof masterip masterport replicaof 127.0.0.1 6379 # 如果主節(jié)點(diǎn)設(shè)置了密碼這里必須配置 # masterauth yourMasterPassword # 從節(jié)點(diǎn)默認(rèn)只讀建議顯式設(shè)置防止誤寫(xiě) replica-read-only yes注意從Redis 5.0開(kāi)始slaveof命令已被replicaof取代兩者作用相同但建議使用新的replicaof。如果你的版本較老使用slaveof。關(guān)鍵配置解析port和bind: 這是區(qū)分不同實(shí)例的核心。綁定127.0.0.1而非0.0.0.0是出于安全考慮防止外部意外連接。pidfile: 指定進(jìn)程ID文件路徑。系統(tǒng)管理工具如systemd或監(jiān)控腳本需要用它來(lái)精確控制特定實(shí)例。dir和dbfilename:必須為每個(gè)實(shí)例設(shè)置獨(dú)立的目錄和文件名。否則多個(gè)實(shí)例的RDB文件會(huì)相互覆蓋導(dǎo)致數(shù)據(jù)混亂或啟動(dòng)失敗。daemonize: 設(shè)置為yes讓Redis以守護(hù)進(jìn)程方式運(yùn)行這是我們手動(dòng)管理時(shí)的常見(jiàn)選擇。如果使用systemd管理則可以設(shè)為no由systemd控制前臺(tái)/后臺(tái)。replicaof: 從節(jié)點(diǎn)的靈魂配置。指向主節(jié)點(diǎn)的地址和端口。4. 啟動(dòng)集群與復(fù)制狀態(tài)驗(yàn)證4.1 順序啟動(dòng)與觀察日志啟動(dòng)順序有講究先啟動(dòng)主節(jié)點(diǎn)再啟動(dòng)從節(jié)點(diǎn)。如果從節(jié)點(diǎn)先啟動(dòng)它會(huì)因找不到主節(jié)點(diǎn)而反復(fù)連接失敗雖然最終能連上但日志會(huì)充滿錯(cuò)誤信息。cd /usr/local/redis/bin # 啟動(dòng)主節(jié)點(diǎn) ./redis-server /redis-cluster/node-6379/conf/redis.conf # 啟動(dòng)從節(jié)點(diǎn) ./redis-server /redis-cluster/node-6380/conf/redis.conf ./redis-server /redis-cluster/node-6381/conf/redis.conf啟動(dòng)后立即查看從節(jié)點(diǎn)的日志這是觀察復(fù)制初始化過(guò)程的最佳窗口tail -f /redis-cluster/node-6380/log/redis.log你應(yīng)該能看到類似如下的關(guān)鍵信息* Connecting to MASTER 127.0.0.1:6379 * MASTER - REPLICA sync started * REPLICAOF 127.0.0.1:6379 enabled (user request) * Background saving started by pid 12345 * RDB: 0 MB of memory used by copy-on-write * MASTER - REPLICA sync: receiving 175 MB from master * MASTER - REPLICA sync: Flushing old data * MASTER - REPLICA sync: Loading DB in memory * MASTER - REPLICA sync: Finished with success這個(gè)過(guò)程描述了從節(jié)點(diǎn)連接主節(jié)點(diǎn)、發(fā)起全量同步生成和傳輸RDB、清空自身舊數(shù)據(jù)、加載新RDB文件的全過(guò)程。數(shù)據(jù)量越大Loading DB in memory階段耗時(shí)越長(zhǎng)。4.2 使用redis-cli驗(yàn)證復(fù)制狀態(tài)啟動(dòng)完成后我們使用redis-cli連接各個(gè)節(jié)點(diǎn)進(jìn)行驗(yàn)證。1. 檢查主節(jié)點(diǎn)視角的復(fù)制信息./redis-cli -p 6379 INFO replication在輸出中找到# Replication部分你會(huì)看到role:master connected_slaves:2 slave0:ip127.0.0.1,port6380,stateonline,offset...,lag0 slave1:ip127.0.0.1,port6381,stateonline,offset...,lag0 master_replid:一串40位的哈希值 master_repl_offset:復(fù)制偏移量connected_slaves:2確認(rèn)兩個(gè)從節(jié)點(diǎn)已成功連接。stateonline和lag0或很小表示復(fù)制連接健康延遲低。2. 檢查從節(jié)點(diǎn)視角的復(fù)制信息./redis-cli -p 6380 INFO replication輸出類似role:slave master_host:127.0.0.1 master_port:6379 master_link_status:up # 關(guān)鍵狀態(tài)up表示連接正常 master_last_io_seconds_ago:1 # 距離上次IO的秒數(shù)值很小說(shuō)明同步活躍 master_sync_in_progress:0 # 0表示沒(méi)有正在進(jìn)行全量同步 slave_repl_offset:... # 從節(jié)點(diǎn)的復(fù)制偏移量master_link_status:up是健康的核心標(biāo)志。3. 測(cè)試數(shù)據(jù)同步在主節(jié)點(diǎn)寫(xiě)入數(shù)據(jù)在從節(jié)點(diǎn)讀取驗(yàn)證復(fù)制功能。# 在主節(jié)點(diǎn)寫(xiě)入 ./redis-cli -p 6379 SET mykey Hello from Master # 在從節(jié)點(diǎn)讀取 (注意從節(jié)點(diǎn)默認(rèn)只讀不能執(zhí)行SET) ./redis-cli -p 6380 GET mykey # 應(yīng)返回 Hello from Master ./redis-cli -p 6381 GET mykey # 應(yīng)返回 Hello from Master4.3 配置systemd服務(wù)生產(chǎn)環(huán)境推薦手動(dòng)啟動(dòng)適合測(cè)試但對(duì)于需要長(zhǎng)期運(yùn)行的環(huán)境使用systemd管理是更規(guī)范、可靠的做法。它為每個(gè)實(shí)例提供開(kāi)機(jī)自啟、日志集成、資源限制和監(jiān)控能力。為每個(gè)實(shí)例創(chuàng)建service文件以6379為例sudo vim /etc/systemd/system/redis-6379.service寫(xiě)入以下內(nèi)容[Unit] DescriptionRedis Master Node on port 6379 Afternetwork.target [Service] Typesimple Userredis # 建議創(chuàng)建一個(gè)專門(mén)的redis用戶更安全 Groupredis ExecStart/usr/local/redis/bin/redis-server /redis-cluster/node-6379/conf/redis.conf --daemonize no # systemd管理時(shí)讓Redis在前臺(tái)運(yùn)行 ExecStop/usr/local/redis/bin/redis-cli -p 6379 shutdown Restartalways RestartSec3 LimitNOFILE65536 # 安全相關(guān)限制服務(wù)能力 PrivateTmpyes ProtectSystemstrict ReadWritePaths/redis-cluster/node-6379/data /redis-cluster/node-6379/log [Install] WantedBymulti-user.target實(shí)操心得Typesimple并讓Redis--daemonize no在前臺(tái)運(yùn)行這樣systemd才能正確捕獲和管理進(jìn)程狀態(tài)。ReadWritePaths是systemd的沙盒特性精確控制服務(wù)可訪問(wèn)的路徑極大地增強(qiáng)了安全性。務(wù)必為每個(gè)端口創(chuàng)建獨(dú)立的service文件如redis-6380.service并修改對(duì)應(yīng)的ExecStart、ExecStop命令和ReadWritePaths路徑。保存后重載systemd并啟動(dòng)服務(wù)sudo systemctl daemon-reload sudo systemctl start redis-6379 sudo systemctl enable redis-6379 # 設(shè)置開(kāi)機(jī)自啟 sudo systemctl status redis-6379 # 查看狀態(tài)對(duì)6380和6381端口重復(fù)此操作。以后管理就可以用systemctl start/stop/restart/status redis-端口號(hào)命令非常清晰。5. 深入核心主從復(fù)制機(jī)制與調(diào)優(yōu)要點(diǎn)搭建成功只是第一步理解其內(nèi)部機(jī)制才能有效運(yùn)維和排錯(cuò)。Redis的主從復(fù)制分為全量同步和增量同步。5.1 全量同步與增量同步流程當(dāng)從節(jié)點(diǎn)首次連接主節(jié)點(diǎn)或主從復(fù)制關(guān)系因網(wǎng)絡(luò)中斷、從節(jié)點(diǎn)重啟等原因丟失時(shí)會(huì)觸發(fā)全量同步從節(jié)點(diǎn)發(fā)送PSYNC命令。主節(jié)點(diǎn)執(zhí)行BGSAVE在后臺(tái)生成當(dāng)前數(shù)據(jù)的RDB快照文件。主節(jié)點(diǎn)將RDB文件通過(guò)網(wǎng)絡(luò)發(fā)送給從節(jié)點(diǎn)。這里有一個(gè)關(guān)鍵點(diǎn)在生成和傳輸RDB期間主節(jié)點(diǎn)新的寫(xiě)命令會(huì)存入一個(gè)專用的復(fù)制緩沖區(qū)Replication Buffer。從節(jié)點(diǎn)清空舊數(shù)據(jù)載入收到的RDB文件。RDB加載完成后主節(jié)點(diǎn)將復(fù)制緩沖區(qū)中積壓的寫(xiě)命令發(fā)送給從節(jié)點(diǎn)從節(jié)點(diǎn)執(zhí)行這些命令最終達(dá)到與主節(jié)點(diǎn)一致的狀態(tài)。之后進(jìn)入增量同步命令傳播階段主節(jié)點(diǎn)每執(zhí)行一個(gè)寫(xiě)命令都會(huì)異步地發(fā)送給所有從節(jié)點(diǎn)。從節(jié)點(diǎn)持續(xù)接收并執(zhí)行這些命令保持?jǐn)?shù)據(jù)實(shí)時(shí)同步。單機(jī)環(huán)境下的特殊優(yōu)勢(shì)因?yàn)镽DB文件通過(guò)本地回環(huán)網(wǎng)絡(luò)傳輸速度極快全量同步的耗時(shí)主要花在主節(jié)點(diǎn)生成RDB和從節(jié)點(diǎn)加載RDB的磁盤(pán)IO和CPU消耗上網(wǎng)絡(luò)不再是瓶頸。這讓你能更純粹地評(píng)估Redis自身的數(shù)據(jù)持久化和加載性能。5.2 關(guān)鍵配置參數(shù)調(diào)優(yōu)建議在配置文件中有幾個(gè)參數(shù)對(duì)復(fù)制性能和穩(wěn)定性至關(guān)重要repl-backlog-size(默認(rèn)1MB)這是復(fù)制積壓緩沖區(qū)的大小。在主從網(wǎng)絡(luò)短暫斷開(kāi)又重連后如果從節(jié)點(diǎn)丟失的偏移量還在這個(gè)緩沖區(qū)內(nèi)則可以進(jìn)行部分重同步增量補(bǔ)發(fā)避免昂貴的全量同步。在單機(jī)環(huán)境下由于網(wǎng)絡(luò)極其穩(wěn)定1MB通常足夠。但在生產(chǎn)跨機(jī)器部署時(shí)應(yīng)根據(jù)業(yè)務(wù)寫(xiě)流量和可能的網(wǎng)絡(luò)中斷時(shí)間調(diào)大此值例如設(shè)置為256mb或512mb。client-output-buffer-limit replica限制主節(jié)點(diǎn)為每個(gè)從節(jié)點(diǎn)分配的復(fù)制輸出緩沖區(qū)大小。如果從節(jié)點(diǎn)同步太慢比如從節(jié)點(diǎn)正在加載RDB緩沖區(qū)可能會(huì)積滿。一旦積滿主節(jié)點(diǎn)會(huì)斷開(kāi)與該從節(jié)點(diǎn)的連接導(dǎo)致復(fù)制失敗。在單機(jī)環(huán)境同步通常很快風(fēng)險(xiǎn)低。但在跨網(wǎng)絡(luò)或從節(jié)點(diǎn)性能較差時(shí)可能需要適當(dāng)調(diào)大。例如client-output-buffer-limit replica 512mb 256mb 60表示硬限制512MB軟限制256MB持續(xù)60秒后斷開(kāi)。repl-disable-tcp-nodelay主節(jié)點(diǎn)向從節(jié)點(diǎn)發(fā)送數(shù)據(jù)時(shí)是否啟用TCP_NODELAY。啟用設(shè)置為no會(huì)減少延遲但可能增加小包數(shù)量禁用設(shè)置為yes會(huì)合并小包節(jié)省帶寬但增加延遲。在單機(jī)千兆/萬(wàn)兆回環(huán)網(wǎng)絡(luò)上延遲極低建議設(shè)置為no啟用NODELAY以獲得最快的同步響應(yīng)。在跨公網(wǎng)等高延遲環(huán)境下可考慮設(shè)置為yes以節(jié)省帶寬。replica-read-only從節(jié)點(diǎn)是否只讀。務(wù)必設(shè)置為yes。這是防止數(shù)據(jù)不一致的關(guān)鍵。如果從節(jié)點(diǎn)被意外寫(xiě)入數(shù)據(jù)這部分?jǐn)?shù)據(jù)在主節(jié)點(diǎn)重新同步時(shí)會(huì)被清空導(dǎo)致寫(xiě)入丟失。6. 運(yùn)維實(shí)操故障模擬、切換與監(jiān)控6.1 模擬主節(jié)點(diǎn)故障與手動(dòng)切換單機(jī)環(huán)境無(wú)法實(shí)現(xiàn)自動(dòng)故障轉(zhuǎn)移那是Redis Sentinel或Redis Cluster的職責(zé)但我們可以手動(dòng)演練切換流程這對(duì)理解主從原理至關(guān)重要。場(chǎng)景假設(shè)主節(jié)點(diǎn)6379進(jìn)程意外宕機(jī)。停止主節(jié)點(diǎn)# 如果使用systemd sudo systemctl stop redis-6379 # 或者用redis-cli /usr/local/redis/bin/redis-cli -p 6379 SHUTDOWN提升一個(gè)從節(jié)點(diǎn)為新主節(jié)點(diǎn) 我們選擇6380作為新的主節(jié)點(diǎn)。連接到6380執(zhí)行命令使其停止復(fù)制并晉升為主節(jié)點(diǎn)。./redis-cli -p 6380 127.0.0.1:6380 REPLICAOF NO ONE # 停止復(fù)制自己成為主節(jié)點(diǎn) OK讓另一個(gè)從節(jié)點(diǎn)6381復(fù)制新的主節(jié)點(diǎn)6380./redis-cli -p 6381 127.0.0.1:6381 REPLICAOF 127.0.0.1 6380 OK修改應(yīng)用配置將應(yīng)用程序中Redis的連接地址從原來(lái)的127.0.0.1:6379改為新的主節(jié)點(diǎn)127.0.0.1:6380。這是手動(dòng)切換中最容易出錯(cuò)和遺漏的環(huán)節(jié)?;謴?fù)原主節(jié)點(diǎn)6379作為新主節(jié)點(diǎn)的從節(jié)點(diǎn)可選 當(dāng)原主節(jié)點(diǎn)6379故障修復(fù)后可以將其作為從節(jié)點(diǎn)加入新集群。./redis-cli -p 6379 127.0.0.1:6379 REPLICAOF 127.0.0.1 6380注意這會(huì)清空6379節(jié)點(diǎn)上原有的數(shù)據(jù)從6380進(jìn)行全量同步。踩坑記錄手動(dòng)切換時(shí)務(wù)必在業(yè)務(wù)低峰期進(jìn)行并提前通知。最關(guān)鍵的一步是同步更新所有客戶端應(yīng)用的連接配置。我曾遇到過(guò)切換了Redis但某個(gè)邊緣服務(wù)配置未刷新導(dǎo)致部分寫(xiě)請(qǐng)求仍發(fā)往舊主節(jié)點(diǎn)已變?yōu)閺墓?jié)點(diǎn)而被拒絕引發(fā)線上問(wèn)題。建議將Redis地址配置在配置中心或環(huán)境變量中便于統(tǒng)一變更。6.2 基礎(chǔ)監(jiān)控與健康檢查沒(méi)有監(jiān)控的運(yùn)維是盲目的。對(duì)于這種單機(jī)集群除了系統(tǒng)級(jí)的CPU、內(nèi)存、磁盤(pán)監(jiān)控Redis自身的狀態(tài)監(jiān)控更為重要。使用INFO命令可以編寫(xiě)一個(gè)簡(jiǎn)單的Shell腳本定期采集INFO replication和INFO stats的關(guān)鍵指標(biāo)。#!/bin/bash PORTS(6379 6380 6381) for port in ${PORTS[]}; do echo Port $port /usr/local/redis/bin/redis-cli -p $port INFO replication | grep -E (role|master_link_status|master_last_io_seconds_ago|connected_slaves|master_sync_in_progress) /usr/local/redis/bin/redis-cli -p $port INFO stats | grep -E (instantaneous_ops_per_sec|total_connections_received|keyspace_hits|keyspace_misses) echo done將上述腳本加入crontab每分鐘執(zhí)行一次輸出到日志文件或發(fā)送給監(jiān)控系統(tǒng)。監(jiān)控master_link_status這是從節(jié)點(diǎn)健康度的生命線。如果變成down需要立即檢查網(wǎng)絡(luò)單機(jī)環(huán)境下基本是進(jìn)程掛了或主節(jié)點(diǎn)狀態(tài)。監(jiān)控master_last_io_seconds_ago這個(gè)值應(yīng)該很小理想情況是1或2。如果持續(xù)大于10說(shuō)明復(fù)制流有延遲需要關(guān)注主節(jié)點(diǎn)負(fù)載或從節(jié)點(diǎn)性能。監(jiān)控keyspace_misses如果這個(gè)值在從節(jié)點(diǎn)上異常高而主節(jié)點(diǎn)正??赡芤馕吨鴱墓?jié)點(diǎn)的數(shù)據(jù)同步延遲導(dǎo)致讀取了過(guò)期或不存在的數(shù)據(jù)雖然Redis復(fù)制是異步的但延遲通常極低。在單機(jī)環(huán)境下這更多是程序邏輯錯(cuò)誤。7. 常見(jiàn)問(wèn)題排查與解決實(shí)錄即使在一臺(tái)機(jī)器上問(wèn)題也會(huì)出現(xiàn)。以下是我總結(jié)的幾個(gè)典型問(wèn)題及排查思路。7.1 從節(jié)點(diǎn)無(wú)法連接主節(jié)點(diǎn)現(xiàn)象從節(jié)點(diǎn)日志持續(xù)報(bào)錯(cuò)Connecting to MASTER ... Error condition on socket for SYNC: Connection refused。排查步驟檢查主節(jié)點(diǎn)進(jìn)程ps aux | grep redis-server確認(rèn)主節(jié)點(diǎn)6379進(jìn)程是否存在。檢查主節(jié)點(diǎn)監(jiān)聽(tīng)端口netstat -tlnp | grep 6379確認(rèn)主節(jié)點(diǎn)是否在127.0.0.1:6379上正常監(jiān)聽(tīng)。檢查防火墻/SELinux單機(jī)環(huán)境下回環(huán)地址通信通常不受防火墻限制但如果是綁定了非127.0.0.1的IP或SELinux在 enforcing 模式可能會(huì)阻止。使用sestatus查看SELinux狀態(tài)臨時(shí)關(guān)閉測(cè)試setenforce 0。檢查主節(jié)點(diǎn)配置確認(rèn)主節(jié)點(diǎn)的bind配置包含了從節(jié)點(diǎn)連接的地址本例中是127.0.0.1并且沒(méi)有設(shè)置protected-mode yes且未配置密碼如果設(shè)置了密碼從節(jié)點(diǎn)必須配置masterauth。7.2 從節(jié)點(diǎn)狀態(tài)為master_link_status:down現(xiàn)象從節(jié)點(diǎn)INFO replication顯示master_link_status:down但主節(jié)點(diǎn)運(yùn)行正常。排查步驟查看從節(jié)點(diǎn)日志tail -f從節(jié)點(diǎn)日志通常會(huì)有更具體的錯(cuò)誤信息。檢查復(fù)制緩沖區(qū)可能是主節(jié)點(diǎn)的client-output-buffer-limit replica設(shè)置過(guò)小導(dǎo)致從節(jié)點(diǎn)同步慢緩沖區(qū)滿后被主節(jié)點(diǎn)強(qiáng)制斷開(kāi)。調(diào)大此參數(shù)或檢查從節(jié)點(diǎn)負(fù)載。檢查主節(jié)點(diǎn)身份驗(yàn)證如果主節(jié)點(diǎn)配置了requirepass從節(jié)點(diǎn)必須配置對(duì)應(yīng)的masterauth。密碼不匹配會(huì)導(dǎo)致連接被拒。檢查主節(jié)點(diǎn)最大連接數(shù)主節(jié)點(diǎn)的maxclients可能已滿無(wú)法接受新的從節(jié)點(diǎn)連接。檢查主節(jié)點(diǎn)的connected_clients數(shù)量。7.3 主從數(shù)據(jù)不一致現(xiàn)象在主節(jié)點(diǎn)寫(xiě)入后從節(jié)點(diǎn)讀取不到或讀取到舊值。排查步驟檢查復(fù)制延遲在主節(jié)點(diǎn)和從節(jié)點(diǎn)分別執(zhí)行INFO replication對(duì)比master_repl_offset主和slave_repl_offset從。兩者的差值就是延遲的字節(jié)數(shù)。在單機(jī)低負(fù)載下這個(gè)值應(yīng)該幾乎為0。確認(rèn)從節(jié)點(diǎn)是否為只讀模式檢查從節(jié)點(diǎn)配置replica-read-only是否為yes。如果被意外改為no并且有客戶端向從節(jié)點(diǎn)寫(xiě)入了數(shù)據(jù)那么這部分?jǐn)?shù)據(jù)是獨(dú)立于主從同步流的會(huì)造成永久性不一致。檢查從節(jié)點(diǎn)是否正在全量同步如果master_sync_in_progress:1說(shuō)明從節(jié)點(diǎn)正在加載RDB此時(shí)數(shù)據(jù)是舊的需要等待同步完成。使用WAIT命令測(cè)試同步強(qiáng)度WAIT命令可以阻塞客戶端直到指定數(shù)量的從節(jié)點(diǎn)完成同步。例如在主節(jié)點(diǎn)執(zhí)行WAIT 1 1000等待1個(gè)從節(jié)點(diǎn)同步超時(shí)1秒。這可以用來(lái)測(cè)試同步的實(shí)時(shí)性但注意WAIT返回的是達(dá)到指定復(fù)制偏移量的從節(jié)點(diǎn)數(shù)并不保證數(shù)據(jù)已持久化到從節(jié)點(diǎn)磁盤(pán)。7.4 啟動(dòng)從節(jié)點(diǎn)時(shí)數(shù)據(jù)目錄被意外清空這是一個(gè)非常危險(xiǎn)的坑原因當(dāng)你啟動(dòng)一個(gè)配置了replicaof的從節(jié)點(diǎn)時(shí)如果其數(shù)據(jù)目錄dir里已經(jīng)存在一個(gè)RDB文件比如之前作為其他角色運(yùn)行過(guò)Redis會(huì)先清空自身所有數(shù)據(jù)然后嘗試從主節(jié)點(diǎn)全量同步。如果你誤操作將一個(gè)有數(shù)據(jù)的主節(jié)點(diǎn)配置為從節(jié)點(diǎn)并啟動(dòng)數(shù)據(jù)會(huì)在瞬間被清空。血淚教訓(xùn)在變更任何節(jié)點(diǎn)的replicaof配置前務(wù)必先備份該節(jié)點(diǎn)的數(shù)據(jù)目錄。尤其是在生產(chǎn)環(huán)境操作從節(jié)點(diǎn)配置要像操作主節(jié)點(diǎn)一樣謹(jǐn)慎。我建議在配置文件中使用絕對(duì)路徑明確指定dir并且不同實(shí)例的dir絕對(duì)不要指向同一個(gè)路徑。