[가상 면접 사례로 배우는 대규모 시스템 설계 기초] 11. 뉴스 피드 시스템 설계

2023. 8. 26. 06:23Dev/System Design

반응형
  1. 요구사항
  2. 개략적 설계
    1. 피드 발행
    2. 뉴스 피드 조회
  3. 상세 설계
    1. 피드 발행 상세 설계
    2. 뉴스피드 조회 상세 설계
    3. 캐시 구조
  4. 마무리

뉴스피드 시스템은 인스타그램이나 트위터와 같이 홈페이지 중앙에서 지속적으로 업데이트되는 포스팅 시스템을 말합니다.

뉴스피드 시스템을 설계하는데에서 고민해야하는 부분은 아래와 같습니다.

  1. 내가 작성한 포스팅을 나를 팔로워한 사용자들에게 발행하는 것
  2. 팔로잉하고 있는 사용자의 피드를 나의 뉴스피드에서 읽는 것

간단하게 표현하자면, 데이터를 쓰는 파트 그리고 데이터를 읽는 파트에 대해 설계하면 됩니다.


1. 요구사항

뉴스피드 시스템을 설계하기 위해 필요한 요구사항들을 생각해봅니다.

  1. 모바일, 웹 모두 지원
  2. 뉴스 피드
    • 내가 직접 포스팅을 올릴수도 있고
    • 팔로잉하고 있는 사용자가 올린 포스팅을 뉴스피드에서 볼 수 있어야 한다.
  3. 스토리 정렬 방식?
    • 생성일시 내림차순으로
  4. 한명의 사용자가 가질 수 있는 최대 친구수는?
  5. 트래픽 규모는?
  6. 피드에 올릴 수 있는 데이터
    • 단순 문자열 뿐만 아니라 이미지나 미디어파일(비디오)도 올릴 수 있다.

2. 개략적 설계

요구사항을 파악했으니, 앞서 이야기 했던 2가지 기능에 대해 개략적으로 설계 해봅니다.

  1. 피드 발행 API
    • 내가 포스트를 발행하면
      • 발행한 포스트 내용이 캐시와 데이터베이스에 기록되고
      • 친구들의 뉴스피드에도 전송된다.
    • POST /v1/me/feed
    • POST {{server}}/v1/me/feed
      Authorization: Bearer {{accessToken}}
      
      {
        "message": "안녕하세요. 반가워요"
      }
      
  2. 뉴스 피드 조회 API
    • 내가 팔로잉한 사용자들의 포스팅을 시간 역순으로 모아서 뉴스피드를 조회합니다
    • GET /v1/me/feed
    • GET {{server}}/v1/me/feed
      Authorization: Bearer {{accessToken}}
      

2.1. 피드 발행

02-1

피드 발행 API를 이용하여 사용자는 모바일 앱이나 웹 브라우저에서 포스팅을 발행합니다.
웹서버는 로드밸런서를 통해 트래픽을 분산합니다.

포스팅은 DB와 캐시에 저장되고,
저장 후에는 fanout service(포스팅 전송 서비스)를 통해 새 포스팅을 친구의 뉴스피드에 push합니다.

그 후, 알림서비스로 푸시 알림을 보냅니다.


2.2. 뉴스 피드 조회

02-2

사용자(client)가 뉴스 피드 조회 API를 요청하면
마찬가지로 로드밸런서를 통해 웹서버를 분산처리하고, 웹서버에서는 뉴스피드 서비스를 호출합니다.
뉴스피드 서비스는 뉴스피드 캐시로부터 피드 정보를 읽어들입니다.
읽어들인 정보를 사용자에게 반환합니다.


3. 상세 설계

3.1. 피드 발행 상세 설계

위에서 설명했었던 피드 발행 부분에서 웹서버와 fanout service(포스팅 전송 서비스)를 더 상세하게 설계해봅니다.

02-3

3.1.1. 웹서버

클라이언트와 통신하는 웹서버에 인증과 처리율 제한 설정을 하여 보안을 높입니다.

  • 피드 발행과 뉴스 피드 조회시 유효한 인증 토큰을 확인합니다.
    • Authorization 헤더가 유효할 경우에만 API를 호출할 수 있도록 인증처리를 합니다.
  • 특정기간동안 한 사용자가 올릴수 있는 포스팅의 수를 제한합니다.
    • 스팸이나 유해 컨텐츠가 자주 올라오는것을 방지할 수 있습니다.

3.1.2. 팬아웃(포스팅 전송) 서비스

사용자 A가 새 포스팅을 올렸을 때, A의 팔로워들에게 포스팅을 전달하는 서비스로, 아래와 같이 2가지 방식으로 구성할 수 있습니다.

  1. 쓰기 시점에 포스팅 전송 (= push 모델)
  2. 읽기 시점에 포스팅 전송 (= pull 모델)

