[Node.js] ์Šค๋ ˆ๋“œ์™€ Event Loop

[์›๋ณธ ๋งํฌ]

Node.js ํ™˜๊ฒฝ์— ๋Œ€ํ•ด์„œ ์ด์•ผ๊ธฐํ•˜๊ฑฐ๋‚˜ ํ‰๊ฐ€ํ•  ๋•Œ ์ž์ฃผ ๊ฑฐ๋ก ๋˜๋Š” ์ฃผ์ œ ์ค‘ ํ•˜๋‚˜๊ฐ€ ์Šค๋ ˆ๋“œ์˜ ํ™œ์šฉ์„ฑ์ด๋‹ค.

ํ”ํžˆ Node ํ™˜๊ฒฝ์„ ๊ฐ€๋ฆฌ์ผœ์„œ ์‹ฑ๊ธ€์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์˜ ๋Ÿฐํƒ€์ž„์ด๋ผ๊ณ  ๋งํ•˜๊ณค ํ•œ๋‹ค.
๊ทผ๋ฐ ์‚ฌ์‹ค ๋˜ ๋ฉ€ํ‹ฐ์ฝ”์–ด ํ™˜๊ฒฝ์„ ์•„์˜ˆ ํ™œ์šฉํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒƒ๋„ ์•„๋‹ˆ๋‹ค. ์ •ํ™•ํžˆ ๋งํ•˜๋ฉด I/O ๋™์ž‘์— ๋Œ€ํ•ด์„œ๋งŒ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™œ์šฉ์„ ๋ณด์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.




์‹ฑ๊ธ€ ์Šค๋ ˆ๋“œ?

Node.js๋Š” C/C++, Java, C# ๊ฐ™์€ ๊ธฐ์„ฑ ์–ธ์–ด๋“ค๊ณผ ๋‹ค๋ฅด๊ฒŒ ์Šค๋ ˆ๋“œ๋ฅผ ์ง์ ‘ ์ œ์–ดํ•˜์ง€ ๋ชปํ•œ๋‹ค.
๋„ค์ดํ‹ฐ๋ธŒ ์Šค๋ ˆ๋“œ๋‚˜ ๊ฒฝ๋Ÿ‰ ์Šค๋ ˆ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์„œ ์ง์ ‘ ๋ฉ€ํ‹ฐ์ฝ”์–ด๋ฅผ ์ฅ์–ด์งœ CPU ์ง‘์•ฝ์ ์ธ ์—ฐ์‚ฐ์„ ํšจ์œจ์ ์œผ๋กœ ํ•ด๋‚ผ ์ˆ˜๋Š” ์—†๋‹ค๋Š” ๋ง์ด๋‹ค.

Promise ๊ฐ™์€ ๋น„๋™๊ธฐ ๋‹จ์œ„๋ฅผ ํ†ตํ•ด ๋™์‹œ์„ฑ์„ ๊ตฌํ˜„ํ•  ์ˆ˜๋Š” ์žˆ์ง€๋งŒ, ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ์™€ ๊ฐ™์€ ๋ณ‘๋ ฌ์„ฑ์„ ๋‹ด๋ณดํ•˜์ง€๋Š” ๋ชปํ•œ๋‹ค.
๊ทธ๋ƒฅ tick ๊ธฐ๋ฐ˜์œผ๋กœ ์‹œ๋ถ„ํ•  ์ฒ˜๋ฆฌ๋งŒ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์ด๋Ÿฐ ๋ถ€๋ถ„์—์„œ๋Š” ํŒŒ์ด์ฌ, ๋ฃจ๋น„์™€ ๋น„์Šค๋ฌด๋ฆฌํ•œ ์‹ฑ๊ธ€์Šค๋ ˆ๋“œ ์–ธ์–ด๋ผ๊ณ  ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.




Event Loop!

ํ•˜์ง€๋งŒ Node.js๋Š” ์ด๋ฒคํŠธ ๋ฃจํ”„๋ผ๋Š” ๋งค์ปค๋‹ˆ์ฆ˜์„ ํ†ตํ•ด I/O ์ž‘์—…์„ ํšจ์œจํ™”ํ•œ๋‹ค.
I/O ์ง‘์•ฝ์ ์ธ ํ™˜๊ฒฝ์—์„œ๋Š” ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ๋ฅผ ์ถฉ๋ถ„ํžˆ ํ™œ์šฉํ•œ๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.

