Post

2025-08-26-TIL

Today I Learned

자바빈이란

자바빈은 원래 비주얼 툴에서 조작 가능한 컴포넌트를 말한다. 자바의 주력 플랫폼이 웹 기반의 엔터프라이즈 방식으로 바뀌면서 이제는 JSP 빈, EJB 같은 표준기술과 자바빈 스타일의 오브젝트를 사용하는 오픈소스 기술을 통해서 이어져왔다.

자바빈(JavaBean)은 자바(Java)에서 재사용 가능한 컴포넌트를 만들기 위한 규약(컨벤션)을 따르는 클래스를 말합니다. 주로 GUI 컴포넌트나 서버 사이드(특히 JSP/서블릿)에서 데이터 전달 객체로 사용됩니다.

자바빈의 특징

  1. 기본 생성자 필요: 매개변수가 없는 public 기본 생성자가 있어야 합니다.
  2. 멤버 변수는 private으로 선언: 외부에서 직접 접근하지 못하게 하고, 캡슐화를 보장합니다.
  3. getter/setter 메서드 제공: getXxx(), setXxx() 형태의 메서드로 멤버 변수에 접근합니다.
  4. 직렬화 가능 (선택적): Serializable 인터페이스를 구현하여 객체를 파일이나 네트워크로 전송할 수 있습니다.

몽고DB에서도 ACID가 보장되는가?

  1. 기본 단일 문서 연산

MongoDB는 단일 문서 연산에 대해서는 예전부터 항상 ACID(원자성, 일관성, 격리성, 지속성) 를 보장했다. 즉, 하나의 문서(document)에 대한 insert, update, delete는 트랜잭션처럼 원자적으로 수행된다.

  1. 다중 문서 트랜잭션
  • MongoDB 4.0 (2018): Replica Set 환경에서 다중 문서 트랜잭션 지원 시작.
  • MongoDB 4.2: Sharded Cluster에서도 다중 문서 트랜잭션 지원 확대.

이를 통해 RDBMS처럼 여러 문서, 여러 컬렉션에 걸친 트랜잭션을 실행할 수 있다.

  1. ACID 특성
  • Atomicity (원자성): 트랜잭션 내 모든 작업이 모두 성공하거나 전혀 실행되지 않음.
  • Consistency (일관성): 트랜잭션 실행 전후로 데이터가 일관된 상태를 유지.
  • Isolation (격리성): 기본적으로 “snapshot isolation”을 제공 → 다른 트랜잭션이 중간 데이터를 보지 않음.
  • Durability (지속성): commit된 데이터는 장애 발생 후에도 유지됨 (Write Concern, Journal 옵션에 따라 보장 수준 조절 가능).
  1. 주의할 점
  • RDBMS의 전통적 트랜잭션만큼 효율적이지는 않을 수 있으며, 다중 문서 트랜잭션은 성능 비용이 큼.
  • MongoDB는 원래 도큐먼트 지향 데이터 모델을 통해 대부분의 경우 단일 문서 안에서 데이터를 구조화하여 트랜잭션이 필요 없도록 설계됨.
  • 따라서 다중 문서 트랜잭션은 “예외적인 상황”에서 사용하는 것이 권장됨.

정리하자면, MongoDB는 단일 문서 수준에서는 항상 ACID를 보장하고, 최신 버전에서는 다중 문서 트랜잭션도 지원하여 완전한 ACID 트랜잭션을 사용할 수 있습니다. 다만 성능과 설계 철학을 고려해 가능하다면 문서 단위로 데이터 모델링하는 것이 가장 바람직하다.

-> NoSQL로 변경하는 이유나 조건을 생각해보기 -> 스키마리스라고 하는건 안됨!!


Mutex와 Semaphore

뮤텍스(Mutex, Mutual Exclusion의 줄임말)는 멀티스레드 환경에서 공유 자원(데이터, 파일, 메모리 등)에 동시에 접근하는 것을 제어하기 위해 사용하는 동기화 기법이다. 쉽게 말하면, “자물쇠” 같은 개념입니다.

  • 여러 스레드가 동시에 접근하면 문제가 생길 수 있는 자원(예: 은행 계좌, 전역 변수 등)에 대해, 한 번에 하나의 스레드만 접근할 수 있도록 보장합니다.
  • 어떤 스레드가 자원을 사용하려면 먼저 뮤텍스를 “잠금(lock)”해야 하고, 다 쓰고 나면 반드시 “해제(unlock)”해야 다른 스레드가 쓸 수 있습니다.

