🌿 jadelog
📚 Study

Designing Data-Intensive Applications - (2) Defining NonFunctional Requirements

status
Public
date
Mar 7, 2026
slug
system-design-foundations-non-functional-requirements
summary
이 챕터는 데이터 중심 애플리케이션의 핵심인 세 가지 비기능적 요구사항(신뢰성, 확장성, 유지보수성)을 정의합니다. 트위터의 타임라인 구축 사례를 통해 읽기/쓰기 시점의 부하 분산 전략(Fan-out)과 트레이드오프를 살펴보고, p99.9와 같은 꼬리 지연 시간(Tail Latency) 관리의 중요성을 강조합니다. 최종적으로는 복잡성을 제어하는 추상화와 변화에 유연한 설계가 장기적인 시스템 운영에 어떤 영향을 미치는지 다룹니다. This chapter defines the three pillars of data-intensive applications: Reliability, Scalability, and Maintainability. Through the case study of X (Twitter) home timelines, it explores the trade-offs of fan-out strategies between write and read paths. It also emphasizes the importance of managing tail latencies (p99.9) and explains how abstraction and evolvability are crucial for long-term system health and managing accidental complexity.
type
Post
category
📚 Study
tags
Designing Data
thumbnail
series
Designing Data-Intensive Applications
notion image
O’Reilly Online LearningO’Reilly Online LearningDesigning Data-Intensive Applications, 2nd Edition
YouTubeYouTubeDistributed Systems lecture series

Chapter 2: Defining NonFunctional Requirements

The Internet was done so well that most people think of it as a natural resource like the Pacific Ocean, rather than something that was man-made. - Alan Kay, in interview with Dr Dobb’s Journal (2012)
 
서비스를 개발하는데 있어서 여러가지 요소를 고려해야 함. 크게 다음과 같음.
  • functional requirements
  • nonfunctional requirements → obvious things… fast, reliable, secure, legally compliant
    • define and measure the performance of a system
    • means for a service to be reliable
    • allowing a system to be scalable
    • making it easier to maintain a system in the long term

Case Study: Social Network Home Timelines

간소화된 X앱을 개발한다고 가정해보자.
완벽한 해결책은 없음. 항상 모든 것에는 trade-offs가 존재함. 따라서 최선일 수 있도록 노력해야 함.

Representing Users, Posts, and Follows

relational database에 모든 데이터를 저장할 경우 다음과 같이 테이블 당 1개로 연결할 수 있다.
notion image
만약 home timeline 화면을 구성하게 된다면, 다양한 걸 고려하여 다음과 같이 SQL 쿼리를 짜야 함
SELECT posts.*, users.* FROM posts JOIN follows ON posts.sender_id = follows.followee_id JOIN users ON posts.sender_id = users.id WHERE follows.follower_id = current_user ORDER BY posts.timestamp DESC LIMIT 1000
: 매번 polling 을 진행해야 하는 상황. 헤비 유저의 경우, 이 쿼리는 very expensive to execute and difficult to make fast

Materializing and Updating Timelines

이 부하를 개선하기 위해서는 매번 폴링을 하는 것보다, 다음 방법을 수행한다.
  1. 서버는 온라인 상태의 followers에게만 새로운 포스트를 전달한다.
      • 대상자가 아닌 사람들은 연산하지 않는다.
  1. precompute: 결과를 미리 연산한 뒤 이를 캐시에 저장해두어 유저가 요청할 때 빠르게 보여준다.
      • 특정 이벤트 발생으로 포스트 생성 비율이 증가할 경우, 즉각적으로 타임라인에 전달하기 보다, enqueue 해두어 followers의 타임라인에 조금은 느리게 보여지더라도 캐시를 통해 전달하여 그 시간 간극을 줄일 수 있다.
