느린 조회 속도
2천만건이 있는 테이블에서
기존에 사용하던 쿼리가 시간이 지나면 지날수록 데이터 양이 많아지면서 조회 속도가 느려지는 현상이 발생했다.
데이터 하나를 조회하는데 165초가 걸리는건…. 정말 말도 안된다고 생각했다.
그래서 팀내에서 회의를 했고 우리가 데이터 조회 속도를 올리기 위한 첫 번째 작업은 데이터 베이스에 인덱스를 적용하는 것이였다.
인덱스
[MYSQL] 📚 인덱스(index) 핵심 설계 & 사용 문법 💯 총정리
인덱스는 쉽게 말해 책 뒷편에 '찾아보기'가 인덱스의 역할과 동일하다고 볼 수 있다. 예를들어 '홍길동'이라는 단어를 찾고싶으면 색인페이지에서 '홍'으로 시작하거나 'ㅎ'으로 시작하는 색인을 찾아보면 빠르게 찾을 수 있다.
위 블로그를 참고하고
이 설계 법칙을 적용 시킨후 인덱스를 다양하게 조합해 조회 성능을 비교 했다.
NOTHING | control point id | collected at | control point id, collected at | (collected at, control point id) | (control point id, collected at) | control point id, collected at,(collected at, control point id) | control point id, collected at,(control point id, collected at) | |
1회 | 237s | 140s | 222s | 118s | 197s | 85s | 131s | 91s |
2회 | 237s | 127s | 220s | 118s | 197s | 88s | 134s | 94s |
3회 | 237s | 129s | 221s | 118s | 196s | 82s | 131s | 88s |
평균 | 237s | 132s | 221s | 118s | 196.67s | 85s | 132s | 91s |
비교 결과 (control point id, collected at) 이렇게 설정한 인덱스가 가장 좋은 성능이 나왔다. 기존 데이터 속도 대비해서 3배 가 빨라진 결과였다.
하지만 아직도 85초라는 엄청나게 느린 조회성능을 가지고 있어 좀 더 개선 시켜야 했다.
mongoDB
MongoDB는 NoSQL 데이터베이스로, 유연한 데이터 모델, 대규모 분산 처리, 빠른 읽기 및 쓰기 작업에 강점을 가지고 있는걸로 알려져있다.
그래서 우리팀도 MongoDB를 사용해서 데이터를 조회할 생각으로
가장 많은 데이터를 가진 관제값을 mongo로 옮기고 조인 없이 where만 사용해서 조회하도록 설계했다.
똑같은 조건에서 같은 결과값을 나오게 하는 쿼리문을 mysql과 mongo로 날려보니 mysql이 훨씬 빠른 속도로 조회가 되는것이다….. 분명 대용량데이터 베이스는 mongo가 좋다고 했는데…..
그래서! 왜 느린지 찾아보니
이러한 결과값을 나타내고 있었다.
우리의 관제값을 첫번째 테스트처럼 mongoDB에서는 전혀 빛을 볼 수없는 구조를 가지고 있었다.
mongoDB를 사용할때 빛을 볼려면 join이 많은 mysql query → mongoDB 이렇게 변경되어야 한다.
Heap OverFlow
데이터베이스에서 단순 합산 그룹화하는 작업을 하면 조회 속도가 매우 느려진다는걸 알게 되었다.
그래서 쿼리에서 group by 와 sum 함수를 빼고 자바에서 더하고 그룹화하는 작업을 하고자 했다.
속도는 개선되었지만 데이터가 조금만 많아지게되면 메모리가 부족해 서버가 꺼져버리는 상황이 오게 되었다.
당장에는 자바를 실행할 때 메모리의 용량을 늘리는 방식으로 해결했지만 이것도 결국에는 데이터가 좀 더 많아지면 서버가 꺼지는 현상을 보게 될것이고 이 것 또한 근본적인 해결책이 아니였다.
집계 테이블
배치로 저장되고 있는데이터에 뒤에 추가 JOB을 붙여서 하루 한달 별로 저장할 수 있도록 개발 했다.
이렇게 하면 저장되는 관제값 ROW수를 획기적으로 줄일 뿐만 아니라 조회할때 미리 계산되어있는 데이터를 불러와 조회되는 ROW수 또한 줄일 수 있게 된다.
결과적으로는 데이터 ROW수를 줄이게 되어 각각 테이블에서 조회하는 속도는 빨라 졌지만 테이블이 3개가 되면서 기존 관제값, 하루단위 관제값, 한달 단위 관제값 이 세개의 테이블을 하나의 테이블 처럼 움직이도록 만들어야 했다.
이 문제를 팩터리 메서드 패턴을 이용하여 프론트에서 보내주는 파라미터에 따라 서로 다른 구현체를 반환하게 만들어서 각 상황에 맞는 테이블에 접근해 데이터를 조회하도록 구현했다.
설정을 완료한 후 조회 해보니 0.02초
캐싱
여기에 더해서
관제값의 과거데이터는 바뀔일이 없다. 라는 특성을 이용해 한번 조회한 데이터는 캐싱을 해놔 다음 조회시 더욱 빠르게 응답값을 낼 수 있도록 설정 하기로 했다.
오늘을 제외한 날짜로 요청이 왔을 때 조회된 데이터를 캐싱할 수 있도록 설정 해놓았고
메모리 관리를 위해 하루에 한번씩 캐시가 초기화 되면 최대 사이즈를 300으로 저장했다.
그 결과 한번 캐싱된 데이터는 0.0005초
같은 데이터 양에서 속도 개선을 이루어 낸건 아니지만
우리가 목표했던 조회 속도를 개선하게 되었다.
'트러블슈팅' 카테고리의 다른 글
어노테이션 기반 권한 관리 (0) | 2024.10.14 |
---|---|
관제값 조회 디자인 패턴 적용 (1) | 2024.10.13 |
배치 리팩터링 (3) | 2024.10.10 |
요금 계산 리팩터링 (0) | 2024.10.10 |
비동기 테스트 처리 (3) | 2024.10.07 |