The Azure Well-Architected Performance Efficiency Pillar: Designing for Load You Don't Have Yet

The Azure Well-Architected performance efficiency pillar finds no autoscale, no baseline, and premium tiers used where standard suffices. For cloud architects designing for real demand.

Marc Dekeyser |

The Azure Well-Architected Performance Efficiency Pillar: Designing for Load You Don’t Have Yet

Nearly every assessment I run turns up the same contradiction. Capacity is fixed. Autoscale is off. And there’s no performance baseline to scale against in the first place.

The performance efficiency pillar asks one question: can a workload meet demand as it changes, scaling up under load and back down when the load passes, without either falling over or paying for headroom it never uses? Most environments answer it by accident. Someone guessed a size once, shipped it, and never connected the guess to anything measured.

It’s the mirror image of cost optimization. That pillar finds the over-provisioning. This one finds the under-provisioning and the static provisioning — workloads pinned to a fixed size and left there. Same root cause, opposite direction: capacity decided without data.

Key takeaways

  • No autoscale configured is the finding I see most. Workloads run at a fixed instance count, sized for an average that’s wrong at both the peak and the trough.
  • No performance baseline exists in most environments. Without one you can’t say whether the system is fast enough, and you can’t tell when it degrades.
  • Premium tiers get used where Standard would carry the throughput. The inverse waste: paying for headroom the workload never touches.
  • Data and caching is the most overlooked lever. The application scales. The database it leans on does not, and nothing sits between them.
  • Performance efficiency and cost optimization are the same conversation. Right-size to actual demand and both resolve.

What the design principles actually ask for

Capacity should track demand through measurement and elasticity, not through a fixed allocation someone picked at design time. The Microsoft Azure Well-Architected Framework treats performance as something you negotiate against data, continuously. That last word is where most environments fall down.

Four principles carry the pillar. Negotiate realistic performance targets, so “fast enough” means something. Meet capacity through elasticity instead of static over-provisioning. Baseline, test, and monitor against the targets to hold performance over time. Make the trade-offs on evidence. The right tier, the right scaling model, the right place to spend.

Then you look at the running environment and the gap writes the findings for you. A workload sitting at a fixed three instances because three felt safe. No load test ever run, so nobody knows what three instances can actually serve. No baseline, so nobody can say whether response times have slipped since launch. A guess that calcified into a fact.

Why no autoscale is the finding I see most

Static capacity is the default. Autoscale is the thing you have to sit down and configure (write the rules, set the bounds), and nobody got around to it. A fixed instance count works fine the day it ships. It only shows its inadequacy under a spike or during a quiet spell, and by then nobody’s looking at capacity.

Azure hands you the scaling mechanisms. The assessment finds them switched off.

Take App Service. A plan on the Standard or Premium tier supports autoscale rules: scale out when CPU or memory crosses a threshold, scale in when it drops back. What I find is a fixed instance count and no rules at all. Sized for the peak, it over-pays at the trough. Sized for the average, it degrades at the peak. Either way the elasticity is sitting there unused.

Virtual Machine Scale Sets are worse in a way, because the whole point of a scale set is to move instance count automatically. I find them pinned to a static count with the autoscale profiles never defined. The construct gets used for management convenience and the capability that justifies it gets ignored.

AKS has two scaling layers. The Horizontal Pod Autoscaler scales pods against CPU or custom metrics; the cluster autoscaler scales the node count. Often neither is configured. A fixed node pool running a fixed pod count, sized by hand.

None of this is hard to fix. It’s defining the rules and the bounds. What’s missing isn’t capability. It’s the configuration, plus the baseline that would tell you where to set the thresholds.

No baseline means no answer

Ask “how fast is this system when it’s healthy?” and there’s no recorded answer. That’s the finding. You can’t prove the workload is meeting its target and you can’t catch it drifting away from one. Nothing visibly breaks, which is exactly why it goes unnoticed. The system is just un-measured.

A baseline is a captured record of behaviour under known load: response time at the median and the tail percentiles, throughput, utilisation at each tier. It’s the reference everything else gets judged against. Without it, “the application feels slow” is unfalsifiable. Autoscale thresholds become guesses. Capacity planning becomes superstition.

So the assessment looks for two things. Evidence that load testing happened: Azure Load Testing runs, results captured, targets defined. And Application Insights configured to track the performance signals continuously. Usually it finds neither, with the app instrumented at defaults. That’s the same observability gap the operational excellence pillar surfaces, seen through the performance lens. You can’t tune what you never measured. And you can’t prove a regulator-relevant performance commitment you never baselined.

