Servers Backup & DR

Patching Failover Clusters with Cluster-Aware Updating and Stretch Clusters via Storage Replica

Patching a failover cluster by hand is how you turn a routine Tuesday into a quorum-loss incident. You drain a node, suspend it, patch it, reboot, resume, wait for storage to resync, and only then move to the next one — and somewhere around node nine at 03:00 you fat-finger the order, reboot a second node in the same site before the first finished resyncing, and the cluster drops below majority. Everything hosting on it goes dark. Cluster-Aware Updating (CAU) exists precisely so a human never has to remember that dance. Get CAU right and a 16-node cluster patches itself overnight with every clustered role staying online, respecting quorum and storage resync at every step. Get it wrong — or skip it — and you are one tired operator away from a self-inflicted outage.

The second half of this article extends that same cluster across two datacenters. A Storage Replica stretch cluster keeps a synchronous, block-level copy of your volumes in a second site, so a metro failure costs you a failover — seconds — not a restore — hours. But a stretch cluster is a different animal from a single-site cluster: quorum math that can split-brain, site-awareness that decides where roles land, a replication log that stalls your entire application if you under-provision it, and a failover that must flip replication direction cleanly under pressure. Every one of those has a correct answer and a dozen ways to get it subtly wrong.

This is the full field guide. We treat CAU and Storage Replica not as two features but as the two halves of one discipline — keeping a clustered, replicated Windows workload available through both planned maintenance and unplanned site loss. You will learn to choose updating modes, wire pre/post scripts that gate on real health, define fault domains and sites, size the SR log from a measured workload, place the witness where it survives the failure it is meant to survive, and read the cluster log and SR event channel when something is wrong at 03:00. Every mechanism comes with real PowerShell, the exact cmdlet to confirm it, and the failure mode it prevents. Because this is a reference you will return to mid-incident, the modes, parameters, limits, events and failure classes are laid out as scannable tables — read the prose once, then keep the tables open. Both features ship in Windows Server Datacenter; the commands target Windows Server 2022 and apply cleanly to 2019 and 2025 except where noted.

What problem this solves

Two production pains, one shared root cause: a cluster is only highly available if you can lose a node — planned or not — without taking down what runs on it. Manual patching breaks that promise. An operator patching a 12-node Storage Spaces Direct cluster by hand has to track, per node, which roles have drained, whether the storage pool has finished repairing after the last node came back, and whether suspending the next node would drop quorum. Miss any one and you get partial data-unavailability (a virtual disk goes offline because too many nodes are down mid-repair) or a full cluster stop (quorum lost). CAU encodes all of that logic — drain, quorum check, resync wait, serial ordering — so the machine tracks it, not a human at 03:00.

The disaster-recovery pain is different but adjacent. A single-site cluster survives node and disk failure; it does not survive the datacenter burning, the metro power event, or the flood. Backups give you recovery, but at the cost of hours of restore and whatever RPO your last backup allows — unacceptable for a settlement database or an EHR that regulators hold to zero data loss. Storage Replica closes that gap by keeping a block-level, synchronous copy of the volume in a second site beneath the filesystem, so a site failover brings the workload up in the surviving site with RPO = 0 and an RTO measured in seconds-to-minutes. Extend the cluster itself across the two sites — a stretch cluster — and the failover is automatic: the cluster’s own health monitoring detects the site loss and brings roles up on the far side.

Who hits this: anyone running Windows Failover Clustering at scale — SQL Server Failover Cluster Instances, Hyper-V clusters, Scale-Out File Servers, general-use file servers — where both planned maintenance without downtime and survival of a site loss are hard requirements. It bites hardest on regulated workloads with contractual RPO/RTO (payments, healthcare, trading), on large clusters where manual patching is genuinely unsafe, and on two-site deployments where the quorum and witness placement decisions are non-obvious and, done wrong, guarantee a split-brain outage the first time the inter-site link blips.

To frame the whole field before the deep dive, here is the map of what this article covers, the pain each piece removes, and the single command that proves it is working:

Capability The pain it removes The one command that proves it
Cluster-Aware Updating Manual, error-prone, downtime-risking node-by-node patching Get-CauReport -ClusterName clu-prod -Last -Detailed
CAU pre/post scripts Patching into a degraded cluster or unhealthy replication Pre-script exits non-zero → run aborts (visible in the report)
Storage Replica (sync) Site loss = hours of restore + non-zero RPO Get-SRGroupReplicationStatus: ContinuouslyReplicating
Stretch cluster + site awareness Roles failing over across the WAN needlessly; no automatic site failover Get-ClusterFaultDomain shows nodes under the right sites
Dynamic quorum + cloud witness Split-brain when the inter-site link dies Get-ClusterQuorum + Get-ClusterNode weights sum odd
Cluster log / SR event channel Blind troubleshooting during a failover Get-ClusterLog; Microsoft-Windows-StorageReplica/Admin

Learning objectives

By the end of this article you can:

Prerequisites & where this fits

You should already be comfortable building a single-site Windows Failover Cluster: creating it with New-Cluster, validating with Test-Cluster, adding storage, and understanding that a cluster is a set of nodes that vote to maintain quorum (a majority) and that clustered roles (groups) move between nodes on failover. Familiarity with Storage Spaces Direct (S2D) — software-defined storage pooling local NVMe/SSD/HDD across nodes into cluster shared volumes — helps, because S2D and stretch clusters share resync and fault-domain concepts. You should know PowerShell remoting (Invoke-Command, WinRM) and how to read cluster and event-log output.

This sits at the top of the Servers / High Availability & DR track. It assumes the foundation from Windows Failover Clustering and Storage Spaces Direct: A Production Build — that article builds the single-site cluster this one patches and stretches. It pairs with Hyper-V Live Migration and Replica for Zero-Downtime VM Mobility (the VM-mobility layer that rides on top of a healthy cluster) and Resilient File Services with DFS Namespaces and DFS Replication (an alternative, file-level replication story where SR’s block-level, single-writer model does not fit). It complements Hardening Windows Server and Building a Reliable WSUS Patch Pipeline — WSUS is the update source CAU pulls from, and this article is the orchestration on top of it.

A quick map of who owns what during a cluster-patching or site-failover event, so you engage the right team fast:

Layer What lives here Who usually owns it Failure classes it can cause
Update source (WSUS / WUfB / MU) Which patches are offered Patch / SecOps team Wrong/missing patches; approval gaps
CAU orchestration Drain order, retries, gates, schedule Platform / cluster admin Aborted runs; over-aggressive MaxFailedNodes
Failover cluster Quorum, groups, health monitoring Platform / cluster admin Quorum loss; role placement; failover
Storage Replica Block replication, log, direction Storage / DR admin Replication stall; log full; failed reverse
Inter-site network Dark fibre / metro links, latency Network team Sync latency spikes; split-brain on link loss
Witness (cloud / file share) The tie-breaking vote Platform + cloud/infra Split-brain if placed in a failing site

Core concepts

Six mental models make every later decision obvious.

A cluster stays up only while it holds quorum. Quorum is a majority of votes. In a classic model every node has one vote and a witness (disk, file share, or cloud) can hold one more; the cluster stays online while more than half the votes are reachable and can talk to each other. Lose majority — too many nodes down, or a network partition where no side has a majority — and the cluster stops to prevent split-brain (two halves both thinking they own the workload, corrupting shared state). Everything about patching order and witness placement is, at bottom, about never accidentally dropping below majority.

CAU is an orchestrator, not a patch source. CAU does not decide which updates to install — a plug-in does that, pulling from WSUS, Windows Update for Business, or Microsoft Update. What CAU owns is the safe sequence: for each node, put it in maintenance, drain its roles elsewhere, install updates via the plug-in, reboot, resume, wait for storage to resync, and only then move on. It is serial (one node at a time), drain-first (nothing serving on a node being rebooted), quorum-respecting (never suspend a node that would break majority), and resync-aware (on S2D/stretch it waits for storage to rebuild before touching the next node).

Storage Replica works beneath the filesystem, one writer at a time. SR does block-level, volume-to-volume replication under NTFS/ReFS — it does not know about files, only blocks. Critically it is single-writer: the destination volume is dismounted and inaccessible while it is a replication target. You cannot read the second site’s copy as a live share; it is a cold, exact block replica that becomes writable only when replication direction flips (on failover). This is the fundamental difference from DFS Replication, which is file-level, multi-master, and lets both copies be read. SR trades that flexibility for exact, crash-consistent, real-time replication with a defined RPO.

Synchronous vs asynchronous is the RPO decision, bounded by latency. In synchronous mode, a write is not acknowledged to the application until it is committed to the SR log on both source and destination — so a site loss loses nothing in flight (RPO = 0), but every write pays the round-trip to the second site (so you need low latency, ≈ ≤ 5 ms round-trip). In asynchronous mode the write acks locally and ships shortly after — surviving high-latency, long-distance links but with a non-zero RPO (you can lose in-flight writes). Metro → synchronous; cross-region → asynchronous. The distance dictates the mode, and the mode dictates the RPO.

The SR log is the beating heart, and it is in the write path. Every write lands in the log volume first, then drains to the data volume. The log absorbs bursts and bridges brief link slowdowns. If the log fills — destination fell behind, link saturated — replication stalls and (synchronous) application writes back up. So the log must be on your fastest storage (NVMe/SSD, because log latency is in the critical path of every sync write) and large enough to ride out the worst burst plus link blip you will realistically see. Under-provisioning the log is the single most common Storage Replica production failure.

