-
20만번의 계산 최적화 진행기Programming/Python 2023. 5. 26. 23:04
회사 시스템의 기능 중
20명의 설문지를 통해서 설문지 마다 계산을 10,000번을 하고그 각각의 계산을 모아서 하나의 리포트로 만들어 평균과 분포에 대한 정보를 제공해주는 기능이 있었다.
그냥 말로 해서 20만번의 계산이지 세부적으로 따지면 더 많은 계산이 있었고 이게 아무 문제없이 돌아가면 좋았겠지만 그러지 못했다.
발생한 문제
이때 발생한 문제가 크게 2가지인데
1. 해당 기능이 동작하는 중에 백엔드 서버의 속도가 느려진다.
2. 계산이 예상한 시간보다 더 오래 걸려 대기시간이 길어진다.
원인 파악
첫번째 원인
모노리틱하게 개발이 되어있었기 때문에 계산 기능이 돌아가면 AWS EC2의 리소스가 100%에 도달했기 때문이다.
그러다보니 다른 기능이 돌아가기는 하지만 리소스가 부족하다보니 엄청 느린 응답속도를 보여주었다.
이거는 서비스 이용자가 떠나기에 충분한 조건이였다.
두번째 원인
해당 문제의 경우에는 사실 처음에 봤을 때에는 문제점을 파악하기가 어려웠다.
이유는 아무래도 코드를 작성하신 분이 데이터 싸이언티스트 분이셨기에
코드를 깔끔하게 작성하시지는 않으셨고 코드가 몇백줄이 아니고 10,000줄 정도가 되었기에 한번에 문제를 파악하기가 어려웠었다.
(이거를 작성하는 와중에 이전의 기억을 더듬으니 토가 쏠렸다)
그래도 어느정도 보다보니 문제점이 발견되기는 했었다.
첫번째: DB query가 계산식 안에 들어가있어 20만번의 계산이 이루어지면 그만큼의 DB호출이 이루어진다는 것
두번째: 필요를 넘어서는 필드들을 가져온다는 것
세번쨰: 비동기 처리 혹은 멀티 프로세싱이 되어있지않아서 직선적인 작업으로 인한 딜레이
문제 해결
첫번째 해결
사실 두번째 원인보다 이게 가장 중요했다.
모노리틱하게 설계가 되어진 탓에
계산 기능이 전체적으로 영향을 끼쳐 서버가 거의 죽었다고 할 정도로 느려져 결과로사용자입장에서는 심각한 장애를 느끼게 한다는 것이다.
그래서 일단 분리를 진행했다.
기존에는 트리거가 20명의 설문자가 있다고 했을 경우 마지막의 설문자가 제출을 했을 때 돌아가는 형태였고
사실 이것을 분리하는 것은 간단했다.
순서도로 간단하게 표현하면
마지막 설문자 -> 설문 제출 -> 설문 정원수가 채워졌는 지 확인 -> 채워졌을 경우 -> 계산 동작 수행 -> 결과 db에 저장
그렇다 보니 채워졌을 경우 내부 로직을 수행하는 부분에서 외부 로직으로 수행하게 변경되어졌다.
그렇게 해서 간단하게 계산 동작을 수행하는 부분을 Flask 로 분리를 했고 API를 만들었다.
이렇게 해서 좋아진 것은 터져도 하나만 터진다는 것이였다.
본 서버에 영향을 안끼치다보니 사용자 입장에서는 더 이상 느린 속도에 대한 답답함을 안 느껴도 되어진 것이다.
두번째 해결
일단은 첫번째로 한 것이 query 부분과 계산 부분을 철저하게 분리 시켜 놓았다.
그렇게 진행을 해서 계산 부분에서는 따로 query를 통해서 db에 작업이 일어나는 것을 방지했다.
두번째로 진행한 것이 계산에 필요한 항목만 가져오는 것이였다.
아무래도 설문지에 점수를 주면서 코멘트를 달고 여러가지 레퍼런스를 첨부를 할 수 있는데 사실 이게 계산할 때에는 점수,
한마디로 숫자만 필요하다. 항목에 대한 점수만 있으면 계산이 가능하다보니 불필요하게 다른 필드를 가져올 필요가 없다.그렇게 필요한 필드인 점수 필드만 가져오는 것으로 진행했고
세번째로 진행한 것이 멀티 프로세싱을 통한 계산이였다.
일전에는 순서도가
1번 설문지 -> ... -> 20번 설문지 -> 평균 취합 및 분포 -> db 저장 이런 식으로 진행이 되어지다보니 너무 선형적인 구조라
문제가 발생했다.그래서 일단 서버 사양을 약간 늘렸고 거기에 더해 멀티프로세싱을 통해서
1번 설문지 (1프로세서) + 6번 설문지 (2프로세서) + 11번 설문지 (3프로세서) + 16번 설문지 (4프로세서) -> 동시진행 후 완료 -> 평균 취합 및 분포 -> Db 저장
결과
일단 앞에서 말한대로 본서버가 죽는 경우는 없어졌다.
그로 인해서 본서버에 대한 사양을 낮출 수가 있었다.
(왜냐하면 임시 방편으로 계속 죽기때문에 본서버의 사양을 임시적으로 스케일업을 했었다, 문제는 프로세스를 하나만 쓰다보니 딱히 개선은 안되었지만)사실 계산 기능때문에 필요이상으로 스펙이 높아졌었는데 (그럼에도 커버를 못했지만) 일단 분리가 되어지다보니
서버에 대한 사양을 적절하게 설정할 수가 있었다.
그리고 예상치 못하게 DB query 최적화를 통해서 DB의 부담도 줄었고 또한, 속도의 개선으로 인해서 결과를 받아보는데 걸리는 시간이 단축되었다.
이전에는 설문자의 수에 비례해서 10~30분 정도 걸렸는데 개선 이후 평균적으로 약 1분 미만으로 계산이 완료되었다.
아쉬운 점
계산 하는 부분을 AWS lambda 로 진행했으면 좋았을 것 같다라는 생각이 든다.
그때 당시(2019)에는 Lambda 가 그렇게 대중적이지 않았던 것으로 생각이 되어지는데 현재에 와서 서버리스 특히 Lambda 를 자주 사용하는데 그러다보니 지금에서는 Lambda로 했으면 비용적으로 관리적인 측면으로 괜찮았을 것 같다라는 생각이 든다.
'Programming > Python' 카테고리의 다른 글
[Fluent Python] 텍스트와 바이트 (0) 2023.06.12 [Fluent Python] 딕셔너리와 집합 (0) 2023.06.12 [Fluent Python] 내장 시퀀스 (0) 2023.06.12 [Fluent Python]파이썬 데이터 모델 (0) 2023.06.12 Synology Chat Webhook 을 통한 메시지 전송(Feat. Jira, Python) (2) 2023.06.03