로딩속도 5분에서 5초로 줄여보았다!

정서희·2022년 9월 2일
2
post-thumbnail

다국어 채팅 앱을 개발하던 당시 겪었던 로딩속도 개선 프로젝트에 대해 정리한 글 입니다.

로딩 속도 튜닝의 필요성

우리는 채팅에 번역시스템을 추가한 서비스를 개발하고있었다.

채팅 앱이라면 빨리 답장해야하는 만큼 로딩속도가 중요한데 기존 앱의 로딩속도는 최소 40초에서 길면 5분까지도 걸렸다.

배치 처리가 되어 있지 않아 정말 문제가 많았다.

로딩속도 개선의 목표는 3초에서 5초 이내로 잡고 로딩속도 개선 프로젝트에 참여하게 되었다.

시도 1 : API 통합하기

기존에 로그인을 할 때 사용하던 API들

  • 기존 API 로그인은 다음 과정을 순차적으로 호출합니다.
  1. 로그인
  2. 이모티콘 리스트 수신
  3. 자동 친구 추가
  4. 단체방들 정보 업데이트
  5. 1:1 채팅방 정보 업데이트
  6. 메시지 번역
    • 4번, 5번에서 번역을 다시 해야하는 메시지들이 있다면 서버에 메시지 번역을 요청한다. 이 때 다른 언어로부터 온 메시지가 10개라면 메시지 번역 API도 10번을 요청한다.
    • 서버에서 다른 번역 서버를 한번 더 거쳐서 오기 때문에 시간이 오래 걸린다.
  7. 마지막 읽은 메시지 index 수신
  8. 친구 목록 업데이트
  9. 알림 설정 서버에 전송
  10. 유저 정보 조회
    • 로그인 과정 중 친구 추천 리스트 생성, 채팅방 내부 유저 정보 조회를 할 때 API를 사용해서 유저 정보를 조회한다.

10가지라는 숫자가 그렇게 놀랍지 않을 수도 있지만 5번과 10번의 경우 로그인 마다 요청 횟수만도 엄청 많아서 한번 로그인할 때 많으면 정말 100개도 넘게 API를 보내고 있었다. (앱을 사용하지 않고 있는 동안 번역해야하는 메시지가 온 만큼 하나씩 번역 요청을 보냈으니.. 정말 한계가 없었던 수준이다. 😂)

신입이었던 내 눈에도 이 과정은 너무나도 비효율적이었다.

😒 ... API의 수가 너무 많은 것 같은데... 이거 통합해도 무리 없을 것 같은데 통합하는건 어떨까요?

감사히 내 의견은 받아들여졌다..!
그리고 멋진 시니어분들의 의견이 쌓여 멋지게 구조를 바꿀 수 있었다.

통합된 API 구조

API중 단순히 정보를 받아오는 API의 경우, 하나로 통합이 되었다.
그 결과 대부분의 API 들이 통합이 되었다.

  1. 로그인 - 유지
  2. 이모티콘 리스트 수신
  3. 자동 친구 추가 - 유지
  4. 단체방들 정보 업데이트
  5. 1:1 채팅방 정보 업데이트
  6. 메시지 번역
  7. 마지막 읽은 메시지 index 수신
  8. 친구 목록 업데이트
  9. 알림 설정 (삭제)
  10. 유저 정보 조회 (삭제)
  11. 통합 로그인 <-- new!!

API 통합 결과 👍

통합 로그인 API의 전송부터 수신까지 평균 15초(15000ms) 정도 걸리게 되었다.

이전보다는 분명 개선되었다는 것이 체감이 되었다.
하지만 목표치인 3~5초에는 한참 못미쳤다.

시도 2 : 통합 로그인 API에서 번역 API 분리

여전히 통합 로그인 API가 느린 이유

서버측에서 시간이 가장 오래 걸리는 이유는 역시, 번역 API 때문이었다.

언어마다 사용하는 API가 달랐는데, 이 중 특정 API는 하나의 번역 송수신에 약 0.7초정도나 필요하였다.
여전히 번역해야하는 수 만큼 로딩 시간도 비례한 문제점도 있었다.
예를 들어, 로그인 시도했을 때 그동안 수신된 채팅이 30개라면 번역에만 20초 정도를 소모해야하는 것이다.

하지만 번역을 굳이 로그인할 때 모두 할 필요는 없으므로 채팅을 보낼 때 서버에서 미리 번역을 해놓아 로그인 과정에서 번역을 하지 않아도 되도록 개선하였다.

번역 API 분리 결과

통합 로그인 API의 전송부터 수신까지 평균 100~200ms로 현저하게 줄일 수 있게 되었다!

시도 3 : 클라이언트 내부 데이터 저장 구조 변경

기존 클라이언트 데이터 저장소

1. Redux

2. SQLite

3. AsyncStorage

이것만 봐서는 그렇게 큰 문제는 없지 않을까? 라고 생각할 수 있다. 하지만문제는 따로 있었다.

대부분의 데이터를 저 세곳 모두 똑같이 저장을 한다는 점이다. 예를 들어,
친구 목록에 관한 데이터를 저장한다고 하면 Redux에 저장하고 SQLite에도 저장을 하고 전역 변수에도 저장을 한다는 뜻이다.

