티스토리 뷰
이슈 발생
Jennifer 모니터링 중 리워드 발급 관련 API에서 지속적으로 에러가 발생하는 것을 발견하여 분석해보았다.
정확한 현상은 두 개 이상의 리워드 발급 요청이 동시에 들어오는 경우 DuplicatedKeyError가 발생하는 현상이었다.
원인 분석
리워드 이력 테이블의 PK는 대리키로 만들어진 bigint 타입의 컬럼인데 auto_increment가 적용되어 있지않은 상태였다.
insert 쿼리 시 서버 어플리케이션에서는 max+1 값을 조회해서 PK value로 넣어주는 방식으로 구현되어 있었다.
이 방식의 문제는 크게 두 가지가 있다.
첫 번째는 insert를 위해 select max(PK) 연산이 수행되어야 하기 때문에 최적화가 어렵다는 점이다.
두 번째는 동시에 들어온 요청은 동일한 max(PK) 값으로 insert할 것이기에 유일성을 보장하기위해 후에 들어온 요청은 실패 처리된다는 점이다.
이슈 해결을 위한 수단
1. auto_increment 적용 : 파티셔닝된 테이블은 정책상 PK 수정이 불가능하여 적용 불가
2. sequence 활용 : MySQL은 지원하지 않아서 사용 불가
3. select ... for update 구문 활용 : lock 점유하는 동안 응답 지연되기 때문에 사용 안함
4. 채번 테이블 : 사용
개선 작업 내용
우선 채번용 테이블을 신규 생성하였다.
이 때 채번 테이블의 PK에 auto_increment 초기값을 설정하였는데 이슈 테이블의 max(PK)보다 여유있게 큰 값으로 설정했다.
(예를 들어 이슈 테이블 max(PK)가 1,000이라면 채번 테이블의 초기값은 1,500 정도로 설정하는 식)
그리고 MySQL function을 신규 생성하였다.
해당 function은 채번용 테이블에 데이터를 insert하고 select last_insert_id() 값을 반환하는 식으로 구현하였다.
(어플리케이션 레벨에서 캡슐화하지 않는 점이 아쉽지만, 기존에 auto_increment 대신 적용된 방식을 고려하여 일관적으로 구현하기 위해 해당 방식으로 구현)
그리고 서버에서 발생시키던 select max(id)+1 쿼리를 select new_function()으로 수정해서 배포하였다.
결과
동시에 들어오는 요청에 대해 하루 약 200건 이상 발생하던 DuplicatedKeyError 발생하지 않는 것으로 확인되었다.
'업무 이슈' 카테고리의 다른 글
리워드 발급 구조 개선 (0) | 2024.11.20 |
---|---|
AWS EKS 환경에서 Scale-out 시 응답지연 현상 해소 (0) | 2024.05.12 |