0Pricing
Coding Interview Prep · 강의

속도 제한기 설계와 트위터 피드 설계

두 가지 대표적인 설계 문제에 프레임워크를 적용합니다. 토큰 버킷 및 슬라이딩 윈도우 속도 제한과 쓰기 시 팬아웃 대 읽기 시 팬아웃 뉴스 피드입니다.

속도 제한기 설계와 트위터 피드 설계은(는) CoddyKit의 무료 Coding Interview Prep 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Coding Interview Prep 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Coding Interview Prep 강의에는 총 4개의 강의가 포함되어 있습니다.

요청률 제한이 필수인 이유

요청률 제한은 주어진 time 창에서 클라이언트가 API에 보낼 수 있는 요청 수를 제어합니다. 이것이 없으면 단일 악성 클라이언트 또는 DDoS 공격이 서버 자원을 고갈시켜 모든 사용자의 서비스 품질을 떨어뜨릴 수 있습니다. 요청률 제한은 무차별 대입 공격을 방어하고, API 무단 수집을 막으며, 공유 자원의 공정한 사용을 보장합니다.

일반적인 요청률 제한 단위는 사용자 ID별, API 키별, IP 주소별, 엔드포인트별 또는 이들의 조합입니다. 일반적인 제한은 사용자당 분당 100개 요청, API 키당 시간당 1000개 요청입니다. 요청률 제한기는 빠르게 작동해야 하며(추가 지연 1ms 미만), 분산되어 모든 API 서버 복제본에서 일관된 제한을 적용해야 합니다.

# Rate limiting scenarios
use_cases = [
    ('API authentication endpoint', '5 attempts per 15 min per IP', 'Brute-force protection'),
    ('Public search API',           '100 requests per minute per key', 'Fair use enforcement'),
    ('Email sending',               '50 emails per hour per user', 'Spam prevention'),
    ('Payment processing',          '10 transactions per second per account', 'Fraud prevention'),
    ('File upload',                 '5 uploads per minute per user', 'Resource quota'),
    ('Notification service',        '1000 pushes per second globally', 'Cost control'),
]
print(f'{'Endpoint/Feature':35s} {'Limit':40s} {'Reason'}')
print('-'*95)
for endpoint, limit, reason in use_cases:
    print(f'{endpoint:35s} {limit:40s} {reason}')

요청률 제한 알고리즘 1: 토큰 버킷

토큰 버킷 알고리즘은 최대 용량이 N 토큰인 버킷을 유지합니다. 토큰은 일정한 속도(예: 초당 10개)로 추가됩니다. 각 요청은 토큰 하나를 소비합니다. 버킷이 비어 있으면 요청을 거부하고, 용량에 여유가 있으면 요청을 허용한 뒤 토큰을 소비합니다.

토큰 버킷은 버스트 처리를 허용합니다. 5초 동안 요청이 들어오지 않으면 버킷이 N개의 토큰까지 채워지고, 그 결과 N개의 요청이 즉시 들어올 수 있습니다. 이는 가끔 발생하는 버스트를 허용할 수 있는 API에 적합합니다. 매개변수는 용량(버스트 크기)과 보충 속도 두 가지입니다.

import time

class TokenBucket:
    def __init__(self, capacity, refill_rate):
        self.capacity = capacity       # max tokens (burst size)
        self.refill_rate = refill_rate # tokens added per second
        self.tokens = capacity         # start full
        self.last_refill = time.time()

    def allow(self):
        now = time.time()
        elapsed = now - self.last_refill
        # Refill tokens based on elapsed time
        self.tokens = min(self.capacity,
                          self.tokens + elapsed * self.refill_rate)
        self.last_refill = now
        if self.tokens >= 1:
            self.tokens -= 1
            return True    # request allowed
        return False       # rate limited

bucket = TokenBucket(capacity=5, refill_rate=2)  # 2 tokens/sec, burst=5
for i in range(8):
    allowed = bucket.allow()
    print(f'Request {i+1}: {"ALLOWED" if allowed else "REJECTED"} (tokens={bucket.tokens:.1f})')
    time.sleep(0.1)  # 0.1s between requests

