///
Search
🔫

OTL 마이그레이션

태그
Project
OTL

Situation

왜 마이그레이션을 해야하는가?

2023년 3월 처음 Sparcs 내 OTL에 들어왔습니다. 모든 학우들이 사용하는 서비스였기에 기대가 많았습니다. 내부에서 본 OTL은 관리가 잘 되지 않는 상태였는데요.
우선 Python Django 기반으로 작성이 되어있었지만, 팀원들은 Django를 할 줄 몰랐습니다. 저도 잘 모르고요. 특히 동아리라는 특성 상 인재 유출입이 심한 구조입니다. 왜냐하면 매 학기마다 새로운 사람이 들어오고 나가기 때문입니다. 그래서 사실상 OTL의 모든 코드가 블랙박스였습니다.
특히 기존 Django 운영 버전이 2.2인 점, Python 버전은 3.6인 점이 마이그레이션에 대한 확신을 강하게 만들었습니다. 당시에 Django가 4버전 이상이었기 때문에 사실상 새로 만드는 것과 무방한 수준이라고 느껴졌습니다.

왜 NestJS 인가?

NestJS가 아니라면 마이그레이션을 할 이유가 없었습니다. 첫 번째로 제가 클라썸에서 NestJS를 사용했기 때문입니다. 특히 현재 상황까지 이르게 된 본질적인 이유는 바로 인수인계와 지속적 관리의 부재였기 때문입니다. 이 근원을 함께 제거하고자 저는 NestJS 온보딩 자료와 함께 세미나 연사로써도 2년간 활동하였습니다.

Action

어떻게 할 것인가?

마이그레이션은 지루한 작업입니다. 더불어 기존에 운영되던 서비스가 있기에 정확하게 수행되어야했습니다. 이에 저는 신속함을 포기하였습니다. 특히 마이그레이션이라는 작업에 동기부여가 약했기에, 더욱 길고 얇게 진행되어야한다고 생각했습니다.
우선 저는 인증 및 프로젝트 세팅을 중간고사까지 마무리하였습니다. 인증 작업은 API 작업 중간에 병렬로 진행하기가 어려울 뿐더러, 사용자 정보를 잘 가지고 오는 것이 가장 중요한 작업 중 하나이기 때문입니다. 이후에는 다음 50개 API에 대한 작업을 병렬적으로 이어갔습니다.
endpoint 정렬
Search
API 리스트
분류
담당자
endpoint
상태
비고
가을 | 선택기능
김기영
김기영
Not Needed
django admin인데, 구현안해도됨
여름 | 핵심기능
don0313@kaist.ac.kr
이동재
Done
여름 | 핵심기능
don0313@kaist.ac.kr
이동재
Done
여름 | 핵심기능
don0313@kaist.ac.kr
이동재
Done
겨울 | 핵심기능
김기영
김기영
Done
여름 | 핵심기능
don0313@kaist.ac.kr
이동재
Done
겨울 | 핵심기능
이동엽
이동엽
Done
여름 | 핵심기능
don0313@kaist.ac.kr
이동재
Done
여름 | 핵심기능
don0313@kaist.ac.kr
이동재
Done
프론트엔드에서 사용하지 않는 API
봄 | 핵심기능
동욱 황
동욱 황
Done
봄 | 핵심기능
이동엽
이동엽
Done
겨울 | 핵심기능
이동엽
이동엽
Done
여름 | 핵심기능
양지웅
양지웅
Done
GET 은 완료
여름 | 핵심기능
양지웅
양지웅
Done
프런트에서 사용하지 않음
봄 | 핵심기능
양지웅
양지웅
Implement complete
여름 | 핵심기능
L
Larry Kwon
Done
봄 | 핵심기능
Not Needed
봄 | 핵심기능
양지웅
양지웅
병찬 박
병찬 박
Test Complete
봄 | 핵심기능
병찬 박
병찬 박
Done
가을 | 선택기능
Not Needed
여름 | 핵심기능
양지웅
양지웅
Done
겨울 | 핵심기능
김기영
김기영
Done
봄 | 핵심기능
L
Larry Kwon
Done
겨울 | 핵심기능
봄 | 핵심기능
don0313@kaist.ac.kr
이동재
김기영
김기영
Done
겨울 | 핵심기능
봄 | 핵심기능
don0313@kaist.ac.kr
이동재
김기영
김기영
Implement complete
Load more
COUNT50
특히 저는 일정 산출 및 팀 관리를 다음과 같이 진행했습니다.
매 학기마다 참가하는 사람들에게 일주일에 투자할 수 있는 시간을 물어보았습니다.
API 별 소요 시간 x API 개수 / 인원수를 고려하여 예상 일정을 계산하였습니다.
특히 현업에서 이 작업을 하게 되었을 때, 백엔드 2명으로 이루어진 팀이 주 40시간을 했을 때, 한 달 정도 소요될 것이라 생각하였습니다.
이는 시간으로 따지면 320시간입니다.
이제 저희 상황을 가정합니다. 시험 주를 제외하면 정규학기마다 8주 정도를 투자할 수 있고 평균적으로 일주일에 3시간씩 사람들이 사용할 수 있다고 가정합니다. 이렇게 하면 한 사람당 24시간을 사용할 수 있습니다. 저희는 평균적으로 4명의 사람이 있었기 때문에 한 학기에 약 100시간을 처리할 수 있었습니다.
이렇게 저는 3학기 정도를 목표를 잡고 차근차근 진행해갔으며 매학기마다 상정한 OKR을 빠듯하게 달성할 수 있었습니다.
이와 동시에 저는 스팍스 신입생 세미나 자료를 함께 제작하였습니다.
이 작업에서는 성능에 대한 극한의 최적화는 과감히 포기했습니다. 일단 코드에 대한 제어권을 가지고 올 수만 있다면 쿼리 최적화는 얼마든지 할 수 있기 때문입니다. 또한 기존의 ERD를 자세히 살펴본 결과, FK가 걸려있어야할 테이블에 FK가 걸려있지 않는 점(MySQL은 FK를 걸 때 인덱스도 같이 만들기 때문에 조인 시 index를 타고 조인을 할 수 있습니다.), 비동기 처리를 전혀 사용하지 않는 코드 구조를 보았을 때, NestJS로 정확히 옮긴다면 성능 향상은 담보되어있는 상황이었습니다.
특히 이번 마이그레이션에서 세션을 버리고, 토큰으로 변화할 예정이었기 때문에 수평확장도 가능해져서 성능은 기존보다 상당히 오를 것이라 예상할 수 있었습니다.

