1. 성능을 개선하려면, 먼저 “측정”이 필요하다
코드를 더 잘 짜고 싶고, 사용자 경험도 좋게 만들고 싶다면
무작정 최적화부터 하는 게 아니라 “현재 상태를 숫자로 측정”하는 것부터 시작해야 한다.
1) 페이지가 느린 것 같은데 얼마나 느린지
2) 서버가 버거워 보이는데 얼마나 바쁜지
3) 비용이 많이 나간다는데 얼마나 줄였는지
이런 것들을 전부 숫자(지표)로 말할 수 있어야 “내가 성능 개선을 했다”는 걸 증명할 수 있고,
개발자 입장에서도 포트폴리오나 회고에 멋지게 써먹을 수 있는 것!
2. 왜 성능 개선이 중요한가?
개발자가 성능을 개선하면, 보통 세 가지가 같이 좋아진다.
1) 사용자 경험(UX) 개선
화면이 빨리 뜨고, 버튼 클릭 후 응답이 빠르면 “이 서비스 잘 만든 것 같다”라는 인상을 줌.
2) 비용 절감
같은 서버로 더 많은 요청을 처리하면 서버 수를 줄이거나, 인스턴스 스펙을 낮출 수 있어서 돈을 아낄 수 있음.
3) 신뢰도 향상
에러가 줄고, 지연이 적어지면 기획/운영/고객 모두에게 “믿고 써도 되는 시스템”이 됨.
3. 백엔드 성능을 볼 때 자주 쓰는 지표들
3-1. 응답 시간 (Response Time)
클라이언트(브라우저/앱)가 요청을 보내고, 서버에서 응답을 돌려줄 때까지 걸리는 시간.
- 예시: /api/user/profile 호출 시 (개선 전: 평균 700ms → 개선 후: 평균 180ms)
- 느낌: 사용자가 “버튼 누르고 얼마나 기다려야 하는지”에 직접적인 영향을 주는 값.
3-2. 처리량 (Throughput, 초당 처리 요청 수 RPS)
서버가 1초에 처리할 수 있는 요청(Request)의 개수.
- 보통 RPS(Requests Per Second) 또는 TPS(Transactions Per Second)로 표현해요.
- 예시: (개선 전: 1,500 RPS → 개선 후: 4,000 RPS)
- 느낌: 동시에 많은 사용자가 몰렸을 때 서버가 버티는 힘.
3-3. 자원 사용률 (Resource Utilization)
서버의 CPU, 메모리, 디스크, 네트워크 등이 얼마나 쓰이고 있는지 비율로 보는 것.
- 예시: (CPU 사용률: 85% → 55% → 메모리 사용률: 90% → 60%)
- 느낌: 항상 80~90% 이상이면, 서버가 숨이 턱턱 막히는 상태라서 장애 위험이 큼. 적절한 선(예: 50~70%)으로 내려주면 안정성이 올라감.
3-4. 지연 시간 (Latency)
특정 구간에서 발생하는 지연 시간을 말할 때 많이 쓴다. 예를 들어 DB 쿼리 실행 시간, 외부 API 호출 시간, 캐시 조회 시간 등
- 예시: (DB 쿼리: 300ms → 40ms), (외부 결제 API 호출: 800ms → 250ms)
- 느낌: 전체 응답 시간 중에서 “어디서 시간이 많이 잡아먹는지”를 찾는 데 쓰는 값.
3-5. 오류율 (Error Rate)
전체 요청 중에서 에러로 끝난 요청의 비율. HTTP 5xx, 4xx 같은 에러 응답. 타임아웃, 예외(Exception) 등.
- 예시: ( 개선 전: 에러율 3% → 개선 후: 에러율 0.3%)
- 느낌: 서버가 아무리 빠른들 에러가 많이 나면 소용이 없음. 성능 개선과 안정성(에러 감소)는 항상 같이 봐야 함.
4. 이런 지표들은 “도구”로 측정한다
백엔드나 API 성능을 테스트할 때는 보통 부하 테스트(Load Test) 도구를 쓴다.
- JMeter
- Apache에서 만든 부하 테스트 도구
- GUI가 있어서 클릭으로도 시나리오 설정 가능
- HTTP, DB, FTP 등 여러 프로토콜 지원
- k6
- 코드(JS-like 스크립트)로 시나리오를 작성하는 부하 테스트 도구
- 개발자 친화적인 CLI 기반
- CI/CD 파이프라인에 넣어서 정기적으로 성능 테스트 자동화하기 좋음
이런 도구로 “동시에 100, 1000, 5000명이 접속하는 상황”을 시뮬레이션해서
응답 시간, 처리량, 에러율 등을 숫자로 뽑아낼 수 있다.
5. 성능 개선 내용을 “A-B-C 패턴”으로 정리하기
성능/비용/안정성 개선을 어필할 때는 A-B-C 패턴으로 정리하면 보기 좋다.
- A (As-Is / 문제 상황)
- 개선 전 상태, 문제가 무엇이었는지
- “느렸다”, “불안정했다”가 아니라 숫자로 말하기
- B (To-Be / 내가 한 일)
- 내가 적용한 기술, 방법, 설계 변경
- 어떤 선택을 했는지 간단하게
- C (Benefit / 그 결과)
- 그래서 수치가 어떻게 바뀌었는지
- 응답 시간, 처리량, 비용, 에러율 등
6. 예제
6-1. 로그인 API 성능 개선
- A (문제)
로그인 API 평균 응답 시간이 650ms였고, 출근 시간(09~10시)에 동시 접속자가 몰리면 1초 이상 걸리는 경우가 자주 발생했습니다.
- B (해결책)
비밀번호 검증 로직에서 불필요한 DB 조회를 제거하고, 사용자 정보 중 자주 쓰이는 필드를 캐시 서버(예: Redis)에 저장했습니다.
- C (성과)
로그인 API 평균 응답 시간: 650ms → 180ms
출근 피크 타임에도 응답 시간이 300ms 이내로 유지
DB CPU 사용률: 75% → 55%로 감소
6-2. 주문 목록 조회 쿼리 최적화
- A (문제)
“주문 내역 조회” 화면이 로딩될 때마다 DB 쿼리 실행 시간이 3초 이상 걸려, 사용자가 리스트를 보는데 답답함을 느꼈습니다.
동시에 조회 요청이 몰리면, 다른 쿼리들도 느려지는 문제가 있었습니다.
- B (해결책)
자주 검색하는 조건(회원 ID, 주문일자)에 맞게 복합 인덱스를 추가하고, 화면에 필요 없는 컬럼과 JOIN을 정리해 쿼리를 단순화했습니다.
최근 3개월 주문만 기본 조회하고, 이전 데이터는 “더보기”로 분리했습니다.
- C (성과)
쿼리 실행 시간: 3초 → 250ms
동일한 서버 환경에서 처리 가능한 조회 요청 수: 약 4배 증가
주문 페이지 이탈률: 18% → 7%로 감소
6-3. 서버 비용 및 로그 저장 최적화
- A (문제)
모든 API에 대해 상세 디버그 로그를 남기면서 매달 로그 저장 비용과 저장소 사용량이 크게 늘어났고, 로그를 쓰느라 API 응답 시간도 약간 느려지는 현상이 있었습니다.
- B (해결책)
디버그 로그를 개발/스테이징 환경으로 제한하고, 운영 환경에서는 에러/경고 중심의 요약 로그만 남기도록 변경했습니다.
오래된 로그는 30일 이후 자동 삭제되도록 수명 주기 정책을 설정했습니다.
- C (성과)
월 로그 스토리지 비용: 90만원 → 30만원
디스크 I/O 부담 감소로 일부 API 응답 시간: 평균 50ms 정도 추가 개선
장애 분석에 필요한 핵심 로그만 남아, 로그 분석 시간도 단축
7. 정리: 초보 개발자가 가져가면 좋은 포인트
7-1. 무조건 먼저 “측정”부터 한다.
응답 시간, 처리량, 오류율 같은 숫자를 빼와야 “개선 전 vs 개선 후”를 말할 수 있다.
7-2. 전체가 아니라, “어디가 느린지”를 쪼개서 본다.
API 전체 시간 안에서도 DB 쿼리 / 외부 API / 로직 처리 이런 구간별 Latency를 보는 습관을 들이면 좋다.
7-3. 개선 내용을 A-B-C로 정리해 둔다.
나중에 포트폴리오, 성과 정리, 이직/연봉 협상에도 큰 무기가 된다.
예: “주문 조회 API 응답 시간을 3초에서 250ms로 단축하고, DB 부하를 줄여 동시 접속 처리량을 약 4배 향상시켰습니다.”
8. 프론트엔드에서 자주 쓰는 성능 지표들
8-1. LCP (Largest Contentful Paint) – “큰 요소가 보이기까지의 시간”
화면에서 가장 큰 콘텐츠(예: 큰 이미지, 큰 텍스트 블록)가 사용자에게 눈에 보이기까지 걸리는 시간.
→ 사용자가 “아, 이제 화면이 떴구나”라고 느끼는 기준에 가까움.
- 예시: (개선 전: LCP 4.8초 → 개선 후: LCP 2.1초)
- 개선에 영향을 주는 것들
- 이미지 용량, 포맷(JPEG → WebP/AVIF)
- 메인 폰트 로딩 방식
- 가장 큰 배너/히어로 영역에 Lazy Loading 적용 여부
- 초기 렌더링을 막는 JS/CSS
8-2. FCP (First Contentful Paint) – “처음 뭐라도 보이기까지의 시간”
화면에 첫 번째 텍스트, 이미지, SVG 등 콘텐츠가 그려지는 시간.
→ 완전히는 아니어도, 최소한 “하얀 화면”은 아닌 상태가 되는 시점.
- 예시: (개선 전: FCP 2.3초 → 개선 후: FCP 1.0초)
- 개선에 영향을 주는 것들
- CSS/JS를 너무 많이 블로킹으로 불러오는지
- 초기 렌더링에 꼭 필요하지 않은 스크립트 지연 로딩(Defer, Async)
- CDN/캐시 적용 여부
8-3. TTI (Time to Interactive) – “제대로 클릭/스크롤 가능한 시간”
화면이 보이긴 하지만, JS가 바빠서 클릭해도 늦게 반응하거나 멈춘 것처럼 보이는 경우가 있음.
TTI는 “사용자가 실제로 상호작용할 수 있는 상태가 되기까지 걸리는 시간”을 말한다.
- 예시 : ( 개선 전: TTI 7초 → 개선 후: TTI 3초)
- 개선에 영향을 주는 것들
- 한 번에 너무 큰 JS 번들을 로딩하는지
- 초기 렌더링 시 복잡한 계산/루프를 많이 돌리는지
- 코드 스플리팅(필요한 페이지/기능만 JS를 나눠서 로딩)
8-4. CLS (Cumulative Layout Shift) – “레이아웃이 덜컥덜컥 움직이는 정도”
페이지가 로딩되는 동안 글과 버튼이 갑자기 아래로 밀리거나 위치가 바뀌는 현상을 숫자로 표현한 지표.
→ 사용자가 잘못 클릭하게 되는 대표적인 빡침 포인트…
- 예시: (개선 전: CLS 0.25 → 개선 후: CLS 0.03)
- 개선에 영향을 주는 것들
- 이미지/영상 태그에 width/height 고정 안 해둔 경우
- 광고/배너가 나중에 끼어들면서 레이아웃 밀어버리는 경우
- 폰트 로딩 때문에 텍스트가 갑자기 리플로우 되는 경우
8-5. 번들 크기 (Bundle Size)
빌드 후 나오는 JS/CSS 파일들의 용량. 브라우저가 다운로드해야 하는 데이터 크기.
- 예시 : (JS 번들: 900KB → 350KB), (CSS 번들: 300KB → 120KB)
- 줄이는 방법 예시
- 사용하지 않는 라이브러리/코드를 제거(Tree Shaking)
- 페이지별 코드 스플릿 (Dynamic Import)
- Moment.js 같은 무거운 라이브러리를 Day.js 등 가벼운 걸로 교체
8-6. 이미지 관련 지표
- 예시로 볼 수 있는 것들
- 주요 이미지 파일 1개 평균 용량: 500KB → 120KB
- 전체 이미지 요청 수: 40개 → 18개
- 이미지 포맷: PNG/JPEG → WebP/AVIF로 전환
- 개선에 쓰이는 기술
- Responsive Image(<img srcset>, <picture>)
- Lazy Loading(loading="lazy")
- WebP/AVIF 사용
- 스프라이트 시트, 아이콘을 SVG로 전환 등
9. 프론트엔드 성능을 측정하는 도구
9-1. Lighthouse
크롬 DevTools 안에 들어있는 웹 성능 분석 도구. 아래 항목들을 점수(0~100)로 보여준다.
- Performance
- Accessibility
- Best Practices
- SEO
- PWA
- 사용 방법 (간단 버전)
- Chrome에서 페이지 열기
- F12 → DevTools 열기
- 상단 탭에서 Lighthouse (또는 Insights) 선택
- “Performance” 위주로 체크 후 Run
- 보고서에서 LCP, FCP, CLS, TBT 등의 수치를 확인
- 장점
- “어느 부분이 느린지”를 구체적으로 지적해줌
- 개선 권장사항을 리스트로 보여줘서, 초보도 방향을 잡기 좋음
9-2. Chrome DevTools – Performance 탭
실제 페이지 로드나 사용자 동작을 녹화(Record)해서 JS 실행, 레이아웃, 페인트, 네트워크 등 어디서 시간이 많이 쓰이는지 볼 수 있음. 메인 스레드가 바쁜 구간, 이벤트 핸들러 실행 시간 등을 세부적으로 확인 가능.
- 언제 쓰나
- 특정 버튼 클릭 후 “이때만 왜 이렇게 느리지?” 같은 문제 디버깅할 때
- 스크롤이 버벅이는 구간 찾기
- 애니메이션이 끊기는 이유 찾기
9-3. Web Vitals(코어 웹 바이탈) + 플러그인
- Core Web Vitals
구글이 특히 중요하게 보는 사용자 경험 지표 세트:- LCP (Largest Contentful Paint)
- FID/INP (입력 반응성)
- CLS (Cumulative Layout Shift)
- 측정 방법
- Chrome 확장 프로그램 “Web Vitals”
- 또는 GA4, 로그 시스템, RUM 도구와 연동해 실제 사용자 기준으로 수집
10. 예제
예제 1. 이미지 최적화 + Lazy Loading
- A (문제)
메인 페이지에 배너 이미지와 상품 썸네일이 많아서 첫 화면이 로드되는 데 5초 이상 걸렸고, LCP도 4.5초 수준이었습니다.
- B (해결책)
기존 JPEG 이미지를 WebP로 변환하고, 화면 아래쪽에 있는 이미지에는 <img loading="lazy">를 적용해 실제로 보일 때만 로드되도록 했습니다.
<img> 태그에 width/height를 명시해 레이아웃 밀림도 방지했습니다.
- C (성과)
LCP: 4.5초 → 2.0초
첫 페이지 이미지 총 용량: 6.2MB → 1.8MB
CLS: 0.18 → 0.04로 개선되어, 레이아웃 이동 현상이 거의 사라짐
예제 2. 번들 크기 줄이기 + 코드 스플리팅
- A (문제)
단일 번들 JS 파일이 1.2MB였고, 초기 로딩 시 모든 페이지의 스크립트를 한 번에 불러와 TTI(상호작용 가능 시간)가 7초 이상 걸렸습니다.
- B (해결책)
라우터 기준으로 페이지 단위 코드 스플리팅을 적용하고, 쓰지 않는 라이브러리를 제거하고, 날짜 처리 라이브러리를 무거운 것에서 가벼운 것으로 교체했습니다.
공통 컴포넌트는 별도의 청크로 분리해 여러 페이지에서 재사용.
- C (성과)
메인 번들 크기: 1.2MB → 380KB
TTI: 7초 → 3.2초
Lighthouse Performance 점수: 52점 → 88점
예제 3. 폰트 & CSS 최적화
- A (문제)
웹폰트를 여러 개(굵기별로 5종) 사용하면서, 첫 로딩 때까지 텍스트가 한동안 안 보이거나 깜빡이는 현상이 있었습니다.
FCP도 3초 초반대로 느린 편이었습니다.
- B (해결책)
실제 사용하는 굵기(Regular, Bold)만 남기고 나머지 폰트는 제거했습니다.
font-display: swap을 사용해 폰트 로딩 전에 시스템 폰트로 먼저 텍스트를 보여주도록 했고, 사용하지 않는 CSS를 정리하고, 빌드 과정에서 CSS를 최소화했습니다.
- C (성과)
FCP: 3.1초 → 1.4초
폰트 다운로드 용량: 900KB → 260KB
텍스트 깜빡임 현상이 줄어들어, 체감 속도가 크게 향상
'CS 전공 지식' 카테고리의 다른 글
| [cs 전공 지식] 브라우저 렌더링 과정 (1) | 2024.07.05 |
|---|---|
| The World Wide Web Consortium(W3C)란? (0) | 2024.06.18 |