RDBMS vs NoSQL

Olivia·3일 전
1

[DB]

목록 보기
1/1

프로젝트마다 다른 데이터베이스를 사용하는 이유가 궁금해졌다

현재 회사에서 3개의 프로젝트를 담당하고 있는데, 흥미롭게도 각 프로젝트가 서로 다른 데이터베이스를 사용하고 있다.
하나는 PostgreSQL(RDBMS)을, 나머지 두 개는 MongoDB(NoSQL)를 사용 중이다.

솔직히 말하면, 지금까지는 각 데이터베이스를 "왜" 선택했는지 깊이 고민해본 적이 없다.

운영 중인 첫 번째 프로젝트는 투입 당시 이미 PostgreSQL이 세팅되어 있었고, 급하게 운영에 들어가야 했기에 기술 선택의 배경을 파악할 여유가 없었다.
나머지 프로젝트들도 선임 개발자들의 결정을 따라갔을 뿐, 그 이유를 깊이 탐구하지 못했다.

그런데 최근 새로운 프로젝트를 시작하면서 또 다시 NoSQL을 사용하게 되자, 문득 의문이 들었다.

"왜 어떤 프로젝트는 RDBMS를 쓰고, 어떤 프로젝트는 NoSQL을 선택하는 걸까?"


데이터베이스를 집🏠으로 비유해보자.

PostgreSQL (RDBMS) = 아파트 🏢

아파트를 생각해보면 모든 집이 똑같은 구조로 되어있다.
101호도 방 3개에 화장실 1개, 102호도 방 3개에 화장실 1개.
규칙이 엄격해서 방을 마음대로 추가하거나 제거할 수 없다.
그리고 아파트 자체는 관리사무소가 있기 때문에 관리가 체계적이고 자유롭게 뭔가 관리할 수 없다.

NoSQL (MongoDB) = 단독 주택 🏠

한 마을에 단독 주택들을 떠올려보자. 각 주택마다 구조가 저마다 다 다르다.
어떤 집은 방이 2개고, 어떤 집은 방만 5개에다 지하실과 다락방이 존재할 수도 있다.
아파트에 비해 자유롭게 개조할 수 있고, 관리사무소가 통제하고 있지 않아서 각자 관리하고 있다.


이번에는 기술적으로 바라보자.

RDBMS (PostgreSQL) = 구조화된 세계

Schema 스키마

RDBMS의 경우 Schema (스키마)라는 미리 정해진 설계도가 존재한다.
모든 데이터가 정해진 테이블컬럼 형식을 따라야 한다. 따라서 RDBMS의 경우, 모든 경우를 위한 컬럼을 미리 다 만들어야한다.
그리고 여기에서는 데이터 타입, 길이, 관계가 엄격하게 정의되고 있다.

ACID 보장

  • Atomicity : 거래가 전부 성공하거나 전부 실패
  • Consistency : 데이터 무결성 유지
  • Isolation : 동시 작업 간 충돌 방지
  • Durability : 한 번 저장된 데이터는 영구 보존

따라서 RDBMS의 경우 정확한 거래 기록이 필수인 금융 시스템이나, 재고 관리 시스템과 같이 복잡한 관계를 가진 데이터를 다뤄야할때 사용하면 좋다.

NoSQL = 유연한 세계

Schema-less

NoSQL의 경우 단독주택처럼 각 문서(document)가 다른 구조일 수 있다. 따라서 필드를 자유롭게 추가/삭제할 수 있기 때문에 빠른 개발과 변경이 잦을 경우 사용하기 유리하다.

Horizontal Scaling 수평적 확장

한 마을에 집들을 더 짓는 것처럼 서버를 늘려서 성능을 향상시킬 수 있고, 대용량 데이터를 처리하거나 분산 처리하기 용이하다.

따라서 NoSQL의 경우 다양한 콘텐츠가 있는 소셜 미디어나, 센서마다 다른 데이처인 IoT 데이터를 수집할때 좋으며, 실시간 분석이 필요한 빅데이터를 다룰때 사용하면 좋다.


실제로 데이터가 어떻게 저장될까?

PostgreSQL의 경우

 학생 테이블 (무조건 이 칸을 다 채워야 함!)
  ┌─────────┬────────┬─────┬────────┬──────────┐
  │ 학생번호  │   이름  │  나이 │   반   │  전화번호  │
  ├─────────┼────────┼─────┼────────┼──────────┤
  │    1    │ 이올뱌   │  17 │  3-2  │ 010-1234  │
  │    2    │ 이슭    │  16 │  2-5  │ 010-5678  │
  │    3    │ 햅삐슭  │  17 │  3-1  │    NULL    │ <- 전화번호 없으면 NULL
  └─────────┴───────┴─────┴───────┴────────────┘
  
  
  성적 테이블 (학생 테이블과 연결됨)
  ┌─────────┬─────────┬──────┬──────┐
  │  성적번호 │  학생번호 │  과목  │ 점수  │
  ├─────────┼─────────┼──────┼──────┤
  │    1    │    1    │ 수학  │  90  │
  │    2    │    1    │ 영어  │  85  │
  │    3    │    2    │ 수학  │  95  │
  └─────────┴─────────┴──────┴──────┘

