백엔드 개발 포트폴리오 | 운동시설 중개 플랫폼
내일배움캠프 4기 웹 개발 과정 Node.js 트랙 수료생 최종 프로젝트 '식스팩'을 소개합니다.
Aug 16, 2023
💡 프로젝트 소개
‘식스팩‘ 은 전국의 운동시설을 중개하는 구독형 플랫폼 서비스 입니다.
서비스 기획 배경
헬스장, 필라테스, 크로스핏 모두 하고싶은 사람 모여라!
어제는 회사 앞 필라테스, 오늘은 집 앞 헬스장, 내일은 새로생긴 크로스핏을 해볼까!?
아직도 매일 똑같은 곳에서 똑같은 운동을 한다고? 🤦♀️
출장이 잦아서 운동을 하고싶어도 못 한다고?🤷♀️
지금 당장 식스팩에서 하고싶은 운동 마음껏 하자! 💪💪💪
서비스 둘러보기
사용자 가이드
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F95cfb24c-9d34-496b-adc8-1ddcb600de07%252F%2525EC%252584%25259C%2525EB%2525B9%252584%2525EC%25258A%2525A4-%2525EC%25258B%25259C%2525EB%252582%252598%2525EB%2525A6%2525AC%2525EC%252598%2525A4-%2525EB%2525B8%25258C%2525EB%2525A1%25259C%2525EC%252585%252594.jpg%3Ftable%3Dblock%26id%3D48968677-2176-4da2-8e19-b6e3070a8e49%26cache%3Dv2&w=3840&q=75)
정기결제 (구독 시스템)
결제 시스템
- 정기 구독형 서비스(매달 1일 자동결제)
- 가맹점에 원활한 정산을 하기 위해 매 달 기준으로 정산
- 때문에 월 중간에 구독시 첫 결제는 남은 일 수 만큼만 계산
- 구독 취소시 해당 월까지는 이용 가능하며 다음 달 부터 멤버십 해지
- 테스트 결제가 가능한 PG사 선정 (토스페이먼츠 or
아임포트
)
- 아임포트 선정 이유 : 두 곳의 개발자용 문서를 모두 검토한 결과 기능별 설명과 관리자 페이지의 기능이 더 잘 갖추어진 아임포트가 주니어 입장에서 조금 더 깊은 이해를 할 수 있을것 같아 아임포트로 선정하였음
QR코드
QR코드를 이용한 입장처리
개요
- 멤버쉽 별 이용가능 운동 시설 분리를 위해 출입 회원의 데이터를 받아야 함
- 회원의 편의성을 위해 간편하게 찍고 들어갈 수 있는 QR코드를 선택
- 가맹점에서는 로그인 된 디바이스에 카메라만 있으면 회원출입관리 가능
구현
- 멤버십 이용 회원 로그인 시 메인화면에 QR코드 생성
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F00269201-b4e7-4ecf-9836-a92a499bc759%252FUntitled.png%3Ftable%3Dblock%26id%3D1aecc34c-4ca8-43dc-b1f7-d8b4bf82f53a%26cache%3Dv2&w=3840&q=75)
- 비즈니스유저의 가맹점 리스트에 각 매장의 QR코드 스캐너 생성
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F75355324-ed60-47dd-9595-a955f5df25d0%252FUntitled.png%3Ftable%3Dblock%26id%3D8127f9fa-9adf-4cf6-8a14-353958fc8265%26cache%3Dv2&w=3840&q=75)
- 회원 검증 로직을 거쳐 입장에 성공하면 DB에 가맹점 정보와 회원정보 저장
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Fa5c257a1-2b3c-41c6-9ac4-8d493eda194b%252FUntitled.png%3Ftable%3Dblock%26id%3Dc736286d-2838-45ef-9ce1-f294ca9262b4%26cache%3Dv2&w=3840&q=75)
- 원활한 테스트를 위해 임시 QR코드 검증버튼 생성
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Fa0185a3f-145a-4ec0-ad46-8b088e57b481%252FUntitled-1.jpg%3Ftable%3Dblock%26id%3Ddc64b4a4-6154-429e-b781-1bc8267911da%26cache%3Dv2&w=3840&q=75)
사용된 기술
- 생성된 QR코드에는 회원의 id가 들어가 있음
- QR코드 스캔을 위해 오픈소스 라이브러리인
jsQR
도입
- QR코드를 이용한 출입관리 로직
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F5789a0fd-3286-4aeb-bfc5-a01954f2d459%252F%2525EC%2525A0%25259C%2525EB%2525AA%2525A9_%2525EC%252597%252586%2525EB%25258A%252594_%2525EB%25258B%2525A4%2525EC%25259D%2525B4%2525EC%252596%2525B4%2525EA%2525B7%2525B8%2525EB%25259E%2525A8.drawio.png%3Ftable%3Dblock%26id%3D70ac40be-a112-4f0a-bff1-b220aaa93c12%26cache%3Dv2&w=3840&q=75)
검색 및 현재 위치기반 업체 리스트 가져오기
검색기능
- 검색은
Elasticsearch
를 이용하여 구현
- 업체이름이나 주소의 일부분만 일치해도 검색결과를 반환(
와일드카드
)
- 자동완성된 업체이름을 클릭 시 해당업체만 검색결과에 반환(
구문 검색
)
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F604fd3e5-86d2-423b-87ca-e8206eac5188%252F%2525EC%25258B%25259D%2525EC%25258A%2525A4%2525ED%25258C%2525A9_%2525EA%2525B2%252580%2525EC%252583%252589%2525EA%2525B8%2525B0%2525EB%25258A%2525A5.gif%3Ftable%3Dblock%26id%3D3eea6b2c-6e6e-4cd3-a8d8-35e3c95b748c%26cache%3Dv2&w=1080&q=75)
코드
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F3c0f6a5b-1bfd-4129-82c8-ba15654513b3%252FUntitled.png%3Ftable%3Dblock%26id%3D45c51182-8c59-44a3-a849-28c98a51cd76%26cache%3Dv2&w=3840&q=75)
현재 위치기반 업체 리스트 가져오기
geolocation API
를 이용하여 현재위치를 가져옴
- 현재위치 텍스트를 백엔드에 전달하여 엘라스틱서치의 매치쿼리를 이용해서 업체 리스트를 반환 (예시 : “전주시” 를 검색하여 리스트 반환)
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F2f5e060a-9ccc-476c-a1e1-61455216ddf9%252FUntitled.png%3Ftable%3Dblock%26id%3Db50cc736-458b-4f35-8a78-8bdcf2d588a5%26cache%3Dv2&w=3840&q=75)
코드
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Fceff9584-b9fa-4143-a29e-7b9f6e1275af%252FUntitled.png%3Ftable%3Dblock%26id%3D22786bce-52ba-4e38-96ab-ad05aacdf872%26cache%3Dv2&w=3840&q=75)
식스팩 일반회원 둘러보기
식스팩 관리자 페이지 둘러보기
식스팩 사업자 페이지 둘러보기
📌 서비스 아키텍처
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F0d2af7fe-a552-4d31-b583-efeaa4fedd08%252F%2525EC%252584%25259C%2525EB%2525B9%252584%2525EC%25258A%2525A4-%2525EC%252595%252584%2525ED%252582%2525A4%2525ED%252585%25258D%2525EC%2525B2%252598-%2525EB%2525B8%25258C%2525EB%2525A1%25259C%2525EC%252585%252594.jpg%3Ftable%3Dblock%26id%3Dfbc4dc12-211a-4ef1-a209-81952a4ba4d0%26cache%3Dv2&w=3840&q=75)
기술스택
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F51161f0b-4508-4aa8-8515-c401990fd7df%252F%2525EC%25258A%2525A4%2525ED%252581%2525AC%2525EB%2525A6%2525B0%2525EC%252583%2525B7(633).png%3Ftable%3Dblock%26id%3D954bc5d7-011b-408f-899e-12680dfa07fe%26cache%3Dv2&w=3840&q=75)
🔧 기술적 의사결정
모바일 기반 서비스
이유
- 실제 서비스 사용성을 고려했을때, 모든 서비스가 모바일에서 이루어진다고 판단
고민
- 추후 앱 출시를 고려하였을때 앱은 서버에서 쿠키를 다룰 수 없음
해결방안
- 서버는 쿠키에 담아야하는 내용을 응답에 담아 프론트에 전달하고
- 프론트에서 토큰을 받고 로컬스토리지에 저장해서 필요할 때마다 요청 헤더에 담아서 보내줌
의사결정
- 쿠키대신 서버와 통신하지 않는
로컬스토리지
에 토큰 저장
- 보안상의 이슈로 추후 로컬스토리지 ⇒
쿠키
로 옮길 예정
Access Token & Refresh Token
도입이유
- 보안을 유지하면서 사용자의 편의성 향상을 위해 도입
고민
- 엑세스토큰만 사용하는경우, 유효기간이 만료될 때까지 권한을 도용당할 수 있어 보안이 취약해질 수 있고, 유효기간이 짧으면 사용자가 로그아웃이 되는 상황이 발생
해결방안
- 리프레쉬토큰을 사용하여 엑세스토큰이 만료되면 리프레쉬토큰과 함께 서버에 요청하여 새로운 엑세스토큰을 발급
의견조율
- 리프레쉬토큰을 어디서 관리해야할까? (프론트 vs 백엔드)
- 프론트 : 쿠키, 로컬스토리지
- 백엔드 : mysql, Redis
의사결정
- 프론트에 토큰 저장
- stateless한 jwt토큰의 특성 때문에 서버의 부하를 줄일 수 있음
- 토큰이 탈취당했을 경우 아무런 조치를 취할 수 없음
- 백엔드에 토큰 저장
- 토큰이 탈취당했을 경우 리프레쉬토큰을 삭제시킬 수 있음
- Redis vs mysql
- mysql에 비해 Redis에 저장 시 속도가 더 빠름
- Redis에 저장 시 DB와의 엑세스 횟수를 줄일 수 있어서 부하를 줄일 수 있음
따라서 Refresh Token은 Redis에 암호화하여 저장하기로 결정
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F4af0aba0-6848-4a6f-953d-8421d15d63f3%252FUntitled.png%3Ftable%3Dblock%26id%3D5661d8a8-9daa-4f4e-84c7-5dca3e795060%26cache%3Dv2&w=3840&q=75)
cache-aside pattern
도입이유
- DB에 직접 접근하는 것보다 캐시에서 데이터를 읽는 것이 더 빠르고 효율적
- 캐시에 데이터가 없는 경우에만 DB에서 데이터를 가져오기때문에 DB부하를 줄일 수 있음
- 캐시와 DB의 동기화 문제를 해결할 수 있음
고민
- 캐시에 보관된 이전 데이터로 인해 데이터 수정,삭제,추가 시 데이터가 즉각적으로 동기화되지 않음
해결방안
- write-through 전략을 이용해서 데이터가 업데이트되면 DB에 수정사항을 저장하고 해당 캐시를 삭제
<예시>
- 조회한 데이터는 캐시에 저장
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Fa55d8b35-8e50-44a2-986b-45f58e6ebbed%252FUntitled.png%3Ftable%3Dblock%26id%3D3390fd3f-5b47-46f5-9a81-ca04e5d87262%26cache%3Dv2&w=3840&q=75)
- 데이터 수정, 삭제, 추가 시에 동기화
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F3f65ff5d-4793-42fa-a8f4-813b387fd339%252FUntitled.png%3Ftable%3Dblock%26id%3D848330b2-9adc-4d6b-9f21-cf44e90e8fe1%26cache%3Dv2&w=3840&q=75)
의견조율
- Redis vs Memcached
의사결정
- 다양한 데이터 유형을 지원하는가?
- Redis는 문자열, 목록 등 많은 데이터 유형을 지원
- Memcached는 키-값 쌍만 지원
- 영속성을 지원하는가?
- 우리는 Refresh Token을 캐시에 저장하기때문에 영속성을 지원해야함
- Redis 지원O , Memcached 지원X
따라서 Redis를 이용하기로 결정
Elasticsearch
도입이유
- 기존 방식인 mysql에서 LIKE를 이용한 검색기능의 성능 향상을 위해 도입
- Elasticsearch는 풀텍스트 검색에 뛰어나고, 거의 실시간으로 색인하고 검색할 수 있음
고민
- mysql과 Elasticsearch의 데이터 동기화 방법 결정
- Logstash
- 애플리케이션 레이어에서 실시간으로 동기화
- 엔티티 리스너 사용
해결방안
, 🗣 의견조율
, ✅ 의사결정
- mysql과 Elasticsearch의 데이터 동기화 방법 결정
- Logstash는 관리 비용이 높고
- 엔티티 리스너는 성능문제가 있을 수 있겠다라고 판단
- 따라서 애플리케이션 레이어에서 실시간으로 동기화하는 방법을 채택
- 데이터의 일관성을 보장할 수 있고, 구현이 어렵지 않아서 촉박했던 시간안에 구현할 수 있을 것이라고 판단
→ 세가지 방법을 비교해본 결과
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Fa7209163-23eb-4517-92e8-9c00ca65fee6%252FUntitled.png%3Ftable%3Dblock%26id%3D361ff212-9a90-4fdd-8796-1043a0b10f52%26cache%3Dv2&w=3840&q=75)
AWS EC2 ⇒ GCP VM인스턴스로 변경
도입이유
- EC2 프리티어로 docker-compose를 통한 배포(nestjs, redis, elasticsearch)를 하기엔 인스턴스의 리소스가 부족
고민
- nestjs, redis, elasticsearch모두 메모리를 많이 사용하는 애플리케이션이므로 EC2 t2.micro, t3.micro 인스턴스에서 실행하면 성능저하, 서버꺼짐의 현상이 일어났고, 추가비용 발생 등의 문제가 우려
해결방안
- 성능이 조금 더 좋은 서버를 사용(무료로 사용가능한 GCP의 서버 사양이 AWS의 프리티어 사양보다 4배정도 성능이 좋음) → GCP(e2-medium) vs AWS(t2-micro)
의견조율
- GCP에 가입하면 제공해주는 크레딧으로 e2-medium vm머신(vCPU 2개, 4GB 메모리)을 무료로 사용
- AWS에 돈을 조금 지불하더라도 EC2의 다른 서버를 사용
의사결정
- 국내 점유율 2위인 GCP를 사용해 보다 다양한 경험을 해보기로 결정
추가 고려사항
- DB는 AWS RDS를 사용하고 있는 상황이다보니 현재 public으로 설정되어 있지만 최종배포 후 에는 GCP 에서 DB로 전송되는 고정ip만 rds에 접근이 가능하도록 아웃바운드 보안규칙에 설정 필요하다 생각됨
🛠️ 트러블 슈팅
정기결제
결제를 진행하면 DB에 데이터가 두번 저장되는 이슈 발생
예상 결제 로직
: IMP.request_pay() ⇒ /complete ⇒ /webhook
실제 결제 로직
: IMP.request_pay() ⇒ /webhook ⇒ /complete
- 아임포트 문의 결과 웹훅(/webhook)을 사용하여 정기결제에 관련된 모든 API를 처리해야 한다는 답변을 받음
- 아임포트 개발 가이드 및 스웨거를 보고 머릿속에 그린 결제 로직과 실제 로직 비교
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Fd8f9ff5f-fbfd-4349-abe0-22dd9fab265a%252FUntitled.png%3Ftable%3Dblock%26id%3D89b3197f-bf32-43e6-89cc-8e7644df7e49%26cache%3Dv2&w=3840&q=75)
Admin 카테고리 별 업체 순위 조회 성능 개선
가맹점 개수가 많아지니 가맹점 순위 데이터 가져오는데 오래걸림
변경 전 코드
- 전체 가맹점 정보를 서버에서 넘겨주고 프론트에서 sorting
- async-await 비동기 방식을 Promise.all 방식으로 수정하여 테스트 해보았지만 유의미한 결과가 나오지 않음 (기존로직이 잘못되었다 판단)
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F363f947d-e1b0-4fd9-8f94-5045e63fa285%252FUntitled.png%3Ftable%3Dblock%26id%3D9080ebff-864f-4533-af77-4bf39e53f305%26cache%3Dv2&w=3840&q=75)
변경 후 코드
- 인자로 받은 카테고리의 상위 10개 가맹점의 데이터만 전송
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Fdf13193f-b3d6-4933-b58c-dfef07d659db%252FUntitled.png%3Ftable%3Dblock%26id%3D0b4bb3ff-f5f9-40a2-9294-15a014bbec1e%26cache%3Dv2&w=3840&q=75)
JMeter 테스트 결과
💡 상황 : 2023년 2월 가맹점 별 정산금액 조회 (전체 ⇒ top10)
평균 속도 155,937ms ⇒ 468ms로 333배 성능 향상
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F6e5f7506-c59f-4ed9-a0ae-79cd016781b9%252FUntitled.png%3Ftable%3Dblock%26id%3Df22cdc7a-f6a2-4aba-854f-49b9674e2ee8%26cache%3Dv2&w=3840&q=75)
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F48a445a2-ab04-4284-809b-740f9520e914%252FUntitled.png%3Ftable%3Dblock%26id%3D1b5e7a30-fc11-4cbf-8991-500925d63188%26cache%3Dv2&w=3840&q=75)
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F151e9e58-b0a6-4662-8e20-afe3e98095c4%252FUntitled.png%3Ftable%3Dblock%26id%3D0dc03882-58fb-4a6e-9db6-16a179c6cc47%26cache%3Dv2&w=3840&q=75)
검색기능 향상
검색기능의 성능향상을 위해 Elasticsearch 이용before (
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F53e61822-754e-4cba-ba00-0a781e4e80f7%252FUntitled.png%3Ftable%3Dblock%26id%3D0bef2e66-27f3-48f9-a46e-c2003aa65133%26cache%3Dv2&w=3840&q=75)
after (
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F911177cd-b80b-4875-9146-5476ce60a483%252FUntitled.png%3Ftable%3Dblock%26id%3D5b41c164-4b15-412f-92b5-c8f81f255c71%26cache%3Dv2&w=3840&q=75)
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F44ea6dd0-0536-4aa1-9d9e-e8c98b32c3cf%252FUntitled.png%3Ftable%3Dblock%26id%3Dd4f01435-762c-4d8a-8c53-7f5732f2b018%26cache%3Dv2&w=3840&q=75)
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Fdc51cb75-d27d-4c21-970b-0b24c291b41c%252FUntitled.png%3Ftable%3Dblock%26id%3De78fbf4a-d488-4756-8cc9-0f127ca11ee6%26cache%3Dv2&w=3840&q=75)
before (mysql
)
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F53e61822-754e-4cba-ba00-0a781e4e80f7%252FUntitled.png%3Ftable%3Dblock%26id%3D0bef2e66-27f3-48f9-a46e-c2003aa65133%26cache%3Dv2&w=3840&q=75)
after (Elasticsearch
)
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F911177cd-b80b-4875-9146-5476ce60a483%252FUntitled.png%3Ftable%3Dblock%26id%3D5b41c164-4b15-412f-92b5-c8f81f255c71%26cache%3Dv2&w=3840&q=75)
JMeter 테스트
상황 : “주소”, “업체이름”에 “서울”이 포함된 모든 업체 검색
(0.01초마다 10초동안 1명의 유저가 test 5번 반복)
결과 : 평균 약
23배
속도차이(데이터 수가 많아질수록 차이가 심해질 것으로 예상)
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F44ea6dd0-0536-4aa1-9d9e-e8c98b32c3cf%252FUntitled.png%3Ftable%3Dblock%26id%3Dd4f01435-762c-4d8a-8c53-7f5732f2b018%26cache%3Dv2&w=3840&q=75)
번외) match vs wildcard (약
2배
속도차이)
하지만 ms 단위여서 큰 차이는 없다고 판단하여 편의성이 더 뛰어난 wildcard쿼리로 결정(추후에
ngram
방식으로 변경 예정)![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Fdc51cb75-d27d-4c21-970b-0b24c291b41c%252FUntitled.png%3Ftable%3Dblock%26id%3De78fbf4a-d488-4756-8cc9-0f127ca11ee6%26cache%3Dv2&w=3840&q=75)
인피니트 스크롤
필요한 만큼의 데이터만 전달해주는 방식으로 변경
before
- 전체 데이터를 넘겨주고 프론트에서 무한스크롤 적용
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Fb4454791-7826-4dbb-afb8-8180948bb165%252F%2525EB%2525AC%2525B4%2525ED%252595%25259C%2525EC%25258A%2525A4%2525ED%252581%2525AC%2525EB%2525A1%2525A4_%2525EC%252584%25259C%2525EB%2525B9%252584%2525EC%25258A%2525A4_%2525EB%2525B3%252580%2525EA%2525B2%2525BD_%2525EC%2525A0%252584.png%3Ftable%3Dblock%26id%3Daa2802b3-45cf-40e1-9229-024d9841181a%26cache%3Dv2&w=3840&q=75)
after
- 스크롤이 특정 위치까지 가면 추가로 데이터 요청해서 가져오는 방식
- 보여지는 개수보다 1개 더 요청해 다음페이지가 있는지 확인하는 방식
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F32b5eadf-1518-4d3a-8aa9-c0d6378ba385%252F%2525EC%25258A%2525A4%2525ED%252581%2525AC%2525EB%2525A6%2525B0%2525EC%252583%2525B7(607).png%3Ftable%3Dblock%26id%3D6ebdee72-e21d-4db7-b0d7-0ea348f2e24e%26cache%3Dv2&w=3840&q=75)
JMeter 테스트
1초에 2000명의 유저가 값을 불러온 결과 평균 약 3.4배의 속도 차이
전체 데이터량은 약 900개 정도였으며, 데이터가 늘어나면 늘어날수록 속도 차이가 점점 더 심해질 것으로 예상.
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Fa1d2b35d-a792-47b4-bb6c-3e055747fc8d%252Fimage.png%3Ftable%3Dblock%26id%3Dcfda3cec-0f39-40bb-b881-21ef0d3ec61f%26cache%3Dv2&w=3840&q=75)
이미지 리사이징
이미지파일의 용량을 줄여서 웹페이지 로딩속도 개선
Sharp
라이브러리 사용before
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F40ce20b4-db0b-42e3-94bb-a162d5b47f9c%252FUntitled.png%3Ftable%3Dblock%26id%3Db6d51057-6011-4fa6-932b-b95a948b81a0%26cache%3Dv2&w=3840&q=75)
after
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F6f357a27-f9bd-49a6-8505-9775221db454%252FUntitled.png%3Ftable%3Dblock%26id%3D121d00ef-0dea-4e6f-b311-b336bb550f84%26cache%3Dv2&w=3840&q=75)
Share article
Subscribe to our newsletter