갱신이 잦은 데이터는 RDBMS 외의 대안을 사용하자.

dasd412·2024년 9월 18일
0

실무 문제 해결

목록 보기
6/17

배경

실무에서 기획에 따라 개발하고 있던 중이었다. 다음은 그 요구사항이다.

  1. 사용자마다 컨텐츠에 대한 커서가 필요하다.
  2. 커서는 원형큐처럼 순환하는 형태다.
  3. 컨텐츠가 추가될 때마다 커서도 추가된다.
  4. 해당 기능은 많은 사용자가 쉽게 접근할 수 있다.

문제 분석

이 원형 큐 커서를 관리하는 데이터를 RDBMS 테이블로 설계했다고 하자. 그러면 무엇이 문제일까?

1. 조회 뿐만 아니라 갱신이 잦다.

사용자가 쉽게 접근할 수 있고, 많이 접근할 수 있는 데이터다. 또한 커서이기 때문에 갱신도 잦다.

현재 사용중인 DBInnoDB 엔진을 사용하고 있다. 이 InnoDB 스토리지 엔진은 레코드 자체만을 잠그는 레코드 락을 갖고 있다. (참고로 InnoDB 엔진은 락 에스컬레이션은 없다고 한다.)

그런데, 해당 엔진은 레코드 자체가 아니라 인덱스의 레코드를 잠근다. 인덱스가 하나도 없는 테이블이라도 내부적으로 자동 생성된 클러스터 인덱스를 이용해 잠근다.

예를 들어, 커서 A,B,C가 있다고 하자. 인덱스가 커서 A에만 걸려있다고 하자. 만약 UPDATE에서 WHERE 조건이 A,B,C에 있다고 하자. 그러면 A,B,C 인덱스가 없기 때문에 UPDATE 1건을 위해 모든 레코드가 다 잠긴다.

만약 인덱스가 하나도 없을 경우에는 테이블 풀 스캔하면서 UPDATE를 작업하고 모든 레코드에 잠금이 걸린다.

그러면 반대로 커서 A,B,C에 전부 인덱스를 걸면 안되냐 할 수도 있다. 하지만 인덱스는 조회 성능을 높이기 위한 도구이지, 갱신이 잦은 데이터에 대해선 적합하지 않은 도구다. 왜냐하면 갱신이 잦은 데이터의 경우 인덱스가 매번 새로이 정렬해야 하기 때문에 해당 시간이 추가 소요된다. 특히 이러한 커서는 갱신이 매우 빈번할 게 뻔하므로 인덱스 자체가 좋지 않다.

2. 굳이 영구적으로 저장할 필요가 없는 데이터

커서 데이터는 굳이 영구적으로 저장할 필요가 없다. 돈과 관련된 데이터도 아니다.


대안

여러가지 이유로 Redis Hash를 사용하기로 했다.

사용 이유

  1. 사용자 ID를 기반으로 빈번한 읽기와 쓰기 작업이 예상된다. 또한 복잡한 트랜잭션이 필요하지 않은 데이터다. 그리고 커서 위치의 빠른 업데이트와 조회가 필요하다. 이러한 특성으로 조회 및 갱신 속도가 빠른 Redis를 선택하였다.

  2. 영구적일 필요가 없는 데이터다. 이는 인메모리 특성을 가진 Redis의 데이터 만료와 잘 어울리는 특성이다.

  3. 사용자 별로 커서 데이터들을 갖는다. 이는 (key = 사용자 Id, value = 커서 데이터들)이라는 Hash 자료구조를 활용하기 적합하다.

  4. Redis의 경우 이미 실무에서 AWS Elastic Cache를 사용하기 때문에, 연결 작업이 매우 쉽다. 그에 따라 개발 작업 소요 기간을 줄일 수 있다.


느낀 점

  1. 기획, 프론트엔드가 어떠한 데이터가 필요하다고 요청이 왔을 때, 그 데이터의 속성을 잘 따져봐야 한다. 영구성이 필요한가? 갱신이 자주 필요한가? 등의 요소를 고려하자. 그리고 적합한 DB를 선택할 수 있어야 한다.
  2. RDBMS도 실무에 들어가니 공부할 게 끝이 없다... 고려할 게 참 많아진다. 그리고 MySQL, Redis 뿐만 아니라 다른 선택지들은 없는지 연구해볼 필요가 있겠다.

참고

  1. RealMySQL 8.0 1권
  2. https://ksh-coding.tistory.com/m/124

profile
시스템 아키텍쳐 설계에 관심이 많은 백엔드 개발자입니다. (Go/Python/MSA/graphql/Spring)

0개의 댓글