마무리가 되간다..!

API가 거의 마무리가 되갈 때즈음이 바로 24년 여름 즈음이었습니다. 저희는 24봄까지 대부분의 API를 완성하였고 약간의 디버깅 정도를 마무리하고 있었습니다.
저는 그 다음 스텝을 생각하였습니다. 바로 테스트인데요. 저는 팀원들과 함께 다음과 같은 기능 사전을 마이그레이션 프로젝트를 시작하면서 함께 만들었습니다. 이를 기반으로 하여 1차로 QA를 진행하였고 백엔드 팀 안에서 2차 QA 리스트를 작성하였고 다른 파트분들과 다함께 QA 리스트를 3차로 진행하였습니다.
기능 사전
BE QA List
OTL 전체 QA List
다 합쳐서 약 200개가 넘는 QA 리스트를 작성하였고, 테스트와 디버깅을 반복하였습니다.

동기부여 문제

마이그레이션 진행에는 팀원들의 동기부여가 많이 떨어지게 됩니다. 새로운 기능을 개발하는 것도 아니고, API를 하나 옮긴다고 하더라도 앱의 동작방식 자체는 비슷했기 때문입니다. 이는 막바지가 될 수록 심해졌습니다. API 갯수는 줄어가는 것에서 어떻게든 진행률로써 동기부여가 가능하지만, 디버깅은 아니기 때문입니다. 이에 저는 github action과 ssh를 이용한 간단한 CD 파이프라인을 만들었습니다. Docker로 구성된 Dev 환경에서 바로바로 속도가 개선됨과 동시에 디버깅된 결과를 확인가능하게 하기 위함이었습니다.

트래픽 기반 자동 테스트

하지만 이렇게 QA리스트를 만들고 통과한다고 하더라도, 자동으로 이러한 작업이 되면 좋겠다 생각하였습니다. 특히 현재 마이그레이션 작업이 기존 서비스를 몇 프로만큼 대체할 수 있는지, 오류율은 얼마인지 실제 트래픽을 바탕으로 측정 및 테스팅이 되었으면 좋겠다 생각했습니다.
당시에 저는 BCG에서 IT 점검 프로젝트에 참여 중이었는데, 이 때 다음과 같은 테크 블로그 글을 보게 되었습니다.
이 글에서 뱅크샐러드는 트래픽을 복제하여 새로운 서비스와 기존 서비스에 동시에 보내 그 응답값의 차이를 비교하는 식으로 하였습니다. 저는 이 방법을 이번 마이그레이션에서도 적용하면 좋겠다고 생각하였습니다.
비록 인증 방식이 다른 점(세션 vs jwt 토큰), Dual Write를 위한 추가적인 작업은 어떻게 하는지 모르는 점이 제약으로 작용했지만 제한적으로라도, 특히 Read 부분에 대한 것만이라도 테스트가 잘 되면 좋다 생각했습니다.
이것에 대한 자세한 여행기는 다음을 참고해주세요!

