커리큘럼
home
React
home

[Stock Pyramid]경매 이벤트의 대용량 트래픽을 처리하기 위한 node.js 기반 어플리케이션 시스템

Specialty
Node.js
FE Github
Specialty
날짜

프로젝트

Stock Pyramid는 경매 이벤트의 대용량 트래픽을 처리하기 위한 node.js 기반 어플리케이션 시스템 구축 프로젝트입니다
keyword : #대용량 트래픽 처리 #검색 속도 향상 #성능 테스트 #nestjs #DB이중화

 기획 배경

대용량 트래픽 처리를 기술적 도전 과제로 삼은 이유

안정적인 시스템을 구축하는 일은 시스템의 신뢰성을 시험하고 평가하는 과정을 수반합니다. 평가를 위해 인프라, 네트워크, DB 등 다양한 요소를 고민하게 됩니다. 이러한 경험은 백엔드 엔지니어로서 기능 구현 뿐만 아니라 한 줄의 코드가 전체 시스템의 관점에 어떤 영향을 미치는지 종합적으로 판단하는 경험을 얻을 수 있는 최적의 프로젝트라 판단했습니다.

 구현 API

생성
입찰(bid) 제출
조회
전체 : 경매(Raffle) 데이터
상세 검색 : 사이즈 별 입찰(bid) 데이터
로그인

 생성 데이터

테스트로 생성된 총 데이터량 약 1TB
경매 데이터(Raffle) : 1만
입찰 데이터(Bid) : 1,200만
상품 데이터(Product) : 1만
유저 데이터(User) : 20만

 서비스 아키텍처 & 기술 도입 배경

프레임워크(nest.js)

옵션 : nest.js, express.js
선정 이유 : 협업 시 일정 수준 이상의 코드 표준화를 달성하기 수월하다고 판단

테스팅 툴(nGrinder)

옵션 : AB, Artillery, JMeter, nGrinder
선정 이유 : 복수의 머신으로 부하 테스트를 진행하고 상세 리포트 제공

모니터링 툴(netdata)

옵션 : New Relic, netstat, htop
선정 이유 : 오픈소스이고 성능 지표가 상세하며 도입 시 복잡한 절차가 필요하지 않음

요청 로드밸런싱 (HAProxy)

옵션 : nginx, apache, Cloud Load Balance Service, HAProxy
선정 이유 : L7 Load Balance 가 가능하여 특정 요청처리를 원하는대로 할 수 있음
원하는 곳에 설치하여 클라우드 로드밸런서 보다 실시간 모니터링이 쉬워짐

DataBase HA (repmgr)

옵션 : pg-pool II, repmgr
선정 이유 : Auto Failover 및 이중화 구성에 있어 메뉴얼 구성에 대한 접근방법이 다양함

DataBase Query Load Balance (pg-pool II)

옵션 : Cloud Service, pg-pool II
선정 이유 : 클라우드 서비스 보다 실시간 리소스 사용률에 대한 모니터링 및 가능해짐

 기술적 도전 및 트러블 슈팅

DB 이중화를 통한 high available 및 Read/Write 속도개선

같은 OS 에서도 기존에 성공했던 절차를 따라 설치 및 세팅을 해도 실패하는 경우가 발생함
같은 centOS 7 에서도 컴퓨터 제공 옵션마다 설치 후 시스템 사용 가능여부가 달라짐
Naver Cloud Server 옵션중 Compact는 실패 High CPU 에서는 성공 Standard 에서는 실패

Postgres Index를 적용하여 검색 속도 개선

입찰 데이터를 검색 시, 기존 1,200만건의 입찰 데이터를 bidSize = 270 , order by createdAt 두 조건으로 full scan하고 있던 상황
bidSizecreatedAt 두 컬럼에 인덱싱 적용 후, 응답 시간이 기존 700ms에서 100ms으로 약 85% 감소
단, 쿼리 실행 계획과 실제 요청 시 Latency의 변화 폭이 차이가 있었다는 점이 특이사항

Redis 캐싱

Raffle 전체 조회 API의 경우, 동시 접속자 수가 증가함에 따라 반복적인 I/O 작업으로 인한 병목이 발생
동일한 결과를 반환하고 데이터 휘발의 걱정이 없는 전체 조회 결과의 경우 캐싱을 하는 것이 적합하다고 판단
처음 실시간 모니터링 기능을 제공하는 Redis cloud을 도입했으나, 테스트 부하의 강도가 증가함에 따라 리소스 부족 현상이 발생하여 로컬 Redis로 변경

Github Actions - Docker Compose 활용한 CI/CD 파이프라인 구축

코드의 변경 사항이 있을때 마다 git push/pull을 하거나 docker 이미지를 만들고 pull을 받는 과정에서 피로도를 느낌
자동화를 하기위해 가장 잘 알려진 방법인 github Actions와 docker compose를 사용함
c6g 시리즈로 서버 구축시 cpu아키택쳐 문제로 도커이미지 빌드시 platform을 linux/arm64지정해줘야하는데, 그것떄문에 빌드하는데 시간이 오래걸림
platform에 따라 다른 방법을 찾아봐야한다(aws 코드디플로이 등등)
(현재 프로잭트에서는 금액 문제로 ncloud로 바뀌게되어 아키택쳐로인한 문제는 해결됨)

Performance Test 디자인

성능 테스트 실험 시, 실험 조건과 변수를 어떻게 설정해야 유의미한 인사이트를 얻을 수 있을지 고민함
Vuser, Agent, 서버 성능, 수평적 확장 여부 등을 주요 변수로 삼고 이를 평가하는 지표를 Throughput, Latency, 테스트 성공/실패 여부 등을 참고

 대용량 트래픽이 서버에 끼치는 영향에 대한 테스트

부하에 대한 신뢰도 검증 Level Test 진행

레벨별 테스트를 진행하여 어느부분에서 병목이 진행되는지 파악이 가능해짐
level 1
Instance Test
nginx를 사용하여 기본 정적페이지 반환 테스트
테스트 목적 : 현제 인스턴스의 컴퓨팅 스팩에서 최대 얼마만큼의 요청까지 처리할수있는지 확인
level 2
Web Application Server Test
‘hellow world’ 반환하는 testApi 만들어서 GET요청
테스트 목적 : 기본적인 NestJs서버의 부하 수용 능력 확인
level 3
Read Only Database Test
프론트엔드에서 요청할 경매 데이터 1만개 GET요청
테스트 목적 : nest서버와 데이터베이스와의 부하 수용 능력 확인
level 4
Write Only Database Test
6000명 vuser가 명당 1000번씩 총 6,000,000개의 POST요청
테스트 목적 : 대량의 post요청시 데이터유실없이 디비에 잘 들어가나 확인
level 5
Write / Read database Test
agent1 = post, agent2 = findAll(with Redis), agent3 = findOne 동시 진행
테스트 목적 : read,write동시 진행시 부하 수용 능력 확인
level 6
Scenario Test
agent1 = login→ findAll→ findOne → POST → findAll … 복합요청
agent2 = POST (Random Interval Pattern)
agent3 = findAll, findOne(Random Pattern)
테스트 목적 : 실제 유저의 사용에 대한 부하 수용 능력 확인