마스터클래스 질의응답 모음
1. 서비스 성능 측정2. 웹 성능 예산1) 예비 분석2) 경쟁사 혹은 유사 사이트 분석 3) 성능 기준 설정ETC) 성능에 대한 관점3. 부하테스트1) 서비스가 얼마나 빠른지(Time)2) 일정 시간 동안 얼마나 많이 처리할 수 있는지(TPS)3) Performance vs Scabaility3) 얼마나 많은 사람들이 동시에 사용할 수 있는지(Users)4. 테스트 종류1) Smoke Test2) Load Test3) Stress Test5. 테스트 도구6. 테스트시 주의할 점7. 테스트 계획1) 전제 조건2) 목표값 설정3) 시나리오 대상8. K6로 작성해보기1) install2) 참고링크3) 실습코드Reference
1. 서비스 성능 측정

- https://www.webpagetest.org/
- 연결을 시도하는 위치, 환경부터 Repeat View(캐싱 등 테스트), 동일한 조건으로 여러 차례 테스트할 수 있음
- 테스트한 결과를 영상으로 기록

2. 웹 성능 예산
- What
- 웹 사이트를 유지하고 운영하는 데 필요한 예산.
- 웹 사이트의 성능을 향상시키기 위해 필요한 서버 자원, 인프라 구축 및 유지보수 비용, 웹 서비스 제공 업체의 요금 등을 포함.
- 웹 성능 예산을 적절히 관리하면 웹 사이트의 성능을 최적화할 수 있음
- How
- 정량 / 시간 / 규칙 기반으로 산정
- 성능 목표에는 정답이 없지만, 3초의 법칙 (3초 안에 로딩되지 않으면 53%의 사용자가 떠나고 로딩 시간이 길어질수록 사용자 이탈률이 늘어남)이 있듯, 서비스의 성능 목표를 두는 것이 필요
- Goal
- 메인 페이지의 모든 오브젝트 파일 크기는 10MB 미만으로 제한
- 이미지를 원본으로 사용하는 것
- 카메라로 찍은 사진 → 용량이 매우 큼
- 보통 모니터 1920x1080 인데, 사진은 이 크기를 매우 초과
- 모든 웹 페이지의 각 페이지 내 포함된 자바스크립트 크기는 1MB를 넘지 않아야 함
- SPA으로 만든 페이지가 10개
- 10개의 페이지 정보를 다 로딩할 필요가 있을까? → Nope
- 필요한 페이지만 로딩 하자
- Dynamic Import
- 검색 페이지에는 2MB 미만의 이미지가 포함
- LTE 환경에서의 모바일 기기의 Time to Interactive는 5초 미만
- Dom Content Loaded는 1초, First Meaningful Paint는 1.5초 미만
- Lighthouse 성능 감사에서 80점 이상
- 어떻게 Dom Content Loaded가 10초인데 Lighthouse 성능이 80점이 나오죠
1) 예비 분석
- 사용자 트래픽이 많은 페이지 혹은 제품 방문 페이지 등 가장 중요한 페이지에 대해
- PageSpeed를 활용하여 FCP, TTI 등의 지표 확인
2) 경쟁사 혹은 유사 사이트 분석
- 경쟁 사이트 또는 유사한 사이트(similarweb 등을 활용)의 성능 분석
- 사용자는 응답시간이 20% 이상일 때 차이를 인식함 (참고) → 분석한 사이트와 20% 이상 성능 차이가 나는지 확인
3) 성능 기준 설정
정량
/시간
/규칙
기반
- 우선 서비스에 중요한 페이지부터 작성
- 예시
- 페이지로드 3초 미만
- TTI 5초 미만
- 압축된 리소스 최대 크기 200KB 미만
- …
- 정량(Quantity based Metric)
- 이미지 최대 크기
- 웹 글꼴 최대 크기
- 글꼴 최대 갯수
- 스크립트 최대 크기
- 스크립트 최대 갯수
- HTML, CSS 최대 크기
- 동영상 최대 크기
- 시간(Timing based Metric)
- FCP, LCP, TTI, TBT, CLS 등 pagespeed에서 제공하는 데이터
- 규칙(Rule based Metric)
- WebPageTest, pagespeed 등 웹 사이트에서 측정한 점수를 지표로 사용
- 우선순위
- 여러 지표들 중 우선순위가 높은 지표 선정
- 사용자에게 컨텐츠가 빠르게 노출되고 렌더링하는 것이 중요 → FCP 우선순위 높음
- 사용자가 관련 링크를 빠르게 클릭해야 할 경우 → TTI 우선순위 높음
ETC) 성능에 대한 관점
- 성능의 개선 및 저하는 수익에 직접적인 영향을 준다 → 화면 응답시간이 느리다고 판단되면, 어느 부분에서 지연현상이 발생하는지 파악해야 함 (참고: https://web.dev/why-speed-matters/)
- 서비스가 얼마나 빠른지(Time) / 일정 시간 동안 얼마나 많이 처리할 수 있는지(TPS) / 얼마나 많은 사람들이 동시에 사용할 수 있는지(Users)
- 성능 개선에는 한계가 생길 수밖에 없음(암달의 법칙) → 부하의 원인을 파악하여 제거
- 브라우저에서 제일 성능을 많이 잡아 먹는 것 → 렌더링
- 의외로 중요한 것 → 반복문
- for vs forEach
- while vs for
- for in vs for of
- → 사용자가 느끼기에 그렇게까지 큰 차이가 없음
- 렌더링은? → 매우 차이가 큼
- 화면은 60Hz, 144Hz, 240Hz
- 1초 → 60번 렌더링
- 16.666ms
- 브라우저 입장에서는 어떤 명령이든 이 시간 동안에만 실행되면 된다.
- 1초 → 144번 렌더링
- 1초 → 240번 렌더링
성능 테스트 vs 부하 테스트 → ?
성능 테스트 → 단일 리퀘스트가 얼마나 빠른가
부하 테스트 → 요청을 얼마나 버틸 수 있는가 (가용성)
서버 개발자에게 제일 중요한 것 → 안죽는거
얼만큼 노동을 시켜야 죽는가 →
어떻게 해야 죽지? → 죽는걸 미리미리 예방해보자
3. 부하테스트
부하란?
요청을 처리하려고 해도 실행할 수 없어서 대기하고 있는 프로세스의 수
https://brainbackdoor.tistory.com/117
1) 서비스가 얼마나 빠른지(Time)