notion image
조회 시점의 부하를 줄이기 위해 쓰기 시점의 Fan-out 전략을 채택하고, 부하 급증 시에는 메시지 큐를 통한 비동기 처리로 시스템 안정성과 타임라인 조회 성능을 동시에 확보한다.
Pre-computing
case A) 읽기 시점 생성: 초당 4억 건의 대규모 lookup이 발생
case B) 쓰기 시점 배달: 초당 약 100만 건의 Write이 발생
→ 쓰기 연산은 다소 증가하지만 전체 시스템 부하를 약 1/400 수준으로 절감하여 읽기 성능을 극대화
 
Decoupling
Queueing; 비동기 처리: 이벤트로 인해 트래픽이 spike하면 즉시 배달하는 대신 큐에 쌓아 순차적으로 처리
→ 새로운 포스트가 타임라인에 나타나기까지 약간의 latency는 발생하더라도, 타임라인 조회는 항상 cache에서 발생하여 시스템 부하와 상관 없이 사용자에게 빠른 응답 속도를 보장
 
  • materialization ← Pre-computing
    • : precomputing and updating the results of a query
  • materialization view ← cache
    • : the timeline cache
  • materialization donwside
    • 만약 많은 셀럽이 동시간에 포스트를 생성하면 많은 양의 작업을 수행해야 함
      • → 그럼 셀럽이 동시간에 포스트를 쓰지 않게 하면 해결되지만 이는 현실적으로 어려움
    • 해결 방법 중 하나로, celebrity 포스트와 ~celebrity 포스트를 분리해서 관리할 것.

Describing Performance

performance를 측정하는 요소에는 크게 2가지 요소
  1. Response time (seconds): the elapsed time
  1. Throughput: somethings per second
 
queueing: 앞선 request가 completed 될 때까지 기다려야 하므로 load가 증가할 수록 response time이 sharply increase하는 원인
  • 계속 요청이 쌓이게 된다면 retry storm 발생
  • load가 줄어든다고 해도 시스템은 reboot 또는 reset 하지 않는 이상 여전히 over-loaded 상태
    • → metastable failure
 
이를 피하기 위해서는
  1. client-side resilience
      • exponential backoff: client side에서 재시도를 랜덤한 시간 이후로 진행
      • circuit breaker: 오류가 반환되거나 타임아웃되는 요청을 그만 보낼 것
      • token bucket algorithm: 클라이언트가 요청을 보내는 속도를 제어(Rate Limiting)하는 알고리즘 / 버킷에 담긴 토큰만큼만 요청을 보낼 수 있게 하여 일시적인 트래픽 폭주를 제어
  1. server-side protectino
      • load shedding: 서버가 과부하 상태에 도달했음을 감지하면, 중요도가 낮은 요청을 선제적으로 거절하여 핵심 기능의 가용성을 유지하는 전략
      • backpressure: send back response asking clients to slow down (ex. HTTP 429 Too Many Requests)
 
성능의 척도는 사용자 경험을 좌우하는 응답 시간과 운영 비용을 결정하는 처리량으로 나뉜다. 특히, 컴퓨팅 자원을 투입한 만큼 최대 처리량을 효과적으로 증대시킬 수 있는 능력을 확장성이라 하며, 이는 고가용성 시스템 설계의 핵심 지표가 된다.
  1. 사용자 관점 → response time
  1. 운영/비용 관점 → throughput
  1. 시스템 설계의 목표 ⇒ scalability

Latency and Response Time

notion image
  1. service time
    1. : 서버가 클라이언트의 요청을 처리하기 위해 실제 작업을 수행하는 시간
      : 순수하게 연산이나 로직이 실행되는 시간만을 의미
  1. queueing time
    1. : 요청이 처리되기 전이나 후에 어딘가에서 기다리는 시간
  1. latency
    1. : 요청이 실제로 처리되지 않고 있는 모든 시간을 통칭
      +) network latency: 요청과 응답이 네트워크 망을 통해 이동하는 시간
  1. response time
    1. : 클라이언트 입장에서 체감하는 전체 시간
      → 클라이언트가 요청을 보낸 시점부터 응답을 받을 때 까지 걸린 모든 지연 요소를 포함한 시간
 
