정보실

웹학교

정보실

Nodejs JSON.stringify가 Express 서버를 죽인 방법

본문

간단한 변경으로 Express 서버에서 최대 300 % 향상된 성능.


원본 : https://itnext.io/how-json-stringify-killed-my-express-server-d8d0565a1a61


Express는 서버를 만들어야 할 때 가장 많이 사용되는 node.js 프레임 워크 중 하나입니다.


다음은 작은 정적 JSON 응답을 리턴 하는 하나의 엔드 포인트만 있는 단순 Express 서버의 예입니다.


const express = require('express')
const app = express()

const json = {a:1}

app.get('/not_cached', (req,res)=>res.status(200).json(json))

app.listen(3000, ()=>console.log('Server started'))

위의 코드를 실행하고 여러 번 autocannon을 사용하여 벤치마킹 하면 2018 MacBook Pro에서 실행되는 서버가 11 초 만에 약 190K 요청을 처리합니다 ~ = 1900 RPS


➜ autocannon http://localhost:3000/not_cached 


우리는 더 잘할 수 있습니다! 


이 예제에는 코드가 거의 없기 때문에 소스 코드 표현, 응답 객체에 대한 json 함수의 정의 (전체 코드는 다음 위치에 있음)를 더 나은 성능으로 볼 수 있는 곳은 한 곳 뿐입니다.


https://github.com/expressjs/express/blob/master/lib/response.js


res.json = function json(obj) {
  var val = obj;

  // allow status / body
  if (arguments.length === 2) {
    // res.json(body, status) backwards compat
    if (typeof arguments[1] === 'number') {
      deprecate('res.json(obj, status): Use res.status(status).json(obj) instead');
      this.statusCode = arguments[1];
    } else {
      deprecate('res.json(status, obj): Use res.status(status).json(obj) instead');
      this.statusCode = arguments[0];
      val = arguments[1];
    }
  }

  // settings
  var app = this.app;
  var escape = app.get('json escape')
  var replacer = app.get('json replacer');
  var spaces = app.get('json spaces');
  var body = stringify(val, replacer, spaces, escape)

  // content-type
  if (!this.get('Content-Type')) {
    this.set('Content-Type', 'application/json');
  }

  return this.send(body);
};

가장 중요한 부분은 22 행에서 엄격하게 발생합니다. 사용하는 모든 res.json에 대해 반환 된 값은 string 화 되어 http 응답으로 전송됩니다. 데이터를 문자열 화 한 후 컨텐츠 유형이 설정되고 응답이 전송됩니다.


JSON.stringify는 CPU와 결합 된 작업이며 노드의 가장 친한 친구가 아니므로 한 번만 시도해 봅시다.


결과를 문자열 화하고 변수에 저장할 수 있으며, 들어오는 각 요청에 대해 content-type을 application / json으로 설정하고 end 메소드를 사용하여 문자열을 소켓에 직접 쓸 수 있습니다.


const express = require('express')
const app = express()

const stringifedJson = JSON.stringify({a:1})

app.get('/cached', (req,res)=>{
    res.setHeader('Content-Type', 'application/json');
    res.end(stringifedJson)
})
app.listen(3000, ()=>console.log('Server started'))

autocannon를 다시 실행하면 11 초 ~ = 3500 RPS로 약 350K 요청이 발생합니다. 80 % 개선


그러나 당신이 말하면, 당신은 나에게 300 % 개선을 약속했습니다! 그리고 당신은 옳을 것입니다! 


성능 차이는 반환 된 객체에 따라 크게 다릅니다. 작은 물체의 작은 변화조차도 중요하다는 것을 보여주고 싶었습니다.


큰 json 객체 (예 : 500–600 Kb)로 동일한 작업을 수행하면 성능이 향상됩니다. 실제로 res.json을 사용하면 실제로 kubernetes에서 실행되는 컨테이너와 같은 제한된 환경에서 서버가 충돌 할 수 있습니다.


결론 


Express를 사용할 때 서버의 RPS 성능이 좋지 않으면 공유 응답을 캐시하고 매번 JSON.stringify를 사용하는 res.json을 사용하는 대신 문자열을 응답 스트림에 직접 쓰십시오.


  • 트위터로 보내기
  • 페이스북으로 보내기
  • 구글플러스로 보내기
  • 카카오톡으로 보내기

페이지 정보

조회 7회 ]  작성일19-10-09 09:40

웹학교