- 시스템 입장 → 응답시간(Response Time)
- 사용자입장 → 사용자가 요청에 대해서 응답을 받은 후에 웹 페이지를 보기 까지(Think Time)
- 성능 테스트 시엔 실제 지연시간이 발생하는 구간을 파악 필요
- 브라우저 → 웹 서버
- 정적 파일 크기
- Connection 관리
- 네트워크 환경
- Server
- DB와 애플리케이션 간 연결의 문제
- 프로그램 로직 상의 문제
- CPU점유율이 많은 경우
- JS에서는 response를 받아서 json으로 변환
- json으로 변환한 다음에, dto로 변환
- 예를들어서, 응답의 크기가 8MB → DTO 변환 → CPU를 혹사
- 요청을 처리할 때 CPU 사용이 많아지고 → 응답이 느려지는
- nodejs → 비동기 처리 → CPU를 점유하고 있으면 문제가 됨
- 멀티 스레드 → CPU점유하고 있더라도 스레드를 나눠서 관리하면 되니까 비교적 리스크가 적음
- 싱글 스레드 + 비동기 → 특정 코드가 CPU 점유율이 높음 → 다른것들을 수행할 수 없음
- 서버의 리소스 부족
- 네트워크 이슈
- 단순히 서버를 늘린다고(Scale out) 해결 X
- 출시 전에 테스트를 하여 최대 응답시간을 파악
- 상위 5%의 화면이 95% 사용자 요청을 받는다는 점을 감안하고 튜닝의 대상을 선정
2) 일정 시간 동안 얼마나 많이 처리할 수 있는지(TPS)
- Transaction
- 시간당 처리율을 나타내는 지표의 기준
- 서버 입장 → 각각의 요청들이 Transaction
- 사용자 입장 → 한 화면을 보기위해 필요한 모든 요청 묶음이 Transaction

- 응답시간

