2022.09.14 경일 메타버스 24주차 2일 수업내용. Node.js - 노드 기능, http 모듈 #2
노드에서 멀티 스레드 방식으로 작업
예시 코드 1
// 3_5_7_worker_threads.js
const {
Worker, isMainThread, parentPort,
} = require('worker_threads');
if(isMainThread) { // 부모일 때
const worker = new Worker(__filename);
worker.on('message', message => console.log('from worker', message));
worker.on('exit', () => console.log('worker exit'));
worker.postMessage('ping');
} else { // 워커일 때
parentPort.on('message', (value) => {
console.log('from parent', value);
parentPort.postMessage('pong');
parentPort.close();
});
}
Console
> node 3_5_7_worker_threads
from parent ping
from worker pong
worker exit
코드 설명
isMainThread
: 현재 코드가 메인 스레드에서 실행되는지 워커 스레드에서 실행되는지 구분
new Worker
를 통해 현재 파일(__filename
)을 워커 스레드에서 실행
워커 생성 후 worker.postMessage
로 부모에서 워커로 데이터 전송
워커는 parentPore.on(’message’)
이벤트 리스너로 메시지를 받는다.
워커는 parentPort.postMessage
로 부모에게 메시지를 보낸다.
부모는 worker.on(’message’)
로 메시지를 받는다.
once(’message’)
를 사용주의 : 워커에서 on
메소드를 사용할 때는 워커를 직접 종료해야 한다.
parentPort.close()
로 부모와의 연결 종료
워커가 종료되면 부모의 worker.on(’exit’)
실행
실습 코드
const {
Worker, isMainThread, parentPort,
} = require('worker_threads');
let count = 0
if(isMainThread) { // 부모일 때
const worker = new Worker(__filename);
worker.on('message', message => console.log('from worker', message));
worker.on('exit', () => {
console.log('worker exit');
clearInterval(interval);
});
const interval = setInterval(() => worker.postMessage(count++), 10);
} else { // 워커일 때
parentPort.on('message', (value) => {
console.log('from parent', value);
parentPort.postMessage(count++);
if (count > 3)
{
parentPort.close();
}
});
}
예시 코드 2
여러 개의 워커 스레드에 데이터를 넘긴다.
postMessage
로 데이터를 보내는 것과 다른 방법
new Worker
를 호출할 때 두 번째 인수의 workerData
속성으로 원하는 데이터를 보낼 수 있다.예시 코드 3
소수의 개수를 구하는 작업
워커 스레드를 사용하지 않는 예제
이중 for문을 돌린다.
const primes = [];
primes
변수 자체가 바뀌는 것이 아닌, 배열 내부의 값이 바뀌기에 const
로 선언예시 코드 4
소수의 개수를 구하는 작업
워커 스레드를 사용하여 여러 개의 스레드로 문제를 나눠 푼다.
상당히 어렵고 코드 양도 많아진다.
let primes = [];
concat
메소드로 primes
배열에 요소를 합치고, 다시 primes
에 대입.primes
변수 자체를 바꾸기에 let
으로 선언멀티 스레딩에서 제일 어려운 과제 ⇒ 일을 나누기
스레드를 8개 사용했더니, 약 6배 정도 빨라졌다.
⇒ 워커 스레드를 여덟 개 사용했다고 8배 빨라지지 않는다.
스레드의 생성과 스레드 간 통신에서 상당한 비용이 발생
노드에서 다른 프로그램을 실행하거나 명령어를 수행할 때 사용하는 모듈
다른 언어의 코드를 실행하고 결괏값을 받을 수 있다.
현재 노드 프로세스 외에 새로운 프로세스를 띄워서 명령을 수행
→ 노드 프로세스에 결과를 알려준다.
exec
과 spawn
의 차이
exec
: 셸 (터미널 명령어 실행 프로세스)을 실행하여 명령어 수행
spawn
: 새로운 프로세스를 띄우며 명령어 실행
{ shell: true }
를 제공하면 exec
처럼 셸을 실행해서 명령어 수행assert
: 값을 비교하여 프로그램이 제대로 동작하는 지 테스트
dns
: 도메인 이름에 대한 IP 주소 획득
net
: HTTP보다 로우 레벨인 TCP, IPC 통신을 할 때 사용
string_decoder
: 버퍼 데이터를 문자열로 바꿀 때 사용
tls
: TLS, SSL 관련 작업에 사용. 보안 관련
tty
: 터미널과 관련된 작업에 사용
dgram
: UDP와 관련된 작업에 사용
v8
: V8 엔진에 직접 접근할 때 사용
vm
: 가상 머신에 직접 접근할 때 사용
p. 138 ~ 158
fs
모듈
기본적으로 콜백 형식 → 실무 사용을 위해 프로미스 형식으로 바꿀 수 있다.
readFile
읽을 파일의 경로 지정 - node 명령어를 실행하는 콘솔 기준
콜백 함수도 인수로 제공
결과물은 버퍼 (Buffer)의 형태로 제공, 반환
writeFile
노드는 대부분의 메소드를 비동기 방식으로 처리
하지만 몇몇 메소드는 동기 방식으로 사용할 수 있다.
비동기 방식은 백그라운드에 요청 처리 위임 가능
동기와 비동기
블로킹과 논 블로킹
return
되는 지 여부노드에서는 동기-블로킹 방식 / 비동기-논 블로킹 방식이 대부분
동기-블로킹 방식
백그라운드 작업 여부를 계속 확인
호출한 함수가 백그라운드 작업이 끝나야 return
됨
코드가 직관적이지만 쉬는 스레드가 생겨 비효율적
비동기-논 블로킹 방식
호출한 함수가 바로 return
되어 다음 작업으로 넘어감
백그라운드 작업 여부는 신경 쓰지 않고 나중에 백그라운드 알림을 받고 처리
코드는 복잡하지만 여러 요청을 동시에 처리 가능해 효율적
자료 : 교과서 “Node.js 교과서” ch. 4 http 모듈로 서버 만들기 p. 169
실제 서버 동작에 필요한 쿠키와 세션 처리, 요청 주소별 라우팅 방법
p. 178 ~ 189
서버에 요청
주소를 통해 요청의 내용을 표현
서버가 이해하기 쉬운 주소가 좋다
⇒ REST
REST
REpresentational State Transfer의 줄임말
서버의 자원을 정의하고 자원에 대한 주소를 지정하는 방법
일종의 약속
서버의 자원 : 서버가 행할 수 있는 것을 통틀어 의미
여기서는 기본적 개념만 빌려 사용한다.
주소
HTTP 요청 메소드
어떤 동작을 행할지 지시
GET
서버 자원을 가져올 때 사용
요청의 본문에 데이터를 넣지 않는다.
데이터를 서버로 보내야 하면 쿼리스트링을 사용
POST
서버에 자원을 새로 등록
요청의 본문에 새로 등록할 데이터를 넣어 보낸다.
표현하기 애매한 동작, 복잡한 동작은 POST
를 사용
PUT
서버의 자원을 요청에 들어있는 자원으로 치환
요청의 본문에 치환할 데이터를 넣어 보낸다.
PATCH
서버 자원의 일부만 수정
요청의 본문에 일부 수정할 데이터를 넣어 보낸다.
DELETE
서버의 자원을 삭제
요청의 본문에 데이터를 넣지 않는다.
OPTIONS
주소 하나가 여러 개의 요청 메소드를 가질 수 있다.
장점
주소와 메소드만 보고 요청의 내용을 알 수 있다.
GET
메소드의 경우 브라우저에서 캐싱할 수 있어 성능이 좋아진다.
HTTP 통신 사용 이유
클라이언트와 무관하게 같은 방식으로 서버와 소통 가능
서버와 클라이언트가 분리되어 있다.
서버를 확장할 때 클라이언트에 구애되지 않아 좋다.
REST를 따르는 서버 → ‘RESTful하다’
코드 작성 전, 대략적인 주소 설계를 먼저 설계하는 것이 좋다.
대략적인 설계 예시
HTTP 메소드 | 주소 | 역할 |
---|---|---|
GET | / | restFront.html 파일 제공 |
GET | /about | about.html 파일 제공 |
GET | /users | 사용자 목록 제공 |
GET | 기타 | 기타 정적 파일 제공 |
POST | /user | 사용자 등록 |
PUT | /user/사용자id | 해당 id의 사용자 수정 |
DELETE | /user/사용자id | 해당 id의 사용자 제거 |
예시 코드
req.method
로 HTTP 요청 메소드를 구분
존재하지 않는 파일을 요청했거나 올바르지 않은 (준비되지 않은) 메소드 요청인 경우
404 NOT FOUND 에러가 응답으로 전송된다.
예기치 못한 에러가 발생한 경우 500 에러가 응답으로 전송된다.
POST
와 PUT
요청의 처리에서, 요청의 본문에 들어있는 데이터를 꺼내기 위해
req.on(’data’)
와 req.on(’end’)
를 사용
req
와 res
는 내부적으로 스트림이므로 요청 / 응답의 데이터는 스트림 형식으로 전달됨
on
메소드에서 알 수 있듯이 이벤트 등록됨받은 데이터는 문자열이므로 JSON.parse
과정이 필요
res.end
를 호출해도 함수는 종료되지 않는다.
- 노드도 자바스크립트 문법을 따르므로
return
을 붙이지 않는 한 함수는 종료되지 않는다.
크롬에서 F12
로 열 수 있는 Network 탭에서 실시간으로 보이는 네트워크 요청 내용
Name : 요청 주소
Method : 요청 메소드
Status : HTTP 응답 코드
Protocol : 통신 프로토콜
Type : 요청의 종류
xhr : AJAX 요청
주의 : 데이터는 메모리에 저장되므로 서버를 종료하면 데이터가 소실된다.
⇒ 영구 저장은 데이터 베이스 사용