데이터베이스를 선택할 때, 주로 나오는 내용은 RDBMS 와 NoSQL 둘 중 어느것을 선택할지에 대한 고민이 자주 나옵니다.
NoSQL과 RDBMS 각각의 장단점에 대해 알아보고, 언제 사용하는게 적합할지에 대해 알아보겠습니다.
Releational DataBase
Order
id | product_id | count | ordered_at | user_id |
---|---|---|---|---|
... | ... | ... | ... | ... |
... | .. | ... | .. | ... |
위와 같이 주문에 대한 정보를 담고 있는 Order라는 테이블이 있다고 가정하겠습니다.
만약 Order라는 테이블에서 주문 상태를 저장하는 order_status 컬럼이 추가되었다고 가정하겠습니다.
id | product_id | count | ordered_at | user_id | order_status |
---|---|---|---|---|---|
... | ... | ... | ... | ... | ... |
... | .. | ... | .. | ... | ... |
그렇다면 아래와 같이 컬럼이 추가되고, 그 과정에서 Order라는 테이블의 schema를 변경해줘야 한다. 즉 스키마의 변경이 유연하지 못하고 경직되어 있다라는 단점이 있습니다.
또한 만약 Order 테이블에 5천만건 정도의 데이터가 있는 상황에서, 스키마를 변경하게 된다면 데이터베이스 서버 전체에 큰 부하가 걸리기에 자칫 잘못하면 서버 장애로 이어질 수도 있습니다.
다음 문제로 RDBMS 특성상 정규화를 통해, 중복을 줄이게 됩니다 그 과정에서 분리된 여러 테이블의 데이터를 가져올 때 join을 사용하게 됩니다. 하지만 만약 join이 일어나는 테이블의 개수가 5개, 심지어는 10개라면 심각한 read 성능 하락이 발생하게 될 것 입니다.
- 물론 위 문제는 역정규화를 통해, 해결 할 수 있습니다
NoSQL 등장 배경
인터넷이 점점 보급화되고, 스마트폰이 출시되는 등 점점 인터넷 사용이 늘어남에 따라 자신의 사진이나 일상 기록등을 공유하고 이야기 할 수 있는 SNS 서비스가 많이 출시되게 됩니다
이 때, RDBMS로는 폭증하는 사용자량을 감당할 수 없고, 높은 수준의 처리량과 빠른 응답시간을 요구하게 됩니다.
그리고 SNS 게시물들의 특성상 정형적인 데이터의 형태가 아닌, 그 형태를 예측할 수 없는 비정형 데이터가 증가하게 되어, RDBMS의 톡성 중 하나인 경직된 스키마에 적합하지 않은 데이터 형태를 띄게 됩니다.
NoSQL(Not Only SQL)이 등장하게 됩니다.
대표적 NoSQL은 MongoDB, Redis, Cassandra등 수많은 데이터베이스 솔루션이 있습니다.
이러한 솔루션의 특징이 아닌 NoSQL의 일반적인 특징에 대해 알아보겠습니다.
flexible schema
몽고DB를 기준으로 설명 하겠습니다.
db.createCollection("student")
위 문장을 통해 RDBMS에서 student 테이블을 생성한 것과 비슷한 일을 할 수 있습니다.
컬럼 이름이나, 제약 조건등을 정할 필요가 없습니다.
db.student.insertOne({
name: "simgee"
})
또한 데이터를 student 컬렉션에 삽입할때는 위와 같이 삽입 할 수 있습니다.
정해져 있는 스키마가 없기 때문에 삽입과 동시에 컬럼을 정해줄 수 있습니다.
db.student.insertOne({
name: "simgee"
address : {
country: "Korea",
state : "Seoul",
city : "Gangnam-gu",
street : "..."
},
certificate: ["AWS architect"]
})
위와 같이 새로운 컬럼을, json 표기법 형태로 손쉽게 넣거나, 배열 형태로 넣어주는 등 다양한 형태의 데이터를 저장할 수 있습니다.
db.student.find({name:"simgee"})
"simgee"라는 이름을 가진 사용자를 조회할때는 위와같이 명령문을 날릴 수 있습니다.
이렇듯 유연한 스키마를 가짐으로써, 데이터베이스 레벨에서 스키마 관리를 할 필요가 없어졌지만 반대로 application 레벨에서 스키마 관리를 해줘야하는 필요가 생긴다는 단점이 있습니다.
중복 허용 (join 회피)
db.getCollection("order").find({})
---
{
"_id": ObjectId("64kvkfgkgh43098gh"),
"product_name" : "Mac M1",
"count" : 5.0,
"user_name" : "simgee",
"phone_number" : "010-1234-5678"
}
{
"_id": ObjectId("24kv213254kfgkgh43098gh"),
"product_name" : "애플 매직 마우스",
"count" : 12.0,
"user_name" : "simgee",
"phone_number" : "010-1234-5678"
"option" : ["당일배송"]
}
mongoDB를 기준으로 만약 order라는 주문 정보를 담고있는 테이블을 조회하면 위와 같이 중복된 데이터가 조회되게 됩니다. 이렇게 중복된 데이터를 허용함으로써 join을 회피해 성능을 향상 시킬 수 있지만 반대로 application 레벨에서 중복된 데이터들이 모두 최신 데이터를 유지할 수 있도록 관리해야한다는 단점이 있습니다.
Scale-Out
NoSQL은 서버 여러 대를 하나의 클러스터로 구성해서 사용하는 방식으로, Scale-Out을 쉽게 할 수 있습니다.
즉, 중복을 허용하다보니, 각각의 컬렉션에서 바로 데이터를 조회하면 원하는 데이터를 조회 할 수 있어 scale-out이 더 편하다는 장점이 있습니다.
NoSQL Consistency
NoSQL은 high-throughput, low-latency를 추구하는 반면에, consistency를 다소 포기하게 됩니다. 만약 데이터의 일관성이 정말 중요한 금융 시스템같은 곳에서는 NoSQL을 사용하기 조심스러운 점이 있습니다.
정리
만약 개발하는 서비스의 특성 상, 데이터의 일관성이 중요하고 스키마가 고정되어 잘 변경되지 않는다면 RDBMS를 사용하는 것이 좋을 것 같습니다.(예를 들어 금융 서비스) 반면에 데이터의 일관성은 포기하더라도 높은 처리량과 낮은 지연시간을 중요시 한다면 NoSQL을 적용해 볼 수 있을 것 같습니다.(예를 들어 SNS 서비스)
제가 진행한 굿즈포유라는 중고 거래 서비스 프로젝트에 빗대에서 생각을 해보면, 상품에 대한 부분이나, 유저 정보, 거래에 대한 정보는 스키마의 변동이 크지 않을 것으로 예상됩니다. 또한 상품의 재고가 관리되어야 한다면, 해당 데이터에 대한 일관성이 중요시 될 수 있을 것 같으며, 거래 상태도 일관성이 보장되어야 할 중요 포인트라 생각합니다. 이러한 부분들을 토대로 RDBMS의 고정적인 스키마와, 트랜잭션 기능등을 이용하기에 적합하다고 생각해 현재 RDBMS 솔루션 중 MySQL을 사용하고 있습니다.
앞서 언급한 RDBMS를 사용함으로 발생할 수 있는 잠재적인 문제들에 대해서도 추후 포스팅을 통해 다뤄보도록 하겠습니다.