https://www.geeksforgeeks.org/node-js-event-loop/
Node.js๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ libuv๋ผ๋Š” ๋ณ‘๋ ฌ์ฒ˜๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ, ์ด๊ฑธ ํ†ตํ•ด ์Šค๋ ˆ๋“œํ’€์„ ๊ตฌ์„ฑํ•˜๊ณ  I/O ์ž‘์—…์„ ๋‹ค์ค‘ํ™”ํ•œ๋‹ค.
๊ทธ๋ฆฌ๊ณ  libuv๋Š” ๋˜ ๋‚ด๋ถ€์ ์œผ๋กœ epoll(Linux), kqueue(Mac), IOCP(Windows) ๊ฐ™์€ ์ปค๋„ ์ˆ˜์ค€์˜ ๋„คํŠธ์›Œํ‚น ๋งค์ปค๋‹ˆ์ฆ˜์„ ์‚ฌ์šฉํ•ด์„œ ์ปค๋„ ์Šค๋ ˆ๋“œ๋ฅผ ํ™œ์šฉํ•œ๋‹ค.

๋ฐฉ์‹์„ ๊ฐ„๋žตํžˆ ์ •๋ฆฌํ•˜๋ฉด ์ด๋ ‡๋‹ค.

  1. File I/O๋‚˜ Network I/O ๊ฐ™์€ ์ž‘์—…์ด ๋ฐœ์ƒํ•˜๋ฉด, ๋Ÿฐํƒ€์ž„์€ ๊ทธ ์š”์ฒญ์„ ์ด๋ฒคํŠธ ํ์— ๋„ฃ๋Š”๋‹ค.
  2. ์ด๋ฒคํŠธ ๋ฃจํ”„๋Š” ์ด๋ฒคํŠธ ํ์— ์ž‘์—…์ด ๋“ค์–ด์˜ค๋ฉด ์Šค๋ ˆ๋“œํ’€์„ ํ™œ์šฉํ•ด ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.
  3. ์Šค๋ ˆ๋“œ์ƒ์—์„œ ์ž‘์—…์ด ์™„๋ฃŒ๋˜๋ฉด ์ด๋ฒคํŠธ๋ฃจํ”„๋Š” ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์ด๋ฒคํŠธ ํ๋ฅผ ํ†ตํ•ด Javascript ์ธก์— ์‘๋‹ตํ•œ๋‹ค.

์ด๋Ÿฐ ๊ตฌ์กฐ ๋•๋ถ„์— ์„œ๋ฒ„ ํ™˜๊ฒฝ์—์„œ๋„ ๊ทธ๋Ÿญ์ €๋Ÿญ ๋‚˜์˜์ง€ ์•Š์€ ํผํฌ๋จผ์Šค๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.
์—ฐ์‚ฐ ์„ฑ๋Šฅ์ด ๊ตฌ๋ฆฌ๊ธด ํ•œ๋ฐ, ์–ด์ฐจํ”ผ ์„œ๋ฒ„ ๊ตฌ์กฐ๋Š” ๋„คํŠธ์›Œํฌ I/O๊ฐ€ ๋Œ€๋ถ€๋ถ„์ด๊ณ , ๋Œ€๋ถ€๋ถ„์˜ ๋ฌด๊ฑฐ์šด ์ผ์€ DB๊ฐ€ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
์ข€ ํŠน์ˆ˜ํ•œ ์˜์—ญ์œผ๋กœ ๊ฐ€๋ฉด ๋ง์ด ๋‹ฌ๋ผ์งˆ ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ๋Œ€๋ถ€๋ถ„์˜ ์Šคํƒ€ํŠธ์—… ์ˆ˜์ค€์—์„œ ์š”๊ตฌํ•˜๋Š” ๊ธฐ๋Šฅ ๋ช…์„ธ์—์„œ๋Š” ์„ฑ๋Šฅ์ด ๊ทธ๋‹ค์ง€ ๋ถ€์กฑํ•˜์ง„ ์•Š๋‹ค.

