뮤텍스
여러 스레드나 프로세스가 공유 자원에 동시에 접근하는 것을 제어하기 위한 동기화 메커니즘이다. 뮤텍스는 일종의 락(lock)으로 작동하여 한 번에 하나의 스레드만 특정 코드 영역을 실행할 수 있게 제한한다. 이렇게 하면 공유 자원에 대한 동시 접근이 제어되어 데이터의 일관성과 정확성이 유지된다.
Node.js에서의 사용
1. async-mutex
JavaScript에서 비동기 작업을 수행할 때 사용되는 뮤텍스(Mutex) 라이브러리이다.
const { EventEmitter } = require("events");
const { Mutex } = require("async-mutex");
class ConfirmRequest extends EventEmitter {
constructor() {
super();
this.currentRequests = 0;
this.mutex = new Mutex(); // 뮤텍스 인스턴스 생성
}
async increment() {
const release = await this.mutex.acquire(); // 뮤텍스 획득
try {
this.currentRequests++;
this.emit("requestIncremented");
} finally {
release(); // 뮤텍스 반환
}
}
async decrement() {
const release = await this.mutex.acquire(); // 뮤텍스 획득
try {
this.currentRequests--;
if (this.currentRequests === 0) {
this.emit("requestCompleted");
}
} finally {
release(); // 뮤텍스 반환
}
}
getCurrentRequests() {
return this.currentRequests; // 이 메서드는 동기적이므로 뮤텍스가 필요하지 않습니다.
}
}
const confirmRequestInstance = new ConfirmRequest();
module.exports = confirmRequestInstance;
서버에서 처리 중인 요청의 수를 파악하는 모듈이다. 동시에 메서드가 호출이 되면 증감이 제대로 이루어지지 않는 문제가 있다. 그래서 뮤텍스를 활용해서 증감이 동기적으로 이루어지게 했다. 증가와 감소 중 하나라도 먼저 실행이 된다면 공유되는 자원은 락이 걸려서 대기 상태에 들어간다.
작동 원리
async-mutex 라이브러리는 내부적으로 큐(Queue)를 사용하여 뮤텍스를 관리한다. 이 큐는 임계 영역에 접근하려는 모든 비동기 작업을 대기열로 관리하게 된다.
- 잠금 요청: 작업이 공유 자원에 접근하려고 할 때, 잠금을 요청한다. 이미 다른 작업이 자원을 사용 중이라면, 이 작업은 일종의 대기열(queue)에 추가된다..
- 잠금 획득: 대기열에서 가장 먼저 대기하고 있는 작업이 공유 자원에 접근할 권한(잠금)을 얻는다. 이 단계에서 해당 작업은 "임계 영역"이라고 부르는 코드 부분을 안전하게 실행할 수 있다.
- 잠금 해제: 작업이 임계 영역을 빠져나가면, 잠금을 해제(release)한다. 이렇게 되면 대기열에 있던 다음 작업이 잠금을 획득하고 임계 영역에 진입할 수 있게 된다.
*임계 영역 (critical section) : 동시에 여러 작업이 접근하면 문제가 발생할 수 있는 코드 부분을 지칭한다. 즉, 임계 영역은 한 번에 하나의 작업만이 접근해야 하는 코드 영역이다.
장점
- 코드 단순화: 복잡한 동기화 조건을 뮤텍스로 간단하게 처리할 수 있다.
- 에러 방지: 동시성 문제를 미리 방지하여 실행 중인 애플리케이션에서 발생할 수 있는 오류를 줄인다.
단점
- 성능 오버헤드: 뮤텍스를 사용하면 작업 사이에 잠금/해제 과정이 추가되므로 약간의 성능 저하가 발생할 수 있습니다.
- *오버헤드 (Overhead)
어떤 작업을 수행하기 위해 필요한 추가적인 자원이나 시간을 의미한다. 예를 들어, 뮤텍스를 사용하면서 잠금과 해제 과정이 필요하기 때문에, 이런 연산이 작업의 전체 성능에 부담을 줄 수 있다. 그래서 뮤텍스를 사용하면서 시간이나 CPU 자원이 추가로 소모되는 것을 오버헤드라고 한다.
- *오버헤드 (Overhead)
- 데드락 위험: 잘못 사용하면 데드락(Deadlock)이 발생할 가능성이 있습니다.
- 데드락 (Deadlock)
두 개 이상의 작업이 서로의 완료를 무한히 기다리는 상황을 의미한다. 이런 상황은 잘못된 뮤텍스 사용으로 인해 발생할 수 있다.
- 데드락 (Deadlock)
처음에는 비동기를 동기로 바꿔준다고 생각했지만 그것이 아니었다. 공유된 자원에서만 동기적로 바꿔주는 것이다. 예를들면 1, 2, 3 순서대로 작업을 시작할 때 동기적이라면 1, 2, 3 순서대로 완료가 되겠지만 뮤텍스는 공유되는 자원에서만 동기적으로 되기에 대기 상태에서 2, 1, 3 이렇게 될 수 있고 이후에 다시 완료되는 것은 3, 2, 1 이 될 수도 있다. 따라서 순서를 보장할 수 없다.
'오늘 뭐했냐 > 개발에 대한 주저리' 카테고리의 다른 글
23.09.01 동기적 처리와 비동기적 처리 (0) | 2023.09.08 |
---|---|
23.08.31 사인드 업로드(Signed Upload) (0) | 2023.09.07 |
23.08.24 node.js (Event 모듈) (0) | 2023.09.03 |
23.08.20 레디스 (Redis) (0) | 2023.08.30 |
23.08.19 쓰레드(thread) (0) | 2023.08.27 |