[Node.js 입문]
데이터베이스 ACID / Node.js의 이벤트 루프
호지98
2024. 5. 23. 19:22
ACID?
ACID는 데이터베이스 시스템에서 트랜잭션이 안전하게 처리되는 것을 보장하는 네 가지 속성을 말한다. 각각의 속성은 Atomicity, Consistency, Isolation, Durability를 의미한다.
- Atomicity (원자성): 트랜잭션 내의 모든 작업이 모두 수행되거나 전혀 수행되지 않아야 함을 의미한다. 즉, 트랜잭션이 완료되면 그 결과가 데이터베이스에 반영되고, 그렇지 않으면 트랜잭션의 모든 작업이 롤백되어 데이터베이스가 트랜잭션 시작 이전 상태로 돌아간다. 이를 통해 트랜잭션 중 일부만 반영되는 상황을 방지한다.
- Consistency (일관성): 트랜잭션이 성공적으로 완료되면 데이터베이스는 일관된 상태를 유지해야 한다. 트랜잭션 수행 전과 후의 데이터베이스는 모든 정합성 제약 조건을 만족해야 한다. 예를 들어, 은행 계좌 이체 트랜잭션의 경우, 돈의 합계가 일치해야 한다.
- Isolation (고립성): 각 트랜잭션은 독립적으로 실행되어야 하며, 다른 트랜잭션의 중간 결과를 참조해서는 안 된다. 고립성은 동시성 제어를 통해 여러 트랜잭션이 동시에 실행되더라도 각 트랜잭션이 독립적으로 처리됨을 보장한다. 예를 들어, 두 개의 트랜잭션이 동시에 같은 데이터를 수정하려고 할 때, 하나의 트랜잭션이 완료될 때까지 다른 트랜잭션이 해당 데이터를 수정하지 못하게 한다.
- Durability (지속성): 트랜잭션이 성공적으로 완료된 후에는 시스템 오류가 발생하더라도 그 결과가 데이터베이스에 영구적으로 반영되어야 한다. 이를 통해 완료된 트랜잭션의 결과가 영구적으로 저장되며, 시스템 재시작 후에도 해당 결과가 유지된다.
이러한 ACID 속성들은 데이터베이스 시스템에서 데이터 무결성과 신뢰성을 보장하기 위한 기본적인 원칙으로, 특히 금융, 전자 상거래, 기업 정보 시스템 등 트랜잭션이 중요한 역할을 하는 시스템에서 필수적으로 요구된다.
Node.js의 이벤트 루프
Node.js에서 이벤트 루프(Event Loop)는 비동기적이고 논블로킹(non-blocking) 방식으로 작업을 처리하는 핵심 이다. Node.js는 단일 스레드로 동작하지만 이벤트 루프를 통해 I/O 작업, 네트워크 요청, 파일 시스템 작업 등의 비동기 작업을 효율적으로 처리할 수 있다. 이벤트 루프의 주요 역할은 콜백 함수들을 적절한 시점에 실행하는 것이다.
이벤트 루프의 동작 원리
이벤트 루프는 다음과 같은 단계들로 구성되어 있다:
- 타이머 단계(Timers):
- setTimeout 및 setInterval에 의해 스케줄된 콜백 함수들이 실행된다.
- 타이머가 만료되면 해당 콜백 함수들이 이 단계에서 실행된다.
- I/O 콜백 단계(I/O Callbacks):
- 타이머와 관련 없는 거의 모든 콜백 함수가 실행된다.
- 예를 들어, 파일 시스템 작업, 네트워크 작업 등의 비동기 I/O 작업의 콜백이 이 단계에서 처리된다.
- 대기 콜백 단계(Idle, prepare):
- Node.js 내부적으로만 사용된다.
- 이벤트 루프가 실행 준비를 하는 단계이다.
- 폴링 단계(Poll):
- 새로운 I/O 이벤트를 가져오고, 적절한 콜백 함수들을 실행한다.
- 이 단계에서 이벤트 루프는 새로운 이벤트가 도착할 때까지 대기할 수도 있다.
- 폴링 단계는 I/O 작업의 콜백을 처리하고, 새로운 I/O 이벤트를 수신할 때까지 블록될 수 있다.
- 검사 단계(Check):
- setImmediate에 의해 스케줄된 콜백 함수들이 실행된다.
- setImmediate 콜백은 폴링 단계가 완료된 후 즉시 실행된다.
- 클로즈 콜백 단계(Close Callbacks):
- 닫기 이벤트가 발생한 콜백들이 실행된다.
- 예를 들어, socket.on('close', ...)와 같은 콜백이 이 단계에서 실행된다.
이벤트 루프의 예
다음은 간단한 Node.js 코드 예제다:
const fs = require('fs');
console.log('Start');
setTimeout(() => {
console.log('setTimeout');
}, 0);
setImmediate(() => {
console.log('setImmediate');
});
fs.readFile('example.txt', (err, data) => {
if (err) throw err;
console.log('File read');
});
console.log('End');
위 코드의 실행 순서는 다음과 같다:
- Start와 End가 즉시 출력된다.
- setTimeout과 setImmediate는 모두 0초 지연으로 설정되었지만, 이벤트 루프의 단계 순서로 인해 setImmediate 콜백이 setTimeout 콜백보다 먼저 실행된다.
- 파일 읽기 작업이 완료된 후 그 콜백이 실행된다.
실제 출력 결과는 다음과 같다:
Start
End
setImmediate
File read
setTimeout
요약
- 단일 스레드: Node.js는 단일 스레드로 동작하지만, 이벤트 루프를 통해 비동기 작업을 효율적으로 처리한다.
- 비동기 작업 처리: 이벤트 루프는 비동기 작업이 완료될 때 해당 콜백을 적절한 시점에 실행한다.
- 단계별 처리: 이벤트 루프는 여러 단계로 구성되며, 각 단계에서 특정 종류의 콜백을 실행한다.
이벤트 루프는 Node.js의 핵심 메커니즘으로, 이를 통해 고성능의 비동기 I/O 처리가 가능해진다.