요청률 제한 알고리즘 2: 슬라이딩 윈도 로그

슬라이딩 윈도 로그는 모든 요청의 타임스탬프를 정렬 집합에 저장합니다. 새 요청마다 윈도 시작 시점보다 오래된 타임스탬프를 remove한 다음, 남은 타임스탬프 수가 제한보다 작은지 확인합니다. 작으면 현재 타임스탬프를 추가하고 allow하며, 그렇지 않으면 거부합니다.

이 방식은 정확합니다. 지난 N초 동안 발생한 요청 수를 정확히 계산합니다. 대신 메모리 사용량이 높다는 단점이 있습니다(사용자별 요청마다 항목 하나). 사용자 10만 명을 대상으로 분당 1000건을 제한하면 최악의 경우 로그 항목이 1억 개가 됩니다. 샤딩과 함께 사용하지 않는 한 매우 높은 트래픽에는 적합하지 않습니다.

import time
from collections import deque

class SlidingWindowLog:
    def __init__(self, limit, window_seconds):
        self.limit = limit
        self.window = window_seconds
        self.logs = {}     # user_id -> deque of timestamps

    def allow(self, user_id):
        now = time.time()
        if user_id not in self.logs:
            self.logs[user_id] = deque()
        log = self.logs[user_id]
        window_start = now - self.window
        # Remove expired timestamps
        while log and log[0] <= window_start:
            log.popleft()
        # Check limit
        if len(log) < self.limit:
            log.append(now)
            return True
        return False

limiter = SlidingWindowLog(limit=3, window_seconds=10)
for i in range(5):
    allowed = limiter.allow('user123')
    print(f'Request {i+1}: {"ALLOWED" if allowed else "REJECTED"}')
    time.sleep(0.5)

요청률 제한 알고리즘 3: 슬라이딩 윈도 카운터

슬라이딩 윈도 카운터는 현재 분과 이전 분이라는 두 버킷을 사용하고, 현재 분이 얼마나 진행되었는지에 따라 가중치를 적용하여 슬라이딩 윈도를 근사합니다. 이를 통해 사용자당 메모리를 O(requests)에서 O(1)로 줄이면서 정확한 슬라이딩 윈도 카운트에 가깝게 계산할 수 있습니다.

공식: estimated_count = prev_count × (1 - fraction_of_window_elapsed) + curr_count. 추정된 수가 제한을 초과하면 거부합니다. 이는 사용자당 메모리가 O(1)이고 정확도가 높기 때문에 클라우드플레어와 콩이 대규모 환경에서 사용하는 알고리즘입니다.

import time
import math

