개요
우리 팀의 현재 killing_part_like
는 문제가 많다.
정합성 문제와 함께 중복 데이터가 사용자에게 전달될 가능성도 존재한다.
현재는 어떻게 해결할 수 있을지 고민하는 시간을 갖고 있다.
너무 느린 API 응답
Locust 로 API 응답 측정
DB 가 느린걸까, 애플리케이션 처리 속도가 느린 걸까
어떻게 측정할 수 있을까
그래서 어떤 게 느릴까
현재 우리의 좋아요 정책
- 메인에서 좋아요 순으로 정렬된 데이터를 가져온다. 현재는 서버에서 특정 기간(1시간, 30분 등)으로 캐싱하지 않고 매번 실시간으로 정렬해서 조회한다.
- 유저가 각 노래의 킬링파트에 좋아요를 누르면 메인의 좋아요 순위가 변경될 수 있다.
- 각 노래의 킬링파트에 유저들의 좋아요한 개수, 내가 좋아요를 눌렀는지 여부가 표시된다.
- 어떤 노래를 들어가서 스와이프를 했을 때, 앞 뒤로 좋아요 순으로 정렬된 데이터를 각각 10개씩 받아온다.
발생할 수 있는 문제점
-
여러 유저가 어떤 노래의 킬링파트에 대해 동시에 좋아요를 눌렀을 때, 정합성 문제가 발생할 수 있다. => 매우 시급
-
정합성 이슈를 고려하지 않는다고 했을 때 -> 유저가 좋아요를 눌렀을 때, DB의 킬링파트 좋아요가 추가되기 때문에 기존에 사용자가 메인에서 보았던 좋아요 순 노래 리스트가 변경될 수 있다. 즉, 기존에 들었던 노래가 스와이프 했을 때 다시 등장할 수도 있다. => 꽤나 시급
-
좋아요 수를 실시간으로 반영하기 때문에 응답을 캐싱하는 것이 불가능하다.
해결 방법
기술적 관점
- 좋아요 정합성 이슈의 해결 방법은 shook-like-issue 에서 확인 가능합니다.
DB Replication 을 적용한다
하나는 읽기 DB, 하나는 쓰기 DB 를 둔다.
- 장점
- 좋아요 읽기 작업 성능을 높일 수 있다.
- 단점
- 일관성 있는 데이터를 얻기 어려울 수 있다.
정책적 관점
좋아요 정합성 문제가 해결되었다고 가정하고 정책을 제안한다.
메인 리스트를 전날 좋아요 순으로 정렬한다
매 요청마다 정렬하지 않고, 전날까지 집계된 좋아요 순으로 정렬한다.
DB 는 그대로 실시간 업데이트 하되, 전날까지 집계된 좋아요 순 정렬을 캐싱해서 서버 인메모리에 저장한다.
- 장점
- 데이터 자체는 실시간으로 처리된다. DB와의 정합성 처리는 신경쓰지 않아도 된다.
- 단점
- 이전에 들었던 노래가 나오는 문제는 해결할 수 없다.
- 좋아요 순 정렬된 리스트의 크기는 고정되어야 한다.
해당 사용자의 좋아요 순 리스트를 고정한다
사용자가 좋아요 순 리스트를 클릭해서 노래 듣기를 선택하는 순간, 해당 시점의 좋아요 리스트를 사용자 id 로 인메모리에 캐싱한다.
그 뒤로 요청을 받을 때마다 인메모리에 캐싱된 값을 가져와서 응답한다.
메인 화면에서의 킬링파트 좋아요 많은 순 차트는 옆에 (마지막 새로고침 N분 전) 이라고 표시되도록 한다.
만약 새로고침을 누르거나, 다시 메인에서 요청을 보내는 경우 캐싱된 값을 업데이트 한다.
- 장점
- 응답 결과를 캐싱하기 때문에 성능이 매우 빠르게 향상될 것으로 예상한다.
- 이전에 들었던 노래가 나오는 문제가 해결된다.
- 단점
- 사용자가 좋아요를 누른 경우, 좋아요를 누른 정보도 캐싱되어야 하는데 이 처리가 좀 빡셀 거 같다.
- 좋아요 순 리스트 개수가 고정되어야 한다.
- 서버가 stateful 하다.
- 사용자가 많아질수록 캐싱해야 하는 양이 늘어난다.
좋아요 처리 버퍼링
차트의 순위를 결정하는 데이터는 실시간으로 수집하지만, 순위 재정렬은 일정 시간 간격으로 이루어진다.
- 좋아요 데이터는 실시간으로 수집한다. 메모리 같은 일시적인 저장 공간에 저장된다.
- 킬링파트의 좋아요 수는 업데이트 하지 않는다.
- 유저의 좋아요는
killing_part_like
테이블에 저장한다.
- 일정 시간마다 버퍼에 저장된 데이터를 한 번에 업데이트한다.
- 킬링파트의 좋아요 수를 한 번에 DB로 업데이트한다.
- DB 가 업데이트 되었기 때문에
킬링파트에 좋아요 수를 표시하되, TOP 3 옆에 마지막 업데이트 시간 표시하기