뮤텍스의 주요 특징

  1. 상호 배제(Mutual Exclusion) 동시에 오직 한 스레드만 임계 구역(Critical Section)에 진입 가능.
  2. 잠금/해제 메커니즘
    • lock() → 자원을 사용하기 위해 잠금
    • unlock() → 자원 사용 후 해제
  3. 블로킹 동작 만약 이미 다른 스레드가 뮤텍스를 잠근 상태라면, 다른 스레드는 잠금이 풀릴 때까지 대기합니다.
  4. 스레드 소유권(Thread ownership) 대부분의 뮤텍스 구현은 잠근 스레드만 해제할 수 있도록 제한합니다.

뮤텍스 vs 세마포어

  • 뮤텍스: 동시에 1개의 스레드만 자원 접근 가능 → “열쇠 하나”
  • 세마포어: 동시에 N개의 스레드까지 자원 접근 가능 → “열쇠 여러 개”

은행 ATM에 뮤텍스가 있다고 하면, 한 번에 한 명만 ATM을 사용할 수 있고, 다른 사람은 앞사람이 끝날 때까지 기다려야 합니다.


세마포어(Semaphore)는 멀티스레드 환경에서 공유 자원의 동시 접근을 제어하기 위한 동기화 기법

뮤텍스(Mutex)와 비슷하지만, 뮤텍스는 한 번에 하나의 스레드만 접근 가능한 반면, 세마포어는 지정된 개수(N)만큼 스레드가 동시에 접근 가능하다는 점에서 차이가 있습니다.

세마포어의 개념

  • 세마포어는 내부적으로 정수 카운터(counter)를 유지합니다.
  • 자원 사용이 가능할 때는 카운터가 감소(acquire)하고, 자원을 반납하면 카운터가 증가(release)합니다.
  • 카운터 값이 0이면 더 이상 자원을 쓸 수 없으므로, 다른 스레드는 대기 상태에 들어갑니다.

세마포어 종류

  1. 이진 세마포어(Binary Semaphore)
    • 카운터 값이 0 또는 1만 가능 → 사실상 뮤텍스와 비슷
    • “열쇠 1개짜리” 세마포어
  2. 카운팅 세마포어(Counting Semaphore)
    • 카운터 값이 0 이상 N 이하
    • 자원 개수가 여러 개인 경우 활용 → “열쇠 여러 개”

세마포어와 뮤텍스의 차이

구분뮤텍스(Mutex)세마포어(Semaphore)
동시 접근 가능 스레드 수1N (설정된 값)
소유권잠근 스레드만 해제 가능소유권 개념 없음 (다른 스레드가 release 가능)
구현 난이도단순상대적으로 다양
사용 사례단일 자원 보호제한된 개수의 자원 풀 관리

비유

  • 뮤텍스: 화장실 열쇠가 1개 → 한 번에 한 명만 사용 가능
  • 세마포어(카운팅 3): 화장실 칸이 3개 있고, 열쇠가 3개 → 동시에 3명까지 사용 가능

데드락이란?

데드락(Deadlock, 교착 상태) 은 둘 이상의 프로세스나 스레드가 서로가 가진 자원을 기다리며 무한정 대기하는 상황을 말합니다. 쉽게 말해, 서로 “네가 먼저 놔야 내가 움직일 수 있어” 하고 기다리다가 아무도 앞으로 진행하지 못하는 상태입니다.

데드락 발생 조건 (Coffman의 네 가지 조건)