- TPS = Transaction Per Second
- https://www.whatap.io/ko/blog/14/
- 서비스 처리 건수 / 측정 시간
- 요청 사용자 수 / 평균 응답시간
- 동시 사용자 수 / 서비스 요청 간격
- User 증가 → TPS는 어느 정도 증가하다가 더 이상 증가하지 않음. Time은 일정하게 유지되다 점차적으로 증가
- 부하(TPS)가 증가 → 지연시간은 변곡점에 이르기도 하는데, 이 경우 시스템 리소스가 누수되고 있는 것은 아닌지 확인 필요
- 데드락
- 스레드가 너무 많은 경우 → 컨텍스트 스위칭 비용이 너무 많아짐 → 요청을 처리할수 없는 상태가 되어버림
- TPS (Transaction Per Seconds)는 Scale out 혹은 Scale up을 통해 증가시킬 수 있음
- 성능테스트와는 다른 점 → 서버를 늘리면 TPS 자체는 증가시킬 수 있음
- 보통 테스트 시에 단순히 응답시간을 기준으로 종료시키지 말고, TPS나 DB Connection, CPU 등을 종합적으로 확인하고 중단시켜야 합니다.
3) Performance vs Scabaility
- 성능에 문제가 있는 경우 → 단일 사용자에 대한 응답 속도가 느려짐
- 확장성에 문제가 있는 경우 → 단일 사용자에게는 빠르지만 부하가 많아질 경우 속도가 느려짐
3) 얼마나 많은 사람들이 동시에 사용할 수 있는지(Users)
얼마나 많은 사람들이 동시에 사용할 수 있는가 → 서비스를 운영하며 늘 화두
사용자 → 관점에 따라 다양한 형태로 존재함
- 시스템 관리자의 관점 → 등록된 사용자 or 등록되지 않은 사용자
- 서버의 관점 → 로그인한 사용자 or 로그인하지 않은 사용자
- 성능 테스터의 관점 → Concurrent User or Active User
- Concurrent User: 웹 페이지를 띄어놓은 사용자처럼, 언제든지 부하를 줄 수 있는 사용자
- Active User: 메뉴나 링크를 누르고 결과가 나오기를 기다리는 등 실제로 서버에 부하를 주고 있는 사용자
Active User 와 Concurrent User 의 비율은 서비스의 성격에 따라 다르므로 이 점을 감안하고 성능테스트를 계획해야 합니다. (성능 테스트시에 VUser는 Active User와 유사합니다.) 가령 수강신청의 경우, 특정 시간대엔 그 비율이 90%에 육박할 수 있어, 전체 평균을 기준으로 테스트할 경우 잘못된 판단을 이끌어낼 수 있습니다.
- keep-alive
- 한 번 연결을 해놓고 유지한다
- 먼저 선점한 사용자가, 어떤 기능을 이용하든 우선순위가 높음
- keep-alive가 끊어져야 뒷사람에게도 기회가 있음
4. 테스트 종류
1) Smoke Test
- 최소한의 부하로 구성된 테스트 → 테스트 시나리오에 오류가 없는지 검증
- VUser를 1 ~ 2로 구성
2) Load Test
- 서비스의 평소 트래픽과 최대 트래픽 상황에서 성능이 어떤지 확인
- 애플리케이션 배포 및 인프라 변경(scale out, DB failover 등)시에 성능 변화 확인
- 외부 요인(결제 등)에 따른 예외 상황을 확인
3) Stress Test
- 서비스가 극한의 상황에서 어떻게 동작하는지 확인
- 장기간 부하 발생에 대한 한계치를 확인
- 최대 사용자, 최대 처리량
- 스트레스 테스트 이후 시스템이 수동 개입없이 복구되는지 확인
5. 테스트 도구
- Apache JMeter
- OS의 영향이 심함
- 윈도우 환경에서 테스트할 때 문제되는 경우가 많음
- 네이티브 앱
- nGrinder
- 설치형 웹서버
- Gatling
- Locust
- K6
- 쉽고
- cloud
6. 테스트시 주의할 점
- 시나리오 기반의 테스트
- 각 사용자마자다
- 회원가입을 하고
- 로그인을 하고
- 게시물을 쓰고
- 게시물을 조회하고
- 게시물을 삭제하기
→ 사용자 인증 + DB 조회
→ 사용자 인증 X, DB 조회
- 동시 접속자 수, 요청 간격, 최대 Throughput 등 부하를 조정할 수 있어야 함
- 부하 테스트 서버 스케일 아웃을 지원하는 등 충분한 부하를 줄 수 있어야 함
- 성능 테스트는 실제 사용자가 접속하는 환경에서 진행
- 로컬 → 로컬 = 무의미
- 내부 네트워크에서 부하를 발생 → 응답시간에 차이가 발생
- 클라이언트 내부 처리시간이 배제되어 있음
- 테스트 DB에 들어 있는 데이터의 양이 실제 운영 DB와 동일해야 됨
- 통상 전체 성능의 70% 이상이 DB에 좌우됨
- 데이터 양이 다름 → 쿼리의 실행계획이 달라짐 or 디스크 입출력 차이 → 성능이 다르게 나타남
- 외부 요인(결제 등)의 경우 시스템과 분리된 별도의 서버로 구성
- 객체 Mocking → Http Connection Pool, Connection Thread 등을 미사용 → I/O가 미발생
- 같은 애플리케이션에 Dummy Controller를 구성 → 테스트 시스템의 자원과 리소스를 같이 사용 → 테스트의 신뢰성 감소
- 네이버 → 포털 → 캐싱을 굉장히 적극적으로 사용함
- 배민, 두나무 → 결제 시스템 → 캐시X, Real을 얼마나 잘 쓰는가
7. 테스트 계획
1) 전제 조건
- Target 시스템의 범위 선정
- 부하 테스트시에 저장될 데이터 건수와 크기를 결정
- 서비스 이용자 수, 사용자의 행동 패턴, 사용 기간 등을 고려하여 계산
- 목표값에 대한 성능 유지기간 선정
- 서버에 같이 동작하고 있는 다른 시스템, 제약 사항 등을 파악 (사이드 이펙트)
2) 목표값 설정
- 예상 1일 사용자 수(DAU)
- 피크 시간대의 집중률 예상
- 최대 트래픽
- 평소 트래픽
- 1명당 1일 평균 접속 혹은 요청수 예상
- Throughput을 계산합니다.
- Throughput → 1일 평균 rps ~ 1일 최대 rps
- 1일 사용자 수(DAU) x 1명당 1일 평균 접속 수 = 1일 총 접속 수
- 1일 총 접속 수 / 86,400 (초/일) = 1일 평균 rps
- 1일 평균 rps x (최대 트래픽 / 평소 트래픽) = 1일 최대 rps
- Latency → 일반적으로 50~100ms이하로 잡는 것이 좋음
- 사용자가 검색하는 데이터의 양, 갱신하는 데이터의 양 등을 파악
3) 시나리오 대상
- 접속 빈도가 높은 기능
- 홈페이지 등
- 서버 리소스 소비량이 높은 기능
- CPU
- 이미지, 동영상 변환
- 인증
- 파일 압축/해제
- Network
- 응답 컨텐츠 크기가 큰 페이지
- 이미지, 동영상 업로드/다운로드
- Disk
- 로그가 많은 페이지
- DB를 사용하는 기능
- 많은 리소스를 조합하여 결과를 보여주는 페이지
- 여러 사용자가 같은 리소스를 갱신하는 페이지
- 외부 시스템과 통신하는 기능
- 결제 기능
- 알림 기능
- 인증/인가
네이버 → 굉장히 계획적임 → 1년치 계획 → 각각의 구성원에 대해 성과를 측정하는 것에 적극적 → 경쟁이 심할 수 있음
기업자체가 계획적인 사람을 좋아하는가?
팀 자체가 계획적으로 움직이는가?
→ 대기업
팀 자체가 인사이트를 통해서 움직이는가?
→ 스타트업
토스 → 구성원의 성과를 측정하지 않음 → 기업의 성과를 측정 → 구성원에게 보상
토스 → 전직원 성과금 = 연봉의 최소 10% ~ 최대 200%
네이버 → 개개인의 성과에 따라 차등 지급
토스 → 목적조직 위주
→ 채팅 팀
→ FE, BE, 디자이너, 기획자, PO 한 팀
→ 서비스를 만들 때, 커뮤니케이션이 미친듯이 빠름 → 일이 너무 많아
네이버 → 기능조직 위주
→ 백엔드 개발자 팀
→ 프론트엔드 개발자 팀
→ 디자인 팀
→ 서비스를 만들 때, 커뮤니케이션이 좀 느릴 수 있음 → 누군가는 답답함을 느낌
→ 안정감. 시니어가 밀집되어있음. 깊게 배울 수 있는 것들이 많음
카카오 → 일이 많이 없다 + 보상도 많이 짜다
대기업(네카라)
→ 연봉테이블
→ 3년차 연봉의 최대치 6500
우형, 토스, 당근, … → 상한선이 거의 없는 편
우형 → 모니터링을 굉장히 빡세게 → 항상 긴장감을 유지하는 곳
8. K6로 작성해보기
1) install
2) 참고링크
3) 실습코드
script.js
import http from 'k6/http'; import { check, group, sleep, fail } from 'k6'; export let options = { stages: [ // target = VUser = Active User { duration: '1m', target: 30 }, { duration: '1m', target: 60 }, { duration: '1m', target: 90 }, { duration: '1m', target: 120 }, { duration: '1m', target: 150 }, ], thresholds: { http_req_failed: ['rate<0.01'], // http 오류는 1% 미만이어야 함 http_req_duration: ['p(95)<200'], // 요청의 95%는 200ms 미만으로 응답해야 함 }, }; const BASE_URL = 'https://httpbin.test.k6.io/'; const USERNAME = '***'; const PASSWORD = '***'; export default function () { const res = http.get('https://httpbin.test.k6.io/'); check(res, { 'status was 200': (r) => r.status == 200 }); sleep(1); }
$ k6 run ./script.js

Reference
- 토스의 서버 인프라 모니터링
