무한스크롤 페이징 설계 면접 질문: OFFSET이 깊어질수록 깨지는 곳
시스템 디자인 Vol.1 · 10장 「끝없이 내려가는 무한스크롤」에서
이런 화면입니다
피드를 내리고, 내리고, 또 내립니다. 바닥에 닿을 때마다 다음 글이 이어 붙습니다. 전체 글은 10만 건입니다.
그런데 한참 내리다 보면 방금 본 글이 한 번 더 나옵니다. 아주 흔한 버그인데, 원인을 설명하는 지원자는 많지 않습니다.
면접관이 이렇게 묻습니다
게시글 10만 건을 최신순 무한스크롤로 보여 줍니다. 내릴 때마다 다음 20개를 불러옵니다. 새 글도 계속 올라옵니다. API와 쿼리를 설계해 보세요.
범위부터 좁힙니다
한 줄로 좁힙니다. 최신순으로 20개씩 끊어 내려 주고, 바닥에 닿으면 그다음 20개. 그 사이에도 새 글이 들어온다. 추천과 광고 섞기는 접고 순수한 최신순 페이징에 집중합니다.
「다음 20개」의 기준이 무엇이냐가 핵심 질문입니다. 앞에서 몇 번째인지로 세는 방식이 어디서 흔들리는지부터 봐야 합니다.
가장 많이 나오는 답
게시판에서 익숙한 페이지 번호를 그대로 씁니다.
GET /posts?page=3&size=20
SELECT * FROM posts
ORDER BY id DESC
LIMIT 20 OFFSET 40;
첫 몇 페이지는 빠르고 정확합니다.
그런데 여기서 깨집니다
깊이 내려갈수록 느려집니다. OFFSET 50000은 앞의 5만 행을 만들어 놓고 버린 뒤에야 20개를 돌려줍니다.
그 사이 새 글이 다섯 개 올라오면 전체 목록이 다섯 칸씩 밀립니다. 다음 페이지를 부르면 방금 본 글 다섯 개가 다시 나옵니다. 같은 글이 두 번 보이는 버그의 정체가 이것입니다.
떨어지는 답은 이런 모양입니다
- 페이지 번호 API를 무한스크롤에 그대로 씁니다.
- 같은 글이 두 번 보이는 버그의 원인을 설명하지 못합니다.
- id 내림차순이 곧 최신순이라고 믿습니다.
면접관은 여기서 멈추지 않습니다
좋아요순 스크롤이면 다음 20개의 기준은 어떻게 되나요?
정렬 기준이 바뀌면 「다음」의 기준도 바뀐다는 것을 아는지 봅니다.
이 목록을 초당 3만 명이 동시에 열면요?
쿼리 하나의 속도와 같은 답을 수만 번 만드는 부하를 구분하는지 봅니다.
이 다음 판단은 책에서 이어집니다
책은 「다음」의 기준을 정한 뒤, id 순이 정말 최신순인지, 같은 시각에 걸린 글을 무엇이 가르는지, 인덱스가 어떤 모양이어야 하는지, 다음이 있는지를 어떻게 아는지까지 차례로 풉니다. 위로 당겨 새 글을 받을 때와 OFFSET을 써도 되는 때도 다룹니다.
10장에서 이어지는 것
- id 순이 곧 최신순인가
- 같은 시각에 걸린 글을 가르는 기준
- 인덱스의 모양
- 다음이 있는지 아는 방법
- 위로 당겨 새 글을 받을 때