A stretch cluster is one cluster in two sites, and quorum is the hard part. Nodes live in two datacenters; each site has its own storage (asymmetric — this is not shared storage); SR replicates one site’s volumes to the other; and the cluster’s site awareness (fault domains) keeps roles in their home site, fails over within a site before crossing the WAN, and enables automatic site failover. The danger is even votes: 2 nodes + 2 nodes, link dies, each side has exactly half — both lose quorum, total outage. The witness in a third, independent failure domain breaks that tie. Dynamic quorum and dynamic witness adjust vote weights automatically to keep the surviving side in the majority through sequential failures.

The vocabulary in one table

Before the deep sections, pin down every moving part. The glossary at the end repeats these for lookup; this table is the mental model side by side:

Concept One-line definition Where it lives Why it matters
Quorum The majority of votes a cluster must hold to stay online Cluster-wide Lose it → cluster stops
Witness An extra tie-breaking vote (disk/file share/cloud) Third failure domain (stretch) Prevents split-brain on link loss
Dynamic quorum Auto-adjusts node vote weights during failures Cluster runtime Keeps survivors in the majority
CAU / Update Coordinator The orchestrator walking nodes one at a time Role or external host Safe, serial, drain-first patching
CAU plug-in Decides which updates to install Per Update Run Microsoft.WindowsUpdatePlugin etc.
Drain / maintenance mode Move roles off a node before reboot Per node Nothing serves on a rebooting node
Storage Replica (SR) Block-level volume-to-volume replication Below the filesystem RPO-defined DR
SR log Volume every write lands in first Fast local storage, per site Fills → replication stalls
Synchronous / asynchronous Ack after remote commit / ack locally SR partnership setting RPO 0 vs RPO > 0
Fault domain / site Topology grouping (node/chassis/rack/site) Cluster metadata Site-aware placement & failover
PreferredSite The site the cluster favours for placement Cluster property Where roles start / return
Stretch cluster One cluster across two sites, SR-replicated Two datacenters Automatic site failover, RPO 0
Cluster set A loose federation of multiple clusters Above the cluster Scale beyond one cluster’s node cap

CAU updating modes: self-updating versus remote-updating

CAU runs as an Update Coordinator that walks the cluster one node at a time. There are two ways to run it, and the choice shapes your whole patch pipeline.

Remote-updating mode. The coordinator runs outside the cluster — on an admin workstation or a management server — and drives an Update Run on demand with Invoke-CauRun. Nothing is installed in the cluster itself. This is the mode for ad-hoc, attended patching, for dry runs before you commit to automation, and for emergency out-of-band patching (a zero-day you must push now, not on Sunday). The coordinator host must stay up for the whole run; if it reboots or loses the network mid-run, the run is interrupted.

Self-updating mode. You add a clustered CAU role (Microsoft.ClusterAwareUpdating) to the cluster. The role schedules itself and, when the window opens, one node temporarily hosts the coordinator, patches every other node, then hands the coordinator role to an already-patched node so the last one can be updated too. This hand-off is the clever bit — it is how a cluster patches its own coordinator without an external box. Fully unattended, no management host required, survives a coordinator-node reboot because the role fails over.

The mechanism (drain → update → reboot → resume → wait) is identical in both modes; the difference is who owns the schedule and where the coordinator lives. My default is self-updating for steady-state monthly patching, with a remote-updating run kept in the toolbox for emergencies and dry runs. The two modes compared on every axis that matters:

Dimension Self-updating Remote-updating
Where the coordinator runs On a cluster node (hands off for the last node) On an external admin host
Schedule owner The clustered CAU role (unattended) You, on demand (Invoke-CauRun)
External host required No Yes (must stay up for the whole run)
Best for Steady-state monthly patching Emergencies, dry runs, one-offs
Survives coordinator reboot Yes (role fails over) No (run interrupted)
Setup Add-CauClusterRole once RSAT-Clustering-AutomationServer on the host
Can patch its own last node Yes (via hand-off) Yes (external host is never patched)
Visibility mid-run Get-CauRun against the cluster Live in the invoking session

Install the tooling on every node and on the management host:

$nodes = 'clu-n1','clu-n2','clu-n3','clu-n4'

Invoke-Command -ComputerName $nodes -ScriptBlock {
    Install-WindowsFeature -Name RSAT-Clustering-PowerShell, FS-FileServer
}

# CAU UI + automation cmdlets on the management workstation (remote-updating):
Install-WindowsFeature -Name RSAT-Clustering-AutomationServer, RSAT-Clustering-PowerShell

Confirm the cluster is actually ready to be updated by CAU. This single command is the best pre-flight check there is — it verifies WinRM, the firewall rules, the required PowerShell remoting, and (for self-updating) that the clustered role is installable:

Test-CauSetup -ClusterName clu-prod

Resolve every warning before going further. The most common failures are a missing Failover Clustering firewall group and the absence of the RemoteShutdown / RestartCluster inbound rule, both of which CAU needs to reboot nodes remotely. What Test-CauSetup checks and what each failure means:

Check What it verifies Common failure Fix
WinRM / PS remoting CAU can drive each node remotely WinRM not running / not configured Enable-PSRemoting -Force on each node
Failover Clustering firewall group Inter-node + coordinator traffic allowed Group disabled by hardening baseline Enable-NetFirewallRule -DisplayGroup 'Failover Clusters'
RemoteShutdown firewall rule CAU can reboot nodes remotely Rule missing → reboot step hangs Enable the “Remote Shutdown” / WMI firewall rules
CAU clustered-role installability Self-updating role can be added S2D/quorum blocking Ensure cluster healthy; retry after fix
Automatic Updates policy WU not fighting CAU AU set to auto-install Set nodes to notify-only; let CAU drive
Same-cluster node membership All nodes reachable/up A node is down/paused Bring the node up before configuring CAU

Turn off each node’s own Automatic Updates auto-install. If Windows Update installs and reboots a node on its own schedule, it will fight CAU and can reboot a node CAU did not drain. CAU wants to be the only thing that patches and reboots these nodes.

Configuring the CAU role, run profiles, and pre/post scripts

For self-updating, register the clustered role and bake the schedule, plug-in, and options into it. The plug-in Microsoft.WindowsUpdatePlugin pulls from whatever the node points at — WSUS, Windows Update for Business, or Microsoft Update.

Add-CauClusterRole -ClusterName clu-prod `
    -DaysOfWeek Sunday `
    -WeeksOfMonth @(2,4) `
    -IntervalWeeks 1 `
    -MaxFailedNodes 1 `
    -MaxRetriesPerNode 2 `
    -RequireAllNodesOnline `
    -CauPluginName Microsoft.WindowsUpdatePlugin `
    -CauPluginArguments @{ 'IncludeRecommendedUpdates' = 'False' } `
    -PreUpdateScript  '\\fs01\cau$\pre-update.ps1' `
    -PostUpdateScript '\\fs01\cau$\post-update.ps1' `
    -StartDate '2026-06-14 02:00:00' `
    -Force

The knobs that matter, what they default to, and the trade-off in each:

Parameter What it does Default When to change Trade-off / gotcha
MaxFailedNodes Hard stop: abort if more than N nodes fail to update (cluster-size dependent) Keep low (1) on small clusters Too high chews through the whole cluster on a bad patch
MaxRetriesPerNode Retries per node on transient failure 3 2–3 for flaky WU Too high wastes the window on a genuinely broken node
RequireAllNodesOnline Refuse to start if any node is down Off Almost always on for stretch/S2D Won’t run while a node is legitimately in maintenance
CauPluginName Which plug-in decides updates Microsoft.WindowsUpdatePlugin Add Microsoft.HotfixPlugin for hotfix shares Hotfix plug-in needs a config XML + share
CauPluginArguments Plug-in-specific options (e.g. update category filter) none Filter to security-only, exclude drivers Wrong QueryString can skip needed updates
PreUpdateScript / PostUpdateScript Cluster-wide hooks, once per run none Gate on health; page on-call Non-zero pre-script exit aborts the whole run
NodeOrder Pin the node sequence availability-aware auto Stretch: one site fully first Wrong order can interleave sites
RebootTimeoutMinutes How long to wait for a node reboot 15 Slow-booting nodes (big firmware) Too low → false “node failed”
WarnAfter / StopAfter Warn / abort if a run runs long none Bound the maintenance window StopAfter can cut a run mid-node

The plug-ins are the pluggable “what to install” layer. The two that ship, and when to use each:

Plug-in What it installs Source When to use
Microsoft.WindowsUpdatePlugin Standard Windows/Microsoft updates WSUS / WUfB / Microsoft Update Default; monthly cumulative + security
Microsoft.HotfixPlugin Arbitrary hotfixes / MSU/CAB from a share SMB share + DefaultHotfixConfig.xml Firmware, drivers, out-of-band QFEs; SAN vendor packages

A common CauPluginArguments set for the Windows Update plug-in — filter what gets offered so CAU installs exactly what your change window approved:

Argument Effect Example value
IncludeRecommendedUpdates Include “recommended” (not just important) 'False'
QueryString WU search filter (categories, severity) "IsInstalled=0 and Type='Software' and IsHidden=0"
'Category' (via query) Restrict to a category (e.g. Security) security-classification GUID in the query