Premium where Standard would do

Premium feels like the responsible choice. Nobody checked whether the workload needed it. That’s the whole mechanism. The performance pillar surfacing cost waste, arriving at the same place as the cost optimization pillar from a different question: does this workload actually use the tier it’s paying for?

The pattern repeats across services.

ServicePremium chosenWhat the workload actually needs
Azure SQL DatabaseBusiness Critical tierGeneral Purpose, where the IOPS and latency suffice
Azure Cache for RedisPremium tierStandard, where the throughput and size fit
App ServicePremium v3 planStandard, where the autoscale ceiling is never reached
StoragePremium SSD on a low-IOPS workloadStandard SSD, matched to actual throughput
Application GatewayWAF_v2 at high capacity unitsRight-sized capacity against real request volume

Premium isn’t wrong. These tiers exist for workloads that need what they guarantee: the latency floor of Business Critical, the clustering and persistence of Premium Redis. The finding is the tier picked without checking whether the workload ever reaches for any of it. The pillar asks you to make that choice on evidence. Most get made on instinct, and instinct rounds up.

The tier everyone forgets to scale

Compute usually scales. The data tier usually doesn’t. So the database becomes the ceiling the moment the application scales into it — and that’s why data and caching moves the needle more than compute scaling ever will. It’s the most overlooked lever here and the one with the biggest payoff when it’s missing.

The failure mode is structural, not a config typo. The application tier autoscales beautifully. Under load it spins up more instances, and every one of them hammers the same Azure SQL Database, which can’t scale horizontally the way a stateless tier can. Throughput collapses at the data tier while compute sits comfortable. Adding application instances makes it worse.

Three levers, and the assessment checks for each.

Caching first. Azure Cache for Redis in front of the database absorbs read load that would otherwise hit the data tier on every request. What I usually find is no cache at all. Every read goes to the database, including reads for data that only changes hourly. It’s often the single highest-impact change available, and it’s absent.

Read replicas next. Azure SQL Database read scale-out and read replicas move read-heavy queries off the primary. Workloads that are 90% reads still route everything to the primary because the replica was never set up.

Then static assets. Content served straight from the application or from storage, no Azure Front Door or CDN in front, putting load on origins that should never see it.

Scale compute against an un-cached, un-replicated database and you’re scaling the wrong tier. No autoscale rule fixes a structural bottleneck.

What a performant configuration leaves behind

Defined performance targets. Captured baselines. Autoscale rules with sensible bounds. Service tiers matched to measured demand. A data tier with caching and read scale-out where the load justifies it. That’s the evidence, and it’s what turns “it performs well” from an assertion into something demonstrated and repeatable.

It’s also a tell for operational maturity. A baseline implies load testing ran. Autoscale rules imply someone understood the demand pattern. Tier choices backed by utilisation data imply the trade-offs were deliberate. A performance-efficient environment is a measured one, almost by definition. And the measurement is the evidence.

Platform Architecture Authority reads the running estate through Azure Resource Graph and correlates provisioned tiers and scaling configuration against Azure Monitor utilisation. It surfaces the static-capacity workloads, the over-tiered services, the un-cached data dependencies. Then it generates the remediation as infrastructure-as-code you review and apply: the autoscale profiles, the tier changes, the caching topology. It’s read-only. A cloud architect still decides which workloads genuinely warrant Premium guarantees and where elasticity matters more than a fixed floor. The platform just makes the current configuration visible, so that decision runs on measured demand instead of the instinct to round up.

FAQ

What is the difference between scaling up and scaling out? Scaling up (vertical) means a bigger instance: more vCPUs or memory on the same resource. Scaling out (horizontal) means more instances sharing the load. The pillar favours scaling out with autoscale for stateless tiers: it adds elasticity and removes single points of failure, where scaling up hits a hard ceiling.

Why does the data tier limit performance more than compute? The application tier is usually stateless and scales horizontally: add instances, add capacity. A relational database holds state and can’t scale horizontally the same way, so it becomes the bottleneck when the application scales into it. Caching and read replicas relieve the data tier. Adding application instances does not.

How is performance efficiency different from cost optimization? Two views of one question: does capacity match demand? Cost optimization finds capacity exceeding demand (over-provisioning). Performance efficiency finds capacity failing to track demand (no autoscale, no baseline) and, in the tier findings, the same over-provisioning. Right-size to measured demand and you satisfy both.

Designing for load you don’t have yet isn’t over-engineering. It’s wiring up the elasticity and capturing the baseline now — so when the load arrives the system scales to meet it, instead of teaching you what you should have measured.