Node.js 백엔드 스터디(2) - Node.js 서버를 k6로 실제 유저 트래픽으로 평가하기
Node.js 와 Express, Restful API 에 대한 나의 경험
이 전에 나의 경험은 공식 가이드 북을 참고하여, 공부한 내용을 블로그에 기록하고, Azure에 배포했던 경험까지 있다.
아래는 이전에 수행했던 링크이며, 중복되는 내용 외에 새로 알게된 내용 위주로 정리하려고 한다.
1. Node.js의 구성요소
- Node.js의 소스 코드는 C++와 자바스크립트, 파이썬 등으로 이루어져 있다.
- Node.js는 각 계층이 각 하단에 있는 API를 사용하는 계층의 집합으로 설계되어 있다.
<출처 - 78페이지, Node.js 백엔드 개발자 되기(박승규 지음)>
- Node.js의 구성요소 중 V8과 libuv가 중요하다.
- V8: 자바스크립트 코드 실행에 필요한 런타임에 사용되는 엔진
- libuv: 자바스크립트 런타임에 필요한 이벤트 루프 및 운영체제 시스템 API를 사용하는데 필요한 라이브러리
2. Node.js의 장단점
- 장점
- 비동기 이벤트 기반 IO를 사용해 동시에 여러 요청을 다루기 용이
- 자바스크립트를 사용해 프론트엔드 개발자의 백엔드 진입이 용이
- 클라이언트와 같은 언어를 사용하면 서버의 코드에 사용된 로직을 클라이언트에서도 사용할 수 있음
- 개발자 생태계가 잘 구성되어 있어서, 패키지 매니저에서 필요한 대부분을 제공함
- V8 엔진이 JIT 컴파일러이므로 서버 기동이 빠름
- 단점
- 기본적으로 CPU를 하나만 사용하므로 멀티코어를 사용하려면 별도의 작업이 필요함
- 비동기 지원하지 않는 IO, CPU 작업은 주의
- 콜백을 중첩해서 계속 사용하면 코드 작성 및 디버깅이 힘들어짐
- 이벤트 기반으로 프로그래밍을 해본 적이 없다면 코드 작성이 타 언어에 비해 어려울 수 있음
3. Node.js 서버 프로그래밍
아래 프로그램은 아래와 같이 동작한다.
- 동작 1. 브라우저에서 localhost:8000 을 접속하면, hello Node.js가 출력
- 동작 2. 콘솔에서는 서버를 호출할 때마다, 카운팅 값이 출력
const http = require("http"); // 1. http 객체 생성
let count = 0;
const server = http.createServer((req, res) => { // 2. 서버 객체 생성
count = log(count); // 3. 카운트 1 증가
res.statusCode = 200; // 4. 결괏값 200
res.setHeader("Content-Type", "text/plain"); // 5. 헤더 설정
res.write("hello\n"); // 6. 응답값 설정
setTimeout(() => {
res.end("Node.js") // 7. 2초 후 Node.js 출력
}, 2000);
});
function log(count) {
console.log((count += 1));
return count
}
server.listen(8000); // 8. 8000번 포트로 서버 실행
- res.statusCode = 200: 요청에 대한 상태 코드를 200으로 설정한다. 주요 상태 코드는 아래 표에서 확인.
코드 | 메시지 | 설명 |
---|---|---|
200 | OK | 요청 처리 성공 |
301 | Moved Permanently | 요구한 데이터를 변경된 URL에서 찾음 |
304 | Not modified | 클라이언트의 캐시에 저장되어 있음 |
400 | Bad Request | 요청 실패. 클라이언트의 요청에 문제가 있음 |
403 | Forbidden | 접근 금지 |
404 | Not Found | 페이지를 찾을 수 없음 |
405 | Method not allowed | 요청한 메서드가 허용되어 있지 않음 |
408 | Request timeout | 요청 시간이 지남 |
500 | Internal Server Error | 서버 에러 |
501 | Not Implemented | 필요한 기능이 서버에 구현되어 있지 않음 |
502 | Bad gateway | 게이트웨이 상태가 좋지 않음 |
503 | Service Unavailable | 서버가 사용 불가 상태임 |
- res.setHeader(“Content-Type”, “text/plain”): HTTP는 요청/응답에 대한 부가 정보를 설정할 수 있다. 부가 정보는 header에 설정하게 되는데, 여기서는 콘텐츠 타입을 ‘text/plain’으로 설정했다.
- server.listen(8000): 사용할 포트 번호를 8000번으로 지정한다. IP가 생략되었으면, 기본값인 localhost 혹은 127.0.0.1로 서버에 접근할 수 있다.
- 포트 번호는 16비트로 이루어져 있으며, 0~1023번 포트는 루트 권한이 필요하다. 1024~49151번은 슈퍼 유저 권한이 없어도 임의로 사용할 수 있다. 49152~65535번의 구간은 일반 사용자들이 자유롭게 사용할 수 있다.
4. curl 내려받기 및 테스트해보기
나는 Postman을 사용하기 때문에, curl에 대한 내용은 패스하였다.
5. 정말로 동시에 요청을 처리하는지 성능 테스트하기
개발 서버와 프로덕션 서버의 가장 큰 차이는 트래픽이다. 그래서 실제 유저의 트래픽이 들어오는 것처럼 테스트할 수 있는 도구 k6가 있다. 아래는 k6 설치 순서와 테스트방법, 결과이다.
- 순서 1. 링크에서 다운로드 및 설치
- 순서 2. hello.js를 테스트하기 위해, ‘hello_test.js’ 파일을 동일한 경로에 생성
// hello_test.js
import http from "k6/http";
export const options = { // 1) 테스트 옵션
vus: 100, // 유저 100명
duration: '10s', // 10초 동안 요청을 보냄
};
export default function () {
http.get("http://localhost:8000"); // 2) 테스트에 사용할 함수 지정
}
- 순서 3. hello_test.js 파일 실행
k6 run hello_test.js
- 순서 4. 실행결과를 아래와 같이 분석해볼 수 있음
- 가상 유저 100명, 최대 40초 동안 테스트한 시나리오. 실제 테스트 시간은 10초, graceful Stop 기본값 30초를 더해서 40초가 됨. gracefulStop 옵션은 최소 30초 동안은 기존 유저값이 유지된다는 의미.
- avg=2.13s 는 평균 2.13초가 걸렸다는 의미. p(90)=2.2s는 90% 요청이 2.2s 이하라는 의미.
- HTTP 요청이 얼마나 실패했는지 보여줌.
- HTTP 요청이 500번 발생했다는 뜻.
- HTTP 요청이 한번 완료되고 다시 시작될때까지 걸리는 시간을 보여줌. 평균 2.13초가 걸림.
- 순서 5. 분석 결과는 평균 2초 걸리는 요청 100개를 동시에 처리했다는 것을 알 수 있음. hello.js 디버그를 살펴보면, 1000번의 카운트가 된 것을 볼 수 있으며, 전부다 응답했음을 알 수 있다.
참고
다음에 다루게 될 것
- Node.js와 http 객체로 서버 만들기
댓글남기기