해결된 질문
작성
·
43
·
수정됨
0
학습 관련 질문을 최대한 상세히 남겨주세요!
고민 과정도 같이 나열해주셔도 좋습니다.
먼저 유사한 질문이 있었는지 검색해보세요.
안녕하세요? 강의 계속 잘 듣고 잇습니다. 이제거의 막바지에 이르렀네요 ㅎㅎ..
게시글 목록조회 최적화와 관련하여 질문드리고자 합니다.
제가 처음에 이해한 바는 최신의 천개의 데이터를 레디스에 적재하고, 그 외의 데이터는 직접 articleServcie를 통해 가져오자 라고 이해를 했었습니다.(hot, cold Data)
그런데 이후의 결과적으로는 아래 두가지 캐시가 존재하게 되었더라구요
1.zset을 활용한 인기글 데이터 관리(목록 조회 최적화)
2.실제 데이터 queryModel(단건 조회 최적화)
이런 구조에서는 zset에서 천개의 데이터를 관리하긴 하지만 실제로 queryModel에는 데이터가 있을지 없을지 확신을 할 수 없는 상황이라는 생각이 듭니다. 즉 실제로 zset에 있는 데이터라 해도 하루가 지났다면 queryModel이 있을지 없을지 모르는 상황이라고 인지했습니다.
질문1) 제가 이해한바가 맞을까요? 맞다면 이 구조를 선택하신 이유가 조금 궁급합니다.
두 캐시를 합쳐서,
queryModel자체를 하나의 캐시에서 천개의 데이터만 관리하면 되지않나? 라는 의문이 생겨가지구요
어차피 천개의 데이터만 관리한다면 메모리를 그렇게 크게 차지 하지 않을 것 같기도 하구요
질문2) 지금과 같은 구조에서는 zset을 활용한 article_id가 그렇게 큰 의미가 있는 부분인가? 라는 생각이 듭니다.
- 어차피 최신순(1000개이하)의 데이터에 대해서 id를 추출하는거면 DB에서 offset을 세어도 그렇게 안느린 거 아닌가? 하는 생각이 들구요
- zset에 포함되어 있더라도, 실제 데이터(QueryModel)가 있는지 없는지 확답을 할 수 없는 상황이니 큰 의미가 있는건가? 하는 의문이듭니다. 차라리 최신 천개의 데이터에 대해서는 조회에 필요한 모든 데이터를 캐싱해둔다면 큰 의미가 있을거라고 생각이 드는데, 지금의 경우에 대해서는 잘 모르겠네요 ㅠㅠ
-결론적으로, 현재 회사에서 RDB를 주로 쓰고 있는 주니어 개발자 입장에서 관련해서 레디스를 도입해본다면.. 아키텍처 복잡도가 올라가는 부분에 비해 엄청 크게 이득이 되는 부분이 있나?? 라는 생각이 많이 들었습니다.
질문3)추가로, 이거는 좀 다른 부분이긴 한데 read-service에서 like, unlike등 업데이트 이벤트 핸들러의 경우 동시요청에 대해서 lostupdate처럼 동작하는 부분이 있을 것 같은데 이부분은 배제하신건지, 혹은 제가 잘못생각하고 있는건지 궁금합니다.
양질의 강의 정말 감사드립니다
답변 1
0
영빈님, 안녕하세요!
강의 막바지에 도달하셨다니 너무 대단하시고, 잘 들어주셔서 저도 뿌듯하네요!
이런 구조에서는 zset에서 천개의 데이터를 관리하긴 하지만 실제로 queryModel에는 데이터가 있을지 없을지 확신을 할 수 없는 상황이라는 생각이 듭니다. 즉 실제로 zset에 있는 데이터라 해도 하루가 지났다면 queryModel이 있을지 없을지 모르는 상황이라고 인지했습니다.
질문1) 제가 이해한바가 맞을까요? 맞다면 이 구조를 선택하신 이유가 조금 궁급합니다.
말씀하신대로 특정 시점에는 zset에 articleId가 있더라도 queryModel 단건 데이터는 없을 수 있습니다.
queryModel의 TTL은 24시간으로 설정해뒀기 때문입니다.
하지만 게시글 목록을 가져오는 readAll 메소드를 살펴보면,
queryModel 데이터가 없을때 원본 데이터 서버로 요청하여 다시 갱신되는 구조 입니다.
따라서 "조회 시점"에는 항상 데이터를 가져올 수 있도록 설계되어 있습니다.
맞다면 이 구조를 선택하신 이유가 조금 궁급합니다.
두 캐시를 합쳐서,
queryModel자체를 하나의 캐시에서 천개의 데이터만 관리하면 되지않나? 라는 의문이 생겨가지구요
zset에 articleId만 저장하는게 아니라 queryModel을 그대로 저장하는 것도 물론 가능합니다.
하지만 단건 queryModel은 이미 별도로 구성되어 있는 상황이고, 이를 통해 단건 조회 API를 대응할 수 있습니다.
그런데 zset에도 queryModel을 저장하고, 단건으로도 queryModel을 저장하면, 데이터가 중복으로 생기기 때문에 저장 공간에 낭비가 생기게 됩니다.
물론, 상위 N건 목록만 관리한다면, queryModel을 zset에 저장한다고 하더라도 저장 공간 비용은 크지 않다고 볼 수 있습니다.
하지만 수천~수만개의 게시판마다 상위 N건 목록을 관리해야 한다면, 저장 공간 비용이 꽤나 부담으로 다가올 수도 있을 것 같습니다.
이 부분은 비용 적절히 고려해서 구현 방향 바꿔도 크게 문제 될 부분은 아닙니다!
또 다른 이유로는, articleId와 articleQueryModel의 갱신을 위한 라이프사이클은 다르다는 것입니다.
현재 articleId만 저장된 zset은 게시글 생성/삭제 시점에만 갱신하면 됩니다.
하지만 zset에 queryModel까지 저장하면, 게시글의 수정/댓글의 생성 및 삭제/좋아요의 생성 및 삭제 시점마다 zset도 갱신해줘야 합니다.
이미 단건 데이터도 해당 시점마다 갱신해주고 있는데, 목록 데이터에서 동일한 데이터를 중복으로 갱신한다면 쓰기 비용이 두 배가 됩니다.
질문2) 지금과 같은 구조에서는 zset을 활용한 article_id가 그렇게 큰 의미가 있는 부분인가? 라는 생각이 듭니다.
시스템마다 사정은 모두 다르기 때문에 크게 와닿지 않으실 수 있지만, 아래 답변들로 의문이 어느 정도 해소되실 수 있을 것 같습니다.
- 어차피 최신순(1000개이하)의 데이터에 대해서 id를 추출하는거면 DB에서 offset을 세어도 그렇게 안느린 거 아닌가? 하는 생각이 들구요
디스크보다 인메모리 기반이 빠르다고는 하지만, 물론 간단한 쿼리의 경우 성능적으로는 DB만으로 제공해도 충분할 때도 많습니다.
정말 밀리세컨드 단위의 미세한 차이는 사용자 입장에서는 느껴지지도 않거든요.
하지만 이러한 캐시는 단순히 속도 측면에서만 사용하는건 아닙니다.
메인 DB의 리소스는 아주 중요하고, 혹여나 메인 DB의 리소스 고갈 등으로 장애가 발생한다면, 시스템 전체로 장애가 전파 됩니다.
사실 상 메인 DB가 장애나는 순간, 시스템 전면 장애인 것이고, 서비스도 정상적으로 서빙할 수 없는 상태가 됩니다.
메인 DB로 향하는 트래픽을 다른 곳으로 분산하고 경계를 만들어낼 수 있다면, 메인 DB의 리소스 고갈을 미연에 방지할 수 있습니다.
특히 Hot Data에 대한 목록 쿼리는 그 트래픽도 많을 것이기 때문에, 이러한 부하를 레디스로 분산할 수 있다면, 메인 DB의 리소스 절약 관점에서는 충분히 큰 값어치가 있습니다.
- zset에 포함되어 있더라도, 실제 데이터(QueryModel)가 있는지 없는지 확답을 할 수 없는 상황이니 큰 의미가 있는건가? 하는 의문이듭니다. 차라리 최신 천개의 데이터에 대해서는 조회에 필요한 모든 데이터를 캐싱해둔다면 큰 의미가 있을거라고 생각이 드는데, 지금의 경우에 대해서는 잘 모르겠네요 ㅠㅠ
위에 언급되었듯이, 실제 데이터(QueryModel)는 "조회 시점"에 원본 데이터 서버에서 가져올 수 있는 구조입니다. 최신 N개로 zset에 포함되어 있더라도, 실제 조회가 되지 않았으면 Hot Data가 아니기 때문에 굳이 캐시에 미리 저장하고 있을 필요는 없습니다.
최신 N개가 Hot Data라는 가정에 대한 설계로 zset에 articleId를 관리하는 것이지, 최신 N개가 항상 Hot Data는 아닐 수 있습니다.
-결론적으로, 현재 회사에서 RDB를 주로 쓰고 있는 주니어 개발자 입장에서 관련해서 레디스를 도입해본다면.. 아키텍처 복잡도가 올라가는 부분에 비해 엄청 크게 이득이 되는 부분이 있나?? 라는 생각이 많이 들었습니다.
웬만큼 트래픽이 나오는 서비스라면 캐시는 거의 필수입니다.
캐시 저장소로서 레디스가 많이 활용되는 것이고, 그러한 상황이라면 인프라 측면에서는 이미 운영할 수 밖에 없는 것이고요.
따라서 캐시를 어차피 사용해야하는 서비스라면 인프라 복잡도 측면에서는 동일하다고 볼 수 있는데(카프카는 논외로 봅니다),
해결하고자 하는 문제와 필요한 전략에 따라 구현 복잡도는 올라가게 되네요.
위에 언급되었듯이 메인 DB의 부하 분산 관점부터 아주 충분한 값어치가 있습니다.
그리고 단순한 쿼리는 사용자가 느끼기에 크게 성능 차이가 와닿지 않으실 수 있는데요,
여러 데이터를 조인해야하는 경우, DB 쿼리로는 해결하기 어려운 조회 요구사항인 경우에는 캐시나 QueryModel이 성능적으로도 엄청나게 큰 차이를 가져옵니다.
조인이나 복잡한 쿼리일수록 DB에 대한 부하는 크고 느립니다.
강의에서의 데이터 관계가 복잡하진 않으나, 실제로는 조인 뎁스가 몇 단계나 될 수도 있고, 수십개의 테이블을 조인해야할 수도 있습니다.
웹 서비스 이용하다보면 하나의 화면에 보여주는 데이터가 아주 많고 복잡한 것을 종종 경험해 보셨을 것 같습니다. 커머스 서비스 정도가 떠오르네요.
질문3)추가로, 이거는 좀 다른 부분이긴 한데 read-service에서 like, unlike등 업데이트 이벤트 핸들러의 경우 동시요청에 대해서 lostupdate처럼 동작하는 부분이 있을 것 같은데 이부분은 배제하신건지, 혹은 제가 잘못생각하고 있는건지 궁금합니다.
시나리오 점검해보면 lost update가 불가능한 케이스는 아닙니다.
예를 들어, 0시 0분 0초에 업데이트된 이벤트보다 0시 0분 1초에 업데이트된 이벤트가 더욱 빠르게 처리될 수도 있습니다.
이벤트는 순서가 달라질 수도 있고, 중복으로 발행될 수도 있으며, 지연 될 수도 있습니다.
물론, 구현 방식에 따라 해결이 불가한 문제는 아니고, 여기에서 상세한 해결책을 언급하기엔 너무 복잡하고 어려운 내용이기 때문에 넘어가도록 하겠습니다.
다만 그 전에, 도메인의 특성을 먼저 이해하고, 반드시 필요한 구현인지 고민해보는 것도 좋을 것 같습니다.
금융처럼 돈을 다루는 도메인이 아니라면 데이터 유실이 엄청나게 큰 문제입니다.
하지만 게시판 서비스에서 캐시 데이터가 일시적으로 유실된다고 해서 문제 될 부분은 거의 없습니다.
구현에 대한 어려움이나 복잡성, 운영 비용(문제를 해결하려면 더 복잡한 인프라와 아키텍처가 필요할 수도 있습니다)까지 감안해서, 어느 정도는 허용 해줘도 된다는 기준을 만들어도 좋습니다.
항상 모든 경우를 대비하고 모든 문제를 대비할 수도 없고, 그럴 필요도 없습니다!
복잡성이 너무 크고, 문제 발생이 잦지 않고, 실시간 해결이 필요할 정도로 치명적인 문제가 아니라면,
오히려 사용자 문의 채널을 운영하는게 훨씬 저렴한 비용일 때도 많습니다. 실제로도 이렇게 많이 운영하고 있고요.
스스로 고민하면서 학습하는 자세 너무 훌륭하네요!
혹시 더 궁금한 점 있으시면 편히 문의 주세요!