์กฐ๊ธˆ ๋” ๋“ค์–ด๊ฐ€๋ณด๋ฉด, ์ด๋ฒคํŠธ๋ฃจํ”„์˜ ๊ฐ ๋ฃจํ”„ ์Šคํ…์€ ์ด๋Ÿฐ ์‹์œผ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค.

https://nodejs.org/en/learn/asynchronous-work/event-loop-timers-and-nexttick

  1. timer: ์ผ๋‹จ ํƒ€์ด๋จธ ๊ด€๋ จ ์ž‘์—…์„ ํ™•์ธํ•ด์„œ ๋จผ์ € ์ฒ˜๋ฆฌํ•œ๋‹ค. setTimeout์ด๋‚˜ SetInterval๋กœ ์˜ˆ์•ฝํ•œ ํ•จ์ˆ˜๊ฐ€ ์ด์— ํ•ด๋‹น๋œ๋‹ค.

  2. pending callbacks: ์ด์ „ ๋ฃจํ”„์—์„œ ๋ณด๋ฅ˜๋œ ์ฝœ๋ฐฑ์„ ์‹คํ–‰ํ•œ๋‹ค.

  3. idle, prepare: ์ด๊ฑด ๋ชฐ๋ผ๋„ ๋œ๋‹ค. ๋‚ด๋ถ€์ ์œผ๋กœ GC๋ฅผ ์œ„ํ•œ ํ™•์ธ์ด๋‚˜ ์žก๋‹คํ•œ ๋‚ด๋ถ€๋™์ž‘์„ ์œ„ํ•ด ์กด์žฌํ•œ๋‹ค.

  4. poll: ์ƒˆ๋กœ์šด I/O ์ด๋ฒคํŠธ๋ฅผ ๋ฐ›๊ณ  ์ฒ˜๋ฆฌํ•œ๋‹ค. readFile ๊ฐ™์€ ํ•จ์ˆ˜๊ฐ€ ์‚ฌ์šฉ๋˜๋ฉด ๊ทธ๊ฑธ ๋ฐ›์•„์ฃผ๋Š” ๊ฒƒ์ด๋‹ค. ์‚ฌ์‹ค ์ด๊ฒŒ ์ ์œ ์œจ์˜ 99% ์ •๋„๋Š” ๋œ๋‹ค.

  5. check: ์ด๋ฒคํŠธ ํ์— ์ถ”๊ฐ€๋œ ๋ชจ๋“  setImmediate() ์ฝœ๋ฐฑ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.

  6. close callbacks: "์†Œ์ผ“ ์—ฐ๊ฒฐ ๋‹ซ๊ธฐ" ๊ฐ™์€ ์ •๋ฆฌ ์ž‘์—…์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.



๋ฌดํ•œ๋ฃจํ”„ ๋บ‘๊ธ€๋บ‘๊ธ€ ๋Œ๋ฉด์„œ ์ € ์Šคํ…๋“ค์„ ๊ณ„์† ๋ฐ˜๋ณตํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
๊ทธ๋ฆฌ๊ณ  Event Loop ์ž์ฒด๋Š” ๋ฉ”์ธ ์Šค๋ ˆ๋“œ ์œ„์—์„œ ๋ˆ๋‹ค.

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ์•…์งˆ์ ์ธ ๋ฌธ์ œ๋ฅผ ๋‚ธ๋‹ค๋ฉด ๋‹จ๊ณจ๋ฉ”๋‰ด๋กœ ๋‚˜์˜ค๋Š” ์†Œ์žฌ๋‹ค.
์›๋ฆฌ๋ฅผ ์ž˜ ์•Œ๋ฉด ๋”๋Ÿฝ๊ณ  ๋น„์ง๊ด€์ ์ธ ์ฝ”๋“œ๋ฅผ ์งœ๊ธฐ ์ข‹๋‹ค.

์ด๋ฒคํŠธ ๋ฃจํ”„์˜ ์ฝ”๋“œ๋Š” ์—ฌ๊ธฐ์„œ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.
https://github.com/nodejs/node/blob/main/deps/uv/src/unix/core.c#L378-#L417




์ตœ์ ํ™” ํฌ์ธํŠธ: setImmediate