최종적으로는 다음처럼 9월 14일에 배포를 성공하였습니다.

Result

마이그레이션 이후 구체적인 수치를 비교해보도록 하겠습니다. 에브리타임에 ‘otl’ 이라고 친 후 나오는 게시글들을 전부 모은 것입니다.
OTL 마이그레이션 이후 게시글.csv
49.2KB
OTL 마이그레이션 이전 게시글.csv
90.9KB
마이그레이션 이전은 22년 12월 말부터 24년 9월 배포까지 수집한 데이터이며 마이그레이션 이후는 배포 이후부터 현재(6월말)까지 모은 데이터입니다. 또한 이 데이터를 보면서 불만에 해당하는 것들을 어노테이션 하였습니다.
OTL 마이그레이션 이후 게시글_불만.csv
4.6KB
OTL 마이그레이션 이전 게시글_불만.csv
15.7KB
시기
전체 게시글 수
불만 게시글 수
불만 비율 (%)
이전
318
117
36.79%
이후
156
35
22.44%
이 수치를 보면 보면 마이그레이션 이후에도 여전히 불만 게시글은 있지만, 현저히 그 수가 떨어진 것을 알 수 있습니다. 특히 기간에 대해 각각 21개월과 10개월로 나눠서 월평균 불만 게시글 수를 보게 된다면
시기
월평균 불만 게시글 수
이전
5.57건
이후
3.50건
다음처럼 약 30프로 이상 감소한 것을 확인할 수 있습니다.
불만 게시글에 대한 유형 분포를 보게 되면
분류
이전 불만 게시글 수
이후 불만 게시글 수
시간표/강의 정보 관련
60
17
접속 오류/버그
15
6
속도/응답 지연
7
2
기타
35
10
다음처럼 속도/접속 오류 등의 면에서 많은 감소를 이루어냈다고 볼 수 있습니다.
속도적인 측면에서 상당한 진전을 이루었는데요. 이전에는 검색에 2초 이상 걸리던 것들이 500ms 밑으로 대부분 처리되는 모습을 보여줍니다. 또한 /session/info 에서 응답하는 내정보 또한 기존에 1초가 넘는 시간대에서 400ms 밑으로 처리되었습니다.

2025 봄학기 수강신청

직전 학기 수강신청에서는 TPS가 40이상이 기록되어도 안정적인 응답속도를 유지하고 있음을 확인할 수 있습니다.

2025 가을학기 수강신청

Coming soon

최근 Sentry 모니터링

최근에는 Sentry를 Self-hosted로 띄워서 자체적으로 OTL을 모니터링하고 있습니다.
이에 따라 더 빠른 버그 대응이 가능해졌으며, API 포인트별로 성능 모니터링 및 최적화를 가능해진바 꾸준한 성능 향상을 위해 노력 중에 있습니다.
가장 핵심적인 ‘과목 검색’, ‘강의 검색’, ‘내 정보’ 불러오는 API 입니다.
과목 검색과 강의 검색의 경우 안정적으로 p95 기준으로 500ms 미만인 것을 알 수 있고 /session/info의 경우 살짝 높습니다. 이 부분은 금일(6월 27일) tracing을 보고, 오래 걸리는 부분을 발견하여 필요없는 쿼리 호출을 제거함으로써 간단한 테스트 시에 400ms → 160ms로 성능이 향상되었습니다.
OTL에는 앞으로도 많은 것들이 남아있습니다.
성능 면에서는 ‘프런트 리팩터링’이 수반되어야하는 것들이 남아있습니다. 현재 API Spec을 Swagger로 자동으로 만들어서 주고 있지만, (Interface 기반 Swagger Document 생성기 개발) 프런트 또한 관리가 안 된지 너무 오래되어 현재 어떤 정보를 필요로 하는지 스스로 모르는 상태입니다. 이것이 명확하게 정의되면 불필요한 쿼리를 모두 제거함으로써 성능을 최적화시킬 수 있을 것으로 기대합니다.
또한 학사 정보 동기화 또한 Message Queue를 통해 사용자 경험을 개선할 수 있는 부분이 있을 것으로 기대합니다. 곧 Read Replica가 생길 예정이라 이를 통한 성능 향상 또한 기대해볼 수 있을 것 같구, Hexagonal Architecture 에서 언급했던 것처럼 더욱 단단한 OTL을 위해 테스트를 해볼 수도 있을 것 같습니다.
캐싱 또한 고려 중인데요. 지금은 URL 기반으로 Json 응답을 캐싱하는 정도에 그치고 있지만, DB를 캐싱한 후 MQ를 통한 invalidation을 하는 것도 고려 중입니다.
앞으로가 기대되는 OTL 열심히 또 해보겠습니다.