A pre-update script worth its salt blocks the run if the cluster is unhealthy. A non-zero exit aborts the whole run before a single node is touched:

# pre-update.ps1 — abort the Update Run if anything is already unhealthy
$bad = Get-ClusterNode | Where-Object State -ne 'Up'
if ($bad) {
    Write-Error "Nodes not Up before patching: $($bad.Name -join ', ')"
    exit 1
}
# Storage Replica must be healthy before we start rebooting nodes
$lag = Get-SRGroup | Get-SRPartnership |
       Where-Object ReplicationStatus -ne 'ContinuouslyReplicating'
if ($lag) { Write-Error 'Storage Replica not in sync; aborting.'; exit 1 }
exit 0

Register the scripts in source control and deploy them to a share the cluster’s machine accounts can read. CAU runs them as SYSTEM on the coordinator, so permission the share to the cluster name object (CNO) and node computer accounts, not a user. Pre- versus post-script responsibilities and the traps:

Aspect Pre-update script Post-update script
Runs Once, before the first node Once, after the last node
Runs per node? No — cluster-wide No — cluster-wide
Runs as SYSTEM on the coordinator SYSTEM on the coordinator
Non-zero exit Aborts the whole run Logged; does not roll back
Good uses Health gate, quiesce backups, page on-call Validate health, resume backups, notify success
Trap Long-running script eats the window Assuming it “undoes” a failed run — it does not
Permissioning Share readable by CNO + node accounts Same

A post-update script that confirms the cluster came back healthy and re-enables what the pre-script quiesced:

# post-update.ps1 — confirm health and resume normal operations
$down = Get-ClusterNode | Where-Object State -ne 'Up'
if ($down) { Write-Warning "Nodes still down after run: $($down.Name -join ', ')" }

# Confirm every clustered role is Online
Get-ClusterGroup | Where-Object State -ne 'Online' |
    ForEach-Object { Write-Warning "Group not Online: $($_.Name)" }

# Re-enable the backup schedule the pre-script paused, notify on-call, etc.
Enable-ScheduledTask -TaskName 'Nightly-Backup' -ErrorAction SilentlyContinue
exit 0

Draining roles, fault domains, and update ordering

The reason CAU is safe is the drain. Before patching a node, CAU puts it into maintenance mode and live-migrates or fails over every clustered role off it — exactly what Suspend-ClusterNode -Drain does interactively. Nothing on that node is serving traffic when the reboot hits. On a Hyper-V cluster the VMs live-migrate (no guest downtime); on a general-use file server the file-server role fails over (a brief SMB reconnect); on S2D the node’s storage contribution is safely taken offline and the pool tolerates it.

CAU’s ordering is availability-aware: by default it updates the node hosting the fewest roles first and, critically, respects the cluster’s quorum so it never suspends a node that would break the majority. On an S2D or stretch cluster, CAU also waits for storage to finish resyncing before moving on — it will not pull a second node while virtual disks are still rebuilding from the first. This resync-await is what prevents the classic manual-patching disaster: two nodes down at once mid-repair, a virtual disk losing too many copies, data going offline.

You can pin the order with -NodeOrder. On a stretch cluster you almost always want to patch one site fully, confirm it is healthy, then patch the other — never interleave sites, or a mid-patch metro link blip could leave you with one rebooting node per site and no quorum:

# Patch Site A nodes first, then Site B, never interleaved
Invoke-CauRun -ClusterName clu-prod `
    -CauPluginName Microsoft.WindowsUpdatePlugin `
    -NodeOrder clu-n1,clu-n2,clu-n3,clu-n4 `
    -MaxFailedNodes 1 -MaxRetriesPerNode 2 `
    -RequireAllNodesOnline -Force -Wait

The drain/suspend/resume lifecycle CAU runs per node, and the interactive equivalent for each step so you can reproduce or debug it by hand:

CAU step What happens Interactive equivalent Confirm
1. Enter maintenance Node marked paused, stops accepting roles Suspend-ClusterNode -Name n -Drain Get-ClusterNode state Paused
2. Drain roles Roles live-migrate / fail over off the node (part of -Drain) Get-ClusterGroup | ? OwnerNode -eq n empty
3. Install updates Plug-in installs approved updates Install-WindowsUpdate (varies) WU history on the node
4. Reboot Node reboots if required Restart-Computer Node returns to DownUp
5. Resume Node rejoins, roles can fail back Resume-ClusterNode -Failback Immediate Get-ClusterNode state Up
6. Wait for resync Storage rebuilds before next node (S2D auto) Get-StorageJob empty; Get-VirtualDisk Healthy

Verify a drain by hand before trusting automation — this is the single most important pre-flight for a first CAU run:

Suspend-ClusterNode -Name clu-n1 -Drain -Wait
Get-ClusterGroup | Where-Object OwnerNode -eq 'clu-n1'   # should be EMPTY
Get-ClusterNode  -Name clu-n1 | Select-Object Name, State # Paused
Resume-ClusterNode -Name clu-n1 -Failback Immediate

Fault domains give CAU (and the cluster) topology awareness beyond just “site.” Windows Failover Clustering understands a four-level hierarchy; defining it makes both placement and CAU ordering smarter:

Fault-domain level What it represents Why it matters for patching/placement
Site A datacenter / metro location Stretch failover boundary; patch one site fully first
Rack A physical rack Spread copies across racks; avoid rack-correlated failure
Chassis A blade chassis Multiple nodes share power/cooling — treat as one failure
Node A single server The unit CAU patches

CAU never reboots two nodes at once. The whole design is serial, drain-first, quorum-respecting, and (on S2D/stretch) resync-aware. If you ever see two nodes down during a CAU run, something is wrong — stop and investigate; do not assume CAU did it. The most likely culprit is a node’s own Windows Update auto-installing and rebooting outside CAU’s control.

Storage Replica modes: synchronous, asynchronous, and log sizing

Storage Replica (SR) does block-level, volume-to-volume replication beneath the filesystem. Two modes, and the distinction is the whole disaster-recovery conversation.

Synchronous. The write is not acknowledged to the application until it is committed to the SR log on both the source and destination. Zero data loss — RPO = 0. The price is latency: every write pays the round-trip to the second site, so you need roughly ≤ 5 ms round-trip and fat, low-jitter links. This is the mode for a metro stretch cluster.

Asynchronous. The write acks locally and ships to the destination shortly after. Survives long-distance, high-latency links, but your RPO is non-zero — you can lose the in-flight writes not yet shipped. Use it across regions, not across a metro. Async also introduces a recovery point objective window you can tune (-AsyncRPO), the maximum seconds the destination may lag before SR warns.

The two modes on every axis that drives the choice:

Dimension Synchronous Asynchronous
Write acknowledged after Committed to log on both sites Committed to local log
RPO 0 (zero data loss) > 0 (seconds–minutes of possible loss)
Latency requirement ≤ 5 ms round-trip Tolerates high latency (100+ ms)
Distance Metro (typically < 50 km) Regional / cross-continent
Application write latency impact Yes — every write waits for remote Minimal — local ack
Link bandwidth need Must keep up with peak write rate Must keep up with average; log buffers bursts
Failover data loss None Up to the RPO window
Typical use SQL FCI, Hyper-V metro stretch Regional DR copy, offsite archive

The log volume is the heart of SR and the part people under-provision. Every write lands in the log first, then drains to the data volume. If the log fills — because the destination fell behind or the link saturated — replication stalls. Microsoft’s guidance is at least 8 GB of log per data volume, sized up for write-heavy workloads and to bridge the longest link blip you expect. Put the log on the fastest storage you have (NVMe/SSD); log latency is in the critical path of every synchronous write. Log sizing rules of thumb:

Log sizing factor Guidance Why
Minimum size 8 GB per replicated data volume Microsoft floor; below this, stalls under burst
Write-heavy workloads 32–64 GB+ (measure with Test-SRTopology) Absorb sustained high write rate + link blip
Storage class NVMe / SSD, dedicated volume Log latency is in every sync write’s path
Filesystem GPT partition, ReFS or NTFS MBR is unsupported for SR volumes
Placement Separate volume from data; not shared Contention on the log stalls replication
Growth Log does not auto-grow — resize deliberately An undersized log silently caps throughput

Two iron rules SR enforces, and the surprises they cause:

  1. Log and data volumes must be GPT, not MBR. An MBR volume is silently ineligible; New-SRPartnership refuses it.
  2. The destination data volume must be at least as large as the source, and the destination volume is dismounted and inaccessible while it is a replication target — you cannot read it on the passive side. This surprises people: the second site’s copy is not a live, browsable share; it is a cold, exact block replica.

The hard SR requirements and limits, as a reference:

Requirement / limit Value Consequence if violated
Edition Windows Server Datacenter (Standard = single 2 TB / 1 partnership, limited) Feature unavailable / capped on Standard
Partition style GPT (both log and data) Volume ineligible for replication
Destination data volume size ≥ source data volume Partnership creation fails
Destination volume state Dismounted while a target Cannot read the passive copy
Log volume Separate, GPT, fast (SSD/NVMe), ≥ 8 GB Under-size → replication stall
Filesystem NTFS or ReFS Others unsupported
Sector sizes Source and destination must match (512e/4K) Mismatch blocks replication
Sync latency (recommended) ≤ 5 ms round-trip High latency cripples app write latency
Firewall (SMB + WS-MAN) TCP 445, 5985; ICMP for Test-SRTopology Setup / topology test fails