head-of-line blocking
: 응답 시간의 변동성이 큰 이유는 서버의 처리 능력보다 Queueing Delay가 훨씬 더 예측 불가능하기 때문
→ 시스템의 병목을 진단할 때는 단순히 서버의 작업 속도만 볼 것이 아니라, 네트워크 지연과 큐 대기 시간을 포함한 실제 사용자 경험 = response times on the client side를 확인해야 함.
 

Average, Median, and Percentiles

High response-time percentiles, also known as tail latencies, are important because they directly affect users’ experience of the service.
↔ 다만, 단순히 빠르면 좋다는 통계 수치를 믿어서는 안됨.
 
tail latencies
: 응답 시간 분포에서 가장 느린 상위 퍼센트(예: p99, p99.9)를 의미
→ 대부분의 사용자가 빠른 응답을 받더라도, 1000명 중 1명이 겪는 느린 속도가 전체 시스템의 평판을 결정할 수 있음
: 시스템을 가장 많이 이용하는 가치있는 고객이 가장 느린 속도를 경험하게 됨 → 이들을 놓치지 않기 위해 p99.9를 관리하는 것은 비즈니스 생존 전략
↔ 아마존도 p99.99를 만족시키는 것은 포기함: 통제 불가능한 랜덤한 사건에 좌우되는 지연을 해결하는 것은 비용 대비 얻는 이득이 적다고 판단했기 때문
 

Use of Response Time Metrics

notion image
 
구분
의미
예시
비고
SLO (Objective)
우리가 달성하고자 하는 기술적 목표
p99 응답 속도를 1초 미만으로 유지하자.
팀 내부의 성능 지표
SLA (Agreement)
고객과의 비즈니스 계약
SLO를 못 지키면 요금의 10%를 환불해줄게.
법적/금전적 보상이 따름

Reliability and Fault Tolerance

소프트웨어에 대해 신뢰성을 정의하려먼
  1. functional correctness: performs the function that the user expected
  1. fault tolerance for users: can tolerate the user making mistakes
  1. performance under load: good enough for the required use case
  1. security & abuse prevention: prevents any authorized access and abuse
 
fault
: 시스템의 한 구성 요고사 예상과 다르게 동작하는 현상
failure
: fault가 쌓여 시스템 전체가 사용자에게 서비스를 제공하지 못하는 상태 (= not meet the SLO)

Fault Tolerance

fault-tolerant
: if it continues providing the required service to users in spite of certain faults occurring
SPOF; Single Point of Failure 를 식별하고, 중복성을 도입하여 시스템을 robust 하게 만들어야 함 더
 
fault injection
: 시스템의 내결함성을 높이기 위해 의도적으로 시스템에 장애를 일으킴
  • 많은 심각한 버그는 실제 장애 자체가 아니라 장애를 처리하는 코드가 제대로 작동하지 않기 때문에 발생
    • → 장애 대응 로직을 지속적으로 훈련시키고 테스트함으로써, 실제 상황이 닥쳤을 대 시스템이 제대로 복구될 수 있다는 확신을 얻을 수 있음
: 이에 대한 방법이 Chaos Engineering ← 결함 주입을 포함하여, 시스템에 의도적인 장애를 주는 실험을 통해 시스템의 견고함을 개선하려는 체계적인 방법론
 

Hardware and Software Faults

However, in a large-scale system, hardware faults happen often enough that they become part of normal system operation.
: 하드웨어에서는 장애가 날 수 밖에 없고, 장비의 개수가 많아질 수록 결함은 반드시 발생
→ 개별 하드웨어의 불완전함을 소프트웨어적인 설계로 극복하는 것이 데이터 중심 어플리케이션 설계의 핵심
 
