발단
- 데이터베이스 정보를 조회하는게 엄——청 느렸음 (대략 5분 정도)
- 문제를 확인 해보았을때 다음과 같은 문제점들이 있었음
- 쿼리안의 쿼리 [물건 → 포함된 물건 → 포함된 물건 정보 → …]
- 3중 조인 + 조건
- 인덱스 없음
- 이를 개선하고자 다음과 같은 시도를 거침
- 최초 쿼리까지는 동기적으로 수행하고 내부 데이터를 가져오는 쿼리들은 비동기로 수행
- 2중 조인에서 정보를 모두 찾을수 있어 축약
- 이는 데이터베이스 마이그레이션을 선행한 덕분임.
- 검색되는 컬럼에 대해서 인덱스 추가…
- 여기서 문제가 발생함
문제
- 실시간으로 운영중인 데이터베이스에 인덱스를 추가함
- 몇 초면 끝날것이라고 예상했던 데이터베이스 인덱스 추가 작업이 X분 이상 지속됨
- 그동안 데이터베이스를 향한 모든 요청이 홀딩됨 → [이거 왜 안돼요?]
원인
- 일반적인 데이터베이스 인덱스는 B-Tree를 사용함
- 인덱스 추가과정은 다음과 같음
- 테이블 스캔 → 테이블 락 or MVCC(다중 동시성 제어) → 인덱스 생성
- 이때 모든 기록은 트랜잭션 로그에 기록됨
- 실시간으로 운영중인 데이터베이스에 인덱스를 추가하면
정합성 보장을 위해서 테이블에 락이 걸림
- 인덱스 생성시 데이터가 변하면 안되기 때문…
- 락이 걸린 테이블에 요청이 들어오면 모두 대기 상태로 전환됨
- 자원 경쟁이 발생함으로써 데이터베이스 속도 저하
- 실시간으로 들어오는 데이터에 대해서도 기록을 해야 하기 때문에
트랜잭션 로그는 더욱 복잡해지고 많아짐 → 오버헤드 발생
- 이는 선행 세션의 작업이 완료 될때 까지 후행 세션이 락을 획득하려고 시도하고 대기 한다는 것을 의미
- 선행 작업 세션은 테이블 컬럼의 모든 정보를 업데이트 해야 되기 때문에 인덱스가 모두 업데이트 될때 까지
후행 세션의 요청들을 대기 로 전환 함
- 그래서 [이거 왜 안돼요?, 이거 멈췄어요!] 하고 대공황이 발생함;
해결
- 하루안에 해결 해야 하기 때문에 우선 서비스를 복구하기 위해 인덱스 추가를 취소하고
가장 빠른 해결책인 사용량이 낮을때 인덱스 추가를 시도함
- 요청이 거의 없던 때라 1분 이내에 모든 인덱스가 추가되었음