<정의>
버퍼
파일을 읽거나 쓸 때 한 덩어리로 처리하지않고 작은 단위로 시간을 절약하는 방법이다.
전송 속도를 조절하거나, 데이터의 흐름을 제어하기 위해 데이터를 한 곳에서 다른 한 곳으로 전송하는 동안
일시적으로 그 데이터를 보관하는 물리적인 메모리 영역이다.
주로 입출력시에 많이 사용하는데,
예를 들어 파일을 읽어올 때 데이터가 바로 전달되지 않고 우선 출력버퍼에 데이터가 저장된다.
그러다가 버퍼가 가득 차거나 특정 경우가 발생 시(개행 문자, 엔터 등) 그 내용을 전달한다.
보통 이렇게 버퍼 단위로 전송할 때, '버퍼를 비운다'고 표현하며,
전달받은 입장에서는 전체 내용을 한번에 다 가져오지 않고 버퍼 하나 크기 만큼만 받게 된다.
<버퍼의 특성>
- 버퍼의 크기는 고정되지 않을 수 있다. 버퍼의 크기는 시스템 설정이나 프로그램 요구 사항에 따라 동적으로 변경될 수 있다.
-많은 시스템에서 버퍼의 기본 크기는 시스템 설정에 의해 결정된다. 사용자가 별도로 설정하지 않으면 시스템이 기본값을 사용한다.
-대부분 사용자가 버퍼의 크기를 설정할 수 있는 옵션을 제공한다. 따라서 사용자가 원하는 크기로 버퍼를 고정할 수 있다.
<버퍼의 종류>
-순차적 버퍼 (Sequential Buffer)
순차적 버퍼는 데이터를 순차적으로 저장하고, 순차적으로 읽어오는 방식으로 동작한다. FIFO(First In, First Out) 원칙을 따르며, 먼저 들어온 데이터가 먼저 나간다.
ex:) 컴퓨터에서 프린터로 데이터를 전송할 때, 데이터는 프린터 버퍼에 순차적으로 저장되고, 프린터는 이 데이터를 차례대로 인쇄한다
-순환 버퍼 (Circular Buffer)
순환 버퍼는 원형 구조를 가지며, 버퍼의 끝에 도달하면 다시 처음으로 돌아가 데이터를 저장한다. FIFO 원칙을 따르지만, 끝에 도달했을 때 처음으로 돌아간다는 점이 특징이다.
ex:) 오디오 스트리밍 시 스트리밍 데이터가 버퍼에 저장되고, 일정량이 차면 초기 위치로 돌아가 다시 데이터를 저장한다.
-이중 버퍼 (Double Buffer)
이중 버퍼는 두 개의 버퍼를 번갈아가며 사용한다. 하나의 버퍼에서 데이터를 읽는 동안, 다른 버퍼에서는 데이터를 쓰는 방식으로 동작한다.
ex:) 그래픽스 렌더링 시 화면에 출력할 이미지 데이터를 하나의 버퍼에 쓰는 동안, 다른 버퍼의 데이터는 화면에 출력된다.
-링 버퍼 (Ring Buffer)
링 버퍼는 순환 버퍼의 일종으로, 고정된 크기의 버퍼가 원형 구조를 가지며, 읽기와 쓰기 포인터가 독립적으로 움직인다. 데이터가 가득 차면 쓰기 포인터가 읽기 포인터를 따라잡기 전까지 기다린다.
ex:) 네트워크 패킷 처리를 위한 버퍼에서 링 버퍼가 사용된다. 패킷이 버퍼에 순서대로 저장되고, 네트워크 인터페이스가 이 데이터를 순차적으로 처리한다.
<버퍼의 장,단점>
장점
- 데이터 흐름 제어(속도 차이 조절) : 버퍼는 데이터의 흐름을 제어하여 일관된 흐름을 유지하도록 도와준다. 송신자와 수신자가 다른 속도로 데이터를 처리하는 경우에 적합하며, 데이터 송수신 간의 속도 차이를 조절하여 비디오 스트리밍에서 끊김 없이 영상을 재생하거나, 실시간 채팅에서 메시지가 순서대로 전달되도록 하는 데 도움을 준다.
- 성능 향상 : 버퍼를 사용하면 데이터를 일정 크기만큼 모아두었다가 처리하기 때문에 적절한 버퍼 크기라면 오히려 cpu사용 횟수나 메모리 접근 횟수가 감소하여 성능이 향상될 수 있다.
- 데이터 손실 방지 : 데이터가 빠르게 생성되지만 수신자가 이를 처리하는 데 시간이 걸리는 경우, 네트워크 지연이나 일시적인 끊김이 발생하더라도 버퍼는 데이터를 일시적으로 저장하여 데이터 손실을 방지할 수 있다. 이는 실시간 스트리밍에서 중요하다. (버퍼링)
- 자원 활용 최적화 : 버퍼는 시스템 자원의 효율적 사용을 돕는다. 예를 들어, 네트워크 트래픽 관리에서 버퍼를 사용하면 트래픽 폭주를 완화하고 네트워크 자원을 최적화할 수 있다.
단점
- 메모리 사용 증가 : 버퍼를 사용하면 데이터를 일시적으로 저장하기 위한 추가 메모리 공간이 필요하다. 이는 시스템의 메모리 자원을 더 많이 소비하게 만든다. 실시간 데이터를 처리하기 위해 큰 버퍼가 필요할 경우, 메모리 사용량이 증가할 수 있다. 이는 자원 제약이 있는 시스템에서 문제를 일으킬 수 있다.
- 복잡성 증가 : 버퍼 관리가 복잡해질 수 있다. 버퍼 오버플로우(Overflow)와 언더플로우(Underflow)를 방지하기 위한 적절한 관리와 제어가 필요하다.
- 버퍼 오버플로우 및 언더플로우 : 버퍼 크기가 한정되어 있기 때문에, 데이터가 너무 빠르게 들어오거나 너무 천천히 처리되면 버퍼 오버플로우(데이터가 넘쳐흐름)나 언더플로우(버퍼가 비어있음)가 발생할 수 있다. 이는 데이터 손실이나 지연을 초래할 수 있다.
- 지연 발생 : 버퍼는 데이터를 일시적으로 저장하기 때문에, 데이터가 실제로 처리되기까지 시간이 걸릴 수 있다. 또한 버퍼 오버플로우로 인한 부가적인 지연도 발생할 가능성이 있다. 이는 실시간 채팅이나 라이브 스트리밍에서 사용자 경험을 저하시킬 수 있다. 특히, 대화형 애플리케이션에서는 지연이 민감한 문제가 될 수 있다.
- 데이터 무결성 문제 : 버퍼가 가득 차거나 비어 있는 상태에서 데이터의 삽입과 삭제가 제대로 관리되지 않으면, 데이터 무결성 문제가 발생할 수 있다.
<버퍼 etc 예시>
-파일 내용을 버퍼로 읽기
const fs = require("fs")
fs.readFile("./1hello.js", (err, bufferData)=>{
console.log(`-----1-1. 파일내용을 버퍼로 읽음-----`)
// fs.readFile("C:\\\\Users\\\\HPE\\\\Downloads\\\\example\\\\cqrs-pattern\\\\docker-compose.yml", (err, data)=>{
if(err){
console.log(err)
}else{
console.log(bufferData) //binary
console.log('\\n')
console.log(bufferData.toString()) //문자열로 변환
}
console.log(`-----1-2. 파일내용을 버퍼로 읽음 종료-----`)
})
버퍼는 데이터를 일시적으로 보관하여 전달하기 때문에
데이터가 일관성이 유지되는 것이 큰 장점이다.
다만, 지연에 민감한 실시간 애플리케이션에서는 버퍼 크기와 관리 방식을 신중하게 선택해야 한다.
적절한 크기의 버퍼를 사용하고 추가적으로 네트워크 상태를 모니터링하여 동적으로 버퍼 크기를 조절하는 방법을 사용해야한다. 그렇지 않으면 버퍼로 인해 오히려 실시간 통신에 방해를 줄 수가 있는 것이다.
그래서 실시간 애플리케이션에서는 버퍼링을 통해 데이터 손실을 방지하고 일관된 데이터 흐름을 유지하는 동시에,(장점)
지연을 최소화하기 위한 설계가 필요하다.
너무 잘게 쪼개면 오히려 cpu사용 횟수나 메모리 접근 횟수가 증가하여, 성능의 저하를 일으킬 수도 있는데
이럴 땐 일괄 처리(batch processing)나 비동기 처리(asynchronous processing)를 결합해 사용하거나 캐시 메모리를 효율적으로 활용하여 메모리 접근 횟수를 줄이는 방법도 있다.
이렇게 하면 CPU와 메모리 자원을 효율적으로 사용함과 동시에 버퍼의 장점을 같이 가져갈 수 있다.
'Backend-dev > nodeJS & express' 카테고리의 다른 글
nodejs로 라우팅 서버 실습해보기! (0) | 2024.07.30 |
---|---|
[javascript] express로 사용자 req 분석하기 (0) | 2024.05.27 |
[javascript] Stream(스트림)이란? | 장,단점과 노드js를 활용한 예시 (0) | 2024.05.25 |
[javascript] Node.js와 express 비교 (0) | 2024.05.25 |
[javascript] 콜 스택과 이벤트 루프 | 동기/비동기 처리 차이? (0) | 2024.05.25 |