Tolerating hardware faults through redundancy
  1. Redundancy 중복성을 추가하여 하드웨어의 불완전함을 보완
    1. : cloud systems tend to focus less on the reliability of individual machines and instead aim to make services highly available by tolerating faulty nodes at the software level.
      → 전통적인 방식: 단일 장비 강화 ↔ 클라우드 방식: 소프트웨어적 대응
      • Availability Zones 가용 영역을 사용함으로써 물리적으로 떨어진 곳에 자원을 배치해 동시에 고장날 확률을 줄임
 
  1. Software Faults
    1. : Correlation 때문에 하드웨어 결함보다 더 다루기가 어려움
      • every node to fail at the same time in particular circumstances: 동시 다발적 발생
      • Cascading failures
      The problem of systematic faults in software has no quick solution.
      1. 시스템의 가정과 상호작용을 깊이 고민하기
      1. 철저한 테스트 및 프로세스 격리
      1. 프로세스가 죽어도 다시 시작할 수 있게 설계 (Crash and restart)
      1. 재시도 폭풍(Retry storms) 같은 피드백 루프 방지
      1. 실제 운영 환경에서의 지속적인 측정과 모니터링
 

Humans and Reliability

Given a choice between more features and more testing, many organizations understandably choose features.
시스템 장애의 가장 큰 원인은 하드웨어나 소프트웨어가 아니라, 바로 사람(운영자 및 개발자)
→ 사람은 반드시 실수한다. 그러니 사람이 실수해도 시스템이 무너지지 않도록 안전장치(추상화, 테스트, 롤백, 모니터링)를 만드는 것이 설계의 핵심
 

Scalability

Scalability
: we use to describe a system’s ability to cope with increased load
확장성에 대해 고민한다는 것은
  • coping with growth
  • add computing resources
  • hit the limits
 

Understanding Load

  1. load parameters examples
      • 웹 서버: 초당 요청 수 (RPS)
      • 데이터베이스: 읽기/쓰기 비율 (Read/Write Ratio)
      • 채팅/메시징: 대화방의 동시 접속자 수
      • 캐시: 히트율 (Cache Hit Ratio)
  1. you can investigate what happens when the load increases
    1. 성능 변화 측정 (자원 고정)
    2. 자원 투입량 계산 (성능 고정)
 
linear scalability 로 자원을 2배 투입하면 load도 2배 늘어나는 상태 → 매우 이상적인 상태
↔ 현실적으로는 부하가 커질수록 자원 효율이 떨어지는 경우가 훨씬 많음
  • 데이터 양이 많아지면 요청 하나를 처리하는 데 필요한 '기본 작업량' 자체가 늘어나기 때문
 

Shared-Memory, Shared-Disk, and Shared-Nothing Architectures

vertical scaling or scaling up 을 위해 하드웨어 리소스를 늘리는 것도 방법이다.
  1. Shared-Memory
    1. : 모든 CPU가 모든 데이터에 빠르게 접근할 수 있어 프로그래밍이 매우 쉬움 ↔ 확장성의 한계가 명확
  1. Shared-Disk
    1. : 여러 대의 서버가 동일한 데이터를 바라보므로 관리가 비교적 수월 ↔ 디스크 저장소 자체가 Bottleneck
  1. shared-nothing architecture / horizontal scaling or scaling out
    1. : 각 노드(컴퓨터)가 자신만의 CPU, 메모리, 디스크를 가짐. 노드 간의 통신은 오직 네트워크를 통해서만 이뤄짐 → 하드웨어 수준에서는 아무것도 공유하지 않고, 모든 조정은 소프트웨어 계층에서 수행
      • 장점
          1. it has the potential to scale linearly
          1. achieve greater fault tolerance
      • 단점
          1. requires explicit sharding
          1. incurs all the complexity of distributed systems
 

Principles for Scalability

There is no such thing as a generic, one-size-fits-all scalable architecture (informally known as magic scaling sauce)
  1. break a system into smaller components that can operate largely independently from one another
    1. → microservices, sharding, stream processing, shared-nothing-architectures
  1. not to make things more complicated than necessary

