var compression = require('compression')
var express = require('express')
var app = express()
app.use(compression())
--trace-sync-io플래그를 사용하면 앱이 동기API를 호출하는 것을 확인할 수
있습니다.console.log()와 console.error()를 사용합니다. 하지만 이
함수들은 터미널 혹은 파일로 출력할 때 동기 함수들입니다. 그래서 배포할 때는
적합하지 않습니다.console.log()보다는 debug를 사용하는 것이 좋습니다. 이 모듈은 DEBUG환경 변수를 사용하고
앱이 비동기적으로 동작하도록 해줍니다.에외를 처리하지 않고 적적한 조치를 취하지 않으면 Express앱은 다운되고
종료됩니다. 따라서 예외들을 적절히 처리해야합니다.
Node/Express는 두 가지 방식으로 에러를 처리합니다.
Node는 비동기 함수에서 첫 번째 인자로 에러를 반환하고 나머지 반환할 값들을
반환합니다. 만약 에러가 발생하지 않는다면 null을 첫 번째 인자로 반한합니다.
callback함수는 반드시 error-frist callback컨벤션을 지켜야합니다.
Express에서는 next()함수를 사용하여 에러를 전파하는 것이 best practice입니다.
에러처리에 대한 자세한 내용들은 다음을 참고하세요.
당신이하지 말아야 할 일 중 하나는 uncaughtException 이벤트를 수신하는 것입니다.
예외가 발생하면 예외가 이벤트 루프로 되돌아갑니다.
uncaughtException을 event listener에 등록하는 것은 프로세스의 기본행동을
변경하게 됩니다. 그러면 프로세스는 예외가 발생해도 계속 실행하게 됩니다. 언듯
듣기에는 앱이 멈추는 것을 방지하기 떄문에 좋아 보이지만 예상치못한 에러가
발생했을 때 프로그램이 계속 실행되는 것은 굉장히 위험한 일입니다.
Try-catch는 동기 코드에서 예외를 catch하는 데 사용할 수있는 JavaScript 언어 구문입니다.
app.get('/search', function (req, res) {
// Simulating async operation
setImmediate(function () {
var jsonStr = req.query.params
try {
var jsonObj = JSON.parse(jsonStr)
res.send('Success')
} catch (e) {
res.status(400).send('Invalid JSON string')
}
})
})
하지만 Try-catch는 동기코드에서만 동작합니다. Node는 주로 비동기적으로
프로그램을 작성하므로 많은 예외를 처리하지 못합니다.
promise들은 어떤 예외든 catch(next)로 처리합니다.
app.get('/', function (req, res, next) {
// do some sync stuff
queryDb()
.then(function (data) {
// handle data
return makeCsv(data)
})
.then(function (csv) {
// handle csv
})
.catch(next)
})
app.use(function (err, req, res, next) {
// handle error
})
모든 동기, 비동기에러들이 에러미들웨어로 전파됩니다. 하지만 두가지 주의해야 할 것이 있습니다.
promise를 맄턴해야합니다. 특정한 라이브러리가
promise를 반환하지 않는다면 promise로 변경해야합니다.const wrap = fn => (...args) => fn(...args).catch(args[2])
app.get('/', wrap(async (req, res, next) => {
let company = await getCompanyById(req.query.id)
let stream = getLogoStreamById(company.id)
stream.on('error', next).pipe(res)
}))
wrap()함수는 reject된 promise들을 처리하고 next()함수를 호출합니다.
NODE_ENV환경변수는 어플리케이션이 동작하는 환경을 나타냅니다. 일반적으로
development와 environment가 있습니다.
성능을 올리는데 가장 간단한 것은 NODE_ENV를 production으로 설정하는
것입니다.
Express에서 NODE_ENV를 production으로 할 경우
Test indicate에서 테스트결과를 확인할 수 있습니다.
환경에 따라 다른 코드를 작성하고 싶다면 process.env.NODE_ENV를 확인하여
작성할 수 있습니다.
production에서는 어플리케이션이 종료되는 것을 원치 않습니다. 만약 앱이 멈추면 앱은 재시작해야 합니다.
노드 애플리케이션은 처리되지 않은 예외가 있을 때 멈춥니다. 예외를 모두 처리하는 것이 더 중요하지만 만약 앱이 종료되었을 때 다시 시작하는 것이 필요합니다.
개발할 때는 CLI에서 서버를 실행시킵니다. 하지만 production에서 이렇게 하면 안됩니다. 앱이 멈추면 다시 시작할 떄 까지 서비스가 멈추게 됩니다. 앱이 멈추었을 때 다시 시작하도록 프로세스 매니저를 사용하는 것이 좋습니다. 프로세스 매니저는 애플리케이션들을 위한 컨테이너로 배포와 높은 가용성, 그리고 애플리케이션을 관리할 수 있도록 도와줍니다. 프로세스매니저는 단순히 앱을 재시작 하는 기능 뿐만 아니라 다음같은 기능들도 제공합니다.
가장 유명한 프로세스 매니저들은 다음과 같습니다.
서버가 재시작 될 때 애플리케이션 또한 재시작되어야 합니다. 시스템들은 여러가지 이유로 다운될 수 있기 때문에 서버가 재시작 될 때 애플리케이션도 또한 재시작 되어야 합니다. systemd와 Upstart가 가장많이 사용됩니다.
Systemd는 리눅스 시스템의 서비스 매니저입니다. 대부분의 리눅스 배포판에서
기본으로 탑재되어 있습니다. systemd서비스 설정파일은 unit file이고
.service라는 이름으로 작성합니다.
[Unit]
Description=Awesome Express App
[Service]
Type=simple
ExecStart=/usr/local/bin/node /projects/myapp/index.js
WorkingDirectory=/projects/myapp
User=nobody
Group=nogroup
# Environment variables:
Environment=NODE_ENV=production
# Allow many incoming connections
LimitNOFILE=infinity
# Allow core dumps for debugging
LimitCORE=infinity
StandardInput=null
StandardOutput=syslog
StandardError=syslog
Restart=always
[Install]
WantedBy=multi-user.target
위의 예제는 직접적으로 node를 실행시킵니다.
쉽게 StringLoop PM을 systemd service로 설치할 수 있는데 그러면 서버가 재시작
될 때 자등으로 StringLoop PM을 실행할 것입니다.
StringLoop PM을 systemd service로 설치하려면 다음과 같이 입력하면 됩니다.
$ sudo sl-pm-install --systemd
그리고 서비스를 재시작할 때는 다음과 같이 입력합니다.
$ sudo /usr/bin/systemctl start strong-pm
Upstart는 만은 리눅스 배포판에서 사용가능한 시스템 도구 입니다. Express혹은
PM을 서비스로서 설정할 수 있고 Upstart가 서버가 재시작 될 때 Express혹은 PM을
재시작 할 것입니다.
Upstart서비스는 job설정파일로 정의되는데 .conf로 끝나는 이름으로
작성됩니다. 밑의 예는 설정파일 예제입니다. myapp.conf를 /etc/init/에 만들고
다음과 같이 설정 할 수 있습니다.
# When to start the process
start on runlevel [2345]
# When to stop the process
stop on runlevel [016]
# Increase file descriptor limit to be able to handle more requests
limit nofile 50000 50000
# Use production mode
env NODE_ENV=production
# Run as www-data
setuid www-data
setgid www-data
# Run from inside the app dir
chdir /projects/myapp
# The process to start
exec /usr/local/bin/node /projects/myapp/index.js
# Restart the process if it is down
respawn
# Limit restart attempt to 10 times within 10 seconds
respawn limit 10 10
StrongLoop PM을 Upstart서비스로서 쉽게 설치할 수 있습니다. 서버가 재시작 될
때 자동으로 PM이 재시작 됩니다.
$ sudo sl-pm-install
설치 후 서비스를 실행시켜줍니다.
$ sudo /sbin/initctl start strong-pm
멀티코어 시스템에서 Node 애플리케이션의 프로세스들의 클러스터를 실행시켜 성능을 향상시킬 수있습니다. 클러스터는 앱의 인스턴스를 여러개 실행시켜 각 CPU core마다 하나의 인스턴스를 실행시켜 인스턴스의 부하를 줄일 수 있습니다.
자바스크립트로 직접 만들면서 배우는 - 자료구조와 알고리즘 강의 바로 가기
실습으로 마스터하는 OAuth 2.0: 기본부터 보안 위험까지 - OAuth 2.0 강의 바로 가기
기계인간 이종립, 소프트웨어 개발의 지혜 - Git 강의 바로 가기
코드숨에서 매주 스터디를 진행하고 있습니다. 메일을 등록하시면 새로운 스터디가 시작될 때 알려드릴게요!