Search

10주차 - 장애 대응 보고서

생성일
2025/04/22 14:35
태그

개요

콘서트 예약 서비스의 핵심 시나리오에 대해 성능 테스트를 수행하던 중 성능적인 이슈를 발견하였고, 이를 적절한 방식을 통해 해결하고자 한다.

장애 인지

이와 같이 핵심 시나리오에 대해 성능 테스트를 수행하던 중 최대 지연 시간(max)의 지표가 전반적으로 좋지 않고, getConcertSeats 요청의 경우에는 최소 지연 시간 168ms, 중간값 지연시간 303ms로 요청 자체의 성능에 문제가 있음을 인지하게 되었다.

원인 분석 및 해결 방안 적용

전반적으로 최대 지연 시간의 성능이 좋지 않은 이유에 대해서는 명확히 원인을 알기 어려운 상황이라 느껴졌고, 일단 콘서트의 좌석 정보를 조회하는 API의 성능이 좋지 않으니 해당 로직에서 문제가 없는지 확인해보았다.
fun getConcertSeat(concertId: Long, concertScheduleId: Long, clockHolder: ClockHolder): List<ConcertInfo.Seat> { val schedule = concertRepository.findSchedule(concertScheduleId) ?: throw CustomException(ErrorCode.ENTITY_NOT_FOUND, "concertScheduleId=$concertScheduleId") val concertSeats = concertRepository.findAllSeatByConcertScheduleId(schedule.id) return concertSeats.map { ConcertInfo.Seat.of(concertId, it, it.isAvailable(clockHolder.getCurrentTime())) } }
Kotlin
복사
해당 API는 위처럼 단순히 콘서트 일정 조회 → 콘서트 좌석 조회의 간단한 조회 로직이다. 로직을 살펴보아도 별다른 문제를 찾지 못하였다.
로직에 문제가 없으니 쿼리의 문제일까 싶어 실행 계획을 확인해보았다.
1.
concertSchedule 조회
explain analyze select * from concert_schedule where id = ?;
SQL
복사
수행 예상 시간 및 실제 수행 시간이 1ms도 채 걸리지 않는 아무 문제 없는 쿼리임을 확인했다.
2.
concertScheduleId 기반으로 concertSeat 조회
explain analyze select * from concert_seat where concert_schedule_id = ?;
SQL
복사
테이블 풀 스캔이 발생하고 그로 인해 예상 시간이 1.174초가 걸린다. 이에 확인을 해보니, MySQL의 락 전파를 막겠다고 FK를 지정하지 않으면서 외래키로 사용하는 concert_schedule_id에 대해 인덱스를 지정해주는 것을 깜빡한 것이였다.
concert_seat에는 데이터가 12만개 가량 저장되어있는데, 테이블 풀 스캔 후 필터링을 수행하니 쿼리 속도가 느린 것으로 예상되었다. 따라서 아래와 같이 인덱스를 지정하고 다시 성능 테스트를 수행해보았다.
alter table concert_schedule add index idx_concert_schedule_id (concert_schedule_id);
SQL
복사

성능 비교

인덱스 적용 후 다시 성능 테스트를 수행해보았을 때, 위처럼 전반적인 성능 개선이 발생하였다.
전과 후의 시간이 크게 줄어들은 API는 다음과 같다.
엔드포인트
인덱스 적용 전
인덱스 적용 후
개선율
GetConcertSeats
중간값 303ms, 최대 1s
중간값 7ms, 최대 52ms
중간값 98% 감소
GetConcertSchedules
중간값 27ms, 최대 782ms
중간값 7ms, 최대 89ms
중간값 74% 감소
GetConcerts
중간값 7ms, 최대 522ms
중간값 9ms, 최대 44ms
최대값 92% 감소
ReserveSeat
중간값 13ms, 최대 487ms
중간값 15ms, 최대 111ms
최대값 77% 감소
단순히 getConcertSeats의 성능이 개선되는 것을 넘어 전반적인 성능의 지표가 향상된 이유는 다음과 같을 것이라 추측한다.
인덱스 적용으로 인한 디스크 읽기의 감소
쿼리 실행 계획 및 조회 성능의 효율 개선으로 인해 DB의 CPU 및 메모리 사용률 감소
쿼리 시간의 감소로 인한 데이터베이스 커넥션 풀 최적화
위의 직접적인 개선점들의 연쇄 효과로 인해, 요청에 대한 처리 시간도 짧아지고 그로 인해 더 많은 요청을 처리할 수 있게 되어 병목 현상도 해결된 것으로 예상된다.

결론

이번 인덱스 미적용으로 인한 장애와 인덱스 적용을 통한 개선 과정을 통해, API의 직접적인 처리 시간 감소효과를 볼 수 있었다. 하지만 여기서 확인할 수 있는 더 중요한 점은, 적절한 인덱스를 구현하는 것이 시스템 전반적으로 연쇄적인 이점을 어떻게 가져다주는지 명확하게 확인할 수 있다는 것이였다.
외래키를 안쓴다면 인덱스를 까먹지 말고 적용하고, 데이터가 누적되고 특정 조회가 많아진다면 단순히 해당 요청의 개선을 넘어서 시스템 전반적 성능 효율화를 위해 적절한 인덱스를 적용해보도록 하자.