책을 읽게 된 계기
당근마켓 플랫폼 팀의 서버 엔지니어로 지원하고 면접을 보면서 저장소
에 관련한 질문을 많이 받았었다. 저장소
는 관계형 데이터베이스
나 다양한 NoSQL 데이터베이스
들을 의미한다고 할 수 있겠다.
많은 질문들이 나왔고, 당시의 나는 사실 데이터베이스 쪽 지식은 거의 전무했던 것 같아 제대로 대답을 못한 게 많았던 것 같다. 인턴 근무를 하면서는 내가 익숙했던 관계형 데이터베이스가 아닌 NoSQL 특히 Redis
나 DynamoDB
등을 주로 사용하는 모습도 많이 보게 되어 NoSQL에 대해 관심이 가게 되었다.
‘왜 관계형 데이터베이스는 수평 Scale이 어렵다고들 하는거지?’, ‘왜 NoSQL은 수평 Scale이 용이하지?’
‘어떤 경우에 관계형 데이터베이스가 아닌 NoSQL을 사용하는 게 적절할까?’
‘정말 NoSQL이어야만하는 경우들이 존재할까?’
위와 같은 궁금증을 갖고 있었고, 그런 면에서 다양한 NoSQL 책들을 찾아보다가 하나의 NoSQL에 딥다이브하는 책보다는 다양한 NoSQL 데이터베이스들이 어떤 특징들을 갖는지 비교해주고, 실제 사용 사례는 어떤 경우가 있을지를 알려주는 책을 읽어보고 싶었다.
NoSQL의 공통된 특징
Key-Value
, Document
, Column family (혹은 Columnar)
류의 NoSQL 데이터베이스들에 대해서는 추후 각 글에서 정리하는 것으로 하고 이번 글에서는 좀 더 전반적인 NoSQL의 특징에 대해 정리하려한다.
NoSQL은 관계형 데이터베이스가 아닌 데이터베이스들을 통칭하는 명칭이기 때문에 각각이 다양한 특징을 갖지만 탄생 목적 자체가 SQL 데이터베이스로 만족할 수 없는 유즈케이스를 위해서 였기 때문에 SQL 데이터베이스의 반대되는 쪽으로는 공통적인 특징을 갖는 편이다.
관계형 데이터베이스와 NoSQL은 절대적으로 누가 더 낫다를 비교할 존재라기 보단 각자가 적절한 목적을 갖는 상호 보완적인 존재이다!
Schemaless
ACID
특성을 갖지 않는다.- 좀 억지 네이밍이긴 하지만
BASE
특성을 기반으로 한다. Eventual consistency
- 분산 시스템, 고가용성, 대규모 트래픽
- 정규화보단 비정규화와 중복
그럼 각 특징에 대해 알아보자.
Schemaless
관계형 데이터베이스는 고정된 테이블 스키마를 갖고, 모든 레코드는 그 스키마 구조를 따라야만한다. 그렇기 때문에 데이터 형태가 계속해서 변경될 수 있는 경우에는 불편할 수 있다. 데이터가 적을 때야 그냥 alter table ...
로 스키마를 변경하면 그만이겠지만 데이터와 트래픽이 많은 실제 프로덕션에서는 이런 작업이 쉽지 않다.
반면 거의 모든 NoSQL 데이터베이스는 스키마를 강제하지 않고 자유롭게 저장할 수 있다.
ACID 특성을 갖지 않는다.
- A (Atomic) - 한 트랜잭션은 원자 단위로 전체 작업이 성공하거나 전체 작업이 실패해야한다. 부분 작업만 적용되어서는 안된다.
- 쉽게 말하면 0과 1의 이분법적 사고라고 볼 수 있다. 한 트랜잭션 내의 일부 작업만 수행한 애매한 상태는 존재해선 안된다!
- C (Consistency) - 데이터베이스에 저장된 데이터는 일관성을 가져야한다.
- 만약 트랜잭션이 적용되었는데 다음 Read 요청 시 해당 데이터가 아직 반영이 안되어있으면 안된다.
- 만약 트랜잭션이 롤백되었는데 해당 데이터가 남아있는 상태가 존재하면 안된다.
- 구글링하다보면 Consistency를 어떤 이유에서인지 column에 대한 제약 조건과 연관지어 설명하는 한국어 자료들을 많이 찾아볼 수 있는데 나는 이는 잘못된 설명이 아닌가 싶다.
- 특히 NoSQL의 Eventual consistency와 대조해보면 column에 대한 제약 조건으로 consistency를 설명하는 것은 더욱 더 잘못된 설명이라고 느껴지지 않나 싶다.
- I (Isolation) - 트랜잭션 과정 중에는 서로 다른 트랜잭션 간에는 서로의 과정에 간섭할 수 없다.
- Isolation은 절대적인 것은 아니고 필요에 따라 얼마나 트랜잭션을 골비시킬 것인지를 의미하는 isolation level을 조절할 수 있다.
Read uncommited
,Read commited
,Repeatable read
,Serializable
와 같은 Isolation level들이 존재한다.
- D (Durability) - commit된 트랜잭션은 시스템이 비정상적으로 종료되더라도 보존되어야한다.
ACID
는 관계형 데이터베이스에서 제공하는 트랜잭션을 지원하기 위해 가져야할 4가지 특성을 의미한다.
NoSQL
은 보통 이런 ACID 특성을 완벽히 제공하지는 않는다. NoSQL에도 트랜잭션이 존재하기는 하지만 아마 ACID 특성을 모두 만족하는 트랜잭션은 아닐 것이다.
ACID 트랜잭션은 정말 엄격하게 일관된 데이터를 강제하기 때문에 이를 위해선 성능을 많은 부분 양보해야하고 분산 시스템에서는 특히 동작하기 힘들 수 있기 때문이다.
BASE 특성을 기반으로 한다.
- BA (Basically available) - 고가용성을 가져야한다.
- S (Soft state) - 유저의 명시적 명령 없이 데이터가 변경될 수 있다.
- Eventual consistency에 의해 데이터가 덮어씌워질 수도 있고
- TTL에 의해 데이터가 사라질 수도 있다.
- E (Eventual consistency) - 결과적으로는 일관성을 띈다.
- 그 과정 속에서 데이터가 일관되지 않은 상태도 존재할 수 있다.
- 사실 Temporary inconsistency가 좀 더 와닿는 표현일 수도.. 포인트는 *‘결과적으로는 일관성을 갖긴 하는구나~’*가 아닌 ‘일시적으로는 일관되지 않을 수도 있구나!’ 이다.
관계형 데이터베이스는 애초에 엄격하게 일관된 데이터들을 저장하기 위한 솔루션이기에 ACID를 지원하지만 NoSQL은 그런 엄격함으로 인해 확장성이나 성능을 제한받지 않고자 탄생한 솔루션이다.
여기서 말하는 성능은 작은 데이터에 대한 성능을 의미하는 게 아니라 대규모 데이터에 대해서도 준수한 성능을 내는 것을 말한다. 데이터가 많아질 수록, 요청이 많아질 수록 범용적인 수준의 서버로는 요청을 다 감당하기 힘든데 이렇게 되면 범용적인 수준의 서버를 수평적으로 스케일 할 수 있어야 한다.
또한 고가용성을 위해서도 수평적으로 스케일할 수 있어야한다. (관계형 데이터베이스의 경우 주로 백업 서버를 대기시켜놓는 이중화를 통해 고가용성을 지원한다.)
하지만 단일 시스템이 아닌 분산 시스템이 되게 되면 모든 노드들이 일관된 데이터를 갖기가 힘들어지는데 이로 인해 엄격한 일관성이 아닌 Eventual consistency를 제공하게 된다.
방금 확장성이나 성능, 고가용성에 대한 흐름으로 나온 내용들이 CAP 이론과 관련된 내용이라고 볼 수 있다. CAP 이론에 대해선 따로 정리하지 않겠다.
정규화보단 비정규화와 중복
나는 모 기업의 기술 면접에서 ‘관계형 데이터베이스에서도 JOIN을 하지 말자는 주장을 내는 사람들도 있는데, 이유가 뭘까요?’ 라는 질문을 받은 적이 있었다. 앞서 말했듯 나는 데이터베이스 관련 지식이 많이 부족하기도 했기 때문에 질문에 대한 대답은 둘째치고 ‘관계형 데이터베이스에서 JOIN을 쓰지 말자는 사람도 있나…?’ 라는 생각 뿐이었다.
계속 얘기하지만 관계형 데이터베이스는 일관되고 이상 현상이 없는 데이터들을 저장하기 위한 솔루션이다. 그리고 그를 위해 테이블 간의 관계를 나타낼 때 테이블을 정규화하고 참조한 뒤 조회할 때에는 필요한 정보들을 JOIN으로 가져온다. 하지만 JOIN은 꽤나 비싼 작업이다.
반면 NoSQL은 어느 정도 데이터의 불일치를 허용하기도 하기 때문에 조회 시 JOIN을 수행하기 보다는 비정규화된 형태로서 중복으로 저장된 데이터를 조회하는 경우가 많다.
개인적으로는 이렇게 비정규화한 형태로 중복된 데이터를 저장하는 방식은 CQRS
와도 어느 정도 비슷한 형태를 갖지 않나싶다. CQRS에서는 데이터를 조작하는 Command 와 데이터를 조회하는 Query의 책임을 분리하는 형태로, Query하는 측에서는 자신들이 조회하기 용이한 형태인 고도화 된 뷰(비정규화된 데이터)로 데이터를 저장한다. 데이터의 원본은 Command를 담당하는 곳에 저장된다.
마치며
이렇게 NoSQL의 공통된 특징에 대해 책에 등장한 내용과 약간의 개인적인 의견을 정리해봤다. 책이 담고 있는 내용은 꽤나 마음에 든다! 특정한 NoSQL 데이터베이스의 기능 자체를 줄줄이 소개하는 것이 아니라 실용적인 예시 상황과 함께 각각의 NoSQL과 RDB에 대한 비교를 해볼 수 있었다.
별점을 준다면 4.5점 정도..? 0.5점은 좀 더 예시가 디테일하고 자세했으면 너무나 좋았을 것 같다. 예시가 아예 없는 것은 아니라 간간히 실제 유즈케이스들이 등장하긴 하지만 너무 간단하게만 짚고 넘어가서 조금 아쉬웠다.
사실 저번 하반기부터 올해 상반기까지 내가 한 게 성장한 게 있나, 새로 배운 게 있나 싶었는데 문득 책을 읽게 된 계기를 회상해보니 저장소 측면에서는 많이 배워가고 있는 것 같아 다행이다.
‘이런 데이터를 나타내려면 당연히 테이블을 이런 식으로 정규화해서…’ 와 같이 단순히 관계형 데이터베이스에서 테이블을 설계하는 기본적인 원칙을 기반으로 한 관점이 아니라 ‘이런 데이터는 관계형 데이터베이스가 아닌 이런 이런 NoSQL을 사용하면 더 적합할 것이고, 전체 데이터 조회용으론 이런 NoSQL을 사용하면 더 적합할 것 같다.’ 와 같이 탈 RDB적 관점도 어느 정도 장착하게 된 것 같아 시각이 좀 넓어지고 있는 듯하다.
작년 2021년 회고에서 2022년에는 짧은 아티클 뿐만 아니라 체계적인 정보를 담은 책을 통해서도 공부를 해보겠다는 결심을 했었는데 2022년 1월이 되자 마자 구매했던 2022년의 첫 책을 포기하지 않고 끝까지 읽게 되어 다행이다! 아마 다음 책은 Real MySQL이나 Spring Boot나 JPA 관련 책이 되지 않을지?! ㅎㅎ