Windows PowerShell脚本远程Redis临时主从同步故障排查
Redis临时主从同步的PowerShell脚本问题
由于项目架构限制,两台远程Linux主机上的Redis均为主库,无法长期维持主从关系,需通过PowerShell脚本结合SSH会话,临时建立主从关系完成数据同步,预期流程为:
- 与从库服务器建立SSH连接
- 在从库执行
SLAVEOF $masterServer $masterPort建立临时主从 - 完成数据同步后执行
SLAVEOF NO ONE解除主从
当前遇到两个问题:
- 手动执行SYNC命令时失败,报错:
SYNC with master failed: -NOMASTERLINK Can't SYNC while not connected with my master
但设置主从的命令已返回{OK},重复执行会提示{OK Already connected to specified master},说明主从关系已建立。 - 手动建立主从后执行SYNC命令,出现超时错误:
ForEach-Object : Exception calling "EndExecute" with "1" argument(s): "Command 'echo SYNC | redis-cli' has timed out."
推测SYNC执行后bash进入监听状态,需按Ctrl+C退出,但发送send -- \x03无效。
附原PowerShell脚本:
param( [Parameter(Mandatory=$true, Position=0)] [string] $MasterServer, [Parameter(Mandatory=$true, Position=1)] [string] $MasterPort, [Parameter(Mandatory=$true, Position=2)] [string] $ReplicaServer, [Parameter(Mandatory=$true, Position=3)] [string] $UserReplicaServer, [Parameter(Mandatory=$true, Position=4)] [string] $PwdReplicaServer ) $SecurePasswd = ConvertTo-SecureString $PwdReplicaServer -AsPlainText -Force $Credentials = New-Object System.Management.Automation.PSCredential($UserReplicaServer, $SecurePasswd) Write-Host "Connecting to Redis host over SSH..." # Connect Over SSH and getting session id. $SessionID = New-SSHSession -ComputerName $ReplicaServer -Credential $Credentials -Force if($SessionID -eq $null){ Write-Host "Error: An error occurred trying to setup the SSH session. Please check the connection string/credentials for the SSH session." exit 1 } else { Write-Host "SSH session created successfully. Running Redis SYNC." } # Commands. $commands = @( @{ Command = "echo SLAVEOF $MasterServer $MasterPort | redis-cli" Description = "Configure replication" }, @{ Command = "echo SYNC | redis-cli" Description = "Sync replication" }, @{ Command = "echo SLAVEOF NO ONE | redis-cli" Description = "Undo replication" } ) # Execute commands on Redis Host foreach ($command in $commands) { $result = Invoke-SSHCommand -Index $SessionID.sessionid -Command $command.Command if ($result.ExitStatus -ne 0) { Write-Host "Error: Failed to execute command '$($command.Command)'. Description: $($command.Description) Error message: $($result.StandardError)" exit 1 } Write-Host "Success: Command '$($command.Command)' executed successfully. Description: $($command.Description)" } Write-Host "Script Worked and Finished!"
问题原因及解决方案
核心问题原因
Redis从库在执行SLAVEOF命令后,会自动发起SYNC全量同步,无需手动执行SYNC命令:
- 手动执行SYNC时,从库已处于主从同步状态,Redis不允许手动触发SYNC,因此报错
NOMASTERLINK; - 手动执行SYNC会导致redis-cli持续监听主库的数据流,不会自动退出,进而引发SSH命令超时。
修改后的脚本逻辑
- 移除手动执行SYNC的步骤;
- 增加等待逻辑,确保从库完成全量同步后再解除主从关系。
修改后的PowerShell脚本
param( [Parameter(Mandatory=$true, Position=0)] [string] $MasterServer, [Parameter(Mandatory=$true, Position=1)] [string] $MasterPort, [Parameter(Mandatory=$true, Position=2)] [string] $ReplicaServer, [Parameter(Mandatory=$true, Position=3)] [string] $UserReplicaServer, [Parameter(Mandatory=$true, Position=4)] [string] $PwdReplicaServer, [Parameter(Mandatory=$false, Position=5)] [int] $SyncTimeoutSeconds = 300 ) $SecurePasswd = ConvertTo-SecureString $PwdReplicaServer -AsPlainText -Force $Credentials = New-Object System.Management.Automation.PSCredential($UserReplicaServer, $SecurePasswd) Write-Host "Connecting to Redis host over SSH..." $SessionID = New-SSHSession -ComputerName $ReplicaServer -Credential $Credentials -Force if($SessionID -eq $null){ Write-Host "Error: Failed to setup SSH session. Check connection/credentials." exit 1 } Write-Host "SSH session created successfully." # 1. 设置临时主从关系 $setupCommand = "echo SLAVEOF $MasterServer $MasterPort | redis-cli" $result = Invoke-SSHCommand -Index $SessionID.sessionid -Command $setupCommand if ($result.ExitStatus -ne 0) { Write-Host "Error: Failed to setup replication. Error: $($result.StandardError)" exit 1 } Write-Host "Success: Replication setup initiated." # 2. 等待同步完成 Write-Host "Waiting for full sync to complete..." $startTime = Get-Date $syncCompleted = $false while (-not $syncCompleted) { # 检查主从连接状态和同步进度 $infoCmd = "redis-cli info replication | grep -E 'master_link_status|sync_full'" $infoResult = Invoke-SSHCommand -Index $SessionID.sessionid -Command $infoCmd if ($infoResult.ExitStatus -ne 0) { Write-Host "Error: Failed to check replication status. Error: $($infoResult.StandardError)" exit 1 } $statusOutput = $infoResult.Output $masterConnected = $statusOutput -match 'master_link_status:up' $fullSyncDone = $statusOutput -match 'sync_full:1' if ($masterConnected -and $fullSyncDone) { $syncCompleted = $true Write-Host "Success: Full sync completed." } else { $elapsed = (Get-Date) - $startTime if ($elapsed.TotalSeconds -ge $SyncTimeoutSeconds) { Write-Host "Error: Sync timed out after $SyncTimeoutSeconds seconds." # 尝试解除主从关系后退出 Invoke-SSHCommand -Index $SessionID.sessionid -Command "echo SLAVEOF NO ONE | redis-cli" exit 1 } Write-Host "Sync in progress... Elapsed: $($elapsed.Seconds)s" Start-Sleep -Seconds 5 } } # 3. 解除主从关系 $undoCommand = "echo SLAVEOF NO ONE | redis-cli" $result = Invoke-SSHCommand -Index $SessionID.sessionid -Command $undoCommand if ($result.ExitStatus -ne 0) { Write-Host "Error: Failed to undo replication. Error: $($result.StandardError)" exit 1 } Write-Host "Success: Replication undone. Redis is now master again." Write-Host "Script completed successfully!"
额外说明
- 脚本增加了同步超时参数
$SyncTimeoutSeconds,默认5分钟,可根据数据量调整; - 通过
redis-cli info replication检查master_link_status:up确认主从连接正常,sync_full:1确认全量同步完成; - 若同步超时,脚本会尝试解除主从关系后退出,避免从库长期处于从节点状态。
内容的提问来源于stack exchange,提问作者Retrosec6
相关产品推荐
相关产品推荐

