11. 뉴스 피드
Last updated
Last updated
트위터나 인스타그램처럼 누군가 게시글을 올리고 이를 다른 사람이 확인할 수 있는 뉴스 피드를 설계해야 한다.
사용자가 피드를 포스트하면 캐시와 데이터베이스에 저장해야 한다. 새 포스팅은 친구의 뉴스 피드에 전송되야 한다.
사용자의 요청을 로드밸런서가 웹 서버들에 분배하고, 웹 서버에서는 내부 서비스들로 요청을 중계하게 된다.
포스팅 저장 서비스는 저장소에 포스팅 정보를 저장하고, 포스팅 전송 서비스는 친구의 뉴스 피드를 캐싱해둔 저장소에 포스팅을 저장한다. 알림 서비스는 새 포스팅이 올라왔음을 사용자의 친구에게 알려야 한다.
클라이언트로부터 요청을 받으며, 인증이나 처리율 제한의 기능도 수행한다.
스팸이나 유해 컨텐츠를 방지하기 위해 특정 기간동안 한 사용자가 올릴 수 있는 포스트 수에 제한을 걸어두어야 한다.
포스팅 전송 서비스 아키텍쳐를 자세히 설계하면 다음과 같다.
그래프 데이터베이스에서 친구 ID 목록을 가져온다.
사용자 정보 캐시에서 친구들의 정보를 가져온다. 특정 사용자의 게시글을 뉴스 피드에서 보이지 않게 mute 하는 등의 속성을 반영하기 위함이다.
친구 목록과 새 포스트의 ID를 메시지 큐에 넣는다.
포스팅 전송 작업 서버는 메시지 큐의 데이터를 읽어 각 사용자의 뉴스 피드 캐시에 데이터를 추가한다.
뉴스 피드 캐시는 <포스트 ID, 사용자 ID> 엔트리를 보관하는 매핑 테이블이다. 캐시에 저장되는 데이터이므로 메모리 크기를 적절하게 유지하기 위해 모든 데이터를 저장하지 않고 ID 정보만 저장한다. 또한, 저장할 수 있는 엔트리의 개수도 제한하도록 한다.
특정 사용자가 새 포스팅을 올렸을 때 해당 사용자의 친구들에게 전달해야 한다. 이 과정을 팬아웃이라고 부른다.
쓰기 시점의 팬아웃 (fanout on write)
Push 모델이라고도 한다.
포스팅을 기록하는 시점에 친구 목록에 있는 사용자들의 뉴스 피드를 갱신한다.
뉴스 피드를 읽는 데 드는 시간이 짧아진다.
친구가 많은 사용자의 경우 친구 목록을 가져와 모든 친구의 뉴스 피드 갱신에 많은 시간이 소요될 수 있다. 즉, hotkey 문제가 발생한다.
서비스를 자주 이용하지 않는 사용자 피드까지 갱신해야 하므로 자원 낭비가 발생할 수 있다.
읽기 시점의 팬아웃 (fanout on read)
Pull 모델이라고도 한다.
사용자가 뉴스 피드를 읽는 시점에 뉴스 피드를 갱신한다.
서비스를 자주 이용하지 않는 사용자는 로그인하기전까지 어떠한 컴퓨팅 자원도 소모하지 않으므로 효율적이다.
hotkey 문제가 발생하지 않는다.
다만 뉴스 피드 읽기에 많은 시간이 소요될 수 있다.
절충안
대부분의 사용자에 대해 Push 모델을 사용하고, 친구나 팔로워가 많은 사용자의 경우 Pull 모델을 사용한다.
모든 친구의 포스팅을 시간 역순으로 모아 뉴스 피드를 만들 수 있다.
사용자가 뉴스 피드 조회를 요청하면 캐시로부터 피드 ID를 조회 후 뉴스 피드 서비스로부터 포스팅을 조회한다.
웹 서버는 피드를 가져오기 위해 뉴스 피드 서비스를 호출한다.
뉴스 피드 서비스는 뉴스 피드 캐시에서 가져온 포스트 ID를 기반으로 완전한 뉴스 피드를 만들어 클라이언트에게 반환한다.
캐시는 다음과 같이 5계층으로 나누어 저장할 수 있다.