본문으로 건너뛰기

· 약 7분
제이

안녕하세요. 카페인 팀의 제이입니다.

저희 서비스에서는 충전소의 요일과 시간대 별로 충전소 혼잡도 정보를 제공을 차별적인 기능으로 제공하고 있습니다.

이를 구현하기 위해서 공공 데이터에서 정보를 수집하고있습니다. 혼잡도를 조회하기 위해서는 약 23만 건의 충전소 7일 24시간 = 약 4000만 건의 데이터 중에서 조회를 하는 형식으로 되어있습니다.

너무 많은 데이터가 있다보니 조회 속도가 많이 느린데요. 오늘은 이를 어떻게 개선했는지 작성해보도록 하겠습니다.

참고로 해당 글의 성능 측정에 이용한 데이터의 수는 약 20만 건입니다.


문제 확인

기존의 저희는 많은 양의 데이터를 감당하기 힘들어서 [오전, 오후] 이렇게 두 부분으로 나눠서 혼잡도를 조회했습니다.

하지만 실제 배포를 하기 위해서 더이상은 오전 오후로 나눌 수가 없었는데요.

정상적인 데이터를 제공하기 위해서 먼저 24시간 기준으로 혼잡도를 갱신하도록 로직부터 바꾸었습니다.

위와 같이 코드를 바꾸니 바로 성능에 문제가 생겼습니다. img

위의 사진과 같이 slow-query를 분석해보았습니다. 혼잡도 업데이트에도 시간이 걸리는 것을 확인할 수 있지만, 조회 시간은 최악의 경우 약 12분 정도로 사용자들이 볼 수도 없었습니다.

이런 문제가 발생한 이유는 다음과 같습니다. 먼저 가장 큰 문제는 데이터가 많기 때문이고, 두 번째로는 비효율적인 API로 인한 문제입니다.

현재 혼잡도 조회시 0~23시까지 모든 요일의 급속과 완속 충전기에 대한 혼잡도를 가져옵니다. 굳이 이럴 필요 없이 선택한 요일에만 혼잡도를 가져온다면 불필요한 조회는 없을 거라고 생각해서 일부분 리팩토링을 하기로 했습니다.

추가적으로 박스터가 DB Replication을 적용해서, Update로 인한 속도 저하 현상도 많이 줄어들 것을 기대할 수 있었습니다.


문제 해결 과정

  • 먼저 기존 코드로 조회시에 속도가 얼마나 나오는지 확인을 해보겠습니다. img 기존의 모든 혼잡도를 들고오는 경우 위와 같이 536ms의 시간이 소모되는 것을 확인할 수 있습니다.

img 위에 사진과 같이 day_of_week 즉 혼잡도를 확인하고 싶은 요일을 추가적으로 조건에 명시해주니 148ms로 줄은 것을 확인할 수 있습니다.

148ms는 아직 한참 느립니다.

먼저 문제를 해결하기 위해서 DB Partitioning을 적용했습니다.

DB Partitioning에 대해 간단하게 설명하자면 큰 테이블을 작은 단위로 관리하는 기법입니다. 하나의 테이블로 보이지만 이를 적용하면 실제로 여러 개의 테이블로 분리해서 관리하는 기법이고, 이를 통해서 조회 및 업데이트 쿼리 성능이 개선될 수 있습니다.

저희 팀은 List partitioning을 적용해서 day_of_week(요일)을 기준으로 파티셔닝을 했습니다. img 위에 사진과 같이 day_of_week를 기준으로 파티셔닝을 했습니다.

img List Partitioning을 적용하고 위에 사진과 같이 조회 쿼리를 다시 날려보면, partitions = p_friday 로 잘 나뉘어진 것을 확인할 수 있습니다.

파티셔닝 작업이 잘 되었으니 이제 API에서 요일 별 혼잡도 조회로 바꿔보겠습니다. 먼저 쿼리를 변경하고 쿼리를 확인해보니 다음과 같이 나왔습니다.

img 위와 같은 조회 쿼리가 나왔으므로 인덱스를 아래와 같이 station_id, day_of_week에 걸어주었습니다.

img 위 실행 속도에서 execution time을 확인해보면 인덱스를 걸고 134ms -> 5ms로 성능이 많이 개선 되었음을 확인할 수 있습니다.

img 실행 계획도 의도한대로 잘 나오는 것을 보실 수 있습니다.


정리

  1. DB Partitioning - (day_of_week : 요일)을 기준으로 파티셔닝
  2. 조회 쿼리에 맞게 인덱스 설정
  3. API 수정 (모든 요일의 혼잡도 조회 -> 해당 요일의 혼잡도 조회)

결과적으로 기존 혼잡도 조회시 511ms가 나왔으나, 요일 별 조회 및 파티셔닝 & 인덱스를 적용하고 execution time = 5ms로 개선