push 모델

포스팅을 올릴 때, 관계된 사용자들에게 바로 새 포스팅을 보냅니다.

뉴스피드가 실시간으로 갱신되기 때문에, 뉴스피드를 읽는데 드는 시간이 짧다는 장점이 있습니다.

다만, 유명인사의 경우, 팔로워들의 모든 뉴스피드를 갱신하는데에 많은 시간이 소요될 수 있다는 문제점이 있습니다.(= hotkey)
서비스를 잘 이용하지 않는 사용자의 경우, 실시간으로 피드 갱신을 하기위한 컴퓨팅 자원 낭비가 비효율적입니다.


pull 모델

로그인을 하지 않을 경우에는 컴퓨터 자원을 소모하지 않기 때문에
서비스에 거의 로그인하지 않는 사용자의 경우, 서비스를 이용할 때에만 피드를 가져오는 pull 모델이 더 효율적입니다.
데이터를 필요할 때 가져오기 때문에, 유명인사가 많은 팔로워들에게 포스트를 push하지 않아도 되기 때문에 hot key문제도 생기지 않습니다.

다만, 서비스를 시작하는 시점에 뉴스피드를 읽어오기 때문에 뉴스피드를 읽는데에 많은 시간이 소요될 수 있다는 단점이 있습니다.


push pull 결합 모델

push모델과 pull모델의 장점을 결합합니다.

  • 뉴스피드를 빠르게 읽어들이기 위해 일반 사용자에 대해서는 push 모델을 사용하고
  • 유명인사 같이 팔로워가 많은 사람의 경우, pull모델 방식으로 포스팅을 가져오도록 합니다

이렇게 설정할 경우, hotkey문제도 해결하고, 뉴스피드도 빠르게 읽어들일 수 있습니다.

02-4
  1. (그래프) DB에서 친구 id 목록을 가져오고
  2. 친구 id 목록을 이용하여 캐시에서 친구 정보를 읽어들여셔, 피드 전송 대상 필터링
    • mute설정한 친구 제외나, 친한친구에게만 보내기 등의 기능도 가능합니다.
  3. MQ에 새 포스팅 id와 친구목록id를 넣습니다
  4. 포스팅 전송 서버가 MQ에서 데이터를 꺼내어 뉴스피드 캐시에 데이터를 넣습니다.

Graph DB
수백만/수십억개의 관계를 효과적으로 다루기 위한 데이터베이스
각 노드는 하나 이상의 레이블을 가질 수 있다는 점에서 RDB와 차이가 있고, 이러한 특성에 의해 빅데이터를 다루는 분야에서 효과적으로 활용할 수 있습니다.
Node는 RDB의 row, Label은 RDB의 table에 해당됩니다.


3.2. 뉴스피드 조회 상세 설계

02-5
  1. 사용자가 뉴스 피드 읽기 요청을 보내면
  2. 로드밸런서에 연결된 웹서버중 하나로 요청이 보내지고
  3. 웹서버에서는 뉴스피드 서비스를 호출합니다.
  4. 뉴스피드 서비스에서는 뉴스 피드 캐시로부터 사용자 id, 포스팅 id 목록을 가져오고
  5. 사용자 캐시와 포스트 캐시로부터 데이터를 각각 읽어와서 뉴스피드를 만듭니다.
  6. 뉴스피드는 json형태로 client에게 전송합니다.

이미지나 미디어 컨텐츠는 cdn에 저장하여 빨리 읽을 수 있도록 합니다.


3.3. 캐시 구조

캐시 구조를 아래와같이 제안합니다.

02-6
  • 뉴스 피드
    • post_id, user_id 쌍이 저장됨
  • 컨텐츠
    • 포스팅 데이터를 보관하는 캐시로, 인기 컨텐츠는 별도의 캐시에 보관합니다
  • 소셜 그래프
    • 사용자간의 관계를 보관합니다.
  • 행위
    • 포스팅에서 행해지는 사용자 행위(좋아요, 답글 등)에 대한 정보를 보관합니다
  • 카운터
    • 좋아요, 답글, 팔로워, 팔로잉 등의 count 정보를 보관합니다.

4. 마무리

뉴스피드 시스템 설계도 다른 시스템 설계와 마찬가지로 정답이라는 것은 없고
요구사항이나 제약조건 따라 시스템을 설계하며, 기술의 장단점을 잘 인지하며 타협을 보는 것이 중요한 부분입니다.

뉴스피드 시스템에서도 다른 시스템 설계와 마찬가지로 아래와 같은 부분들을 설계시 고려해볼 수 있습니다.

  • 데이터베이스 규모 확장
  • 많은 데이터를 캐시할 수 있는 방법
  • 여러 데이터 센터를 지원하는 방법
  • 컴포넌트 간의 결합도를 낮추기 위한 Message Queue 활용
728x90
반응형