-
N+1 문제가 해결되어있는 줄 알았는데 아니었다?잡담 2023. 5. 29. 20:06
서론
특정 사람의 특정 날짜 이동경로를 취합해서 csv 로 제공해주는 API 가 있었다.
그런데 여기에서 문제가 발생한다.
특정 사람의 특정 날짜 이동경로를 csv로 받는데 시간이 너무 걸린다는 것이다.
그때 거짓말 보태서 한 5분에서 ~ 10분 정도가 걸렸던 것 같다.
참고로 이 프로젝트의 경우에는 csv 로 받는 것은 관리자가 수동으로 버튼을 클릭을 해야지 동작을 한다.
그렇게 많은 사람들이 호출하는 API는 아니었다.
그래도 이거는 큰 문제였다.
그런데 해당 소스코드를 봤을 때에는 문제를 바로 확인을 할 수가 없었다.
이유는 초기에는 이렇게 오래걸리는거면 N+1문제라고 생각을 했고 그쪽으로 확인을 하려고 할 때
기존 개발자가 그거는 문제없이 처리했다고 했고 그래서 그부분을 배제하고 코드를 봤었다.
그리고 이거외에도 나는 다른 일을 하고있어서 그렇게 시간을 할애할 수가 없었고 그러다보니
언뜻보고 넘어가면서 왜지? 라는 의문을 남긴체 넘어갔다.
그때 로직이 어떻게 되었냐면
1. 해당 사람, 해당 날짜의 이동경로 내역을 가져온다.
2. 이동 경로에는 이동수단, 시간, 평균 속도, 평균 가속도 등등이 표현되었다.
3. 이동 경로에 연결된 위치 정보를 가져온다.
4. csv 에 입력 후 저장
그런데 이게 하나의 함수 안에 있어서 파악이 어려웠다.
그러다가 나에게 할당된 일을 대부분 마치고 컨펌을 기다리고있는 남는 시간에
아직도 해당 문제로 골머리를 앓고있는 개발자를 보고 다시 코드를 살피면서 문제를 파악했다
문제해결
일단 접근 방법은 기능을 하나씩 빼면서 진행하는 형태로 했다.
기능순서의 역순으로 하나씩 배제하면서 시간을 찍었다.
csv-> ... -> 이동경로 내역 순으로 진행을 했다.
그렇게 하다가 문제를 발견했다.
기존에 N+1 문제를 해결했다고 했던 개발자의 말을 믿고 그 부분을 대충보고 넘어가기도 했고 변수명이 진짜 절묘하게
되어있어서 문제를 파악하는데에 오래걸렸다.
진짜로 나중에는 1줄씩 주석처리를 하면서 문제를 파악했다.
요지는 이랬는데
1번 시점에서 이동경로 내역을 가져오면서 eager loading 을 통해서 연결된 위치정보를 가져왔다.
3번 시점에서 이동경로에 연결된 위치 정보를 eager loading 을 통해서 가져온 걸 안쓰고 다시 DB에 query를 날려서 가져왔다
(lazy loading).
그렇게 되어지다보니 그때 이동경로에 포함된 위치정보가 약 5만개 정도였는데 그게 N+1 문제가 터져서 속도 저하의 주범이 된 것이였다.
근데 진짜 정말로 언뜻보면 눈에 진짜 안띄게 작성이 되어있었다.
그러다보니 찾는데에 진짜 애를 많이 먹었었다.
그런데 나중에는 진짜 엄청 작은 단위를 주석처리하다가 얘는 왜 이렇게 작성되었지 하면서 지우고 나니까 속도가 정상으로 나왔었다.
그때 문제 파악하고 수정을 해서 진행을 하니 동작이 잘 되었고 또한 겸사겸사,
코드 리팩토링을 통해서 조금 더 보기쉽게 작업하고, 여러번 db에서 가져와 연산을 하는 작업을 한번 db에서 가져오는 형태로 변경했었다.
결론
일단 속도는 정상적으로 나왔다.
그렇지만 이 문제를 해결하기 위해 할애했던 시간이 그렇게 크지는 않지만 짬짬히 한 시간을 합치면 그래도 1~2일 정도는 되었을 거다.
그러면서도 이 문제가 그렇게 오랜 시간을 걸려야했던 문제였을까?
라고 생각하면 내 생각은 그렇지가 않다.
왜냐하면?
이 문제같은 경우는 N+1 문제라기보다는 너무 복잡하게 짜여진 코드가 문제였다.
이렇게 말하는 이유는 간단한 예시로 요리를 들자면
재료를 마트에서 사오고, 요리 시작(준비, 다듬기, 본요리), 접시에 담아서 내놓기 이렇게가 순서라면
그때의 소스코드 작성은 재료를 마트에서 사왔다가 요리를 하다가 다시 재료를 마트에서 사오는 것의 반복이었기 때문이다.
그러다보니 소스코드를 읽는 입장에서도 매우 힘들고 문제 파악은 더욱 더 힘들다.
DB 에 원하는 정보를 가져오기 => 받은 정보를 통해서 계산 => CSV 에 담아 저장하기
이렇게 진행을 했어야 했다면
소스코드가 DB에서 원하는 정보가져오기 => 받은 정보를 통해서 계산 => 부족한 게 있네 다시 DB에서 가져오기 => 받은 정보를 통해서 계산 (반복)
이렇게 하다보니 문제가 발생할 수 밖에 없는 형태였다.
아마도 개인이 맡아서 하는 프로젝트라 코드를 의식에 흐름대로 짜다가 나중에 개발이 완료되어지고나서 리팩토링이 안되어지다보니
이러한 문제가 발생했던 것 같다.
그러다가 다른 개발자(본인)이 봤을 때 보기가 어려워서 더욱 더 그랬던 것 같다.
'잡담' 카테고리의 다른 글
Server Driven Design 요소 및 템플릿화 (0) 2023.06.03 디자인 제외하고 혼자서 어플개발기 (0) 2023.05.30 기존 EB 로 진행되어지던 프로젝트 Lambda 로 전환 (0) 2023.05.29 ERP 중 매출액 현황 계산 최적화 (0) 2023.05.29 이상하게 데이터가 누락되어지는 경우 잡아내기 (2) 2023.05.29