Maintainability

소프트웨어 비용의 대부분은 초기 개발이 아니라 제품 출시 이후의 유지보수 단계에서 발생한다: 버그 수정, 시스템 운영 유지, 장애 원인 조사, 새로운 플랫폼에 맞춘 조정, 새로운 사용 사례를 위한 수정, 기술 부채 해결, 그리고 신규 기능 추가 등
많은 사람들이 조직을 떠난 뒤, 이 시스템에 대한 지식과 왜 이렇게 디자인되었는지 파악해야 한다.
Every system we create today will one day become a legacy system if it is valuable enough to survive for a long time.
이 시스템을 유지보수하게 될 미래 세대의 고통을 줄여주기 위해, 시스템을 디자인할 때 유지보수성을 생각해야 한다.
  1. Operability: keep system running smoothly
  1. Simplicity: make it easy to understand
  1. Evolvability: make it easy to make changes
 

Operability: Making Life Easy for Operations

Automation can be two-edged sword
  1. 역설적인 숙련도 요구: 자동화로 해결할 수 없는 아주 복잡한 문제들만 남아 운영팀은 자동화 이전보다 훨씬 더 높은 수준의 문제 해결을 해야 함
  1. 추적의 어려움: 사람이 수동으로 명령어를 입력하다 사고를 치면 뭘 잘못했는지 알기 쉬우나 자동화 시스템이 오작동하면 수많은 추상화 계층 속에서 어디가 망가졌는지 찾을 수 없음
 
이를 해결하기 위해서는…
  • 모니터링 툴을 도입
  • 디펜던시를 제거
  • 이해를 위한 좋은 수준의 문서화 필요
  • 관리자가 주도권을 잃어서는 안된다
  • 예측 가능한 동작을 정의해서 의외성을 최소화 해야 한다.
 

Simplicity: Managing Complexity

프로젝트가 커지다보면 너무 복잡해지고 이해할 수 없는 상태가 된다 → 이런 복잡성이 시스템 유지보수 비용을 높이게 된다.
 
복잡도의 정의
  1. essential complexity: 문제 자체에 내제된 복잡함 / 비즈니스 로직의 복잡함
  1. accidental complexity: 도구, 언어, 인프라로 인해 발생한 복잡함
→ 그러나 이 경계는 고정된 것이 아니고 계속 변하게 된다.
 
복잡함을 관리하기 위해서는 abstraction 을 해봐야 한다.
  • 알 필요 없는 것의 격리 → 추상화를 통해 복잡한 내부 동작을 숨김
  • 재사용성 → 비슷한 류의 문제에 적용
  • 품질의 선순환 → 추상화된 컴포턴트를 하나 개선하면 그것을 사용하는 모든 곳에 혜택이 전파된다.
⇒ 좋은 추상화는 개발자가 what 과 how에 집중할 수 있게 한다.
 

Evolvability: Making Change Easy

Agile 패턴은 변화를 받아드릴 수 있게 한다. → TDD test driven development & refactoring
 
  1. 조직적 차원 : agile → 기획이 변경되면 개발 방향을 틀 수 있는 유연함
  1. 기술적 차원 : TDD, refactoring → 코드를 고쳐도 시스템이 깨지지 않는다는 확신
⇒ system wide agility(→ evolvability) : db, message queue, cache 등이 얽혀 있는 거대한 시스템 전체를 어떻게 하면 애자일하게 유지할 것인가?

Summary

  1. reliability 신뢰성
      • fault vs. failure → 결함이 장애로 이어지지 않게 설계하는 것이 중요함
  1. scalability 확장성
      • load parameters를 정의하여 수직 확장 vs. 수평 확장 고려
  1. maintainability 유지보수성
      • operability: 운영 팀이 시스템을 원활하게 돌릴 수 있도록 모니터링 도구를 제공
      • simplicity: 복잡도를 낮추기. 우연적 복잡도를 추상화로 제거하여 예측 가능한 동작을 만드는 것
      • evolvability: 비즈니스 요구사항은 변함으로, 유연하게 설계하기