Validate a server pair before committing — Test-SRTopology runs a real workload sample and emits an HTML report with measured latency, throughput, IOPS, and a recommended log size:

Test-SRTopology `
    -SourceComputerName clu-n1 -SourceVolumeName D: -SourceLogVolumeName E: `
    -DestinationComputerName clu-n3 -DestinationVolumeName D: -DestinationLogVolumeName E: `
    -DurationInMinutes 30 -ResultPath \\fs01\sr$\report

Run it during a busy period — sizing on idle numbers is exactly how you fill a log in production. The report’s recommended log size assumes it sampled your real peak; if you ran it at 3 a.m. on an idle box, its recommendation is meaningless. What Test-SRTopology measures and how to read it:

Report field What it tells you What to do with it
Average / peak write IOPS Your real write load Feeds the log-size recommendation
Round-trip latency Whether sync is viable > 5 ms → reconsider sync or the link
Throughput (MB/s) Link + storage sustained rate Must exceed peak write rate for sync
Recommended log size Log GB to absorb your workload Provision at least this, on NVMe
Initial sync estimate How long the first full copy takes Plan the initial sync window

Building a two-site stretch cluster with replicated volumes

A stretch cluster is a single failover cluster whose nodes live in two sites, with SR keeping each site’s storage in sync. The shape: two nodes in Site A, two in Site B, asymmetric storage (each site has its own disks — this is not shared storage), and SR replicating Site A’s volumes to Site B. On failover the cluster brings roles up in the surviving site and SR flips replication direction so the survivor becomes the source.

First, install the feature everywhere and tell the cluster which node lives where using fault domains and sites. Site awareness is what makes the cluster keep roles local, fail over within a site before crossing the WAN, and order placement sensibly:

$all = 'clu-n1','clu-n2','clu-n3','clu-n4'
Invoke-Command -ComputerName $all -ScriptBlock {
    Install-WindowsFeature -Name Storage-Replica, FS-FileServer -IncludeManagementTools -Restart
}

# Define sites and assign nodes (fault-domain awareness)
New-ClusterFaultDomain -Name SiteA -Type Site -Location 'DC-East'
New-ClusterFaultDomain -Name SiteB -Type Site -Location 'DC-West'
Set-ClusterFaultDomain -Name clu-n1 -Parent SiteA
Set-ClusterFaultDomain -Name clu-n2 -Parent SiteA
Set-ClusterFaultDomain -Name clu-n3 -Parent SiteB
Set-ClusterFaultDomain -Name clu-n4 -Parent SiteB

# Prefer keeping groups in their home site; cross-site failover only when needed
(Get-Cluster).PreferredSite = 'SiteA'

# Confirm the topology
Get-ClusterFaultDomain | Format-Table Name, Type, ParentName, Location

What site awareness buys you once fault domains are defined — the behaviours that turn a “cluster that happens to span two sites” into a real stretch cluster:

Behaviour What it does Controlled by
Storage affinity Roles placed on nodes local to their storage Fault domains + SR partnership
Failover affinity Fail over within the site before crossing the WAN Site fault domains
Preferred site Roles start / return to the favoured site (Get-Cluster).PreferredSite
Cross-site heartbeat tuning Longer thresholds tolerate WAN latency/jitter CrossSiteDelay, CrossSiteThreshold
Site-aware quorum Dynamic quorum favours the preferred site in a 50/50 split PreferredSite + dynamic quorum

Cross-site heartbeat parameters matter on a stretch cluster: the default sub-second heartbeat thresholds tuned for a LAN are too twitchy for a WAN and will cause false failovers on a normal latency blip. Loosen them for the cross-site path only:

# Tolerate WAN jitter on the inter-site heartbeat (values are examples — tune to your link)
(Get-Cluster).CrossSiteDelay     = 1000   # ms between heartbeats across sites
(Get-Cluster).CrossSiteThreshold = 20     # missed heartbeats before the site is 'down'
Heartbeat parameter Scope Default (ms / count) Stretch guidance
SameSubnetDelay / Threshold Within a subnet 1000 ms / 10 Leave near default
CrossSubnetDelay / Threshold Across subnets 1000 ms / 20 Baseline for multi-subnet sites
CrossSiteDelay / Threshold Across sites 1000 ms / 20 Raise threshold if the link jitters

Now establish the replication partnership. Add the disks to the cluster first, then create the SR partnership between the Site A data volume and its Site B counterpart, each with its own log:

New-SRPartnership `
    -SourceComputerName clu-n1 -SourceRGName rg-SiteA `
    -SourceVolumeName 'C:\ClusterStorage\DataA' -SourceLogVolumeName 'L:' `
    -DestinationComputerName clu-n3 -DestinationRGName rg-SiteB `
    -DestinationVolumeName 'C:\ClusterStorage\DataB' -DestinationLogVolumeName 'L:' `
    -ReplicationMode Synchronous `
    -LogSizeInBytes 32GB

ReplicationMode Synchronous is the line that buys you RPO = 0. The cluster now sees the replicated volume as a single resource that can move between sites; whichever site owns it is the source, and SR flips replication direction automatically on failover. The key New-SRPartnership parameters:

Parameter Meaning Notes
-SourceRGName / -DestinationRGName Replication group names (per side) Logical grouping of volumes replicated together
-SourceVolumeName / -DestinationVolumeName Data volumes (paths or drive letters) Destination ≥ source in size
-SourceLogVolumeName / -DestinationLogVolumeName Log volumes (per side) Fast, GPT, separate from data
-ReplicationMode Synchronous or Asynchronous Metro → Sync; region → Async
-LogSizeInBytes Log size ≥ 8 GB; size from Test-SRTopology
-AsyncRPO (async only) max lag seconds Warn threshold for async drift
-SeedVolume Skip initial full copy if pre-seeded Speeds first sync on huge volumes

Watch the initial sync complete before declaring the stretch cluster ready — until it does, the destination is not yet a valid failover target:

# Initial sync progress — NumOfBytesRemaining trends to ~0, status becomes ContinuouslyReplicating
while ((Get-SRGroup -Name rg-SiteA).Replicas.ReplicationStatus -ne 'ContinuouslyReplicating') {
    Get-SRGroup -Name rg-SiteA |
        Select-Object -ExpandProperty Replicas |
        Format-Table ReplicationStatus, NumOfBytesRemaining
    Start-Sleep -Seconds 30
}
Write-Host 'Initial sync complete — destination is now a valid failover target.'

Quorum: dynamic quorum, witness types, and split-site placement

A two-site cluster with an even number of nodes (2+2) has a fatal quorum problem: if the inter-site link dies, each site holds exactly half the votes and both sites lose quorum — a split brain that takes the whole cluster down. The witness is what breaks the tie, and where you put it is the entire decision.

The witness must live in a third, independent failure domain — never in Site A or Site B. If it sits in Site A and Site A is the site that fails, you lose the witness and two nodes at once: game over. Witness types compared:

Witness type Where it lives Best for Pros Cons
Cloud witness An Azure Storage account (tiny blob) Stretch clusters with internet egress Neutral third domain; cheap; no third site needed Requires HTTPS to Azure; storage account + key
File-share witness An SMB share (ideally a third site) No internet egress, but a genuine third site exists Simple; on-prem A share inside Site A/B defeats the purpose
Disk witness A shared clustered disk Single-site clusters with shared storage Robust; holds cluster DB copy Not usable for a stretch cluster (no shared disk across sites)
No witness Odd node count where dynamic quorum suffices Nothing to manage Even-node split-site → split-brain risk
# Cloud witness — the third, neutral vote for a stretch cluster
Set-ClusterQuorum -CloudWitness `
    -AccountName 'stcluwitness' `
    -AccessKey  '<storage-account-key>' `
    -Endpoint   'core.windows.net'

# Or a file-share witness in a genuine THIRD site:
# Set-ClusterQuorum -FileShareWitness '\\fs-thirdsite\clu-witness$'

# Confirm every node and the witness each hold one vote
Get-ClusterQuorum | Format-List *
Get-ClusterNode | Select-Object Name, DynamicWeight, NodeWeight

Dynamic quorum and dynamic witness are on by default and they are your friends here: the cluster automatically adjusts vote weights so the surviving site retains the majority during a sequential failure, and toggles the witness vote to keep the total odd. You do not manage these by hand, but you must read them correctly in logs — a node’s effective weight (DynamicWeight) changes over time and differs from its assigned weight (NodeWeight). The two quorum mechanisms:

Mechanism What it does On by default Why it matters on a stretch cluster
Dynamic quorum Removes a failed node’s vote so the survivors still hold a majority Yes Lets a cluster survive down to the last node in a sequential cascade
Dynamic witness Adds/removes the witness vote to keep the total votes odd Yes Prevents an even-vote deadlock as nodes come and go
LowerQuorumPriorityNodeID (legacy) Which node loses in a 50/50 tie Optional Superseded by PreferredSite for site-level ties
PreferredSite Favoured site wins a 50/50 site split Optional The site that stays up when the link dies cleanly

The failure scenarios a 2+2 stretch cluster faces, and what keeps it alive in each:

Failure Votes lost What survives Depends on
One node in Site A fails 1 node 3 nodes + witness (majority) Dynamic quorum
Site A fails entirely (both nodes) 2 nodes Site B (2) + witness = 3 of 5 → majority Witness in a third domain
Inter-site link dies (clean partition) none, but split The PreferredSite (with the witness) PreferredSite + witness reachability
Witness fails alone 1 (witness) 4 nodes (still majority) Dynamic witness drops its vote
Site A + witness fail together 2 + witness Site B has 2 of remaining — may drop quorum Witness must NOT share Site A’s domain

Dynamic quorum protects against sequential failures. A simultaneous, instantaneous loss of two same-site nodes before the cluster recomputes weights can still momentarily drop quorum. The cloud witness is what carries you through that window — which is exactly why it must not share a failure domain with either site. Place it wrong and you have engineered a single point of failure into your DR design.

If quorum is genuinely lost (a real double failure), you can force a surviving partition online — the last-resort recovery. Use it knowingly; forcing the wrong partition online is how you lose the writes that were only on the other side:

# LAST RESORT: force quorum on a surviving node when the cluster is stopped
# Run ON the node you are CERTAIN has the most-current data (usually the SR source side)
Start-ClusterNode -Name clu-n3 -FixQuorum
# Then adjust node weights so the survivors form a majority, and bring groups online.

Automatic site failover and controlled failback

A properly built stretch cluster fails over automatically when a site is lost: the cluster’s health monitoring detects that Site A’s nodes are unreachable, quorum is preserved (Site B + witness), the clustered roles come online in Site B, and SR flips replication direction so the Site B copy becomes the writable source. No human, no restore. What you must test is that this actually happens cleanly, and that you can fail back to the primary site once it recovers.

The failover sequence, step by step, and where it can go wrong:

Step What happens Time scale Failure mode if misbuilt
1. Site A lost Nodes unreachable, heartbeats time out seconds (per CrossSiteThreshold) Too-twitchy heartbeat → false failover on a blip
2. Quorum check Site B + witness = majority immediate Witness in Site A → quorum lost, no failover
3. Roles fail over Groups come online in Site B seconds Storage not replicated → role can’t mount volume
4. SR direction flips Site B copy becomes source seconds Log/partnership unhealthy → resync instead of flip
5. Application resumes Clients reconnect to Site B seconds–minutes DNS/VIP not site-aware → clients can’t find it
6. (later) Site A returns Nodes rejoin, become SR destination on recovery Split-brain if forced online during the outage

Move the role to force a failover for testing — this is the drill that matters. Simulate losing Site A and confirm roles and storage come up in Site B, then fail back cleanly:

# Move the replicated role to Site B and let SR reverse direction
Move-ClusterGroup -Name 'FS-Stretch' -Node clu-n3
Get-ClusterGroup 'FS-Stretch' | Select-Object Name, OwnerNode, State

# Confirm SR flipped: clu-n3 is now source, clu-n1 is destination
Get-SRPartnership | Select-Object SourceComputerName, DestinationComputerName

# Controlled failback to Site A once it is healthy again
Move-ClusterGroup -Name 'FS-Stretch' -Node clu-n1

Watch the SR event channel during the failover — Microsoft-Windows-StorageReplica/Admin. Key events mark direction changes and resync; a clean failover shows the destination becoming source within seconds and replication resuming in the new direction without a full resync. If you see a full resync kick off, the failover was not clean (the destination was behind, or the log was inconsistent). The SR events to know:

Event ID Channel Meaning Action
1215 StorageReplica/Admin Replication direction changed (failover/reverse) Expected on a clean failover
5009 StorageReplica/Admin Replication resumed / continuously replicating Confirms healthy state after flip
5015 StorageReplica/Admin Resync started On failover = the flip was NOT clean
1237 StorageReplica/Admin Log full / write blocked Log too small or link saturated
4004 / 4102 StorageReplica/Operational Partnership / replica state change Trace during setup and failover
1241 StorageReplica/Admin Async RPO exceeded Destination lagging past the RPO window

To manually reverse replication (e.g., after a planned site swap where you want Site B to be the long-term source), use Set-SRPartnership:

# Manually reverse direction: make Site B the source, Site A the destination
Set-SRPartnership -NewSourceComputerName clu-n3 -SourceRGName rg-SiteB `
                  -DestinationComputerName clu-n1 -DestinationRGName rg-SiteA

Cluster sets: scaling beyond one cluster

A single failover cluster tops out — practically and supportability-wise — around 64 nodes, and operationally you often want fault isolation between clusters (a bad patch or a quorum event on one cluster should not touch another). Cluster sets are the answer: a loose federation of multiple failover clusters into a single, larger software-defined datacenter, with a management cluster coordinating and a unified cluster-set namespace so VMs can live-migrate between member clusters. This is where you go when one stretch cluster is not enough — many clusters, unified management, fault domains that are entire clusters.

Cluster sets vs a single (stretch) cluster, so you place the boundary correctly:

Dimension Single / stretch cluster Cluster set
Scale ceiling ~64 nodes Thousands of nodes (many member clusters)
Fault isolation Node/site within one quorum Entire clusters are the fault domain
VM mobility Within the cluster Across member clusters (live-migrate)
Quorum blast radius One quorum for everything Each member cluster has its own quorum
Management One cluster Management cluster + set namespace
Storage Replica stretch Yes (within the cluster) Per member cluster
Best for HA + metro DR for one workload set Hyperscale Hyper-V, many isolated clusters
CAU One CAU config CAU per member cluster

A minimal cluster-set creation (each member cluster and the management cluster already exist):

# Create the cluster set on a management cluster, then add member clusters
New-ClusterSet -Name CS-Prod -NamespaceRoot 'SOFS-ClusterSetMaster' `
    -CimSession mgmt-cluster

Add-ClusterSetMember -ClusterName clu-prod-a -CimSession CS-Prod `
    -InfraSOFSName 'SOFS-A'
Add-ClusterSetMember -ClusterName clu-prod-b -CimSession CS-Prod `
    -InfraSOFSName 'SOFS-B'