setImmediate๋Š” ํŠน์ˆ˜ํ•œ ์ตœ์ ํ™” ํฌ์ธํŠธ๊ฐ€ ํ•„์š”ํ•  ๋•Œ ์‚ฌ์šฉ๋˜๋Š” ํŠน์ˆ˜ํ•œ ํ•จ์ˆ˜ ์ค‘ ํ•˜๋‚˜๋‹ค.

์œ„์— ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด setImmediate๋Š” ์ด๋ฒคํŠธ ๋ฃจํ”„ ์Šคํ… ์ค‘ poll ๋‹ค์Œ์œผ๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค.
๊ฑฐ์˜ ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„์— ์‹คํ–‰๋˜๋Š” ์…ˆ์ธ๋ฐ, ์ด๊ฑธ ์ด์šฉํ•ด์„œ ํ˜„์žฌ ์ž์‹ ์ด ์ฒ˜๋ฆฌํ•˜๋Š” ์ž‘์—…์˜ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๋’ค๋กœ ๋ฏธ๋ฃฐ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋ฆฌ์†Œ์Šค๋ฅผ ์–‘๋ณดํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

๊ทธ๋ž˜์„œ ๋ญ”๊ฐ€ ์˜ค๋žซ๋™์•ˆ CPU๋ฅผ ์žก์•„๋จน๋Š” ๋ฌด๊ฑฐ์šด ์—ฐ์‚ฐ์ด ์žˆ๋Š” ๊ฒฝ์šฐ์—๋Š” setImmediate๋กœ ๋„์›Œ์„œ ๋‹ค๋ฅธ ๋” ์ค‘์š”ํ•œ I/O ์ž‘์—…์ด ์šฐ์„ ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜๊ฒŒ๋” ์œ ๋„ํ•˜๊ณค ํ•œ๋‹ค.

๊ด€๋ จ ํฌ์ŠคํŠธ
https://rclayton.silvrback.com/scheduling-execution-in-node-js




์ตœ์ ํ™” ํฌ์ธํŠธ: Event Loop Lag

Event Loop์€ ์œ„์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ ์ฃผ๊ธฐ์ ์œผ๋กœ ๋ฉ”์ธ ์Šค๋ ˆ๋“œ๋ฅผ ์ ์œ ํ•˜์—ฌ ๋Œ€๊ธฐ ์ค‘์ธ ์ž‘์—…๋“ค์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.
์ด๋•Œ, ๋ฉ”์ธ ์Šค๋ ˆ๋“œ๊ฐ€ ๋‹ค๋ฅธ ์ž‘์—…์œผ๋กœ ์ธํ•ด ์ ์œ ๋˜์–ด Event Loop๊ฐ€ ๋Œ€๊ธฐํ•˜๋Š” ์‹œ๊ฐ„์ด ๊ธธ์–ด์ง€๋Š” ๊ฒƒ์„ Event Loop Lag์ด๋ผ๊ณ  ํ•œ๋‹ค.
I/O๊ฐ€ ์ด๋ฒคํŠธ๋ฃจํ”„๋ฅผ ํ†ตํ•ด ๋น„๋™๊ธฐ๋กœ ๋ˆ๋‹ค๊ณ ๋Š” ํ–ˆ์ง€๋งŒ, ์ด๋ฒคํŠธ๋ฃจํ”„ ์ž์ฒด๊ฐ€ ๋™๊ธฐ ์ฝ”๋“œ์— ์˜ํ•ด์„œ ๋ธ”๋Ÿญ๋  ์ˆ˜ ์žˆ๋Š” ๊ตฌ์กฐ๋กœ ๋˜์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋‹ค.

์•„๋ฌดํŠผ Lag์ด ๋†’๋‹ค๋ฉด ํŠน์ •ํ•œ ์ž‘์—…์ด ๋ฉ”์ธ ์Šค๋ ˆ๋“œ๋ฅผ ์˜ค๋ž˜ ์žก๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์œผ๋กœ, Node.js์˜ Event Loop ๊ตฌ์กฐ๋ฅผ ์ด์ƒ์ ์œผ๋กœ ํ™œ์šฉํ•˜๊ณ  ์žˆ์ง€ ๋ชปํ•˜๋‹ค๋Š” ๋œป์ด ๋œ๋‹ค.

1. Lag ์ธก์ •๋ฒ•

