Guide · System design
Non-Functional Requirements: Availability, Reliability, Scalability
23 min readUpdated By Saket Bhatnagar
Researched and drafted with AI, reviewed and edited by Saket Bhatnagar.
In short
- Non functional requirements say how well a system must work: how fast, how often it is up and how much load it takes. Good ones are numbers you can measure.
- Fast becomes a latency target, a limit on how long a request takes, at a percentile. A p99 of 1 second means 99 of every 100 requests finish within 1 second. Averages hide the slow ones.
- Reliable becomes an SLO, a target for a measured number called an SLI, such as 99.9% of order requests good each month. Each extra nine (99.9% to 99.99%) cuts allowed downtime tenfold.
- Scalable becomes a peak load with a speed attached, such as 750 orders a second with p99 still under 1 second. A load test, sending that much test traffic on purpose, proves it.
- Beginners can stop once SLI, SLO and SLA, a promise with a penalty, make sense. Engineers get the error budget, the failure an SLO allows: one 12-minute slowdown spent 38 times a month's budget. They also get the five-minute glitch rule of SEBI, India's market regulator.
What goes wrong when requirements just say fast and reliable?
Nobody can test them, so after an incident nobody can say whether the system failed. Good non-functional requirements each need a number and a way to measure it, so anyone can check the result.
Picture a common setup. A stock-broking app in India serves about 40 lakh (4 million) registered users, mostly first-time investors placing small orders from their phones. The setup is made up, but the problem is real.
Its product document had one line about quality: the app must be fast, reliable and scalable. Everyone agreed with that line, and nobody asked what the words meant.
Then came a busy IPO listing day. An IPO, or initial public offering, is when a company first sells its shares to the public; listing day is when those shares start trading. In the first minutes, three times the usual number of users opened the app.
For 12 minutes, placing an order took 6 to 9 seconds instead of under 1 second. About 1 in 20 orders failed with a timeout, and users watched a spinning wheel while prices moved.
This was more than an annoyed-user problem. SEBI, India's market regulator, has a framework for technical glitches at stock brokers. Its version dated 9 January 2026 is the current one as of 19 October 2026.
It covers brokers with online trading platforms and more than 10,000 registered clients on 31 March of the previous financial year. So this broker is in scope.
A glitch is a malfunction in the broker's systems, during the exchange's trading session, that stops, slows down or alters trading functions such as log-in and order placement. It must last five minutes or more without a break.
Some causes are excluded, such as problems at the exchange itself. For a glitch that counts, the broker must tell the exchanges and its clients within 2 hours.
After the incident, the head of engineering asked the reliability team one question: did the app break its requirements, and by how much? Nobody could answer, because the requirements had no numbers. This guide turns those three words into numbers.
What are non-functional requirements?
Non-functional requirements are the qualities a system must have while it does its job: how fast, how available, how secure and how much load it handles. Functional requirements say what the system does.
For the broking app, "a user can place a buy order" is a functional requirement. "99% of buy orders are confirmed within 1 second" is a non-functional one. The first describes a feature. The second says how well it must work.
A fitness goal shows the difference. "Get fit" is like "fast and reliable": everyone agrees with it, and nobody can ever fail it. "Run 5 km in under 30 minutes, three times a week, by March" can be checked every Sunday.
Map the parts. The 5 km is the user action, like placing an order. The 30 minutes is the speed target. Three times a week is the time window, and March is the deadline.
Where the picture breaks: you run one race at a time, but a service answers thousands of requests a minute. So a service needs percentiles over many requests, not one timing.
People also call these quality attributes, or the ilities, because so many names end that way. ISO/IEC 25010, the international standard for software product quality, groups them into nine characteristics in its 2023 version.
- Functional suitability: does it do the right things, completely and correctly.
- Performance efficiency: speed, resource use and capacity.
- Compatibility: working alongside other systems and sharing data with them.
- Interaction capability: how easy the product is to learn and use. The 2011 version called this usability.
- Reliability: working correctly over time. Faultlessness (no faults in normal use), availability, fault tolerance and recoverability sit inside it.
- Security, maintainability, flexibility and safety. Scalability sits inside flexibility, which the 2011 version called portability.
Here is the map the team drew. Read it left to right. Each vague word from the product document becomes one measurable number, and all three numbers land on one sheet.
From three words to three numbers
Drag to exploreNotice that each number names an action, a limit and a window, so the team can check it every week (targets made up).
Diagram connections:
- Fast to p99 order latency
- Reliable to Good order requests
- Scalable to Peak orders per second
- p99 order latency to Requirements sheet
- Good order requests to Requirements sheet
- Peak orders per second to Requirements sheet
- Fast: Vague word in the product document
- Reliable: Vague word in the product document
- Scalable: Vague word in the product document
- p99 order latency: Under 1 second during trading hours
- Good order requests: At least 99.9% of them each month
- Peak orders per second: 750 a second with p99 still under 1 second
- Requirements sheet: Every number has an owner and a dashboard
| Area | Functional: what it does | Non-functional: how well |
|---|---|---|
| Orders | A user can place, change or cancel an order | 99% of orders get a reply within 1 second |
| Login | A user can log in with a PIN | 95% of logins finish within 2 seconds |
| Portfolio | A user can see holdings and today's profit | Prices on screen are at most 2 seconds old |
| Money | A user can add funds through UPI, India's instant bank-transfer system | A confirmed deposit is never lost, even if a data centre fails |
How do you turn "fast" into a latency target?
You set a latency target for one user action, at a percentile, over a time window. For example: 99% of order requests get a reply within 1 second, measured over each trading day.
Latency is how long one request takes, from the moment it is sent to the moment the answer comes back. You measure it in milliseconds, written ms. One second is 1,000 ms.
A percentile tells you how slow the slow requests are. The 95th percentile, written p95, is the time within which 95% of requests finish. The median, or p50, is the middle value: half the requests take that long or less.
Why not just use the average? Go back to the runner. Say you run 5 km in 26 minutes four times and in 45 minutes once. Your average is 29.8 minutes, under target, yet one run went badly.
Requests work the same way. Below are ten order times from one minute of the incident. The helper uses the nearest-rank method: sort the times, then pick the value at that position in the list.
import math
def percentile(times_ms, p):
ordered = sorted(times_ms)
rank = math.ceil(p / 100 * len(ordered)) # nearest-rank method
return ordered[max(rank, 1) - 1]
order_times = [120, 140, 135, 150, 2900, 160, 145, 130, 170, 155]
print("average:", sum(order_times) / len(order_times)) # 420.5
print("p50:", percentile(order_times, 50)) # 145
print("p95:", percentile(order_times, 95)) # 2900Run it and you should see 420.5, 145 and 2900, all in milliseconds. The average describes nobody. Nine orders took under 200 ms, and one took almost 3 seconds.
The p50 of 145 ms shows the normal experience. The p95 of 2,900 ms shows the user who probably gave up. With only ten samples, p95 is just the slowest one; real systems compute it over thousands of requests.
Monitoring tools do this work for you. Prometheus, an open-source metrics system, can count request times in buckets, called a histogram. Its histogram_quantile function then estimates percentiles from those buckets on the server.
The word estimates matters. In a classic histogram, the error is limited by the width of the bucket the percentile lands in. Prometheus's documentation uses a target of 95% of requests within 300 ms as its running example.
Where should you measure latency?
Measure as close to the user as you can, so the number includes every step behind it. Here is the path of one order. Notice where the monitoring box gets its timings: the load balancer, which spreads requests across servers.
Where the broking app measures order latency
Drag to exploreTiming at the load balancer covers every hop behind it, including the slow exchange call, but not the phone's network.
Diagram connections:
- Trading app to Load balancer
- Load balancer to Order service
- Order service to Orders database (Save first)
- Order service to Risk check
- Risk check to Stock exchange (Send if allowed)
- Load balancer to Monitoring (Time of every request)
- Trading app: User taps Buy on a phone
- Load balancer: Spreads requests and starts the timer
- Order service: Checks the order is complete and valid
- Orders database: Saves every order before it is sent
- Risk check: Confirms the user has enough funds
- Stock exchange: Matches the buy with a seller
- Monitoring: Builds p50, p95 and p99 for every minute
In this setup, the load balancer is the first machine the broker runs that a request touches. It still cannot see time spent on the user's mobile network. Some teams also time requests inside the app itself to cover that gap.
The team sets a speed target for each user action, because some actions matter far more than others:
- Place, change or cancel an order: p99 under 1 second during trading hours.
- Log in: p95 under 2 seconds.
- Open the portfolio screen: p95 under 1.5 seconds.
What is availability and how do you calculate the nines?
Availability is the share of time, or of requests, in which a service works when users need it. You write it as a percentage like 99.9%, and people call each 9 a "nine".
There are two common ways to count. Time-based availability divides good minutes by total minutes. Request-based availability divides good requests by total requests. The broking team uses the second, because a minute at market open carries far more orders than a minute at noon.
A good request needs a clear rule. Here, an order request is good if it succeeds within 2 seconds. A reply that arrives after 9 seconds counts as bad, even though the server technically answered. The 2-second line is looser than the 1-second p99 target on purpose: it marks requests users would call failed, not just slow.
The table turns each target into allowed downtime. The last column counts only the hours users can trade. On NSE, the National Stock Exchange of India, the normal market runs 9:15 am to 3:30 pm as of 19 October 2026.
| Target | Per 30-day month, all hours | Per year, all hours | Per month, trading hours only |
|---|---|---|---|
| 99% (two nines) | 7.2 hours | 3.65 days | About 79 minutes |
| 99.9% (three nines) | 43.2 minutes | 8.76 hours | About 7.9 minutes |
| 99.95% | 21.6 minutes | 4.38 hours | About 3.9 minutes |
| 99.99% (four nines) | 4.3 minutes | 52.6 minutes | About 47 seconds |
| 99.999% (five nines) | 26 seconds | 5.3 minutes | Under 5 seconds |
That is 375 minutes a day, and the table assumes 21 trading days a month. You can check any row yourself. The function below multiplies the allowed failure share by the minutes in the window.
def allowed_downtime(target, window_minutes):
return (1 - target) * window_minutes
month = 30 * 24 * 60 # 43,200 minutes in a 30-day month
trading = 375 * 21 # 7,875 trading minutes in a 21-day month
print(round(allowed_downtime(0.999, month), 1)) # 43.2
print(round(allowed_downtime(0.999, trading), 1)) # 7.9
print(round(allowed_downtime(0.9999, month), 1)) # 4.3It prints 43.2, 7.9 and 4.3, all in minutes. Now look at the trading-hours column. Counted in time, a 99.9% target allows under 8 minutes of trouble a month, and the IPO-day slowdown lasted 12.
Counted in requests, it was worse, because the slowdown hit the busiest minutes of the month. The error budget section below works out by how much.
Each extra nine cuts the allowed downtime by ten times. Google's Site Reliability Engineering (SRE) book warns that each step towards 100% can cost far more than the one before. Each extra nine usually needs spare machines in another location and automatic failover, which means switching to a spare copy by itself.
How parts in a chain and side by side combine
Parts in a chain multiply their availability. If an order passes through three parts in a row, each 99.9% available and failing independently, the whole path is about 99.7%.
Parts side by side help instead. Two independent 99.9% copies are both down at once only 0.0001% of the time, before you count the load balancer in front of them. Real copies share networks, settings and releases, so they fail together more often than this maths says.
What is the difference between availability and reliability?
Availability asks whether the service is up and answering when you need it. Reliability asks whether it does the right thing, without failing, over a period of time.
ISO/IEC 25010 describes reliability as how well a system performs specified functions, under specified conditions, for a specified period of time. Availability is one part of reliability in that model, next to faultlessness, fault tolerance and recoverability.
Here is how they split apart in the broking app. Every screen can load quickly while 1 in 200 orders silently stays stuck as pending. The app is available, but it is not reliable.
So the team tracks reliability with numbers of its own:
- Success rate: the share of orders that reach the exchange and come back with a final status. Target: 99.95% each day.
- MTBF, mean time between failures: how long the system runs, on average, between incidents.
- MTTR, mean time to recovery: how long it takes, on average, to get back to normal after an incident.
- Durability: whether data, once saved, stays saved. A confirmed order or deposit must never disappear.
For this broker, MTTR is the number to watch first. SEBI's line is five contiguous minutes. If spotting a bad release and rolling it back takes under five minutes in total, the slowdown it caused ends before it crosses the line.
Two more numbers cover big disasters, like losing a whole data centre. NIST, the US standards body, defines both. RTO, the recovery time objective, is how long systems may stay in recovery before it hurts the business.
RPO, the recovery point objective, is the point in time to which data must be recovered after an outage. In plain words, RPO says how much recent data you can afford to lose.
The team sets an RPO of zero for orders and money, so nothing confirmed is ever lost. That means copying each confirmed write to a second site before the user sees it confirmed.
Chart data can be rebuilt, so its RPO is 15 minutes. For a full site failure, the RTO is 30 minutes.
These numbers cannot be set alone. SEBI's January 2026 circular asks stock exchanges to review their rules for brokers' disaster recovery sites, including defining RTO and RPO. The broker's targets must fit inside whatever the exchanges set.
How do you write a scalability requirement?
You write it as a peak load the system must handle at a stated speed, plus the growth it must absorb. "Scalable" alone means nothing until you say to what load, and by when.
The key word is throughput: how much work a system finishes per second, such as orders per second. Scalability is the ability to keep throughput rising as load rises, without the speed target breaking.
On a normal day, the broking app peaks at about 150 orders per second, in the first minutes after the market opens. On IPO listing day it reached 450. The order service started slowing at about 300.
Notice that the requirement needs a speed attached. "Handles 750 orders per second" is meaningless if each order then takes 9 seconds. So the team writes: handle 750 orders per second for 30 minutes, with p99 still under 1 second.
Find the busiest minute
Pull orders per second from the logs for the ten busiest days of the last year. The normal peak is about 150.
Look at the worst day
IPO listing day reached three times the normal peak. The day the yearly Union Budget is announced, and big results days, come close.
Add headroom
Plan for five times the normal peak, 750 orders per second, so one surprise day does not break the app.
Attach the speed target
At 750 orders per second for 30 minutes, p99 must stay under 1 second and the success rate above 99.9%.
Prove it with a load test
Replay recorded traffic at that rate every month and before any known busy day. The test passes only if the report shows p99 under 1,000 ms.
Review it every quarter
Users are growing about 60% a year (made up), so the peak number goes up each quarter, not once.
The regulator expects this kind of planning too. SEBI's January 2026 circular asks brokers to do capacity planning for their entire trading infrastructure, including servers, network and trading apps. It also asks them to monitor peak load.
What is the difference between SLI, SLO and SLA?
An SLI is a number you measure, an SLO is your target for it, and an SLA is a promise to customers with a consequence if you miss it. Together they turn requirements into daily decisions.
SLI. A service level indicator is a measured number that reflects what users feel. Example: the share of order requests in a day that succeeded within 2 seconds.
SLO. A service level objective is the target for an SLI over a time window. Example: at least 99.9% of order requests are good in each calendar month.
SLA. A service level agreement is a promise to someone outside the team, with a consequence for missing it, often a refund or penalty. The broker has no paid SLA with its users.
SEBI's glitch rules work like an outside promise instead. A long enough slowdown must be reported, and the exchanges publish glitch incidents on their websites.
Google's SRE book adds a practical habit. Keep your internal SLO tighter than anything you promise outside. The gap gives you time to react before you break the promise.
How the error budget decides releases
The SLO also gives you an error budget: the amount of failure the target allows. With a 99.9% SLO, 0.1% of requests may go wrong. The team can spend that budget on risky releases and experiments.
The runner has a budget too. Three sessions a week is about 13 in a month, and you might accept one missed session. Miss three, and you stop adding new exercises until the routine is back.
Here is how those pieces connect. Follow the arrows from the SLI to the morning question, which decides between features and fixes.
How the broking team uses its SLO each month
Drag to exploreNotice the decision box: the budget question turns a reliability number into a yes or no on releases.
Diagram connections:
- SLI: good order requests to SLO: 99.9% each month (Compared with)
- SLO: 99.9% each month to Outside promise (Must also respect)
- SLO: 99.9% each month to Error budget (100% minus the target)
- Error budget to Budget left this month?
- Budget left this month? to Keep shipping features (Yes)
- Budget left this month? to Pause risky releases (No)
- SLI: good order requests: Measured every minute at the load balancer
- SLO: 99.9% each month: Internal target set by the team
- Outside promise: SEBI glitch rules and exchange reporting
- Error budget: 0.1% of order requests may go wrong
- Budget left this month?: Checked every morning before market open
- Keep shipping features: Normal release pace
- Pause risky releases: Fix the order path first
Below is the budget maths the team runs each morning, using request counts. It is a sketch: the two counts would come from the monitoring system, not be typed in by hand.
SLO = 0.999 # 99.9% of order requests must be good
def budget_report(total, good):
allowed_bad = total * (1 - SLO)
actual_bad = total - good
left = allowed_bad - actual_bad
return round(allowed_bad), actual_bad, round(left)
# Month so far, including IPO listing day
allowed, used, left = budget_report(6_300_000, 6_060_000)
print(allowed, used, left) # 6300 240000 -233700
print(round(used / allowed, 1)) # 38.1
if left < 0:
print("Budget spent: pause risky releases, fix the order path")Run it and you should see 6300 240000 -233700, then 38.1 and the pause message. The allowed_bad line turns the SLO into a count: of the requests so far this month, 6,300 may go wrong.
The if line applies a rule the team agreed in advance, so nobody argues about it during a bad week. Google's SRE book describes the same rule: when SLO misses use up the error budget, releases are temporarily halted.
Now the head of engineering has an answer. The IPO-day slowdown produced about 240,000 bad requests, roughly 38 times the month's budget. In time it looked like 12 minutes against 8. In requests it was far worse, because those minutes carried many times the orders of an average minute.
How do you choose which non-functional requirements matter most?
Start from what hurts users and the business most when it goes wrong, and set strict numbers only there. Everything else gets a looser, cheaper target.
Requirements also pull against each other. Stronger correctness can cost speed. More nines cost money. When parts of a system lose network contact, you may have to choose between refusing requests and serving possibly stale data.
The broking app makes that choice differently for each part:
- Orders and money: correctness first. If the system is unsure, it rejects the order rather than risk a wrong trade. RPO is zero.
- Order path speed and availability: strict, but only during trading hours. Outside them, the targets relax.
- Charts and news: availability first. A price chart that is 15 seconds old is acceptable, and its SLO is 99.5%.
- Security and compliance: not traded away for speed. Login checks and audit logs, records of who did what, stay on even on the busiest day.
The regulator draws a similar line. SEBI's circular does not treat issues in decision-support tools, such as technical charts, as technical glitches. That is one more reason the charts can get a looser target.
Writing these down early saves arguments later. When an engineer asks whether to add a cache, a fast copy of recent data, in front of the portfolio screen, the sheet answers. Prices may be 2 seconds old, so a 1-second cache fits.
How do you explain non-functional requirements in a system design interview?
Spend the first few minutes turning the product into three to five numbers, then use those numbers to justify every design choice. Interviewers want to see that your boxes and arrows follow from targets.
Ask about users and scale
How many daily users? What is the busiest minute? Is the system read-heavy (mostly reading data) or write-heavy (mostly saving it)? Do some rough estimation maths out loud.
Pick the qualities that matter
For a trading app: order latency, availability in trading hours, durability of money, and peak throughput. Say which ones you will relax.
Put a number on each
p99 under 1 second for orders, 99.9% good requests a month, RPO zero for money, 750 orders per second at peak.
Name the trade-off
Say what you give up: for example, rejecting uncertain orders instead of accepting them, or showing slightly old charts.
Tie numbers to components
Two copies of the order service in different data centres for availability. A cache for the portfolio screen. Extra machines added before IPO days.
Say how you will measure
Name the SLI, where it is measured, and the alert that fires when failures use up the error budget faster than planned.
Questions people ask
- What are examples of non-functional requirements?
- Common examples are latency, availability, reliability, scalability, durability, security and maintainability. Written well, each has a number. For example: 99% of searches return within 300 ms, the service is available 99.9% of each month, and no confirmed payment is ever lost. Cost and compliance are often added too.
- Is security a non-functional requirement?
- Yes, security is usually listed as a non-functional requirement, and ISO/IEC 25010 treats it as a quality characteristic. Some parts of it are also functional, such as a login screen or a permission check. The non-functional part describes qualities like how data is protected and how fast a breach is detected.
- What is a good availability target for a new app?
- There is no standard number, so start from what users would notice and what you can measure. Convert any target into minutes before agreeing to it. 99.9% allows about 43 minutes of downtime in a 30-day month, which is already hard for a small team without automatic failover. Tighten in steps once you have a few months of data.
- Why use p99 instead of average latency?
- Because the average hides slow requests, and slow requests are what users remember and complain about. A p99 target says that 99 out of 100 requests must finish within a limit. It forces you to fix the slow tail, not just the typical case. Google's SRE book makes the same point about averages.
- What is the difference between an SLO and an SLA?
- An SLO is an internal target, and an SLA is an external promise with a consequence, often a refund or penalty. Google's SRE book suggests keeping the internal SLO tighter than what users are promised, so teams can react before they break it. Missing an SLO starts a conversation inside the team; missing an SLA can cost money or trust.
- How do you check that a latency target is met?
- Record the time of every request where users enter your system, then compute the percentile over the agreed window. With Prometheus, you record a histogram and use histogram_quantile to estimate the percentile. Put a bucket edge exactly at your target, so the share of requests under it is exact, and check it after every load test.
- Who writes non-functional requirements?
- Usually product managers and engineers write them together, with the SRE or operations team checking that each one can be measured. Product knows what users and the business need. Engineers know what each extra nine or extra second costs. Regulators can add hard limits, as SEBI's glitch rules do for Indian stock brokers.
Sources and further reading
- SEBI circular: Review of Framework to address the technical glitches in Stock Brokers' Electronic Trading Systems (9 January 2026), paras 5.1, 5.2, 6.1, 7.1, 8.1, 8.2 and 11.1
- SEBI press release PR No. 04/2026: Ease of Compliance review of the technical glitch framework
- ISO: ISO/IEC 25010:2023 Product quality model (edition 2, November 2023)
- ISO/IEC 25010:2023 characteristics and sub-characteristics, summary in the arc42 Quality Model
- Prometheus documentation: Histograms and summaries
- Google SRE book, chapter 4: Service Level Objectives
- Google SRE book, chapter 3: Embracing Risk (error budgets)
- NSE India: market timings for the equity segment
- NIST CSRC Glossary: recovery time objective (NIST SP 800-34 Rev. 1)
- NIST CSRC Glossary: recovery point objective (NIST SP 800-34 Rev. 1)