싱글톤 패턴이란? Node.js와 함께 배우는 구현과 활용법

2025. 2. 3. 19:36Tech Insights/Design Pattern

반응형

싱글톤 패턴이란?

싱글톤 패턴(Singleton Pattern)은 특정 클래스의 인스턴스를 하나만 생성하고, 이를 전역적으로 공유하는 디자인 패턴입니다. 이를 통해 불필요한 객체 생성을 방지하고, 시스템 자원을 효율적으로 사용할 수 있습니다.

싱글톤 패턴의 특징

  1. 유일한 인스턴스 유지: 애플리케이션 전반에서 단 하나의 객체만 유지됩니다.
  2. 전역 접근 가능: 인스턴스를 여러 곳에서 공유하여 동일한 데이터를 사용할 수 있습니다.
  3. 메모리 절약: 동일한 객체를 여러 번 생성하는 비용을 줄일 수 있습니다.

싱글톤 패턴이 사용되는 경우

사용 사례설명

로깅 시스템 모든 모듈에서 동일한 로깅 인스턴스를 사용
환경 설정(Config) 어플리케이션 설정 값을 싱글톤 객체에서 관리
이벤트 버스 이벤트 리스너를 관리하는 객체를 싱글톤으로 유지

싱글톤 패턴 구현 방법

1️⃣ 기본적인 싱글톤 패턴 (ES6)

class Singleton {
  constructor() {
    if (!Singleton.instance) {
      Singleton.instance = this;
    }
    return Singleton.instance;
  }

  sayHello() {
    console.log("Hello from Singleton!");
  }
}

const instance1 = new Singleton();
const instance2 = new Singleton();

console.log(instance1 === instance2); // true
instance1.sayHello();

2️⃣ Node.js 모듈을 활용한 싱글톤 패턴

// singleton.js
class Singleton {
  constructor() {
    if (!Singleton.instance) {
      this.data = "초기화된 데이터";
      Singleton.instance = this;
    }
    return Singleton.instance;
  }
}

module.exports = new Singleton();
// main.js
const singleton1 = require("./singleton");
const singleton2 = require("./singleton");

console.log(singleton1 === singleton2); // true
singleton1.data = "변경된 데이터";
console.log(singleton2.data);

싱글톤 패턴의 단점과 해결 방법

단점: 동기화 문제

싱글톤 객체가 여러 프로세스 또는 멀티 스레드 환경에서 동시에 접근될 경우, 데이터 동기화 이슈가 발생할 수 있습니다.

Node.js 는 싱글쓰레드/비동기 기반이기 때문에 문제가 발생할 가능성이 거의 없지만, 저자의 편의를 위해 예시는 Node.js 코드입니다.

해결 방법:

  • Mutex(뮤텍스) 활용: 단일 프로세스에서 공유 자원의 접근을 제어합니다.

Mutex를 활용한 싱글톤 객체 보호

const { Mutex } = require('async-mutex');

const mutex = new Mutex();
class Singleton {
  constructor() {
    if (!Singleton.instance) {
      Singleton.instance = this;
      this.counter = 0;
    }
    return Singleton.instance;
  }

  async safeIncrement() {
    const release = await mutex.acquire();
    try {
      this.counter++;
      console.log(`Counter: ${this.counter}`);
    } finally {
      release();
    }
  }
}

const singleton = new Singleton();
singleton.safeIncrement();
singleton.safeIncrement();

실제 서비스 사례

1️⃣ 싱글톤을 활용한 캐시 시스템

싱글톤 패턴은 대규모 웹 서비스에서 캐시 시스템을 구현할 때 유용하게 사용됩니다. 예를 들어, 인기 있는 API 요청 결과를 캐싱하여 성능을 최적화할 수 있습니다.

class CacheManager {
  constructor() {
    if (!CacheManager.instance) {
      this.cache = new Map();
      CacheManager.instance = this;
    }
    return CacheManager.instance;
  }

  set(key, value) {
    this.cache.set(key, value);
  }

  get(key) {
    return this.cache.get(key);
  }
}

const cache1 = new CacheManager();
cache1.set('user_1', { name: 'Henry', age: 30 });

const cache2 = new CacheManager();
console.log(cache2.get('user_1')); // { name: 'Henry', age: 30 }

이처럼 싱글톤 패턴을 사용하면, 여러 부분에서 동일한 캐시 데이터를 활용할 수 있어 API 요청 부담을 줄이고 성능을 향상시킬 수 있습니다.

2️⃣ 싱글톤을 활용한 로깅 시스템

로그 기록은 대부분의 애플리케이션에서 중요한 역할을 합니다. 싱글톤 패턴을 사용하면 모든 요청에서 동일한 로깅 인스턴스를 사용하여 일관된 로그를 유지할 수 있습니다.

class Logger {
  constructor() {
    if (!Logger.instance) {
      Logger.instance = this;
    }
    return Logger.instance;
  }

  log(message) {
    console.log(`[LOG]: ${message}`);
  }
}

const logger1 = new Logger();
const logger2 = new Logger();

logger1.log("첫 번째 로그");
logger2.log("두 번째 로그");

console.log(logger1 === logger2); // true

이처럼 싱글톤 패턴을 활용하면, 여러 모듈에서 동일한 로깅 인스턴스를 공유하여 로그의 일관성을 유지하고, 중복된 인스턴스 생성 비용을 줄일 수 있습니다.

3️⃣ 싱글톤을 활용한 환경 설정 관리

대규모 애플리케이션에서는 환경 설정을 한 곳에서 중앙 집중식으로 관리하는 것이 중요합니다. 싱글톤 패턴을 활용하면 설정 값을 한 번만 로드하고, 애플리케이션 전반에서 동일한 값을 공유할 수 있습니다.

class ConfigManager {
  constructor() {
    if (!ConfigManager.instance) {
      this.config = {
        apiBaseUrl: "https://api.example.com",
        maxConnections: 10,
      };
      ConfigManager.instance = this;
    }
    return ConfigManager.instance;
  }

  get(key) {
    return this.config[key];
  }

  set(key, value) {
    this.config[key] = value;
  }
}

const config1 = new ConfigManager();
const config2 = new ConfigManager();

console.log(config1.get("apiBaseUrl")); // "https://api.example.com"
config1.set("apiBaseUrl", "https://new-api.example.com");
console.log(config2.get("apiBaseUrl")); // "https://new-api.example.com"
console.log(config1 === config2); // true

이처럼 싱글톤 패턴을 활용하면, 환경 설정 값을 한 곳에서 관리하고 여러 모듈에서 쉽게 접근할 수 있으며, 설정 값이 변경되더라도 모든 인스턴스에 즉시 반영됩니다.

결론: 싱글톤 패턴을 언제 사용해야 할까?

  • 상태를 유지해야 하는 공통 서비스 (ex. 로깅, 설정)
  • 전역적으로 동일한 인스턴스를 공유해야 할 때 (ex. 이벤트 버스)
  • 멀티 스레드 또는 프로세스 환경에서 주의가 필요함

하지만 무조건 싱글톤을 적용하면 오히려 문제를 일으킬 수 있으므로, 필요할 때만 적절하게 활용해야 합니다. 

반응형