데드락이 발생하려면 다음 네 가지 조건이 동시에 만족해야 합니다:

  1. 상호 배제(Mutual Exclusion): 한 자원은 동시에 하나의 프로세스(또는 스레드)만 사용할 수 있다.
  2. 점유 대기(Hold and Wait): 자원을 하나 이상 점유한 상태에서, 다른 자원을 기다린다.
  3. 비선점(Non-preemption): 이미 점유된 자원은 강제로 빼앗을 수 없다.
  4. 순환 대기(Circular Wait): 프로세스들이 서로가 가진 자원을 요구하면서 원형으로 기다리는 관계가 형성된다. (예: A → B → C → A)

예시 (간단한 상황)

  • 스레드 A가 자원 1을 잡고, 자원 2를 기다림
  • 스레드 B가 자원 2를 잡고, 자원 1을 기다림 → 서로 양보하지 않으므로 무한 대기 → 데드락 발생

해결 방법

  • 예방(Prevention): 위의 4가지 조건 중 하나라도 깨트리도록 설계
  • 회피(Avoidance): 자원 할당 그래프 등을 통해 안전 상태(Safe state)에서만 자원 할당
  • 탐지 및 회복(Detection & Recovery): 데드락 발생 시 탐지 후 강제로 프로세스를 중단하거나 자원을 회수

라이브락이란?

Deadlock (교착 상태)

  • 여러 스레드가 서로 자원을 기다리며 아무도 진행하지 못하는 상태.
  • 완전히 멈춤.
  • 예: 스레드 A는 자원 X를 가지고 Y를 기다림, 스레드 B는 자원 Y를 가지고 X를 기다림.

Livelock (활성 교착 상태)

  • 여러 스레드가 계속 상태를 바꾸면서(양보하면서) 실제로는 진척이 없는 상태.
  • 계속 움직이지만, 일은 안 됨.
  • 예:
    • 좁은 복도에서 두 사람이 마주봄.
    • 서로 “먼저 지나가세요” 하면서 동시에 왼쪽으로 비킴 → 또 막힘.
    • 동시에 오른쪽으로 비킴 → 또 막힘.
    • 무한 반복 → 결국 둘 다 못 지나감.

특징 정리

구분DeadlockLivelock
상태스레드가 멈춤스레드가 계속 움직임
원인서로 자원 점유 후 대기서로 양보/재시도 논리 충돌
비유차가 교차로에서 서로 막혀 정지좁은 복도에서 서로 비켜주려다 계속 막힘

예시

  • Deadlock:
    • 스레드 A가 mutex1 잡고 mutex2 기다림.
    • 스레드 B가 mutex2 잡고 mutex1 기다림.
    • → 둘 다 영원히 멈춤.
  • Livelock:
    • 스레드 A, B가 자원 충돌 → 서로 충돌 피하려고 lock 해제 후 재시도.
    • 그런데 둘 다 동시에 해제 → 동시에 다시 시도 → 또 충돌.
    • → 무한 반복, 진전 없음.

RedLock

RedLock은 Redis에서 제안된 분산락(Distributed Lock) 알고리즘이에요. 단일 인스턴스에서 SETNX + EXPIRE로 락을 구현할 수 있지만, 단일 Redis 서버에 장애가 생기면 신뢰성이 떨어지죠. 이를 보완하기 위해 Salvatore Sanfilippo(레디스 창시자)가 제안한 것이 RedLock입니다.

핵심 아이디어

  • 다수(보통 5개)의 독립된 Redis 인스턴스에 동일한 락을 요청합니다.
  • 클라이언트는 모든 인스턴스에 SET key value NX PX <timeout>을 시도합니다.
  • 과반수(예: 5대 중 3대) 이상에서 락 획득에 성공하면 락을 얻었다고 간주합니다.
  • 락의 유효 시간은 네트워크 지연 등을 감안하여, 시도에 걸린 시간을 빼고 계산합니다.
  • 실패하거나 과반수 확보를 못하면, 이미 잡은 락을 모두 해제하고 다시 시도합니다.

보장하려는 것

  1. 상호 배제(Mutual Exclusion): 동시에 여러 클라이언트가 같은 자원을 잠글 수 없음.
  2. 내구성(Fault Tolerance): 일부 Redis 노드가 죽거나 분할되어도 동작.
  3. 자동 해제(Safety): 클라이언트 장애 시 TTL이 지나면 락 자동 해제.