# Live-migrate a set VM across member clusters
Move-ClusterSetVM -CimSession CS-Prod -VMName 'vm-app01' `
    -Node 'clu-prod-b-n1'

The rule of thumb: use a stretch cluster for HA + metro DR of a workload; reach for cluster sets when you have outgrown a single cluster’s node count or need entire-cluster fault isolation. They are not mutually exclusive — member clusters within a set can themselves be stretch clusters.

Architecture at a glance

Picture the system as two datacenters and a neutral tie-breaker, with two orchestration layers riding on top. In Site A (DC-East) sit clu-n1 and clu-n2; in Site B (DC-West) sit clu-n3 and clu-n4. All four are members of one failover cluster — this is the stretch cluster — but their storage is asymmetric: Site A owns its local NVMe/SSD pool, Site B owns its own. There is no shared disk spanning the metro. What keeps the two sides consistent is Storage Replica, running beneath the filesystem: the Site A data volume (C:\ClusterStorage\DataA) replicates synchronously — every write committed to the SR log on both sides before the application sees an ack — to its Site B counterpart (C:\ClusterStorage\DataB), with a dedicated NVMe log volume on each side absorbing the write stream. The destination volume is dismounted; it is a cold, exact block replica, not a browsable share.

Sitting above the storage is the cluster’s quorum brain. Each of the four nodes holds one vote; a fifth vote lives in a cloud witness — a tiny blob in an Azure Storage account, reachable from both sites over HTTPS, deliberately placed in a third failure domain that shares nothing with either datacenter. Dynamic quorum trims a failed node’s vote so the survivors keep a majority; dynamic witness toggles the witness vote to keep the total odd; PreferredSite = SiteA decides who wins a clean 50/50 partition. Trace the failure: Site A burns → its two votes vanish → Site B’s two nodes plus the cloud witness make three of the five remaining votes → majority preserved → roles fail over to Site B → SR flips direction, making the Site B copy the writable source, with no full resync. That is the whole point: a failover (seconds), not a restore (hours), at RPO = 0.

The two orchestration layers complete the picture. Cluster-Aware Updating patches the whole thing without downtime: an Update Coordinator (a cluster node in self-updating mode, handing off for its own last node) walks the cluster one node at a time, draining roles off each node before it reboots, respecting quorum so it never suspends a node that breaks majority, waiting for storage to resync between nodes, and — via a pinned NodeOrder — patching Site A fully, confirming health, then Site B, never interleaving the sites. A pre-update script gates the whole run on real health: if any node is down or SR is genuinely diverged, it exits non-zero and the run aborts before a single reboot. If you outgrow this one cluster, cluster sets federate many such clusters under one management plane with VM mobility between them — each member cluster keeping its own quorum blast radius. The reader’s mental walk is: storage replicates synchronously beneath the filesystem → quorum plus a third-domain witness survives a site loss → the cluster fails over automatically and SR reverses → CAU keeps it all patched, one drained node at a time, one site before the other.

Real-world scenario

Meridian Settlements, a payments processor, ran a 4-node stretch cluster across two metro datacenters 38 km apart, hosting the SQL Server FCI behind their settlement service. RPO was contractually zero — the settlement ledger could not lose a committed transaction — so Storage Replica ran synchronous over dark fibre with a measured ≈ 2 ms round-trip. Two nodes in DC-East (clu-n1, clu-n2), two in DC-West (clu-n3, clu-n4), a cloud witness in an Azure Storage account in a third region, PreferredSite = DC-East. Monthly patching had been a quarterly all-hands maintenance window — four engineers, a bridge call, hours of manual drain-patch-reboot — until they moved to CAU self-updating.

The first automated run aborted halfway through, on a Sunday at 02:30, with one node (clu-n1) already patched and the run refusing to continue. The on-call engineer’s first instinct was that CAU had broken. It had not — the abort was their own pre-update gate working exactly as designed.

The cause: their pre-update.ps1 checked Get-SRGroup for ContinuouslyReplicating before each Update Run, and the dark-fibre provider had a 6 ms latency spike that night from a re-route. At 6 ms — three times the normal round-trip — synchronous writes backed up, the SR log on the source crept toward full, and ReplicationStatus flipped out of ContinuouslyReplicating into a catching-up state. The gate did its job and aborted rather than reboot a node while replication was unhealthy — which, had it proceeded, would have taken a node down while writes to the settlement DB were already stalling. Exactly the outcome the gate exists to prevent.

But the gate was too binary. It treated any deviation from ContinuouslyReplicating — including a transient, self-healing catch-up of a few megabytes — as a hard stop. The fix was not to weaken the gate; it was to make it tolerant of transient lag while still blocking on real divergence, and to split CAU into a per-site NodeOrder so Site A fully completed and resynced before Site B was touched:

# pre-update.ps1 — tolerate transient lag, block on genuine divergence
$g = Get-SRGroup | Get-SRPartnership
$diverged = $g | Where-Object {
    $_.ReplicationStatus -ne 'ContinuouslyReplicating' -and
    $_.NumOfBytesRemaining -gt 64MB    # bounded catch-up is acceptable
}
if ($diverged) { Write-Error 'SR genuinely behind; aborting run.'; exit 1 }
Start-Sleep -Seconds 30   # ride out a brief link blip, then re-check
$g = Get-SRGroup | Get-SRPartnership
if ($g.ReplicationStatus -contains 'Error') { exit 1 }
exit 0

They also oversized the SR log from 8 GB to 32 GB on NVMe so a latency spike no longer threatened to fill it, and loosened the cross-site heartbeat threshold slightly so a normal jitter would not risk a false failover. The next month’s run completed unattended in 41 minutes, every settlement transaction served throughout, the FCI staying online as each node drained, patched, and rejoined. The quarter after, they added a second workload cluster and federated both with a cluster set for unified management.

The incident as a timeline, because the order of realization is the lesson:

Time Event Interpretation Correct response
02:00 CAU run starts, clu-n1 drains & patches Normal
02:28 Dark-fibre re-route → 6 ms latency spike Link degraded (automatic) SR log absorbs it
02:30 ReplicationStatus leaves ContinuouslyReplicating SR catching up Pre-gate re-checks, not panics
02:31 Pre-update gate for clu-n2 exits non-zero Gate blocks on any deviation Too binary — this was the bug
02:31 Run aborts, one node patched, three not CAU did the safe thing Don’t blame CAU
+1 day Gate rewritten (tolerate < 64 MB lag) Distinguish blip from divergence The real fix
+1 day Log 8 GB → 32 GB NVMe; per-site NodeOrder Remove the root cause Harden the design
+1 month Run completes unattended in 41 min Correct behaviour The payoff

The lesson on the wall: “Synchronous SR makes link quality a first-class patching dependency. Your CAU pre-script is the right place to encode that — tolerant of jitter, intolerant of real data loss. And a gate that aborts is CAU protecting you, not failing you.”

Advantages and disadvantages

Running a clustered, replicated, self-patching Windows workload buys enormous resilience — and adds real operational surface area. Weigh it honestly:

Advantages Disadvantages
CAU makes patching unattended and safe — drain-first, serial, quorum- and resync-aware — eliminating the manual-error class of outage CAU adds a scheduling/gating layer you must configure correctly; a bad MaxFailedNodes or a fragile pre-script can abort or over-run windows
Storage Replica gives RPO = 0 metro DR beneath the filesystem — a failover, not a restore Synchronous SR makes link latency a first-class dependency; a jittery link degrades every application write
A stretch cluster fails over automatically on site loss — no human, no restore procedure Stretch quorum is subtle; a mis-placed witness guarantees a split-brain the first time the link dies
Site awareness keeps roles local and fails over within a site before crossing the WAN Asymmetric storage + SR means the passive copy is dismounted — no live read of the DR site
Both features are built into Windows Server Datacenter — no third-party replication licence Requires Datacenter edition and (for cloud witness) Azure; Standard edition is heavily capped for SR
Cluster sets let you scale past one cluster with entire-cluster fault isolation Every added layer (CAU, SR, quorum, cluster sets) is more to monitor, more to get wrong, more to troubleshoot at 03:00
The SR log absorbs bursts and brief link blips, smoothing replication An under-provisioned log stalls replication (and, synchronous, stalls app writes) — the most common SR failure
Test-SRTopology and Test-CauSetup give pre-flight proof before you commit The tests are only as good as when you run them — idle sizing under-provisions the log

This model is right when you have a hard requirement for both zero-downtime maintenance and survival of a site loss — regulated workloads (payments, healthcare, trading), business-critical SQL/Hyper-V, anything with contractual RPO/RTO. It is over-engineered for a single dev cluster or a workload where hours of restore and non-zero RPO are acceptable (use backups or async SR there). The disadvantages are all manageable — but only if you know they exist, size the log from a real measurement, place the witness in a third domain, and write the pre-gate to tell a blip from divergence.

Hands-on lab

You will build a two-node Storage Replica pair and simulate the failover, then configure CAU on a small cluster and watch a drain. Storage Replica requires Windows Server Datacenter; this lab uses two VMs (sr-src, sr-dst) each with a data disk and a fast log disk. Run from an elevated PowerShell that can remote into both.

Step 1 — Prep both servers. Install the feature and confirm edition:

$pair = 'sr-src','sr-dst'
Invoke-Command -ComputerName $pair -ScriptBlock {
    Install-WindowsFeature -Name Storage-Replica, FS-FileServer -IncludeManagementTools
    (Get-WindowsEdition -Online).Edition   # must be *Datacenter*
}
Restart-Computer -ComputerName $pair -Wait -For PowerShell

Expected: Storage-Replica installs; edition contains Datacenter.

Step 2 — Prepare GPT volumes on each server. Bring the data and log disks online as GPT, format, and assign letters (D: data, E: log). SR refuses MBR:

Invoke-Command -ComputerName $pair -ScriptBlock {
    # Data disk → D:, Log disk → E: (adjust disk numbers to your VM)
    Get-Disk | Where-Object PartitionStyle -eq 'RAW' |
        Initialize-Disk -PartitionStyle GPT -PassThru |
        Out-Null
    # (In a real run, create partitions and format D: and E: as NTFS/ReFS here.)
    Get-Volume | Select-Object DriveLetter, FileSystem, SizeRemaining
}

Expected: D: and E: exist on both, GPT, NTFS/ReFS. The destination D: must be the source D:.

Step 3 — Test topology BEFORE committing. Measure latency and get a recommended log size:

Test-SRTopology -SourceComputerName sr-src -SourceVolumeName D: -SourceLogVolumeName E: `
    -DestinationComputerName sr-dst -DestinationVolumeName D: -DestinationLogVolumeName E: `
    -DurationInMinutes 10 -ResultPath C:\Temp\SRReport
Invoke-Item C:\Temp\SRReport\TestSrTopologyReport-*.html

Expected: an HTML report with round-trip latency, throughput, and a recommended log size. In a lab the latency is ~0 ms (same host); read the shape of the report.

Step 4 — Create the replication partnership (synchronous).

New-SRPartnership -SourceComputerName sr-src -SourceRGName rg-src `
    -SourceVolumeName D: -SourceLogVolumeName E: `
    -DestinationComputerName sr-dst -DestinationRGName rg-dst `
    -DestinationVolumeName D: -DestinationLogVolumeName E: `
    -ReplicationMode Synchronous -LogSizeInBytes 8GB

Expected: the partnership is created and initial sync begins. Note the destination D: dismounts — you can no longer browse it on sr-dst.

Step 5 — Watch it reach ContinuouslyReplicating.

Get-SRGroup -Name rg-src |
    Select-Object -ExpandProperty Replicas |
    Format-Table ReplicationStatus, NumOfBytesRemaining, NumOfBytesRecovered

Expected: ReplicationStatus becomes ContinuouslyReplicating and NumOfBytesRemaining trends to ~0. That is healthy synchronous replication.

Step 6 — Reverse direction (simulate a failover). Make the destination the new source:

Set-SRPartnership -NewSourceComputerName sr-dst -SourceRGName rg-dst `
    -DestinationComputerName sr-src -DestinationRGName rg-src
Get-SRPartnership | Select-Object SourceComputerName, DestinationComputerName

Expected: sr-dst is now the source, sr-src the destination; D: mounts on sr-dst and dismounts on sr-src. Watch Microsoft-Windows-StorageReplica/Admin for event 1215 (direction change).

Step 7 — (Cluster half) Confirm CAU readiness on your cluster and watch a drain by hand:

Test-CauSetup -ClusterName clu-lab
Suspend-ClusterNode -Name clu-lab-n1 -Drain -Wait
Get-ClusterGroup | Where-Object OwnerNode -eq 'clu-lab-n1'   # should be empty
Resume-ClusterNode -Name clu-lab-n1 -Failback Immediate

Expected: Test-CauSetup passes; the drain moves all groups off clu-lab-n1; resume brings it back.

Validation checklist. You proved the SR fundamentals hands-on: GPT-only volumes, Test-SRTopology before committing, the destination dismounting as a cold replica, ContinuouslyReplicating as the healthy synchronous state, and a clean direction reversal — the mechanics behind a stretch-cluster failover. And you watched a CAU drain empty a node without downtime. What each step proved:

Step What you did What it proves Real-world analogue
1–2 Datacenter edition + GPT volumes The hard requirements are real Why an SR build fails on Standard/MBR
3 Test-SRTopology first Sizing must come from measurement Not filling the log in production
4–5 Create partnership, reach ContinuouslyReplicating The healthy synchronous steady state The state your pre-gate checks for
6 Reverse direction How a failover flips SR without a full resync Automatic site failover
7 CAU readiness + drain Nodes drain to zero before reboot Zero-downtime patching

Teardown.

Remove-SRPartnership -SourceComputerName sr-dst -SourceRGName rg-dst `
    -DestinationComputerName sr-src -DestinationRGName rg-src
Remove-SRGroup -ComputerName sr-src -Name rg-src
Remove-SRGroup -ComputerName sr-dst -Name rg-dst
# Optionally uninstall the feature:
# Invoke-Command $pair { Uninstall-WindowsFeature Storage-Replica }

Common mistakes & troubleshooting

The playbook — the part you bookmark. First as a scannable table you read at 03:00, then the highest-value entries expanded with the full confirm-command detail.

# Symptom Root cause Confirm (exact cmd / path) Fix
1 CAU run aborts almost immediately Pre-update script exits non-zero (health gate) Get-CauReport -Last -Detailed shows the pre-script failure Fix the underlying health issue, or make the gate tolerant of transient lag
2 Two nodes down during a CAU run A node’s own Windows Update auto-installed + rebooted Node’s WU history; Failover Clustering event log Set nodes to notify-only; let CAU be the only patcher
3 SR replication stalled; app writes backing up SR log full (undersized or link saturated) Get-SRGroup LogUsedSize/remaining; event 1237 Grow the log (NVMe); fix the link; size from Test-SRTopology
4 New-SRPartnership fails Volume is MBR, or destination smaller than source Get-Disk | ft PartitionStyle; compare volume sizes Convert to GPT; grow the destination
5 Can’t read the DR-site copy Destination volume dismounted while a target Get-SRPartnership shows it as destination By design — it mounts only when it becomes source
6 Whole stretch cluster down after link blip Split-brain: even votes, witness in a failing site Get-ClusterQuorum; witness location Move witness to a third domain (cloud witness)
7 Cluster stops when Site A fails Witness was in Site A → lost witness + 2 nodes Get-ClusterQuorum -Cluster; node/witness weights Cloud witness or third-site file share
8 False failover on normal WAN jitter Cross-site heartbeat threshold too tight (Get-Cluster).CrossSiteThreshold Raise CrossSiteDelay/CrossSiteThreshold
9 Failover triggered a full resync Destination was behind; log inconsistent at failover Event 5015 (resync) instead of 1215 Ensure ContinuouslyReplicating before failover; size log
10 Sync SR crippling application latency Round-trip latency too high for synchronous Test-SRTopology latency > 5 ms Fix the link, or switch to asynchronous
11 CAU never reboots / hangs at reboot step RemoteShutdown firewall rule missing Test-CauSetup flags it Enable Remote Shutdown / clustering firewall rules
12 S2D/stretch: CAU very slow between nodes Waiting (correctly) for storage resync Get-StorageJob; Get-VirtualDisk health Expected — do not force; let resync finish
13 Async destination lagging past RPO Link can’t keep up with average write rate Event 1241; Get-SRGroup RPO More bandwidth; reduce write rate; accept larger RPO
14 Test-CauSetup warns on remoting WinRM / PS remoting not configured on a node Test-CauSetup output; Test-WSMan node Enable-PSRemoting -Force on the node
15 Roles keep failing over across the WAN No site awareness (fault domains not set) Get-ClusterFaultDomain empty of sites Define sites, assign nodes, set PreferredSite

The highest-value entries, expanded:

1. CAU run aborts almost immediately. Root cause: The pre-update script exited non-zero — usually a health gate catching a down node or SR not in ContinuouslyReplicating. Confirm: Get-CauReport -ClusterName clu-prod -Last -Detailed shows the pre-script step and its exit; the message names the failed condition. Read the cluster’s %windir%\cluster\Reports for the run log. Fix: If the gate caught a real problem (a down node, genuine SR divergence), fix that first. If it tripped on a transient blip (brief latency spike, small NumOfBytesRemaining), make the gate tolerant — a bounded lag threshold plus a short re-check window (see the scenario). The abort is CAU protecting you; do not “fix” it by removing the gate.

3. SR replication stalled; application writes backing up. Root cause: The SR log filled — undersized for the workload, or the link saturated so the destination fell behind and the log couldn’t drain. Synchronous writes then back up because they wait for the remote commit. Confirm: Get-SRGroup | Select Name, LogVolume, LogSizeInBytes and the replica’s used/remaining log; event 1237 in Microsoft-Windows-StorageReplica/Admin is the log-full marker. SR performance counters (Storage Replica Statistics) show the log approaching capacity. Fix: Grow the log on NVMe/SSD, sized from a peak-load Test-SRTopology; fix the link bandwidth; for cross-region use async so a slow link doesn’t block app writes. Under-provisioning the log is the number-one SR failure — treat the log as production-critical fast storage, not an afterthought.

6/7. Split-brain / cluster down when a site or the link fails. Root cause: Witness placement. An even-node stretch cluster with the witness inside Site A (or B) loses the witness and two nodes when that site fails — dropping below majority. Or on a clean link partition with no reachable neutral witness, both halves lose quorum. Confirm: Get-ClusterQuorum shows the witness type and resource; check where the witness lives (a file share inside Site A is the classic mistake). Get-ClusterNode | Select Name, DynamicWeight, NodeWeight shows current votes. Fix: Put the witness in a third, independent failure domain — a cloud witness (Azure blob) is ideal because it shares nothing with either datacenter. If you must use a file-share witness, it must be in a genuine third site. Set PreferredSite so a clean 50/50 partition resolves in favour of the intended survivor.

9. Failover triggered a full resync instead of a clean flip. Root cause: At the moment of failover the destination was behind or the log was inconsistent, so SR couldn’t just reverse direction — it had to resync. Often follows a failover done while ReplicationStatus was not ContinuouslyReplicating. Confirm: Microsoft-Windows-StorageReplica/Admin shows event 5015 (resync started) rather than 1215 (direction changed) cleanly. Get-SRGroup shows NumOfBytesRemaining climbing during recovery. Fix: Only fail over (in a planned move) when replication is healthy — check ContinuouslyReplicating first. Size the log so a burst never leaves the destination behind. On an unplanned site loss a resync may be unavoidable, but a correctly sized, healthy partnership minimizes it.

Reading the cluster log

When a failover, a quorum event, or a CAU abort needs deep forensics, the cluster log is the truth. It is not on by default in a readable place — you generate it with Get-ClusterLog, which dumps a detailed, timestamped log per node:

# Generate cluster logs for all nodes into a folder, last 24h, local timezone timestamps
Get-ClusterLog -Destination C:\Temp\ClusterLogs -TimeSpan 1440 -UseLocalTime

# For a single node:
Get-ClusterLog -Node clu-n1 -Destination C:\Temp -TimeSpan 240

The diagnostic sources and when to reach for each:

Source Command / location Best for
Cluster log Get-ClusterLog%windir%\Cluster\Reports\Cluster.log Quorum events, failovers, resource state changes — the deep truth
CAU report Get-CauReport -Last -Detailed; %windir%\Cluster\Reports Why an Update Run aborted; per-node result
Failover Clustering event log Get-WinEvent -LogName Microsoft-Windows-FailoverClustering/Operational Node up/down, group moves, health
Storage Replica Admin Get-WinEvent -LogName Microsoft-Windows-StorageReplica/Admin Direction change (1215), resync (5015), log full (1237)
SR performance counters Get-Counter '\Storage Replica Statistics(*)\*' Log usage, bytes remaining, write latency
Test-Cluster Test-Cluster -Node ... Post-change validation; supportability
Get-ClusterResource Get-ClusterResource | ? State -ne 'Online' Which specific resource is stuck

Best practices

Security notes

The security controls that also improve resilience — they pull in the same direction:

Control Mechanism Secures against Also prevents
CNO-scoped CAU share + signed scripts Share ACL + ExecutionPolicy AllSigned SYSTEM-level code injection on every patch Accidental broken/edited-in-place scripts
Dedicated SR replication network Segregated VLAN + SMB encryption Sniffing raw block traffic Replication contending with app traffic
Cloud-witness key rotation Secret manager + periodic rotation Leaked key granting witness/storage access Stale-credential quorum failures
Scoped clustering firewall rules Rules limited to cluster subnets Lateral movement via cluster ports Cross-VLAN noise/interference
Forwarding cluster/SR events to SIEM Event subscription Undetected forced-quorum / witness tamper Blind troubleshooting after an incident

Cost & sizing

The bill drivers and how they interact with the design:

A rough monthly picture for a 4-node metro stretch cluster (2+2), illustrative INR:

Cost driver What you pay for Rough INR / month Notes / watch-out
Windows Server Datacenter (per host) Per-core licence, 16-core min × 4 hosts Large (dominant) Scales with cores; the real cost
SR log volumes (NVMe) Fast dedicated log per node ~₹1,000–3,000 (amortized) Must be fast; in the write path
Inter-site link (sync-grade) Low-latency metro / dark fibre ~₹40,000–150,000+ Latency decides sync viability; often the constraint
Cloud witness (Azure Storage) Tiny blob + transactions ~₹5–50 Effectively free; always use it
Data storage (both sites) 2× the usable capacity (each site full copy) 2× your storage cost Stretch = you buy the capacity twice
Egress (witness / async) HTTPS to Azure; async replication traffic small–moderate Async cross-region egress can add up

Sizing rules of thumb, as a table:

Dimension Rule of thumb
Nodes per site (stretch) Minimum 2+2 (so a site loss still leaves an HA pair)
Witness Always, in a third domain (cloud witness by default)
SR log 8 GB floor; size from peak-load Test-SRTopology; NVMe
Sync latency budget ≤ 5 ms round-trip; beyond that, use async
Storage capacity 2× usable (each site holds a full copy)
Single-cluster node ceiling ~64; beyond that, cluster sets
Bandwidth (sync) ≥ peak write rate; (async) ≥ average write rate

Interview & exam questions

1. What are CAU’s two updating modes and how does self-updating patch its own last node? Remote-updating runs the Update Coordinator on an external host driving an on-demand Invoke-CauRun; self-updating adds a clustered CAU role that schedules itself. Self-updating patches its own last node via a coordinator hand-off: one node coordinates, patches every other node, then hands the coordinator role to an already-patched node so the original coordinator can be updated too. No external host needed.

2. Why is CAU safe to run unattended on a large cluster? Because it is serial (one node at a time), drain-first (every clustered role is live-migrated/failed over off a node before it reboots), quorum-respecting (it never suspends a node that would break majority), and on S2D/stretch resync-aware (it waits for storage to finish rebuilding before touching the next node). It encodes the exact logic a careful human would follow, without the human error.

3. Synchronous vs asynchronous Storage Replica — what’s the trade-off? Synchronous acks a write only after it’s committed to the SR log on both sites → RPO = 0, but every write pays the round-trip, so it needs low latency (≈ ≤ 5 ms) and suits metro distances. Asynchronous acks locally and ships shortly after → tolerates high-latency/long-distance links but with a non-zero RPO (you can lose in-flight writes). Distance dictates the mode; the mode dictates the RPO.

4. Why is the SR log volume so important, and how do you size it? Every write lands in the log first, then drains to the data volume; the log absorbs bursts and bridges brief link slowdowns. If it fills, replication stalls (and synchronous, app writes back up). Size it from a peak-load Test-SRTopology run (8 GB floor, often 32–64 GB+), on NVMe/SSD because log latency is in the write path. Under-provisioning it is the most common SR failure.

5. Why can’t you read the DR-site copy of a Storage Replica volume? SR is single-writer: the destination data volume is dismounted and inaccessible while it’s a replication target — it’s a cold, exact block replica, not a live share. It only mounts and becomes writable when replication direction flips (on failover). This is the fundamental difference from DFS Replication, which is file-level and multi-master.

6. A 2+2 stretch cluster loses its inter-site link. What happens, and how do you prevent an outage? Each site holds exactly half the votes, so both sides can lose quorum — a split-brain that takes the whole cluster down. Prevent it with a witness in a third, independent failure domain (a cloud witness is ideal) so one side plus the witness holds the majority, and set PreferredSite so a clean 50/50 partition resolves in favour of the intended survivor.

7. Where must you NOT place the quorum witness for a stretch cluster, and why? Never inside Site A or Site B. If the witness is in Site A and Site A fails, you lose the witness and two nodes simultaneously, dropping below majority — the cluster stops. The witness must share no failure domain with either site, which is why a cloud witness (neutral, third region) is the standard choice.

8. What do dynamic quorum and dynamic witness do? Dynamic quorum removes a failed node’s vote so the survivors still hold a majority, letting a cluster survive down to the last node in a sequential cascade. Dynamic witness adds/removes the witness’s vote to keep the total number of votes odd, avoiding an even-vote deadlock. Both are on by default; you read them (a node’s DynamicWeight vs NodeWeight) rather than manage them.

9. On a stretch cluster, why pin CAU’s NodeOrder to one site before the other? So the cluster never has one rebooting node in each site at the same time. If a metro link blip hit while a node in each site was down mid-patch, you could drop quorum. Patching Site A fully — confirming health and storage resync — before touching Site B keeps at least one full, healthy site available throughout.

10. During a failover you see SR event 5015 (resync) instead of 1215 (direction change). What does that mean? The failover was not clean: at the moment of failover the destination was behind (or the log was inconsistent), so SR had to run a resync rather than simply reverse direction. It usually follows failing over while replication was not ContinuouslyReplicating. Prevent it by only doing planned failovers when replication is healthy, and by sizing the log so bursts never leave the destination behind.

11. When do you reach for cluster sets instead of a single (stretch) cluster? When you’ve outgrown a single cluster’s ~64-node ceiling, or you need entire-cluster fault isolation (a quorum event or bad patch on one cluster must not affect another), while still wanting unified management and VM mobility across clusters. A cluster set federates multiple failover clusters under a management cluster with a set namespace; member clusters can themselves be stretch clusters.

12. What’s the single command to verify a cluster is ready for CAU, and name two things it checks? Test-CauSetup -ClusterName <name>. It verifies PS remoting/WinRM, the Failover Clustering firewall group, the RemoteShutdown rule CAU needs to reboot nodes, that Automatic Updates isn’t set to auto-install (fighting CAU), and — for self-updating — that the clustered CAU role is installable. Resolve every warning before enabling self-updating.

These map to AZ-800 (Administering Windows Server Hybrid Core Infrastructure) — failover clustering, Storage Spaces Direct, storage migration/replication — and AZ-801 (Configuring Windows Server Hybrid Advanced Services) — high availability, disaster recovery, stretch clustering, and cluster patching. A compact cert-mapping:

Question theme Primary cert Objective area
CAU modes, drain, ordering AZ-801 Manage failover clustering; apply patches
Storage Replica sync/async, log sizing AZ-800 / AZ-801 Implement disaster recovery; Storage Replica
Stretch cluster, site awareness AZ-801 Implement stretch clusters; site-aware failover
Quorum, witness, dynamic quorum AZ-800 Configure quorum & witnesses
Cluster sets AZ-801 Scale and manage clustered infrastructure
Troubleshooting (cluster log, SR events) AZ-801 Monitor and troubleshoot HA/DR

Quick check

  1. In CAU self-updating mode, how does the cluster manage to patch the node that is hosting the Update Coordinator?
  2. You must replicate a volume to a datacenter 900 km away over a 40 ms link with zero tolerance for the application being slow. Which SR mode, and what’s the RPO consequence?
  3. A 2+2 stretch cluster’s inter-site link dies cleanly. Both sites go offline. What single design change would have kept one site running?
  4. True or false: on an S2D stretch cluster, CAU sometimes waits a long time between nodes, and you should force it to hurry up.
  5. During a planned site-failover test you notice a full resync started (SR event 5015). What did you most likely do wrong?

Answers

  1. Via a coordinator hand-off: one node hosts the coordinator and patches every other node, then passes the coordinator role to an already-patched node, which then patches the original coordinator node. That hand-off is exactly why self-updating needs no external host.
  2. Asynchronous — a 40 ms link is far beyond the ≈ 5 ms synchronous latency budget, and forcing synchronous would make every application write wait 40 ms+ (crippling). The consequence is a non-zero RPO: on a site loss you can lose the in-flight writes not yet shipped to the destination.
  3. Add a witness in a third, independent failure domain — a cloud witness — so one site plus the witness holds a majority when the link partitions. (Setting PreferredSite determines which site survives a clean 50/50 split.) The outage happened because 2+2 with no reachable neutral witness leaves neither half with a majority.
  4. False. The wait is CAU (correctly) waiting for storage to resync before pulling the next node. Forcing it would risk taking a second node down while virtual disks are still rebuilding, potentially dropping too many copies and taking data offline. Let the resync finish (Get-StorageJob empties).
  5. You most likely failed over while replication was not ContinuouslyReplicating — the destination was behind, so SR had to resync rather than cleanly reverse direction (which would show event 1215). Always confirm ContinuouslyReplicating before a planned failover; size the log so bursts don’t leave the destination behind.

Glossary

Next steps

You can now patch a cluster without downtime and stretch it across two sites with zero data loss. Build outward:

windows-serverfailover-clusteringcluster-aware-updatingstorage-replicastretch-clusterdynamic-quorumdisaster-recoverycluster-sets
Need this built for real?

Vinod is a Senior Cloud Architect (22+ yrs) — available for Azure / AWS / GCP architecture, landing zones, and migrations.

Work with me

Comments

Keep Reading