Series : Designing Data-Intensive Applications
  • 1.
    Designing Data-Intensive Applications - (1) Trade-offs in Data Systems Architecture
  • 2.
    Designing Data-Intensive Applications - (2) Defining NonFunctional Requirements
Related Posts
📚 Study
Claude Code 완전 정복: 에이전틱 개발자를 위한 필수 워크플로우와 컨텍스트 최적화

Claude Code 완전 정복: 에이전틱 개발자를 위한 필수 워크플로우와 컨텍스트 최적화

Feb 26, 2026

시스템 프롬프트를 절반으로 줄이고 성능은 높이는 Claude Code 해킹 비법! AI가 지시를 잊어버리는 '컨텍스트 드리프트' 현상을 막고, 크고 복잡한 개발 문제를 단계별로 격파하는 노하우를 공개합니다. Discover the ultimate Claude Code hacking secrets to cut your system prompts in half while boosting performance! Learn how to prevent "context drift" where AI forgets instructions, and master the art of breaking down complex development problems step-by-step.

AI에이전트
Claude Code
Agentic Developer
Context Drift
📚 Study
Series: Designing Data-Intensive Applications

Designing Data-Intensive Applications - (1) Trade-offs in Data Systems Architecture

Feb 9, 2026

데이터 집약적 애플리케이션 설계에 대한 내용으로, 운영 시스템(OLTP)과 분석 시스템(OLAP)의 차이를 설명하며, 데이터 웨어하우스와 데이터 레이크의 개념을 다룬다. 클라우드 서비스와 자체 호스팅 시스템의 장단점을 비교하고, 분산 시스템과 단일 노드 시스템의 전환 시점을 논의한다. 또한, 데이터 시스템과 법률, 사회의 균형을 맞추는 중요성에 대해서도 언급한다.

Designing Data
⚙️ Data Engineering
PySpark: 대용량 분산 처리 DataFrame 기초

NEWPySpark: 대용량 분산 처리 DataFrame 기초

Mar 30, 2026

PySpark는 Apache Spark를 Python 환경에서 사용할 수 있게 해주는 API로, 대량의 데이터를 분산 처리할 수 있다. 핵심 구조로는 Driver Node, Worker Node, Cluster Manager가 있으며, RDD와 DataFrame이 주요 데이터 구조이다. 학습 로드맵은 DataFrame 기초 조작, 스파크 최적화 및 고급 기능, 확장 모듈 다루기로 구성된다. Lazy Evaluation, SparkSession 생성, 데이터 불러오기 및 변환, 집계, 조인 등의 기법을 통해 성능을 최적화할 수 있다. 또한, Spark SQL, Structured Streaming, MLlib 등의 확장 모듈을 활용하여 데이터 엔지니어링을 강화할 수 있다.

PySpark
Data Engineering
🔎 Practice
Google Antigravity 시작하기 및 실제 프로젝트 구현해보기

Google Antigravity 시작하기 및 실제 프로젝트 구현해보기

Feb 28, 2026

구글 안티그래비티를 실제 프로젝트에 적용하며 얻은 기술적 통찰을 정리한다. 단순한 코드 추천을 넘어 스스로 계획을 수립하고 실행하는 '에이전트'로서의 특징과, 실제 배포 과정에서의 생산성 및 쿼터 관리 효율성을 분석한다. 개발자의 역할이 단순 코더에서 전체 프로세스를 관리하는 디렉터로 변화하는 지점을 가식 없이 기술한다. This post provides a technical review of Google Antigravity based on real-world project application. It explores its capabilities as an autonomous "Agent" that goes beyond code suggestions to planning and execution. The review analyzes productivity gains and the realities of quota management, highlighting the industry's shift where developers evolve from manual coders into strategic directors of AI agents.

AI & Tools