좋아요 기능 구현에 대한 고민

프로젝트에서, 좋아요 기능을 가진 도메인들은 likeCount를 직접 필드로 포함시키지 않고, 대신 중간 테이블을 통해 카운트 쿼리로 좋아요 수를 가져온다. 처음에는 동시성 문제를 회피하기 위한 선택으로 이 방식을 도입했다. 그러나, 시간이 지나면서 이 결정이 최선인지에 대한 의문이 들기 시작했다.

1. 중간 테이블에서 count query 방식

완료된 프로젝트에서 좋아요 기능이 포함된 도메인을 조회할 때, 저장소에서 count 쿼리를 사용하여 중간 테이블에서 좋아요 수를 가져오는 방식의 코드이다. 이 방법은 필드에 직접 좋아요 수를 저장하는 것보다 동시성 문제에 대해 상대적으로 안전하다고 생각했다. 중간 테이블을 통한 조회가 동시성 이슈를 완전히 해결했다고 확신할 수는 없지만, 적어도 직접 필드에 저장하는 것보다는 더 안전한 선택이라고 판단했다.

그러나, 사용자가 많고 해당 도메인에 대한 조회 요청이 많아지면, 필드에 직접 저장하는 방식에 비해 응답 속도가 느려질 것은 예상한다. 가상의 사용자를 설정하여 부하 테스트를 진행해본 결과, 현재까지는 조회 성능에 큰 문제를 느끼지 못했지만, 내가 설정한 테스트 환경에서의 결과일 뿐, 성능이 항상 안전하다고 장담할 수는 없다.

2. 도메인에서 필드로 관리

이렇게 필드로 관리하면 어떨까.

필드로 좋아요 수를 관리하는 방식은 동시성 문제에 취약할 수 있다. 당장 구글에 검색하면 좋아요 수에 대한 동시성 문제 관련 포스팅이 엄청 많다. 실제로도 구현 하고나서 멀티스레드 환경에서 테스트를 진행하면 기대했던 것과 다른 결과가 나타난다.

동시성 문제를 해결하려면 synchronized 키워드를 사용하거나 Concurrency API를 활용할 수 있다. synchronized 키워드를 사용하면 해당 코드 블록에 대한 동시 접근을 제한하여 동시성 문제를 해결할 수 있다. 하지만, 이 방법은 단일 인스턴스에서만 유효하며, 여러 인스턴스를 사용하는 경우 추가적인 동기화 작업이 필요 할 것이다.

JPA를 사용하는 경우, 낙관적 락(Optimistic Lock), 비관적 락(Pessimistic Lock), 분산 락(Distributed Lock)과 같은 다양한 락 기법을 고려해 볼 수 있다. 응답 속도는 중간 테이블을 사용해 관리하는 것보다 빠를것이다.

Summary

두 방법 전부 장/단점이 명확하다. 서비스의 요구사항, 규모, 성능, 구현 복잡도 등 복합적인 요소들을 종합해서 서비스에 더 적합한 방법을 적용하는건 누구나 다 그렇게 생각한다.

두 방법의 장점을 나열해봤다.

조회 마다 count query 발생

  • 동시성 이슈를 최소화할 수 있다.

  • 데이터 일관성을 유지할 수 있다. 이게 가장 큰 이점이라고 생각한다.

필드에서 관리

  • 쿼리 간소화

  • 응답 단축

  • 성능 향상

  • 관리하기 편함

실시간 SNS같은 경우, 좋아요가 빈번하게 업데이트 될 것이다. 이 과정에서 일관성을 유지하는게 더 중요하다고 생각한다. 중간 테이블을 사용하면 관련 정보들을 좀 더 섬세하게 관리할 수 있을것이다.

하지만 많은 사용자를 유치하고 있는 SNS 경우, 여러 사용자에게 조회되는 상황에서 성능을 고려하지 않을 수 없다. 두 방법중 명확하게 어떤것이 좋고 나쁘다라고 판단하기 어렵다. 아직 경험과 지식이 많이 부족하다고 느낀다.

합당한 기준을 세우고 복합적인 요소를 고려했을 때 어느 것이 더 적합한지 판단을 내릴 수 있도록 노력이 많이 필요하다는 것을 100번 느끼게 되었다.

Last updated