아이디어
최근에 매일메일 좋아요 기능에 대한 동시성 문제를 고민하면서 재밌는 아이디어가 생각나서 짧게 남긴다. 한 사용자는 한 게시글에 달린 답변 당 최대 한 번의 좋아요만 수행할 수 있다. 쉽게 이야기하자면, 인스타 게시물의 좋아요 버튼(토글)이라고 생각하면 된다.
insert into comment_like (member_id, comment_id) values (1, 2);
아이디어는 다음과 같다.
select *
from comment_like cl
where
cl.comment_id = 1 and
cl.member_id = 2
- 동시 요청을 제어하지 않으며, 모든 동시 요청들을 유효하다고 판단한다. (서버에서 최소한의 개수 검증 코드는 작성)
- 백그라운드에서 중복된 comment_like 레코드를 주기적으로 지워주는 건 선택의 몫이다.
- 조회의 경우, 위와 같은 쿼리의 결과를 CommentLike 객체의 리스트로 변환한다. 그리고 중복을 제거한다. (스택을 사용하거나, Set을 사용할 수 있다.)
comment_like 레코드가 1억 건이 반환되면, oom이 발생하겠지만.. 코어가 10개인 내 노트북을 기준으로, 동시 호출로 인한 중복 저장은 최대 10건 정도이다. 따라서, t2.micro ec2 2대인 상황에서는 위 쿼리에서 1억 건이 반환될 이유가 떠오르지 않는다. 해당 방식의 단점은 추가적인 cpu 리소스를 사용한다는 점, 추가적인 DB 저장 공간을 사용할 수 있다는 점, 인지 비용(왜 중복을 제거해야 하지?)이 든다는 점이다. 당장 해당 방식을 채택하지는 않을 테지만, 해당 방식이 합리적인 상황도 분명 있을 것이라 생각한다.
민수와의 대화
위 아이디어를 보고, 민수가 유니크로 막으면 되지 않는가?라고 이야기했다. 아래는 그에대한 나의 답변이다.
원래는 유니크에 대한 한계 케이스도 작성했었는데, 작성하다보니 유니크가 더 나은 것 같아서 해당 아이디어를 보류 시켰어요. ㅋㅋㅋ
[궁금하실까봐 생각했던 한계 케이스를 남깁니다.]
가령, 미디엄의 좋아요 기능을 만든다면, (클랩이라고 하던가?) 한 사용자가 게시글에 여러번 좋아요(최대 제한 수는 있습니다.)를 누를 수 있어야합니다. 이때, 유니크를 사용하려면(member_id, comment_id, sequence) 조합으로 사용해야 한다고 생각했어요. (다른 방법이 있으면 공유 부탁 드립니다.)
만약, 10개의 요청이 아주 빠른 간격으로 서버로 전달되며, 해당 기능이 5개의 좋아요 제한이 있다면 10개의 요청이 도착해도 5개의 좋아요를 채울 수 없을 수도 있어요.
- (1, 2, 지금 시퀀스가 뭐지? = 0) = 성공
- (1, 2. 지금 시퀀스가 뭐지? = 0) = 실패
- (1, 2, 지금 시퀀스가 뭐지? = 1) = 성공
- (1, 2, 지금 시퀀스가 뭐지? = 1) = 실패
- (1, 2, 지금 시퀀스가 뭐지? = 1) = 실패
해당 방식으로 접근하면, 스키마 변경 없이 10개 요청 중에서 좋아요 제한 수만큼은 성공, 나머지 요청은 무시하면 되므로 10개 요청으로도 좋아요 제한 수를 채울 수 있다고 생각했어요.