nodejs - http server 퍼포먼스 측정

_·2020년 5월 11일
0

nodejs code

목록 보기
9/10
post-thumbnail

https://behonestar.tistory.com/33
http://www.incodom.kr/Status_code
https://velopert.com/287


결과 :


수행해야 할 내용 :


서버에서 첫 요청이 들어올 때부터 setTimeout()로 서버 강제 종료 전까지 총 10초동안 요청을 받은 횟수를 카운트 하고, 1초당으로 평균을 구하여 출력한다.

웹 서버 코드 ::

  • index.js // entry point.
  • web_server.js // http 서버 구동을 위해.
  • _logger.js // 후에 로그 기록을 위해 작성
  • _system.js // 자주 사용하는 코드 모아둠.
  • server_config.json // 서버 설정 파일 분리용도.

퍼포먼스 측정 요청용 클라이언트 측 코드 ::

  • client.js // 약 10초간 지속적으로 서버에 요청.

html 및 관련 파일 ::

  • index.html
  • style.css
  • calc.js

단, client.js 를 통해 요청할 때에는 index.js 파일만 요청하였다.

웹 브라우저로 테스트 하면 index.html의 내용 중에 구성하는데 필요한 js 파일과 css 파일 및 파비콘 파일도 별도로 요청을 하게 된다.


// 서버 측 코드

/**
 * index.js, main()
 */

"use strict";

// require()
//const { print, errPrint, parseCookies } = require(`./_system.js`);
//const logger = require('./_logger.js')
const server = require('./web_server.js');

// starting point.
server.start();
/**
 * web_server.js
 */

"use strict";

// require()
const { print, errPrint, getFile, parseCookies } = require(`./_system.js`);
const logger = require('./_logger.js')
const serverConfig = require('./properties/server_config.json');
const http = require(`http`);

// constants
const GATEWAY_IP = serverConfig.GATEWAY_IP;
const PORT = serverConfig.PORT;
const HTML_PATH = serverConfig.HTML_HOME_PATH;
const DEFAULT_REQUEST_FILE = serverConfig.DEFAULT_REQUEST_FILE;

// create server.
const server = http.createServer(requestListener);

let flag = true;
let check = true;
let count = 0;

function requestListener(req, res) {
    if(flag){
        flag = false;
        setTimeout(()=>{
            check = false;
            print(`10초 요청 확인 종료. count : ${count}`);
            print(`1초당 요청 처리 횟수 : ${count/10}`);
            // 서버 강제 종료
            throw new Error('server turn off');
        }, 10000);
    }
    const ip = req.headers['x-forwarded-for'] ||
        req.connection.remoteAddress ||
        req.socket.remoteAddress ||
        req.connection.socket.remoteAddress;
    let requestUrl = req.url;

    if (requestUrl === '/')
        requestUrl = DEFAULT_REQUEST_FILE;

    //print(`${ip}에서 '${req.url}' 요청.`);
    logger.http(`${ip}에서 '${req.url}' 요청.`);

    if (requestUrl === '/favicon.ico') {
        getFile(`${HTML_PATH}/favicon32.png`)
            .then((data) => {
                res.writeHead(200);
                res.end(data);
                print(`'${req.url}' 요청 '${requestUrl}' 응답 완료.`);
                if(check)++count;
            }).catch((error) => {
                errPrint(error);
                throw new Error('File not found.');
            });
    } else {
        getFile(`${HTML_PATH}/${requestUrl}`)
            .then((data) => {
                let html = data.toString();
                    res.writeHead(200);
                    res.end(html);
                    print(`'${req.url}' 요청 '${requestUrl}' 응답 완료.`);
                    if(check)++count;
            }).catch((error) => {
                errPrint(error);
                getFile(`${HTML_PATH}/error/page404.html`)
                .then((data) => {
                    res.writeHead(404);
                    res.end(data);
                    throw new Error('File not found.');
                });
            });
    }
}

function setCookies(request, response) {
    const cookies = parseCookies(request.headers.cookie);
    print(`${request.url}, ${cookies}`);
    response.writeHead(200, { 'Set-Cookie': 'mc=test' })
}

function start() {
    // port open. server start.
    server.listen(PORT);

    // add event : listening
    server.on(`listening`, () => {
        print(`PORT : ${PORT} open. 응답 대기 중..`);
    });

    // add event : error
    server.on(`error`, (error) => {
        errPrint(`error event : ${error}`);
    });
}



