해결된 질문
작성
·
18
0
안녕하세요 강사님.
강의에서 Path Enumeration 방식을 활용해 데이터베이스 조회 성능을 최적화하는 방법을 매우 유익하게 배웠습니다.
실제 대규모 서비스 환경에서 이 조회 결과를 Redis로 캐싱하려고 할 때, 캐시를 저장하는 자료구조 선택에 대해 강사님의 의견을 듣고 싶습니다.
현재는 Path를 기반으로 DB에서 계층 구조를 유지하며 정렬된 댓글 목록을 조회하고 있습니다. 이 결과를 Redis에 저장하는 방법으로 아래 두 가지를 고려하고 있습니다.
1. List 구조 (LRANGE)
장점: DB에서 조회한 정렬 순서를 그대로 Redis에 저장할 수 있어, 조회 시 한 번에 가져올 수 있습니다.
고민: CUD(특히 중간 삽입) 발생 시 전체 List를 삭제하고 DB에서 다시 조회해 재저장해야 하므로 비효율적일 수 있습니다.
2. Sorted Set 구조 (ZADD)
장점: 각 댓글을 멤버로 저장하고 Path 값이나 정렬 기준을 score로 부여하면, CUD 발생 시 해당 멤버만 ADD/REMOVE로 처리할 수 있어 갱신이 효율적입니다.
고민: Path 기반의 정렬 값을 Redis의 score로 매핑하는 과정이 다소 복잡합니다.
이처럼 캐싱 로직의 구현 복잡도(Sorted Set)와 갱신 효율성(List의 TTL 전략) 사이의 균형을 고려할 때,
강사님께서는 무한 depth 댓글 구조를 캐싱할 때 어떤 Redis 자료구조가 더 적합하다고 생각하시는지 궁금합니다.
감사합니다.
답변 1
1
Minyoung Park님, 안녕하세요!
결론부터 말씀드리면 2번 방식이 적절할 것 같습니다.
목록성 데이터는 변경이 잦기 때문에, 변경 시마다 캐시를 초기화한다면 캐시 히트율도 떨어지고, 말씀 주신 중간 삽입 방식도 비효율적으로 동작하기 때문입니다.
하지만 1번 방식도 캐시 쓰기 전략을 달리하면 문제 없는 상황일 수도 있습니다.
말씀하신 전략은 cache-aside(db에서 조회하고, 리스트 데이터를 통으로 캐시에 저장)으로 이해하였는데요, 1번도 동일하게 write-through 전략을 사용하면(db에 데이터를 쓰고, 실시간으로 개별 요소에 대해서도 캐시에 반영) List 구조를 사용해도 될 것으로 보입니다.
물론, 위처럼 하려면 쓰기 순서가 목록 노출 순서와 일치해야 한다는 전제가 있긴 합니다. (갱신마다 전체 순서를 다시 업데이트해줘도 되지만, 대규모 데이터에서는 적절치 않음)
또, 아무래도 List 자료구조다보니 수정/삭제 같은 경우 O(n)으로 더욱 느리게 될 수 있고요.(데이터가 적다면 문제될 부분은 아니지만, 대규모 데이터를 가정하면 이 구현 방법은 채택하기 어렵습니다.)
따라서 유연성이나 성능적인 측면에서는 대해서는 여전히 2번이 유리하다고 판단되네요.
2번의 path -> score 고민 사항에 대해서는, CommentPath에서 다음 댓글의 path를 구할때 문자열 값을 integer로 변환하는 코드가 이미 있기 때문에, 이를 참고하면 큰 어려움은 없으실 것 같습니다.
리스트 데이터를 캐시할 때 고려해야하는 부분은,
언급주신 갱신에 대한 문제 외에도 메모리 기반이라 모든 데이터를 저장할 수는 없다는 점, 페이징이 필요한 경우도 같이 고민해보시면 좋습니다.
1번 방법처럼 하는 경우 데이터가 적어서 한방 조회가 가능할 때에는 적절할 수 있겠지만, 페이징이 필요하다면 캐시 키를 마땅히 설정하기도 애매해집니다.(경우의 수가 무한한 페이지 파라미터를 캐시 키로 설정할 수는 없으므로)
참고로, 위 내용들이 모두 고려된 방식으로, "게시글 조회 최적화" 챕터에서 2번 전략에 대해서 직접 구현하게 됩니다!
친절한 답변 감사합니다! 강의 잘 보고 있습니다.