Lag ์ธก์ •์šฉ์œผ๋กœ ์ œ๊ณต๋˜๋Š” Node.js ์ „์šฉ ๋„๊ตฌ๋“ค์ด ์กด์žฌํ•œ๋‹ค.
๋ˆ๋‚ด๊ณ  ์“ธ๊ฑฐ๋ผ๋ฉด New Relic, Appdynamics, Dynatrace ๊ฐ™์€ ์˜ต์…˜์ด ์žˆ๊ณ , ์˜คํ”ˆ์†Œ์Šค ๋ฒ„์ „์œผ๋กœ๋Š” ์ด๋Ÿฐ๊ฒŒ ์žˆ๋‹ค.
https://www.npmjs.com/package/nodejs-dashboard

2. Lag ๊ฐœ์„ 

๊ณผ๋„ํ•œ Lag์„ ๊ฐœ์„ ํ•˜๋Š” ๊ฒƒ์—๋Š” ๋ช‡๊ฐ€์ง€ ์˜ต์…˜์ด ์กด์žฌํ•œ๋‹ค.


  1. ๋™๊ธฐ ์ฝ”๋“œ๋ฅผ ์ตœ๋Œ€ํ•œ ๋‹ค ๋น„๋™๊ธฐ ์ฝ”๋“œ๋กœ ์ „ํ™˜ํ•œ๋‹ค.

  2. worker_threads API ์‚ฌ์šฉ

  3. C++๋กœ ๋„ค์ดํ‹ฐ๋ธŒ ์• ๋“œ์˜จ ์งœ์„œ ๋ฐ•๊ธฐ

  4. child_process ์‚ฌ์šฉ



ํ•„์š”์™€ ์ƒํ™ฉ์— ๋”ฐ๋ผ์„œ ์‹ ์ค‘ํ•˜๊ฒŒ ์„ ํƒํ•˜๋ฉด ๋œ๋‹ค.

์ฐธ์กฐ
https://medium.com/nodejsmadeeasy/nodejs-event-loop-lag-5d5928fd03c




์ตœ์ ํ™” ํฌ์ธํŠธ: Event Loop Utilization

Event Loop Utilization์€ Event Loop๊ฐ€ ์–ผ๋งˆ๋‚˜ ๋ฐ”์˜๊ฒŒ ์ž‘์—…์„ ํ•˜๊ณ  ์žˆ๋Š”์ง€ ๋‚˜ํƒ€๋‚ด๋Š” ์ตœ์ ํ™”์šฉ ์ˆ˜์น˜๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ 0๊ณผ 1 ์‚ฌ์ด์˜ ๊ฐ’์„ ๊ฐ–๋Š”๋ฐ, 1์— ๊ฐ€๊นŒ์šธ ์ˆ˜๋ก Event Loop๊ฐ€ ์‰ฌ๋Š” ์‹œ๊ฐ„ ์—†์ด ํ•ญ์ƒ ์–ด๋–ค ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
๋งŒ์•ฝ ์„œ๋ฒ„๊ฐ€ ์ด๋ฏธ Max RPS์— ๋„๋‹ฌํ•ด์„œ ๋” ์ด์ƒ์˜ ํŠธ๋ž˜ํ”ฝ์„ ๋ฐ›์ง€ ๋ชปํ•˜๊ณ  ์žˆ๋Š”๋ฐ, Event Loop Utilization์ด 1๋ณด๋‹ค ๋‚ฎ๋‹ค๋ฉด Loop๋ฅผ ์ถฉ๋ถ„ํžˆ ํ™œ์šฉํ•˜์ง€ ๋ชปํ•˜๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

Event Loop Utilization๋Š” Node.js์—์„œ ์ œ๊ณตํ•˜๋Š” perf_hooks๋ผ๋Š” API๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์ธก์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
https://nodejs.org/api/perf_hooks.html

์ฐธ์กฐ
https://blog.platformatic.dev/the-nodejs-event-loop



์ฐธ์กฐ
https://nodesource.com/blog/event-loop-utilization-nodejs/
https://nodejs.org/en/learn/asynchronous-work/event-loop-timers-and-nexttick
https://github.com/libuv/libuv
https://stackoverflow.com/questions/63770952/nodejs-setimmediate-function-realtime-usecase-and-example
https://www.korecmblog.com/blog/node-js-event-loop