11장은 뉴스 피드 시스템 설계에 대해서 다루고 있다.
뉴스 피드는 간단하게.. 음 인스타 피드랑 비슷하다고 생각하면 좋다.
대충 요런 느낌.
유명한 면접 단골 질문이라고 한다. 뉴스 피드 시스템 설계는,
1단계 문제 이해 및 설계 범위 확정
시스템 설계 면접에서 제일 중요한 건 무엇일까?
바로 요구사항 확정이다.
책에서는 다음과 같은 요구사항을 제시하고 있다.
- Cross Platform이 지원되야 한다.
- 뉴스 피드 페이지에, 새로운 스토리를 올릴 수 있고 다른 친구들의 스토리도 볼 수 있어야 한다.(instagram)
- 뉴스 피드에 표시되는 정렬 기준은, 간단하게 시간 흐름 역순으로 표시된다.
- 한 명은 최대 친구 5000명을 가질 수 있다.
- 트래픽 규모는 매일 천만 명이 방문한다.
- 스토리에 이미지나, 미디어 파일이 포함될 수 있다.
2단계 개략적 설계안 제시 및 동의 구하기
위 요구사항에 맞춰, 뉴스 피드 시스템의 주요 기능은 다음으로 요약된다.
- 피드 발행 스토리를 포스팅하면, 해당 데이터를 캐시와 데이터베이스에 저장한다. 새 포스팅은 친구의 뉴스 피드에도 전송된다.
- 뉴스 피드 생성
뉴스 피드는 모든 친구의 포스팅을 시간 흐름 역순으로 모아서 만든다고 가정.
주요 API는 다음과 같다.
API
POST /v1/me/feed [피드 발행]
Prameter:
- Body : 포스팅 내용
- Authorization 헤더 : API 호출을 위해 인증 인가로서 사용된다.
GET /v1/me/feed [피드 읽기]
Parameter:
- Authorization 헤더 : API 호출을 위해 인증 인가로서 사용된다.
피드 발행
시스템의 개략적 형태는 아래와 같다.
- 사용자 : 포스팅을 올리는 주체
- 로드밸런서 : 트래픽을 각 웹 서버로 분산한다.
- 웹 서버 : HTTP 요청을 내부 서비스로 중계한다.
- 포스팅 저장 서비스 : 새 포스팅을 데이터베이스와 캐시에 저장한다.
- 포스팅 전송 서비스 : 새 포스팅을 뉴스 피드에 푸시한다. 뉴스 피드 데이터는 캐시에 보관하여 빠르게 읽어갈 수 있도록 한다.
- 알림 서비스 : 친구들에게 새 포스팅이 올라왔음을 알리거나, 푸시 알람을 보낸다.
뉴스 피드 생성
사용자가 보는 뉴스 피드는 다음과 같이 생성된다.
- 사용자 : 뉴스 피드를 읽는 주체다.
- 로드 밸랜서 : 트래픽을 웹 서버로 분산한다.
- 웹 서버 : 트래픽을 뉴스 피드 서비스로 보낸다.
- 뉴스 피드 서비스 : 캐시에서 뉴스 피드를 가져오는 서비스다.
- 뉴스 피드 캐시 : 뉴스 피드를 렌더링 할 때 필요한 피드 ID를 보관한다.
3단계 상세 설계
뉴스 피드 발행에서 상세 흐름은 웹 서버와 전송 서비스에 초점이 맞춰진다.
- 웹 서버
웹 서버는 클라이언트와 통신할 뿐 아니라, 인증이나 처리율 제한 등의 기능도 수행한다. 적법한 유저인지, 스팸이나 유해 콘텐츠를 막는 역할이나 한 사용자가 올릴 수 있는 포스팅 수 제한을 수행한다.
- 포스팅 전송(팬아웃) 서비스
- 쓰기 시점에 팬아웃하는 모델
- 뉴스 피드가 실시간으로 갱신된다.
- 새 포스팅이 기록되는 순간 뉴스 피드가 생신되므로 뉴스 피드를 읽는데 드는 시간이 짧아진다.
- 친구가 많은 사용자의 경우 친구 목록을 가져오고 그 목록에 있는 사용자 모두의 뉴스 피드를 갱신하는데 많은 리소스가 소요될 수 있다. 핫키라고 부르는 문제다.
- 읽기 시점에 팬아웃하는 모델
- 비활성화된 사용자, 또는 서비스에 거의 로그인하지 않는 사용자의 경우에는 이 모델이 유리하다. 리소스 낭비를 줄일 수 있다.
- 데이터를 친구 각각에 푸시하지 않기 때문에 핫키 문제도 생기지 않는다.
- 뉴스 피드를 읽는데 많은 시간이 소요되어 사용자 경험이 안좋아질 수 있다.
- 그래프 데이터베이스에서 친구 ID 목록을 가져온다.
- 사용자 정보 캐시에서 친구들의 정보를 가져온다. 친구들의 정보는 사용자 설정에 따르도록 한다.
- 친구 목록과 새 스토리의 포스팅 ID를 메세지 큐에 넣는다.
- 팬아웃 작업 서버가 메세지 큐에서 데이터를 꺼내어 뉴스 피드 데이터를 뉴스 피드 캐시에 넣는다. 뉴스 피드 캐시는 <postId, userId>의 순서 쌍을 보관하는 매핑 테이블이라고 볼 수 있다. 따라서, 새로운 포스팅이 만들어질 때마다 레코드가 추가 된다. 테이블에는 Id만 저장하며 모든 데이터를 저장하는 것은 메모리가 낭비되기 때문이다. 또한, 캐시 메모리 크기를 적정선을 유지하며 지나치게 커지면 조정시키도록 한다. 보통은 최신 피드만을 확인하기 때문에 사용자가 보고싶은 것과 캐시 데이터가 다른 캐시 미스가 일어날 확률이 적다
팬아웃은, 어떤 사용자의 새 포스팅을 사용자와 친구 관계에 있는 모든 사용자에게 전달하는 과정이다. 팬아웃은 두 가지 모델이 있는데, 하나는 post(write) 시점에 팬아웃하는 모델이고, 다른 하나는 읽는(read) 시점에 팬아웃하는 모델이다.
포스팅이 완료되면 바로 해당 사용자의 캐시에 해당 포스팅을 기록하는 방식이다.
Pros
Cons
피드를 읽어야 하는 시점에 피드를 갱신한다. 요청 기반(on-demand) 모델이다. 사용자가 홈페이지에 진입하거나, 타임라인을 새롭게 로딩하는 시점에 포스트를 가져온다.
Pros
Cons
본 11장의 설계안은 두 모델을 적절히 취합하여 구성한다.
뉴스 피드를 빠르게 가져올 수 있도록 하는 것은 아주 중요하기 때문에, 대부분 사용자에게 푸시 모델을 사용한다.
친구나 팔로워가 많은 사람의 경우 팔로워에게 해당 사용자의 포스팅을 필요한 순간(on-demand)에 가져가도록 읽어 들이는 시점에 하여 과부하를 줄인다.
아울러, 안정 해시를 통해 요청과 데이터를 보다 더 고르게 분산하여 핫키 문제를 줄일 것이다.
다음은 이전 전체 설계 모델 중 팬아웃만을 따로 떼어낸 것이다.
적절히 두 모델의 장단점을 취합한 위 팬아웃 서비스는 다음과 같이 동작한다.
피드 읽기 흐름 상세 설계
이미지와 비디오의 경우 CDN에 저장하여 빨리 읽도록 하고,
클라이언트가 뉴스 피드를 어떻게 읽는지 살펴보면,
- 사용자가 뉴스 피드를 읽으려는 요청을 보낸다.
- 로드 밸런서가 요청을 웹 서버 가운데 하나로 보낸다.
- 웹 서버는 피드를 가져오기 위해 뉴스 피드 서비스를 호출한다.
- 뉴스 피드 서비스는 뉴스 피드 캐시에 포함된 postId 목록을 가져온다.
- 뉴스 피드를 만들어 클라이언트로 JSON 형태로 보낸다.
캐시 구조
캐시는 뉴스 피드 시스템의 핵심 컴포넌트다. 본 설계안은 총 5개의 layer로 계층을 나눠놨다.
- 뉴스 피드 : 뉴스 피드 ID를 보관한다.
- 콘텐츠 : 포스팅 데이터를 보관한다. 인기 콘텐츠는 따로 보관한다.
- 소셜 그래프 : 사용자 간 관계 정보를 보관한다.
- 행동 : 포스팅에 대한 사용자의 행위에 관한 정보를 보관한다. 포스팅에 대한 좋아요, 답글 등이 이에 해당한다.
- 횟수 : 좋아요 횟수, 응답 수, 팔로어 수, 팔로잉 수 등의 정보를 보관한다.
4단계 마무리
추가적으로 고민할 점은 다음과 같다.
- 데이터베이스 규모 확장
- Scale up VS Scale out
- SQL VS NoSQL
- Master-Slave 다중화
- replica에 대한 읽기 연산
- 일관성 모델
- 데이터베이스 샤딩
- Web Tier Stateless 하게 운영
- 많은 데이터 캐시 최적화
- 메세지 큐를 통한 컴포넌트간 결합도 낮추기
- 핵심 메트릭에 대한 모니터링
Share article