무한 스크롤과 랜덤 정렬, 커서 기반 페이징과 함께 쓸 수 있을까?
인스타그램과 같은 피드 구조를 구현하실 때, 무한 스크롤과 랜덤 정렬을 동시에 적용하고 싶으셨던 적이 있으신가요?
저 역시 유사한 구조를 구현하려다 예상치 못한 충돌을 겪었고, 이를 해결하기 위해 고정된 랜덤 시드를 도입하는 방식으로 문제를 풀게 되었습니다.
이 글에서는 그 과정을 정리하여 공유드리고자 합니다. 특히 커서 기반 페이징과 랜덤 정렬은 어떻게 공존할 수 있는가에 대한 고민이 중심입니다.
문제 상황: 커서 기반 페이징과 랜덤 정렬의 충돌
처음 의도는 다음과 같았습니다.
- 피드에 게시글을 무한 스크롤로 불러오고 싶다
- 사용자마다 매번 다른 랜덤 정렬 순서로 보여주고 싶다
이 두 가지를 동시에 적용하려고 했을 때 한 가지 중요한 사실을 깨달았습니다.
“커서 기반 페이징은 고정된 정렬 순서를 전제로 작동하는데,
랜덤 정렬은 매번 다른 결과를 만들기 때문에, 두 방식은 정면으로 충돌한다.”
커서 기반 방식은 이전 페이지의 마지막 항목을 기준으로 다음 항목의 위치를 정확히 예측할 수 있어야 합니다. 하지만 랜덤 정렬을 적용하면 동일한 조건에서조차 결과가 달라지므로, 페이징 커서가 무의미해지는 문제가 발생합니다.
해결 방향: 고정된 랜덤 시드(Random Seed)의 도입
그래서 다음과 같은 방식으로 문제를 해결하였습니다.
- 사용자가 피드를 처음 요청할 때, 서버가 랜덤 시드(seed) 를 생성하여 클라이언트에 전달합니다.
- 이후 무한 스크롤을 통해 페이지를 추가로 요청할 경우, 클라이언트는 이 랜덤 시드를 계속 유지합니다.
- 게시글 ID와 랜덤 시드를 조합하여 고정된 정렬 키(sort key) 를 계산합니다.
- 이 정렬 키를 기준으로 커서 기반 페이징을 적용합니다.
이렇게 하면 사용자에게는 세션 중 일관된 랜덤 정렬 피드를 보여줄 수 있으며, 커서 기반의 안정적인 페이징도 가능합니다.
구현 방식 예시
📌 정렬 키 계산 방식
게시글마다 다음과 같은 방식으로 정렬 키를 계산합니다:
sortKey = hash(seed + postId); // 예: CRC32 해시 사용
이 정렬 키는 동일한 시드에 대해서는 항상 같은 값을 반환하므로,
정렬 순서 역시 변하지 않습니다.
📌 커서 기반 페이징 로직
SELECT * FROM posts
WHERE hash(seed + post_id) > :lastCursor
ORDER BY hash(seed + post_id)
LIMIT 20;
이 방식은 해시값 기준으로 오름차순 정렬하여 커서 이후의 게시글을 페이징 처리합니다.
사용자가 계속 스크롤할수록, 정해진 랜덤 순서대로 다음 게시글이 불러와집니다.
추가 고민: 새로운 게시글이 추가된다면?
이 구조에서 새롭게 떠오른 질문이 하나 있었습니다.
“그렇다면, 피드를 보는 도중에 새로운 게시글이 생긴다면 어떻게 되는가?”
결론부터 말씀드리면, 문제 없습니다.
새로운 게시글은 동일한 시드로 해시 계산을 하게 되므로 기존 피드 내 적절한 위치에 배치되지만,
사용자는 계속해서 기존 커서 이후 정렬된 게시글만 불러오기 때문에,
세션 중에는 피드 순서가 유지되고 새 게시글로 인한 페이징 오류도 발생하지 않습니다.
사용자 경험 흐름 정리
- 피드 최초 요청 시
- 서버는 고정된 random_seed를 생성해 응답에 포함합니다.
- 무한 스크롤 페이지 요청 시
- 클라이언트는 동일한 random_seed를 포함하여 요청합니다.
- 새로고침 또는 앱 재시작 시
- 새로운 random_seed가 발급되어, 전혀 새로운 랜덤 피드가 생성됩니다.
정리하며
처음에는 무한 스크롤과 랜덤 정렬을 동시에 사용한다는 것이 불가능해 보였지만,
랜덤 시드 기반의 정렬 키 생성이라는 아이디어를 통해 이 둘을 자연스럽게 결합할 수 있었습니다.
항목 | 설명 |
문제 | 커서 기반 페이징과 매번 달라지는 랜덤 정렬은 충돌하는 구조 |
해결 | 고정된 랜덤 시드를 발급하고 해시 정렬 키를 만들어 커서 기반 페이징에 활용 |
결과 | 한 세션 동안은 일관된 랜덤 순서, 새로고침 시 새로운 피드 제공 가능 |
장점 | 성능과 UX의 균형 유지, 확장성 있는 구조 |
후속 과제
- 추후 팔로우/팔로잉 기능이 추가되었을 때, 정렬 기준이 복합적으로 될 수 있어 정렬 로직을 재조정할 필요가 있습니다.
- 사용자 맞춤형 피드에 적용하려면, 시드 외에도 필터/우선순위 로직과의 결합을 고려해야 합니다.
- 캐싱 전략, 정렬 키 생성의 성능 최적화 등도 장기적으로는 고민해볼 만한 부분입니다.
'트러블슈팅&기술선택' 카테고리의 다른 글
MSA 도입했음에도 다시 모놀로틱으로 돌아간 이유 (1) | 2025.03.28 |
---|---|
백엔드에서 "관리자"와 "사장"은 같은가? (1) | 2025.03.28 |
MSA 정합성 문제 해결: Spring Cloud Feign Client & Kafka 활용 (0) | 2025.03.27 |
ELK vs Loki (0) | 2025.03.24 |
모놀로틱 아키텍처의 한계와 MSA 적용 이유 (0) | 2025.03.24 |