Node.js 의 이해…
Node.js가 대체 뭔가요?
비전공자를 위한 1부터 100까지
서버 마이그레이션 중 만난 “Node20 vs Node22” 소동을 계기로, 개념부터 차근차근 정리합니다
얼마 전 새솔CRM 서버를 이전하는 작업을 하다가, “Node가 22인 줄 알았는데 20으로 나온다”는 상황을 마주했습니다. 분명 예전 서버에서 업그레이드까지 했는데, 새 서버에서는 버전이 다르게 나오니 당황스러웠죠. 이 사건을 계기로, 정작 Node가 뭔지는 한 번도 제대로 짚고 넘어간 적이 없다는 걸 깨달았습니다.
이 글은 코딩을 전공하지 않은 분들을 위해, Node.js라는 개념을 처음부터 끝까지 쉬운 비유로 풀어보는 글입니다.
우리가 코드를 짠다는 건 결국 사람이 읽을 수 있는 글자를 쓰는 것뿐입니다. 컴퓨터는 이 글자만 봐서는 아무것도 못 합니다. 그래서 이 글자를 읽고 실제로 컴퓨터가 이해하는 동작으로 바꿔주는 번역기 역할의 프로그램이 반드시 필요합니다. 이걸 흔히 “엔진” 또는 “인터프리터”라고 부릅니다.
Java 코드 → Java 엔진(JVM)이 읽고 실행
JavaScript 코드 → JavaScript 엔진이 읽고 실행
즉 어떤 언어든, 그 언어를 “이해하고 실행해줄 엔진”이 어딘가에 설치돼 있어야 코드가 돌아갑니다. 엔진이 없으면 그냥 텍스트 파일일 뿐입니다.
여기가 핵심입니다. 1995년, JavaScript는 넷스케이프(초창기 웹브라우저 회사)에서 “웹페이지를 좀 더 살아 움직이게 만들자”는 아주 구체적인 목적 하나만으로 만들어졌습니다. 버튼 누르면 색깔 바뀌고, 입력폼에 이메일 잘못 쓰면 경고 뜨고, 이런 것들이요.
그래서 JavaScript를 실행하는 엔진 자체를 처음부터 브라우저라는 프로그램 안에 통째로 내장시켜 만들었습니다. 따로 떼서 팔거나 독립적으로 설치할 수 있는 물건이 아니라, 브라우저의 부품 중 하나로 태어난 거예요.
반면 PHP, Java, Python 같은 언어들은 처음부터 서버(그냥 컴퓨터라고 생각하시면 됩니다)에서 독립적으로 실행되도록 설계됐습니다. 브라우저 없이도 그 자체로 “저를 실행해주는 프로그램(엔진)”이 컴퓨터에 설치되면 바로 돌아갔습니다.
할 수 있었던 것: 화면의 글자·버튼을 바꾸기, 사용자 클릭에 반응하기, 입력값 검사하기
할 수 없었던 것: 컴퓨터의 파일을 읽고 쓰기, 데이터베이스에 접속하기, 다른 컴퓨터로부터 요청을 받아 응답하기(서버 역할)
왜냐면 이런 기능들은 브라우저가 애초에 제공해주지 않았거든요. 브라우저는 “웹페이지를 보여주는 프로그램”이지 “파일 시스템을 다루는 프로그램”이 아니니까요. JavaScript 입장에서는 하고 싶어도 그런 문(API)이 아예 없었던 겁니다.
이 때문에 Node.js가 나오기 전까지는 웹사이트 하나를 만들려면 언어가 최소 두 개 필요했습니다.
개발자도 보통 “프론트엔드 개발자”와 “백엔드 개발자”로 나뉘어서, 서로 다른 언어를 쓰며 협업하는 구조였습니다.
2009년, 라이언 달(Ryan Dahl)이라는 개발자가 구글 크롬 브라우저 안에 있던 JavaScript 엔진(V8)을 브라우저에서 물리적으로 분리해서, 독립적으로 실행 가능한 프로그램으로 다시 포장했습니다. 그리고 여기에 브라우저가 주던 기능(화면 조작) 대신, 서버가 필요로 하는 새로운 기능들을 새로 붙여줬습니다: 파일 읽고 쓰기, 네트워크로 요청 받고 응답하기, 데이터베이스 연결하기 같은 것들이요. 이렇게 만들어진 프로그램이 Node.js입니다.
그 결과 이제 JavaScript는 화면도 짜고, 서버도 짤 수 있는 언어가 됐습니다. 새솔CRM처럼 화면(프론트엔드)과 서버(백엔드) 전체를 JavaScript 하나로 만들 수 있는 게 바로 이 덕분입니다.
Node.js는 계속 업데이트되는 소프트웨어입니다. 마치 스마트폰 운영체제(iOS, 안드로이드)가 버전이 올라가듯, Node.js도 시간이 지나며 버전이 올라갑니다. 지금 이야기하고 있는 Node 20, Node 22가 바로 그 버전 번호입니다.
Node.js로 프로그램을 만들 때, 모든 기능을 처음부터 다 짜지 않습니다. 다른 사람들이 미리 만들어둔 “부품(패키지)”을 가져다 씁니다. 새솔CRM에서 PDF를 만들 때 쓰는 puppeteer, 데이터베이스로 쓰는 better-sqlite3 같은 것들이 전부 이런 부품입니다.
여기서 이번에 실제로 겪었던 일이 등장합니다. 새솔CRM에서 PDF를 만들 때 쓰는 puppeteer라는 부품을 예전 서버에서 최신 버전(25번대)으로 업그레이드했었습니다. 이 최신 puppeteer는 “나는 Node 22 이상에서만 정식으로 작동을 보장한다”고 적혀 있었습니다.
그런데 서버를 새 곳으로 이사(마이그레이션)하면서, 코드와 부품 목록(package.json)은 그대로 옮겨졌지만, 서버 자체의 Node.js 버전은 옛날 버전(20)으로 남아있었던 것입니다.
모든 부품이 puppeteer처럼 관대한 것은 아닙니다. 데이터베이스를 다루는 better-sqlite3 같은 부품은 순수 JavaScript가 아니라, 컴퓨터가 더 빠르게 이해할 수 있는 “기계어에 가까운 코드(네이티브 애드온)”로 일부가 만들어져 있습니다.
실제로 이번에 Node를 22로 올리는 작업을 하다가, 이 부분에서 실제 장애가 발생했습니다. Node 버전만 22로 바꾸고 better-sqlite3라는 나사는 옛날 규격(20용)으로 그대로 뒀더니, “이 나사는 이 드라이버에 안 맞습니다”라는 에러(NODE_MODULE_VERSION 불일치)가 나면서 서비스가 잠깐 멈췄습니다. 나사를 새 규격(22용)으로 다시 깎아 끼우자(재빌드) 바로 정상화됐습니다.
서버에서는 프로그램을 그냥 실행만 하는 게 아니라, 죽으면 자동으로 재시작해주고 여러 개를 동시에 돌려주는 관리자 프로그램(pm2)을 씁니다.
이번에 발견된 재미있는(?) 특징은, cluster 모드로 여러 창구(워커)를 열 때는, 각 창구가 관리자(pm2 데몬) 자신의 아가미(Node 버전)를 그대로 물려받는다는 점이었습니다. 개별 창구마다 “너는 Node 22 써” 하고 따로 지정해도 소용이 없고, 관리자 자신의 Node 버전을 바꿔야 아래 창구들도 다 같이 바뀝니다. 이걸 모르고 개별 지정만 바꿨다가, 나사(better-sqlite3)와 드라이버(실제 Node 버전)가 어긋나면서 짧은 장애로 이어졌던 것입니다.
| 용어 | 쉬운 설명 |
|---|---|
| JavaScript | 원래 브라우저 안에서만 동작하던 프로그래밍 언어 |
| Node.js | JavaScript를 브라우저 밖(서버)에서도 실행하게 해주는 프로그램 |
| 버전(20, 22 등) | Node.js의 업데이트 단계 번호 |
| npm | 부품(패키지)을 받을 수 있는 온라인 상점 |
| package.json | 어떤 부품을 쓰는지 적어둔 목록표 |
| node_modules | 실제로 받은 부품들이 쌓인 창고 |
| 네이티브 애드온 | Node 버전에 맞춰 다시 조립(재빌드)해야 하는 예민한 부품 |
| pm2 | 프로그램을 관리·재시작해주는 관리자 프로그램 |
| cluster 모드 | 한 프로그램을 여러 창구로 복사해서 동시에 운영하는 방식 |