로그인 과정에서 발생하는 모든 데이터의 업데이트도 저렇게 세곳 모두 업데이트를 계속 한다.

하지만 저렇게 쓴 이유는 레거시 코드이기 때문에 명확히 알 수는 없지만 추측을 하자면

1. 상태관리를 하기 위해 Redux를 사용했다.
2. 앱을 종료했다가 다시 켜도 유지되어야하는 정보를 저장하기 위해 SQLite를 사용했다. (일반적인 Redux는 유지되지 않는다.)
3. 모든 정보를 Redux와 SQLite에 넣을 수 없으니 전역 변수에도 저장하여 개발 용이성을 높인다.

해결 방법

Redux-Persist를 사용하여 Redux의 정보가 사라지지 않도록 하면 SQLite를 사용하지 않아도 된다!
또한 상태관리까지 한번에 할 수 있다.

1. SQLite, AsyncStorage 삭제

당신은 우리와 함께 갈 수 없습니다.

Redux-Persist를 사용한다면 SQLite를 굳이 사용할 이유가 없기 때문에 프로젝트에서 삭제하기로 하였다.

redux-persist와 sqlite의 다운로드 비교 그래프

실제로 React Native에서는 redux-persist를 SQLite보다 월등하게 많이 사용하고 있다.

일부 데이터는 AsyncStorage를 사용하고 있었는데... (몇몇 설정에 관한 정보)
굳이 AsnycStorage를 따로 써야하는 이유를 찾지 못했다.

결론 : SQLite와 AsyncStorage를 사용하는 코드는 삭제하였다.

2. Redux Persist 도입

기존에 앱을 재시작해도 유지가 되어야 하는 데이터의 경우에는 SQLite에 넣었다. 그리고 그런 데이터의 경우에는 대부분 상태관리도 필요하기 때문에 Redux에도 넣었다.

Redux Persist를 사용하면 SQLite에 넣는 과정없이 상태관리와 데이터 저장을 한번에 할 수 있어서 효율적이다.

Redux를 Redux Persist로 바꾸는 과정은 그리 어렵지 않았다.
궁금하신 분들은 링크 에서 확인해보시면 될것 같습니다! 😊

결과


우리 팀은 크게 3가지를 개선하였다. (이 외에도 자잘한 변경 사항도 있다.)

1. 비효율적인 로그인 과정에서의 API 구조

2. 로그인과정에서 번역 제외

2. 비효율적인 클라이언트 내부 데이터 저장 구조

그 결과, 평균 로딩시간이 기존 40초~5분에서 현재 3~5초90%이상 단축했다. :)

후기

성능을 튜닝한 경험이 생겨서 정말 기쁘다!

비록 딱 같은 유저가 기존 버전에서는 ##초가 걸렸는데 지금은 #초가 걸린다!
같은 자료는 없지만 정말 개편 이전에는 하루 웬종일 로딩창을 봐야 끝났는데 이제는 잠깐만 기다려도 로딩이 끝나는 점이 너무 좋다. 실제로, 로딩이 너무 길어서 로딩이 오류가 난게 아닌가? 하고 개발자들 마저 오해하는 상황도 많을 정도로 로딩이 정~말 오래걸렸었다. 몇초가 아니라 분단위로 로딩이 필요했다... 하지만 이제는 길어도 10초안에는 로딩이 되어서 체감이 커서 좋다. 단순히 UI를 더 그리고 바꾸고 기능을 하나 더 구현하는 것보다 성능 튜닝을 위해 고민하고 개발하고 테스트할 때가 훨씬 재미있었던 것 같다. 유익한 시간이라고 생각한다 👍

제대로 문서를 만들고 분석하고 개편하지 않은점이 아쉽다.

API하는데만 몇초정도 걸리고, 클라이언트 단에서는 어디서 얼마나 걸리는지, 기존 시간이 정확히 평균 시간이 어느 상황에서 어느 정도나 걸리는지 등을 분석하지 않고 바로 개편부터 한 점이 아쉽다.

API만 수정했을때 얼마나 단축되고, 내부 데이터 저장 구조만 개편 했을때 얼마나 단축되는지 미리 분석하지 않은 점이 너무 아쉽다.

지금 이 글을 작성하면서 성능 개선에 관한 글에는 이런 정확한 수치가 상당히 중요하다는 점을 알아 슬플 뿐이다.

데이터 구조를 바꾸는 것은 꽤 신중해야했다.

처음에는

아니 그냥 ~ SQLite, AsyncStorage쓰던거 redux-persist로 바꾸면 되는거니까
오래 걸려도 2주면 되겠지 😗~

라고 생각했다.

하지만 현실은 많이 달랐다.
구조를 바꿈으로서 사소한 모든 기능을 다시 개발해야 했다.

앱을 새로 만들듯 다시 해야 했다.

QA도 생각보다 엄청 많이 나오고... 2주면 될 줄 알았는데 기존 기능을 다 구현하고 크리티컬 버그까지 전부 수정하는 데에는 2달이 넘는 시간이 필요했다.

데이터 구조를 바꾼다는 것은 정말 신중하게 고려하고 해야하는 점 같다. 그냥 무턱대고 성능에 나쁘다고 막 바꾸는 행동은 위험하다.


참고자료 😎

profile
어제보단 오늘이 더 강한 웹/앱 개발자입니다

0개의 댓글