[SERVER] 커뮤니티 설계 고민(2) 좋아요수 조회 방법과 탈퇴한 회원 처리

JINNI·2025년 6월 26일
0

[TIL] Java+Spring

목록 보기
19/20

Post테이블에 TotalLike 필드 같은 걸 추가해서 누가 Like를 누를 때마다 갱신해주는게 좋은지 아니면 그때그때 PostLike 테이블 쫙 돌면서 해당 post_id에 해당하는 레코드 개수를 세는게 좋은지..(Comment 테이블도 동일한 고민..)

게시글 상세 조회 시 해당 게시글에 눌린 좋아요 수를 함께 확인하는 기능이 있을 것이라 생각했다.
이 경우, 게시글 전체 조회 API나 게시글 상세 조회 API 모두에 좋아요 수를 함께 보내줘야 할 것이며 조회가 잦아질 것이라고 생각했다.

조회가 빈번하다면 TotalLike 필드를 따로 두고 Kafka, Queue, Redis 등을 활용해 비동기적으로 갱신하는 게 일반적이고 카운팅 정확성이 중요한 실시간 처리에는 쿼리 카운팅을 사용한다고 한다.

접근 방식장점단점사용 시점
실시간 count 쿼리 (COUNT(*) FROM PostLike WHERE post_id = ?)정확도 100%느림, 대량 요청 시 부하드물게 조회할 때
total_like 필드 (DB에 저장)빠름, 리스트 뷰에 적합동기화 필요 (트리거 or 코드 처리)빈번한 조회 시 유리

그러나.. 정확도 를 중요시하는 입장에서 시간에 따라 정확하지 않을 수 있는 total_like 필드를 사용하는 것이 과연 옳을까 생각해보게 되었다.
서버 개발자 입장에서 속도정확도는 목숨과도 같은 거 아닌가..
생각한 두가지 방식이 트레이드오프 관계에 있는 듯해 고민이 생겼다.

✅ 실시간 count 쿼리 날리고 인덱스 튜닝으로는 안되나?

인덱스가 있어도 COUNT(*)은 결국 인덱스에 대한 전체 스캔을 행해야 하고..
수천만, 수억 개의 row가 쌓이는 경우 성능이 아주 느려짐
인덱스 튜닝을 아무리해도 전부 스캔해야 함.

✅ total_like 필드 정확도를 높여볼까?

트랜잭션 실패 시 count가 반영되지 않아 데이터 불일치가 발생할 수 있음.
좋아요와 동기적으로 처리 시 병목 가능성이 있고..
-> 좋아요 추가와 total_like + 1을 같은 트랜잭션에서 처리
-> 좋아요 요청 시 Kafka, Redis 등에 이벤트를 발행하고 소비자가 total_like 필드를 갱신하는 방법

✅ Materialized View라는 것이 있다!

PostgreSQL, Oracle 등에 있는 Materialized View는 실제 데이터를 저장해 두고 주기적으로 Refresh한다고 한다.
조회 속도는 total_like 필드 방식처럼 빠르다!
하지만 갱신 시점 간에 데이터 지연이 존재하고 이 Refresh하는 시점을 수동으로 하거나 주기적으로 자동 갱신해줘야 하는 issue 발생..
실시간성이 중요한 커뮤니티 서비스에서(일주일 TOP100 이런게 아니라 사용자가 조회할 때마다 계속 보여줘야 하니..)는 썩 좋은 방법으로 보이지 않는다.

✅ Redis 캐시

like_count를 Redis에 저장하고 좋아요/취소 시 Redis의 count도 갱신한다.
속도는 Redis가 가장 최강이며 정확도나 확장성이 높다.
다만 Redis TTL을 적절히 설정하고, 장애 시 fallback 로직 구현을 필수적으로 해줘야 한다.

✅ 결론

  1. DB에 PostLike 테이블 저장 (정확한 기록)
  2. Redis에 post_id → count 캐싱
  • 좋아요/취소 시 Redis count도 갱신
  • 없으면 COUNT(*) + Redis에 저장
  1. 정기적으로 DB → Redis 동기화 job 운영
  2. Post 테이블의 total_like는 optional (필요 시 denormalized)

만약에 유저가 탈퇴했을 때 (알 수 없음) 처리를 해주고 싶다면.. 여전히 유저ID는 남아 있고 이메일, 나이 같은 개인정보만 삭제해주면 되는 건지?

기획적으로 유저가 탈퇴했을 때 유저가 작성했던 모든 댓글이나 게시글, 좋아요 개수 등이 사라지면 안된다고 생각했다.
에브리타임 같은 익명 커뮤니티 서비스를 생각해서 유저가 탈퇴한 경우 (알 수 없음) 처리되고 (알 수 없음) 처리된 유저의 모든 개인정보는 삭제되는 것을 생각했다.

이전 글에서 CommentLike 테이블은 comment_like_id를 기본키로 하고 (comment_id, user_id)를 복합키로 설정한다는 결론을 내렸다.

unique key, foreign key는 null이 되어도 된다.
따라서 유저 ID는 null이나 남겨두고, 개인정보만 NULL 또는 마스킹 처리하는 것이 일반적이다.
User 테이블은 삭제하지 않고, 탈퇴여부(예: is_deleted) 같은 플래그를 사용하면 된다.

user_id를 남겨둔다면 해당 user_id가 정확히 어떤 사람인지 특정할 수는 없으나(개인정보는 마스킹하므로) 해당 user_id가 남긴 글이나 댓글이 무엇인지 알 수 있으므로 완전한 삭제가 아니다.
따라서 null 처리를 통해 탈퇴한 user_id에 해당하는 사람이 우리 커뮤니티 서비스에서 어떤 활동을 했는지 모르게 한다.

다만 보통 탈퇴하고도 개인정보를 바로 삭제하지 않고 갖고 있는 경우가 있고..
이런 경우를 고려해 (알 수 없음) 처리는 하되 user_id는 null 처리는 일정 기간 보류하는 것도 생각해볼 수 있겠다.
여기까지는 현재로서는 크게 고민할 필요 없는 부분이므로 생각하지 않겠다!

profile
천재 개발자 되기

0개의 댓글