class SlidingWindowCounter:
    def __init__(self, limit, window_seconds=60):
        self.limit = limit
        self.window = window_seconds
        self.buckets = {}   # user_id -> {prev_count, curr_count, curr_window_start}

    def allow(self, user_id):
        now = time.time()
        window_start = int(now // self.window) * self.window

        if user_id not in self.buckets or self.buckets[user_id]['window'] < window_start - self.window:
            self.buckets[user_id] = {'prev': 0, 'curr': 0, 'window': window_start}
        elif self.buckets[user_id]['window'] < window_start:
            self.buckets[user_id] = {'prev': self.buckets[user_id]['curr'], 'curr': 0, 'window': window_start}

        b = self.buckets[user_id]
        fraction = (now - window_start) / self.window
        estimated = b['prev'] * (1 - fraction) + b['curr']

        if estimated < self.limit:
            b['curr'] += 1
            return True
        return False

limiter = SlidingWindowCounter(limit=5, window_seconds=10)
for i in range(7):
    print(f'Request {i+1}: {"OK" if limiter.allow("user1") else "RATE LIMITED"}')
    time.sleep(0.3)

레디스를 사용한 분산 요청률 제한

여러 애플리케이션 서버가 있는 분산 시스템에서는 요청률 제한을 중앙 집중식으로 처리해야 합니다. 그렇지 않으면 각 서버가 자체 카운트를 추적하여 제한이 사실상 서버 수만큼 늘어나기 때문입니다. 원자적 연산을 지원하는 레디스가 표준적인 해결책입니다. 고정 윈도 카운터에는 INCR과 EXPIRE를 사용하고, 슬라이딩 윈도 로그에는 ZADD와 ZCOUNT를 사용합니다.

루아 스크립트 방식은 여러 레디스 연산을 원자적으로 처리하여 두 서버가 제한 바로 아래에서 동시에 증가시킬 때 발생하는 경쟁 조건을 방지합니다. 레디스는 루아 스크립트를 하나의 명령으로 처리하므로 분산 잠금 없이도 원자성이 보장됩니다.

# Distributed rate limiting with Redis (pseudocode / simulation)

# Fixed window counter using Redis INCR + EXPIRE
def redis_fixed_window(redis_client, user_id, limit, window_sec):
    key = f'rl:{user_id}:{int(time.time() // window_sec)}'
    count = redis_client.incr(key)          # atomic increment
    if count == 1:
        redis_client.expire(key, window_sec)  # set TTL on first request
    return count <= limit

# Sliding window with sorted set
def redis_sliding_window(redis_client, user_id, limit, window_sec):
    now = time.time()
    key = f'rl:{user_id}'
    # Remove old entries, count recent, add current
    # Atomic with Lua: multi-step operation
    lua_script = '''
    local key = KEYS[1]
    local now = ARGV[1]
    local window = ARGV[2]
    local limit = ARGV[3]
    redis.call('ZREMRANGEBYSCORE', key, '-inf', now - window)
    local count = redis.call('ZCARD', key)
    if count < tonumber(limit) then
        redis.call('ZADD', key, now, now)
        redis.call('EXPIRE', key, window)
        return 1  -- allowed
    end
    return 0  -- rejected
    '''
    print('Redis Lua script ensures atomicity across ZREM + ZCARD + ZADD')

트위터 피드 설계: 요구 사항

트위터와 유사한 뉴스 피드 시스템을 설계해 보겠습니다. 기능 요구 사항은 사용자가 최대 280자의 트윗을 게시하고, 다른 사용자를 팔로우하며, 팔로우하는 사람들의 트윗을 최신순으로 정렬된 피드에서 볼 수 있어야 한다는 것입니다. 비기능 요구 사항은 일일 활성 사용자 3억 명, 하루 5억 개 트윗, 2초 이내에 로드되는 피드, 약 100:1의 읽기:쓰기 비율입니다.

용량 추정치는 다음과 같습니다. 하루 5억 개 트윗 ÷ 86400 ≈ 초당 5800개 트윗입니다. 읽기는 초당 약 58만 건입니다. 트윗 하나는 약 300바이트이므로 5억 × 300바이트 = 하루 150GB의 새로운 트윗 저장 공간이 필요합니다. 피드 집계가 핵심 엔지니어링 과제입니다.

# Twitter feed requirements and estimates
reqs = {
    'Functional': [
        'Post tweet (text, image, video)',
        'Follow/unfollow users',
        'View home feed (tweets from followees, newest first)',
        'View user timeline (all tweets by one user)',
        'Like and retweet',
        'Search tweets (basic keyword)',
    ],
    'Non-functional': [
        '300M DAU, 500M tweets/day => 5800 writes/sec',
        '100:1 read:write => 580K feed reads/sec',
        'Feed load < 2 seconds (p95)',
        '99.99% availability',
        'Tweets retained indefinitely (tweets never deleted by default)',
    ],
    'Estimates': [
        'Storage: 500M tweets * 300B = 150 GB/day, 54 TB/year',
        'Media: separate object store (S3), CDN-served',
        'Feed cache: 300M users * top-100-tweets * 100B = 3 TB (hot feeds in Redis)',
    ],
}
for category, items in reqs.items():
    print(f'{category}:')
    for item in items: print(f'  - {item}')
    print()

쓰기 시 팬아웃: 미리 계산된 피드

쓰기 시 팬아웃에서는 사용자 A가 트윗을 게시할 때 시스템이 즉시 모든 팔로워의 피드에 해당 트윗을 분배합니다. 팔로워가 피드를 요청하면 이미 레디스에 미리 계산되어 저장되어 있으므로, 피드 크기를 k라고 할 때 O(k)인 간단한 레디스 목록 읽기만 수행하면 됩니다(일반적으로 트윗 1000개로 제한).

문제는 수백만 명의 팔로워를 보유한 유명인이 대규모 팬아웃 연산을 만든다는 것입니다. 저스틴 비버가 트윗 하나를 게시하면 1억 명이 넘는 팔로워의 피드에 동시에 기록해야 합니다. 이는 트위터가 실제로 겪었고 ‘유명인 문제’라고 부른 문제입니다. 쓰기 팬아웃 서비스는 이러한 급증을 처리할 수 있도록 비동기 및 큐 기반으로 동작해야 합니다.

# Fan-out on write (push model)
fan_out_steps = [
    '1. User posts tweet => write to tweets table (source of truth)',
    '2. Publish event to message queue (Kafka topic: tweet-created)',
    '3. Fan-out workers consume from queue:',
    '   a. Fetch list of followers from follows table',
    '   b. For each follower: LPUSH feed:{follower_id} tweet_id',
    '   c. Trim feed to last 1000 tweets: LTRIM feed:{follower_id} 0 999',
    '4. Feed read: LRANGE feed:{user_id} 0 99 => hydrate tweet_ids => response',
]
for step in fan_out_steps:
    print(step)

print('\nPros:')
print('  - Feed reads are O(1): just read from Redis list')
print('  - Feed is always sorted by recency automatically')
print('\nCons:')
print('  - Celebrities with 100M followers => 100M Redis writes per tweet')
print('  - Fan-out lag: followers may see tweet 10-30 seconds late at peak')
print('  - Inactive users waste Redis storage for precomputed feeds')

하이브리드 팬아웃: 유명인 문제 해결

하이브리드 방식은 일반 사용자에게는 쓰기 시 팬아웃을 사용하고 유명인에게는 읽기 시 팬아웃을 사용합니다. 팔로워 수가 기준(예: 100만 명)을 초과하면 해당 사용자를 유명인으로 분류합니다. 일반 사용자의 경우 게시 시점에 모든 팔로워의 피드로 트윗을 전송합니다. 유명인의 경우 트윗을 NOT 전송하고, 팔로워가 피드를 읽을 때 시스템이 유명인의 최근 트윗을 가져와 미리 계산된 피드와 병합합니다.

이 하이브리드 모델은 트위터가 실제로 사용하는 방식과 유사합니다. 유명인은 트윗을 자주 게시하지 않고 병합 비용도 O(f)이므로 병합 단계가 빠릅니다. 여기서 f는 사용자가 팔로우하는 유명인 계정 수이며, 일반적으로 작습니다.

# Hybrid fan-out implementation sketch
CELEBRITY_THRESHOLD = 1_000_000   # followers > 1M => celebrity

def on_post_tweet(user_id, tweet_id, follower_count):
    if follower_count <= CELEBRITY_THRESHOLD:
        # Fan-out to all followers (async via Kafka)
        print(f'User {user_id}: fan-out tweet {tweet_id} to {follower_count} followers')
        # => queue to fan-out workers
    else:
        print(f'Celebrity {user_id}: tweet {tweet_id} stored in timeline only')
        # => only write to tweets table + user timeline
        # => followers get it on demand when reading feed

def get_home_feed(user_id, followees):
    # 1. Get precomputed feed (fan-out on write tweets)
    precomputed = f'LRANGE feed:{user_id} 0 499'   # up to 500 tweets

    # 2. Find celebrity followees
    celebrity_followees = [u for u in followees if is_celebrity(u)]

    # 3. Fetch recent tweets from celebrities (fan-out on read)
    celebrity_tweets = []
    for celeb in celebrity_followees:
        tweets = f'GET tweets WHERE user_id={celeb} ORDER BY created_at DESC LIMIT 20'
        celebrity_tweets.extend(tweets)

    # 4. Merge and sort by recency
    combined = merge_and_sort(precomputed, celebrity_tweets)
    return combined[:100]

print('on_post_tweet for regular user:')
on_post_tweet('user123', 'tweet_abc', 500)
print('on_post_tweet for celebrity:')
on_post_tweet('celebrity456', 'tweet_xyz', 50_000_000)

트위터 피드: 전체 아키텍처

완전한 트위터 피드 아키텍처는 여러 시스템을 결합합니다.

  • 트윗 서비스: 트윗을 카산드라에 기록합니다(높은 쓰기 처리량, 시계열 데이터)
  • 팬아웃 서비스: 트윗 ID를 레디스의 팔로워 피드로 전송하는 비동기 작업자(카프카 소비자)
  • 피드 서비스: 레디스 피드에서 읽고, 트윗 ID를 전체 트윗 객체로 채우며, 유명인의 트윗을 병합합니다
  • 팔로우 서비스: 그래프 데이터베이스 또는 샤딩된 SQL에서 소셜 그래프(누가 누구를 팔로우하는지)를 관리합니다
  • 타임라인 서비스: 사용자가 작성한 트윗을 제공합니다(홈 피드와 별도)
# Twitter architecture summary
architecture = '''
[User] --> [API Gateway + Load Balancer]
                |
    +-----------+-----------+
    |           |           |
[Tweet Svc] [Feed Svc]  [Follow Svc]
    |           |           |
[Cassandra] [Redis Feeds] [Graph DB]
    |           |
[Kafka] <-- [Fan-out
    |        Workers]
[S3 + CDN]  (tweet_ids
(media)      => follower
             feed lists)

Key design choices:
- Tweets stored in Cassandra (PRIMARY KEY (user_id, created_at))
- Feed stored in Redis as list of tweet_ids per user (LPUSH/LTRIM/LRANGE)
- Fan-out via Kafka + workers (decoupled, retryable, scalable)
- Hybrid: regular users = push; celebrities = pull-on-read
- Hydration: tweet_ids -> full tweet objects via Cassandra read
'''
print(architecture)

요청률 제한기 헤더와 오류 응답

잘 설계된 요청률 제한기는 HTTP 응답 헤더를 통해 클라이언트에 제한을 알립니다. 이를 통해 클라이언트는 재시도 대기 시간 로직을 구현하고 대시보드에 사용량을 표시할 수 있습니다. 표준 헤더는 다음과 같습니다.

  • X-RateLimit-Limit: 해당 윈도에서 허용되는 최대 요청 수
  • X-RateLimit-Remaining: 현재 윈도에 남은 요청 수
  • X-RateLimit-Reset: 윈도가 초기화되는 시점의 유닉스 타임스탬프
  • Retry-After: 다시 시도하기 전에 기다릴 시간(429 응답일 때)

요청률 제한 응답에 사용하는 HTTP 상태 코드는 429 요청이 너무 많음입니다.

# Rate limit response headers
def build_rate_limit_headers(limit, remaining, reset_timestamp, retry_after=None):
    headers = {
        'X-RateLimit-Limit': str(limit),
        'X-RateLimit-Remaining': str(max(0, remaining)),
        'X-RateLimit-Reset': str(int(reset_timestamp)),
    }
    if retry_after is not None:
        headers['Retry-After'] = str(retry_after)
    return headers

import time

# Simulated response for allowed request
headers = build_rate_limit_headers(
    limit=100,
    remaining=73,
    reset_timestamp=time.time() + 45
)
print('Allowed request headers:')
for k, v in headers.items():
    print(f'  {k}: {v}')

# Rate limited response
headers_429 = build_rate_limit_headers(
    limit=100,
    remaining=0,
    reset_timestamp=time.time() + 30,
    retry_after=30
)
print('\n429 Too Many Requests headers:')
for k, v in headers_429.items():
    print(f'  {k}: {v}')

속도 제한 알고리즘 비교

면접에서 알고리즘을 선택하는 데 도움이 되도록 모든 속도 제한 알고리즘을 요약하여 비교합니다:

  • 토큰 버킷: 버스트를 허용하고 토큰을 일정한 속도로 보충합니다. 가끔 버스트가 허용되는 애플리케이션 프로그래밍 인터페이스에 적합합니다(가장 일반적인 선택).
  • 누수 버킷: 버스트와 관계없이 고정된 출력 속도로 요청을 처리합니다. 트래픽을 일정한 흐름으로 조절하는 데 적합합니다.
  • 고정 윈도 카운터: 가장 단순하며 공간 복잡도 O(1)입니다. 문제는 윈도 경계에서 제한량의 두 배에 해당하는 버스트가 발생한다는 것입니다(예: 11:59에 100개 + 12:00에 100개).
  • 슬라이딩 윈도 로그: 가장 정확하며 경계에서 급증하지 않습니다. 문제는 요청 수에 비례하는 메모리가 필요하다는 것입니다.
  • 슬라이딩 윈도 카운터: O(1) 공간으로 슬라이딩 로그를 근사합니다. 클라우드플레어에서 사용합니다.
# Algorithm comparison matrix
comparison = [
    ('Token Bucket',          'Allows bursts',     'O(1)',         'Most APIs, default choice'),
    ('Leaky Bucket',          'Smooth output rate', 'O(1)',         'Traffic shaping, message queues'),
    ('Fixed Window Counter',  'Very simple',        'O(1)',         'Low-traffic, approximate OK'),
    ('Sliding Window Log',    'Most accurate',      'O(requests)', 'High-accuracy, low traffic'),
    ('Sliding Window Counter','Approximate+fast',   'O(1)',         'High-traffic, Cloudflare-style'),
]
print(f'{'Algorithm':30s} {'Burst Handling':20s} {'Memory':15s} {'Use Case'}')
print('-'*85)
for name, burst, mem, use in comparison:
    print(f'{name:30s} {burst:20s} {mem:15s} {use}')

빠른 확인

이 수업에서 다룬 자료구조 및 알고리즘 & 코딩 면접 준비 개념에 대한 이해도를 확인해 보세요.

수업 요약

이 수업에서는 속도 제한기가 토큰 버킷(버스트 허용), 슬라이딩 윈도 카운터(O(1) 메모리) 또는 슬라이딩 윈도 로그(가장 정확함)를 사용하여 요청 속도를 제어하며, 레디스의 원자적 연산으로 분산 속도 제한을 구현할 수 있다는 점과, 트위터 피드가 쓰기 시 팬아웃을 사용하여 빠른 읽기를 위해 팔로워 피드를 레디스에 미리 계산해 저장하고, 유명인 계정에는 대규모 쓰기 증폭을 피하기 위해 하이브리드 풀 모델을 사용한다는 점을 배웠습니다. 다음으로는 문제 신호를 문제를 가장 빠르게 해결하는 알고리즘 패턴에 대응시키는 패턴 인식 요약표와 함께 핵심 과정 섹션에 들어갑니다.

자주 묻는 질문

“속도 제한기 설계와 트위터 피드 설계” 강의는 무료인가요?

네 — “속도 제한기 설계와 트위터 피드 설계” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Coding Interview Prep 강의 전체를 잠금 해제할 수 있습니다. Coding Interview Prep 강의에는 총 4개의 강의가 포함되어 있습니다.

“속도 제한기 설계와 트위터 피드 설계”에서 뭘 배우나요?

두 가지 대표적인 설계 문제에 프레임워크를 적용합니다. 토큰 버킷 및 슬라이딩 윈도우 속도 제한과 쓰기 시 팬아웃 대 읽기 시 팬아웃 뉴스 피드입니다. 브라우저에서 직접 실행하는 실습 코드로 Coding Interview Prep을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Coding Interview Prep을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Coding Interview Prep은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“속도 제한기 설계와 트위터 피드 설계” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Coding Interview Prep 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Coding Interview Prep 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 시스템 설계 면접 프레임워크
  2. 확장 가능한 데이터 저장소: SQL과 NoSQL
  3. 캐싱, CDN과 부하 분산
  4. 속도 제한기 설계와 트위터 피드 설계
← Coding Interview Prep(으)로 돌아가기