군만두의 IT 개발 일지

[스터디9] 04. 뉴스 피드 시스템 설계 - 실습2 본문

학습일지/시스템 설계

[스터디9] 04. 뉴스 피드 시스템 설계 - 실습2

mandus 2025. 7. 8. 20:42

목차

    3장. 시스템 설계 면접 공략법

    이전 게시글에 이어 3장에 나온 것처럼 "시스템 설계 면접"을 대비해서 "뉴스 피드 시스템"에 대해서 설계한 아키텍처를 구현하기로 했다.

    3단계 상세 설계

    1) 시스템 목표 및 기능 범위 재확인

    1~2단계에서 정한 요구사항을 바탕으로 시스템이 달성해야 할 구체적인 목표를 다시 정리해보자.

    기본 요구사항

    • DAU: 1,000만 명 (일간 활성 사용자)
    • 친구 관계: 최대 5,000명
    • 플랫폼: 모바일 앱 + 웹 앱 지원
    • 핵심 기능: 포스트 발행, 뉴스 피드 조회 (시간 역순)
    • 미디어: 이미지, 비디오 파일 지원

    아키텍처 설계 방향

    • MSA(마이크로서비스 아키텍처) 기반
    • 포스트 서비스, 피드 서비스, 사용자 서비스 분리
    • 비동기 처리 → 메시지 큐 활용
    • 캐시 전략으로 성능 최적화

    2단계에서 설계한 아키텍처를 바탕으로 다음과 같이 뉴스 피드 시스템의 핵심 영역에 집중하기로 했다.

    1. 피드 발행(Feed Publishing) - 포스트 서비스 중심
    2. 피드 생성(Feed Building) - 피드 서비스 중심
    3. 뉴스 피드 가져오기(Feed Fetching) - 사용자 서비스와 연동

    2) 전체 시스템 아키텍처

    먼저 2단계에서 설계한 MSA 구조를 자세히 그려봤다.

    3) 데이터베이스 설계

    2단계에서 정한 MSA 구조에 맞게 각 서비스별로 데이터베이스를 분리해서 설계했다.

    포스트 서비스 DB (MySQL)

    CREATE TABLE posts (
        post_id BIGINT PRIMARY KEY AUTO_INCREMENT,
        user_id BIGINT NOT NULL,
        content TEXT,
        media_urls JSON,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        
        INDEX idx_user_created (user_id, created_at DESC)
    );

    사용자 서비스 DB (MySQL)

    CREATE TABLE users (
        user_id BIGINT PRIMARY KEY AUTO_INCREMENT,
        username VARCHAR(50) UNIQUE NOT NULL,
        email VARCHAR(100) UNIQUE NOT NULL,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    );
    
    CREATE TABLE friendships (
        user_id BIGINT,
        friend_id BIGINT,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        
        PRIMARY KEY (user_id, friend_id)
    );

    피드 서비스 캐시 (Redis)

    # 사용자별 피드 목록 (포스트 ID만 저장)
    feed:user:{user_id} → [post_id_1, post_id_2, post_id_3, ...]
    
    # 포스트 상세 정보 (한 번만 저장)
    post:{post_id} → {user_id, content, created_at, ...}

    4) 피드 발행(Feed Publishing) 상세 설계

    피드 발행 플로우

    1. 포스트 작성: 사용자가 포스트 작성 요청
    2. 포스트 저장: 포스트 서비스에서 MySQL에 저장
    3. 미디어 처리: 이미지/비디오가 있으면 S3에 업로드
    4. 이벤트 발행: Redis에 "새 포스트 생성됨" 메시지 보냄
    5. 백그라운드 처리: 워커가 메시지를 받아서 친구들 피드 업데이트

    5) 피드 생성(Feed Building) 상세 설계

    팬아웃 모델 선택

    여러가지 찾아보고 친구 수에 따라 구분할 수 있는 하이브리드 모델을 선택했다.

     

    모델 Push 모델 Pull 모델
    동작 피드를 미리 만들어둔다. 요청할 때 피드를 만든다.
    장점 피드를 빠르게 보여줄 수 있다. 인플루언서처럼 친구가 많아도 문제 없다.
    단점 친구가 많은 사람은 처리 시간이 오래 걸린다. 피드를 보여주는 데 시간이 걸린다.
    사용 대상 (친구 수가 적은) 일반 사용자 (친구 수가 많은) 인플루언서

    피드 생성 플로우

    6) 뉴스 피드 가져오기 (Feed Fetching) 상세 설계

    성능 향상을 위해 Redis를 활용한 캐시 전략을 설계했다. 사용자별 피드 목록, 포스트 정보를 캐시에 저장할 것이다.

    피드 조회 플로우

    7) 성능 최적화 방안

    데이터베이스 최적화 - 인덱스 활용

    -- 사용자의 포스트를 빠르게 찾기 위한 인덱스
    CREATE INDEX idx_user_created ON posts(user_id, created_at DESC);
    
    -- 친구 관계를 빠르게 찾기 위한 인덱스
    CREATE INDEX idx_user_friends ON friendships(user_id);

    비동기 처리 - 메시지 큐 활용

    • Redis를 메시지 큐로 사용한다.
    • 포스트 생성과 피드 업데이트를 분리해서 처리한다.
    • 시스템이 느려져도 사용자는 포스트 작성을 빠르게 완료할 수 있다.

    비동기 처리 - 워커 서비스

    • 백그라운드에서 피드 업데이트를 처리한다.
    • 여러 개의 워커를 동시에 실행해서 빠르게 처리한다.

    4단계 마무리

    면접에서 추가로 논의할 수 있는 주제들

    확장성 관련

    • 사용자가 더 많아지면 데이터베이스를 어떻게 나눌 것인가?
    • Redis 메모리가 부족하면 어떻게 할 것인가?
    • 서버가 죽으면 어떻게 복구할 것인가?

    성능 관련

    • 응답 시간을 어떻게 측정하고 개선할 것인가?
    • 피크 시간에 트래픽이 몰리면 어떻게 처리할 것인가?

    기능 확장

    • 실시간 알림은 어떻게 구현할 것인가?
    • 사용자 취향에 맞는 개인화된 피드는 어떻게 만들 것인가?

     

    2단계에서 설계한 MSA 기반 뉴스 피드 시스템(포스트 서비스, 피드 서비스, 사용자 서비스)을 바탕으로 3~4단계를 진행했는데, 생각보다 고려할 점이 많았다.

     

    특히 서비스끼리 어떻게 통신할지, 캐시를 어떻게 활용할지 같은 부분이 중요한 것 같다. 팬아웃 모델 개념도 어려웠는데, 실제로 설계하면서 각 기술들이 왜 필요한지 약간 이해가 됐다. 기술 선택과 아키텍처를 왜 선택했는지를 설명할 수 있도록 잘 준비해야 할 것 같다.

    참고 자료

    1) Vagelis Bisbikis, "Fan-Out and Fan-In Patterns: Building a Personalized Feed in Laravel", 2025.02.10, https://medium.com/@vagelisbisbikis/fan-out-and-fan-in-patterns-building-a-personalized-feed-in-laravel-676515f65e03

     

    이 글은 『 가상 면접 사례로 배우는 대규모 시스템 설계 기초』 책을 학습한 내용을 정리한 것입니다.

    Comments