5단계 — 개선 전후 비교 전체 실험을 숫자로 정리한다."빠른 것 같다"가 아니라 "p95가 얼마에서 얼마로 바뀌었다"로 말하는 것이 목표다.실험 전체 흐름① baseline → 서버의 정상 상태 측정② 인덱스 있음 → email 검색 기준점③ 인덱스 제거 → 병목 재현④ pool 한계 → sleep 없이 VU 100명, pool 포화 시도수치 비교표실험VUsleepp95avgmedRPS에러율① baseline101s12.03ms5.63ms4.31ms19.760%② 인덱스 있음501s20.73ms11.63ms7.75ms49.380%③ 인덱스 없음501s29.04ms18.63ms18.48ms49.030%④ pool 테스트0→100없음11.71ms6ms5.38ms8,7430%실험별 해..
nodejs
4단계 — 병목 찾기: 인덱스 실험같은 API, 같은 VU 수(50명), 달라진 건 인덱스 하나.숫자가 어떻게 바뀌는지 본다.실험 설정엔드포인트: GET /users/search?email=userN@test.comVU: 50명, 30초변수: uq_email 인덱스 유무데이터: 10,000건쿼리:SELECT id, name, email, created_at FROM users WHERE email = ?이 쿼리가 인덱스 없이 실행되면 MySQL은 10,000건을 처음부터 끝까지 전부 훑는다(풀스캔).인덱스가 있으면 B-Tree 구조로 바로 찾아간다.결과 비교인덱스 있음 (uq_email 존재)http_req_duration: avg=11.63ms min=936µs med=7.75ms max=12..
3단계 — 결과 분석baseline 테스트를 실행했다. 실제 나온 수치를 항목별로 뜯어본다.실행 환경VU: 10명시간: 30초대상: GET /health, GET /users?page=1&limit=20seed 데이터: 10,000건전체 결과 █ THRESHOLDS http_req_duration ✓ 'p(95)항목별 해석Thresholds — 통과 기준✓ 'p(95)두 기준 모두 통과(✓).p95가 500ms 기준에 12.03ms — 기준의 2.4% 수준. 여유가 매우 크다.에러율 0% — 600개 요청 중 실패 0건.http_req_duration — 응답시간avg=5.63ms min=433µs med=4.31ms max=57.28ms p(90)=9.83ms p(95)=12.03..
2단계 — k6 설치 & 기본 시나리오 작성API가 준비됐으면 이제 부하를 줄 도구가 필요하다.이 단계에서는 k6를 설치하고, 첫 번째 부하테스트를 실행한다.왜 k6인가도구시나리오 작성결과 가독성설치JMeterGUI/XML — 복잡보통Java 필요ArtilleryYAML — 제한적보통Node 필요autocannonCLI 한 줄 — 단순보통Node 필요k6JavaScript — 자유로움좋음단독 바이너리JS로 시나리오를 짤 수 있어서 조건 분기, 로그인 후 토큰 재사용 같은 복잡한 흐름도 쉽게 표현된다.결과도 p95, p99, RPS 등 필요한 수치를 깔끔하게 출력한다.설치brew install k6핵심 개념Virtual Users (VU)VU는 브라우저 탭 하나라고 생각하면 된다.VU 10명 = 브라우저 ..
1단계 — 테스트 대상 API 준비부하테스트를 하려면 테스트 할 대상이 있어야 한다.이 단계에서는 MySQL + Express API를 세팅하고, 테스트용 데이터 1만 건을 넣는다.왜 빈 DB로 테스트하면 안 되는지?테이블이 비어있으면 MySQL이 스캔할 행이 없으니 쿼리가 비현실적으로 빠르다.실제 서비스는 수만~수백만 건의 데이터가 쌓인 상태에서 운영된다.부하테스트도 그에 맞는 환경에서 진행해야 의미 있는 숫자가 나온다.테스트 환경은 1만건의 데이터로 진행한다.Docker로 MySQL 띄우기로컬에 MySQL을 직접 설치하지 않고 Docker를 쓰는 이유:docker-compose down -v 한 줄로 DB를 완전히 초기화해 실험을 반복할 수 있다팀원이 같은 환경을 그대로 재현할 수 있다# docker..
Node.js + TypeScript 게시판 만들기 — Phase 8/9: 에러 핸들링 + 마무리들어가며이번 글에서는 프로젝트 마무리 작업을 합니다. 404/500 에러 페이지를 만들고, 홈 라우트를 정리합니다.에러 페이지 뷰에러 코드와 메시지를 받아 표시하는 공통 에러 페이지를 만듭니다. 홈으로 돌아가기404와 500 모두 이 하나의 뷰를 재사용합니다. status와 message만 다르게 전달합니다.app.ts 에러 핸들러홈 라우트// '/' 접속 시 글 목록으로 리다이렉트app.get('/', (req, res) => { res.redirect('/posts');});404 핸들러// 등록된 라우트 중 일치하는 게 없을 때 여기로 떨어짐app.use((req, res) => { res...
Node.js + TypeScript 게시판 만들기 — Phase 7: 내 정보 조회/수정들어가며이번 글에서는 로그인한 유저가 자신의 닉네임과 비밀번호를 수정할 수 있는 내 정보 페이지를 구현합니다.메서드경로설명GET/users/me내 정보 페이지PUT/users/me닉네임 / 비밀번호 수정userController내 정보 조회export async function getMe(req: Request, res: Response) { const userId = (req.session as any).user.id; // 세션 정보가 아닌 DB에서 직접 조회 const user = await findUserById(userId); res.render('users/me', { title: '내 정보', u..
Node.js + TypeScript 게시판 만들기 — Phase 6: 댓글 CRUD + jQuery AJAX들어가며이번 글에서는 댓글 작성/수정/삭제를 구현합니다. 댓글 작성은 일반 폼 submit을 쓰고, 수정과 삭제는 페이지 새로고침 없이 jQuery AJAX로 처리합니다.구현할 라우트입니다.메서드경로방식설명POST/comments/:postId폼 submit댓글 작성PUT/comments/:idAJAX댓글 수정 (본인만)DELETE/comments/:idAJAX댓글 삭제 (본인만)commentController댓글 수정/삭제는 AJAX 요청이므로 응답을 JSON으로 반환합니다.// 댓글 수정export async function putUpdate(req: Request, res: Response)..
Node.js + TypeScript 게시판 만들기 — Phase 5: 게시글 CRUD + 페이지네이션들어가며이번 글에서는 게시글의 목록, 작성, 상세, 수정, 삭제를 구현합니다. 목록에는 페이지네이션도 추가합니다.구현할 라우트는 다음과 같습니다.메서드경로인증설명GET/posts전체 글 목록 + 페이지네이션GET/posts/new✅글 작성 폼POST/posts✅글 작성GET/posts/:id글 상세 + 댓글GET/posts/:id/edit✅글 수정 폼PUT/posts/:id✅글 수정 (본인만)DELETE/posts/:id✅글 삭제 (본인만)postModel — DB 쿼리페이지네이션 쿼리// 전체 게시글 수 (총 페이지 수 계산용)export async function countPosts(): Promis..
bcrypt와 express-session 설치 과정에서 나온 에러였다. 원인은 내가 설치한 라이브러리들중 node 버전과 호환이 안되는 경우 발생되는 에러였다.node 버전을 해당 라이브러리가 지원되는 버전으로 낮추거나 라이브러리들을 업데이트 해주는 방식으로 해결하면 된다. 라이브러리 업데이트npm update Node 버전 낮추기nvm 사용해서 낮추기// 설치할 수 있는 노드 버전 찾기nvm list available// 원하는 버전의 노드 설치해주기// 18이상부터 해당 에러가 잘 발생했어서 17로 낮췄다.nvm install 17// 17 버전 사용하기nvm use 17 brew 사용해서 낮추기homebrew 공식 사이트에서 원하는 node 버전을 확인하고 설치// 원하는 버전의 노드 설치bre..