상품 조회 성능 개선기

Picbel·2024년 1월 6일
0

회고

목록 보기
7/7

문제 파악

23년 9월 부터 서비스의 상품 조회가 느리다는 피드백이 많이 왔습니다.
유저 측 피드백 보다는 내부 관리자 분들의 고충이 굉장히 컷습니다.
사실 서비스를 시작한 22년 12월부터 상품 조회가 느리다는 것은 인지하고있었습니다.
(느릴수 밖에 없는 구조였구요.)
서비스 오픈 시 필요한 기능에 좀 더 시간을 쏟자는 개발팀과 사업팀 의견이 모여서 상품 조회 개선은 추후로 미루어졌습니다.

시간이 흘러 상품 조회에 불만의 목소리가 나왔고 특히 출고량이 늘면서 운영팀, 물류팀의 업무속도에도 영향을 줄 정도였습니다.
(출고될 상품 조회하는데 너무 많은 시간을 소요...)
이제 서비스 오픈 때 부터 묵히던 원인을 해결 할 시간입니다.

문제 원인

문제의 원인은 간단합니다. 흔히들 말하는 JPA의 N+1 문제였습니다.
상품조회시 필요한 정보를 구성하기위해 조회해야할 table은 총 13개입니다.
이렇게 된 이유는 정규화의 레벨을 굉장히 높게 가져가자는게 당시 개발팀의 의견이었고 table설계시에도 영향을 주었습니다.
처음부터 13개는 아니었습니다.(최초는 9개? 였던걸로 기억합니다.)
추후 요구사항으로 상품 도메인에 정보가 추가되었고 해당 정보를 저장하는 table이 늘어나게되면서 13개를 전부 조회해야했습니다.
최초 9개의 경우 fetch하는 방향으로 해결하였으나 추후 추가된 table 정보를 읽느라 상품 한개당 2~4개의 쿼리가 추가로 나가게되었고 조회 성능이 굉장히 떨어지게되었습니다.
개선전 20개의 상품을 조회시 1322ms의 응답속도였습니다.

해결 방안

결론적으로 말하면 in-memory cache 를 이용하여 문제를 해결하였습니다.
해당 방법을 선택한 이유는 상품정보가 캐시에 적합한 데이터 구조라는 점이 크게 작용하였습니다.
상품정보를 table 13개로 나누어 저장한 이유와 연결 되는 부분인데요.
상품의 공통된 정보를 따로 추려서 정규화되어있어 cache를 적용하기 적합한 데이터구조를 이미 가지고 있었습니다.
13개중 8개의 table정보가(정확히는 도메인 단위로 캐시) 캐싱에 굉장히 적합한 데이터였습니다.

이제 cache를 어떤 cache를 쓸지?를 고민해봐야했습니다
크게 고민했던것은 redis를 이용한 분산 캐시서버가 직접 내부 in-memory cache를 구현하는 방법중 하나를 선택해야했습니다.

먼저 redis를 이용하면 추후 트래픽이 몰려 서버를 하나 더 띄우더라도 일관된 캐시 데이터를 제공 할 수 있다는것이 큰 장점입니다.
하지만 위에서 기술하였듯 최종 선택은 in-memory cache를 선택하였는데요.
이유는 해당 작업에서 원했던 것은 조회 속도 개선이 가장 큰 초점이었던 만큼 redis와 통신하는 i/o 통신 비용 또한 절약하고 싶었습니다.
또한 캐시 대상 데이터가 아주 많지 않아서 서버 내부에서 memory로 들고있기에도 충분한 데이터 크기라 생각되었습니다. (캐시 대상 도메인에 따라 편차가 있지만 5mb ~ 20mb 정도)
수정이 자주 일어나지 않아서 추후에 트래픽 분산을 위해 서버를 더 띄워도 일관된 데이터를 보장하기 적합하다 판단되었습니다.

만약 수정이 된다면 모든 서버의 캐시를 갱신해야하는 추가 작업이 필요하지만 수정빈도가 3개월에 한번 정도라 다른 방법으로 풀 수 있다 생각하였습니다. 이부분은 추후 고도화 예정입니다.

아직 서버를 여러대 띄워서 분산시킬 정도의 트래픽이 몰리지 않는다는 점도 해당 의사결정에 영향을 미쳤습니다.

개선 결과

상품 조회 개선입니다.

상품 갯수개선전개선후개선률
20개1322 ms100ms92%
50개3630 ms120ms96%

관리자 주문 조회 개선입니다.
주문조회는 주문+상품+고객정보 외 등등등 읽어오는 정보가 많아 상품조회의 개선률만큼은 아니지만 유의미한 개선체감이 되었습니다.

주문 조회 개선개선전개선후개선률
7일간 주문 조회8570ms1978ms76%

고도화 해야 할 것들

꽤 만족스러운 개선결과가 나왔습니다.
하지만 앞으로의 숙제로 남겨놓고 간 일들도 있는데요
캐시 대상 데이터가 수정이 일어낫을때 캐시 데이터의 일관성 보장에 관한 문제가 있습니다.
최초 계획시엔 수정이 일어나면 이벤트를 발행하여 각 서버가 이벤트를 소모하여 cache를 업데이트 하는 방식을 구상하였습니다.
하지만 현재는 cache에 ttl을 설정하여 5분마다 새로운 정보를 읽어오는 방향으로 문제를 해결하였습니다.
1. 데이터의 수정주기가 굉장히 길고 수정보단 신규 데이터 등록이 더 많다는 점
2. 이벤트 스트리밍 솔루션 적용 등 개발하는 비용을 투자할 만큼 1번의 이유때문에 임팩트도 크지않다는 것
이 주요 결정이었고 추후 고도화 예정으로 남겼습니다

후기

현재 프로젝트의 초창기 개발 1년 이후 운영 1년가까히 하면서 꼭 해결하고 싶던 문제인데 정말 많이 해결되서 굉장히 뿌듯합니다.
개발할때부터 이건 추후에 이렇게 해서 해결해야지 하고 묵히고있던 일이어서 더더욱 그렇게 느끼는것 같습니다.
하지만 앞으로 신규개발할 일이 있다면 처음개발부터 너무 높은 정규화보단 조회를 생각하며 적당히 반정규화 한 후에 캐시를 적용하여 속도를 빠르게하는 방식으로 할것 같네요.
초기 생각보다 느려지는 지점이 빨리온다는걸 체감하게된게 큰것 같습니다.

profile
Software Developer

0개의 댓글