절차 요약

  1. N개의 Redis 노드에 시도 (SET NX PX).
  2. 과반수 성공 시 락 획득.
  3. 락 유지 시간 = TTL - (획득에 걸린 시간).
  4. 사용 후 해제 스크립트(Lua로 value 검증 후 DEL) 실행.

하지만 RedLock은 논란이 많다. Martin Kleppmann 같은 분산시스템 연구자는 “네트워크 파티션 상황에서 안전성을 보장할 수 없다”는 이유로 비판했다. Redis 공식 문서도 “RedLock은 꼭 필요한 경우가 아니라면 쓰지 말고, 대부분은 단일 Redis + Sentinel이나 클러스터 + SET NX PX로 충분하다”는 입장이다.


팩토리 메서드 패턴

팩토리 메서드(Factory Method) 패턴은 객체 생성을 서브클래스에 위임하는 디자인 패턴입니다.

즉, 객체를 생성하는 과정을 직접 new로 호출하는 대신, 팩토리 메서드(생성 전용 메서드)를 통해 생성하도록 하여 객체 생성 과정과 사용을 분리하는 것이 핵심이에요.

주요 개념

  1. Creator (추상 클래스/인터페이스)
    • 팩토리 메서드를 선언하는 역할.
    • 구체적인 객체 생성을 직접 하지 않고, 서브클래스가 구현하도록 위임.
  2. Concrete Creator (구체적인 생성자 클래스)
    • Creator의 팩토리 메서드를 오버라이드해서 실제 객체를 생성.
  3. Product (인터페이스/추상 클래스)
    • 팩토리 메서드가 생성하는 객체의 공통 인터페이스.
  4. Concrete Product (구체적인 제품 클래스)
    • 실제 생성되는 객체.

팩토리 메서드 (Factory Method 패턴에서의 의미)

  • 의미: 객체 생성을 서브클래스에 위임하기 위한 오버라이드 가능한 메서드.

  • 형태: 보통 추상 메서드 또는 인스턴스 메서드.

  • 의도: “객체 생성” 자체를 확장 가능한 구조로 만들기.

  • 예시 (Java):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    abstract class Dialog {
        // 팩토리 메서드 (패턴의 핵심)
        abstract Button createButton();
      
        public void renderDialog() {
            Button okButton = createButton();
            okButton.render();
        }
    }
      
    class WindowsDialog extends Dialog {
        @Override
        Button createButton() { // 👉 여기서 `createButton()`이 바로 **팩토리 메서드**.
            return new WindowsButton();
        }
    }
    
  • 다형성(상속)을 활용해서 “어떤 객체를 만들지는 서브클래스가 결정”.


정적 팩토리 메서드 (Static Factory Method)

  • 의미: static 키워드를 붙여 객체를 반환하는 유틸리티 메서드.

  • 형태: 클래스의 static 메서드.

  • 의도: 객체 생성을 더 직관적이거나 효율적으로 감싸기 위함. (new 대신 메서드 호출)

  • 예시 (Java, JDK 내부):

    1
    2
    3
    
    // 정적 팩토리 메서드 예
    Integer i1 = Integer.valueOf(10);  // new Integer(10) 대신
    Boolean b = Boolean.valueOf(true); // new Boolean(true) 대신
    

장점:

  • 이름을 가질 수 있음: valueOf, of, from 같은 이름으로 의도를 드러냄.
  • 객체 캐싱 가능: 같은 값을 요청할 때 같은 객체를 반환할 수 있음 (Boolean.TRUE, Integer 캐싱).
  • 하위 타입 반환 가능: 반환 타입을 인터페이스로 두고, 실제 구현체는 감출 수 있음.

비교 요약

구분팩토리 메서드 (패턴)정적 팩토리 메서드
정의서브클래스에서 오버라이드하여 객체 생성static 메서드로 객체 생성
목적객체 생성 과정을 다형성으로 확장 가능하게 하기new를 숨기고, 더 직관적/효율적인 생성 제공
활용GoF 디자인 패턴 중 하나일반적인 코드 스타일/관용구
예시createButton() (Dialog → WindowsDialog)Integer.valueOf(), List.of()
This post is licensed under CC BY 4.0 by the author.