module.exports = {
    start,
}
/**
 * _system.js
 */

"use strict";

const fs = require(`fs`);
const print = text => console.log(text);
const errPrint = text => console.error(text);

if (typeof alert === "undefined") {
    //print("alert is undefined.");
    //function alert(text) { console.log("alert : ", text) };
    var alert = text => print("alert : " + text);
}


const getFile = (filename) => {
    return new Promise((resolve, reject) => {
        fs.readFile(filename, (error, data) => {
            if (error) {
                reject(error);
            } else {
                resolve(data);
            }
        });
    });
}

module.exports = {
    print,
    errPrint,
    alert,
    getFile,
}

// ./properties/server_config.json

{
    "GATEWAY_IP" : "127.0.0.1",
    "PORT" : 8080,
    "HTML_HOME_PATH" : "./html",
    "DEFAULT_REQUEST_FILE" : "index.html"
}
/**
 * _logger.js
 */

const winston = require('winston');
const moment = require('moment');
const winstonRotate = require('winston-daily-rotate-file');

const LOG_PATH = "./log";

/*
const levels = { 
  error: 0,
  warn: 1,
  info: 2,
  http: 3,
  verbose: 4,
  debug: 5,
  silly: 6
};
/**/
const logger = new winston.createLogger({
    transports: [
        new winston.transports.Console({
            level: 'debug',
            format: winston.format.printf(
                data => `${moment().format(`YYYY-MM-DD HH:mm:ss.SSS`)} [${data.level.toUpperCase()}] -> ${data.message}`),
        }),
        new winstonRotate({
            level: 'debug',
            filename: `${LOG_PATH}/log_`,
            maxsize: 100,   // byte 단위이나, 제대로 작동 안하는 듯 하다.
            maxFiles : 1024,
            format: winston.format.printf(
                data => `${moment().format(`YYYY-MM-DD HH:mm:ss.SSS`)} [${data.level.toUpperCase()}] -> ${data.message}`),
        }),
    ]
});

module.exports = logger;

// 퍼포먼스 측정용 클라이언트 코드

/**
 * client.js
 */

"use strict";

// require()
//const { print, errPrint } = require(`./_system.js`);
const http = require(`http`);
const serverConfig = require('./properties/server_config.json');

// constants
const PORT = serverConfig.PORT;

const options = {
    host: 'localhost',
    port: PORT,
    path: '/',
};

if (true) {
    let timer = setInterval(() => {
        const req = http.request(options, (res) => {
            res.on('data', (data) => {
              // print(data);
            });
            res.on('end', () => {                
            });
        });
        req.end();
    }, 0.0001);
    setTimeout(()=>{clearInterval(timer)}, 10001);
}

// html 파일 및 관련 파일들.

<!--
    file name : index.html
    <link rel="shortcut icon" href="127.0.0.1:8080/favicon32.png" type="image/x-icon" />
-->

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>node.js web server</title>
    <link rel="stylesheet" href="./themes/style.css" type="text/css" media="all" />
    <script src="./js/calc.js" type="text/javascript"></script>
</head>
<body>
<p></p>
한글

</body>
</html>
/**
* author : velog.io/@___
* path : ./themes/style.css
*/

@charset "UTF-8";


.calc_table{
    position: relative;
    background-color: #FFFFFF;
    border: 1px solid;
    width: 100%;
    max-width: 202px;
    min-height: 320px;
    text-align: center;
    table-layout: fixed;
}

.calc_input{
    border: none;
    text-align: right;
}

td {
    border: 1px solid;
}

/**/
body { 
    /*
    background-color: #00FFFF;
    /**/
    background-image: url("https://media.vlpt.us/images/___/post/8322958b-7949-4b69-b28e-d2c02737e8df/%EB%B3%B4%EB%85%B8%EB%B3%B4%EB%85%B8200.png");
    background-repeat: repeat;
}
/**/

.main_container{
    position: absolute;
    width:100%; 
    /*
    top: 100px;
    /**/
}

.calc_area{
    position: relative;
    height: 100%;
    width: 202px;
}
/**
* author : velog.io/@___
* path : ./js/calc.js
*
* .. 내용없음. html 로드 시, js 파일을 요청하는 테스트를 위해 만든 파일.
*/

일단 측정은 하고 멈추려고 서버를 강제로 내렸으나, 별로 좋은 방법으로 보이진 않는다.

근데 머리로 안되겠으면 일단이라도 이렇게 구현은 해야지.


profile
_

0개의 댓글