특징:

  • 이올뱌의 성적을 보려면 학생번호 1을 찾아서 성적 테이블과 연결해야 한다.
  • 새로운 정보(예: 혈액형)를 추가하려면 전체 테이블 구조를 바꿔야 한다.
    현재 학생 테이블에는 학생 번호, 이름, 나이, , 전화번호만 존재하기 때문이다.
  • 모든 학생이 똑같은 정보를 가져야하고 만약 정보가 없다면 NULL이 들어와야 한다.

NoSQL의 경우

[
    {
      "학생번호": 1,
      "이름": "이올뱌",
      "나이": 17,
      "반": "3-2",
      "전화번호": "010-1234",
      "성적": [  // 바로 여기에 성적 정보를 넣음!
        {"과목": "수학", "점수": 90},
        {"과목": "영어", "점수": 85}
      ],
      "특별활동": ["개발부", "과학동아리"]  // 이올뱌만 있는 정보
    },
    {
      "학생번호": 2,
      "이름": "이슭",
      "나이": 16,
      "반": "2-5",
      "전화번호": "010-5678",
      "성적": [
        {"과목": "수학", "점수": 95, "담당선생님": "김선생님"}  // 이슭의 선생님 
  // 정보 추가
      ],
      "알레르기": ["먼지"]  // 이슭만 있는 정보
    },
    {
      "학생번호": 3,
      "이름": "햅삐슭",
      "나이": 17,
      "반": "3-1"
      // 전화번호 필드 자체가 없어도 OK
    }
  ]

성능 차이에서 비교해보자

RDBMS

정확하지만 느릴 수 있다.
복잡한 관계 연산(join)때문에 느려질 수 있지만, 데이터 정확성은 더 높을 수 있다.

NoSQL

빠르지만 주의해야함.
실제로 단순한 조회는 빠르게할 수 있었지만, 연결을 해서 보거나 좀더 깊은 데이터만 뽑아 보려고할 때 연산이 어려운 것을 느꼈다.


실제 프로젝트와 비교해보자.

3개의 프로젝트는 성격이 아주 다르다.

A 프로젝트 : K8s 관리 플랫폼 MongoDB 사용

쿠버네티스를 관리하고 있기때문에 쿠버네티스 리소스(pod, service, deployment ...)가 계속해서 변화할 수 있기 때문에 동적인 데이터 구조를 가지고 있다.
시스템 이벤트들이 각각 다른 형태의 메타데이터를 보유하고 있고, 클러스터가 커질수록 대량의 로그와 매트릭 데이터를 처리해야하기 때문에 MongoDB를 사용하게 되었다.

  @Schema({ versionKey: false })
  export class Event {
    @Prop() podName: string;
    @Prop() uid: string;
    @Prop() timestamp: string;
    @Prop() type: string;
    @Prop() reason: string;
    @Prop() message: string;
  }

B 프로젝트 : 자동차 소프트웨어 관련 시스템

차량 소프트웨어 배포의 경우 실패하면 안되기 때문에 엄격한 데이터가 일관적이여야한다.
또한 사용자 - 이벤트 - 권한 등등 서로 밀접하게 연결되어있어서 테이블마다 복잡하게 엮여져있다.

  @Entity('')
  export default class TABLE {
    @PrimaryColumn() versionId: string;
    @Column({ nullable: true }) eventId: string;
    @Column({ nullable: true }) versionName: string;
    @Column({ type: 'boolean', nullable: true }) approval: boolean;
    @Column({ type: 'json', nullable: true })
    part: { ecuNm: string; scomoNodeNm: string }[];
  }

그러나 B 프로젝트의 경우, Kafka로 거의 1초마다 대량의 로그 데이터를 수신 받고 있다. 그리고 로그에는 JSON 형태로도 저장하고 있기때문에 이런 용도라면 MongoDB가 더 적합할 것이라고 생각했다.

하지만, Kafka 메세지를 수신받기 전 이미 PostgreSQL 기반으로 시스템이 구축되어 있고, 로그 데이터보다 통합 관리의 목적으로 다른 테이블에 있는 데이터들이 더욱 중요하기 때문에 PostgreSQL을 사용하고 있다.
또한 각 테이블마다 매우 밀접하게 연결되어있어서 Kafka를 제외하고서는 PostgreSQL이 운영자 입장에서 더욱 편하게 사용할 수 있었다.

profile
👩🏻‍💻

0개의 댓글