본문 바로가기

Cloud Firestore

Cloud Firestore #1 NoSQL 데이터베이스란 무엇인가?

우선 저는 백엔드 전문가가 아님을 밝히고 글을 시작하겠습니다.

 

앱개발에 Cloud Firestore를 사용하기 위해 공부하는 중이며 공부한 내용을 정리도 할겸 글을 작성하게 되었습니다. 저와 마찬가지로 백엔드 지식이 전무한 분들을 위해 작성하였으니 편하게 읽어주시면 감사하겠습니다. 그리고 잘못된 내용이나 추가했으면 하는 내용이 있다면 댓글로 알려주시면 정말 감사하겠습니다.

 

본 글은 유튜브 채널의 Firebase 공식 채널의 영상

What is a NoSQL Database? How is Cloud Firestore structured? | Get to know Cloud Firestore #1

https://www.youtube.com/watch?v=v_hR4K4auoQ&list=PLl-K7zZEsYLluG5MCVEzXAQ7ACZBCuZgZ&index=1

를 참고하여 작성되었음을 밝힙니다.

 

 

Cloud Firestore에 대해 알아보는 첫 번째 시간입니다.

 

Cloud Firestore란 구글에서 지원하는 NoSQL 데이터베이스 서비스입니다.

 

NoSQL은 non-SQL 또는 non-relational 이라고 하는데 잘 와닿지 않습니다.

 

SQL(Structured Query Langauge)은 데이터베이스 관리 시스템에서 데이터를 관리하기 위해 고안된 프로그래밍 언어입니다. 주로 데이터베이스에서 자료를 검색하거나 관리하기 위해 사용되는 언어라고 생각하시면 됩니다. 그렇다면 non-SQL은 무슨 의미일까요?

 

개념을 잡기 위해 기존 방식부터 설명하고 NoSQL의 특성에 대해 설명한다면 이해가 더 쉬울것 같습니다.

 

 

기존 데이터베이스(MySQL 등의) 작동 방식

 

MySQL 등 기존의 데이터 베이스 관리에는 테이블을 사용합니다. 모든 테이블은 잘 정돈되어 있고 엄격한 규칙을 가집니다. 예를 들어 식당 평점 앱을 고려해봅시다. 여기서 유저의 정보를 저장한 Users 테이블이 다음과 같다고 해봅시다.

 

<Users>

ID username age login-date is_admin
123 'Harry Kane' 27 20200819 1
456 'Heung-min Son' 28 20200810 0
789 'Jose Mourinho' 'old enough' 20200726 0

 

데이터 테이블의 age 열은 int형의 자료형만 가질 수 있기 때문에 예제처럼 String형의 'old enough' 값은 넣을 수가 없습니다. 데이터들이 잘 정돈되어 있어서 보기는 좋지만 유연함이 부족합니다. NoSQL 데이터베이스는 

 

이렇게 잘 정돈된 테이블들을 만들어 놓고 각 정보를 합칠 때에는 각각의 ID를 이용합니다. 예로 식당 평점 시스템 앱의 데이터베이스가 다음과 같다고 해보겠습니다.

 

<Restaurants>

ID Name City Cuisine Avg. Score
24 'Tacos' 'Seoul' 'Mexican' 4.4
46 'sushiya' 'Incheon' 'Japanese' 4.5
68 'halmae gugbab' 'Busan' 'Korean' 4.7

 

<Reviews>

ID RestaurantID Stars AuthorID Text
1a 24 5 456 ...
2b 46 3 123 ...
3c 24 4 789 ...

 

기존 방식은 위에 작성된 표와 같이 정돈된 테이블을 갖고 각각의 ID로 데이터들을 연결합니다. 예를 들어 리뷰 1a의 경우는 RestaurantID가 24니까 'Tacos' 식당에 관한 리뷰임을 알 수 있고, AuthorID가 456이니 작성자가 'Heung-min Son'임을 알 수 있습니다.

 

그리고 SQL을 사용하여 데이터베이스에서 데이터를 수집할 수 있습니다. 

 

SELECT * FROM Restaurants, Reviews, Users
WHERE Restaurants.ID = 24
AND Reviews.RestaurantID = Restaurant.ID
AND Reviews.authorID = Users.ID

 

위 SQL 코드를 이용하면 다음과 같은 결과를 얻을 수 있습니다.

 

24 'Tacos' 'Seoul' 'Mexican' 4.4
1a 24 5 456 ...
2b 24 4 789 ...
456 'Heung-min Son' 28 20200810 0
789 'Jose Mourinho' 57 20200726 0

 

 

NoSQL의 기본 작동 방식

 

간단하게 기존 방식에 대해 알아보았습니다. 그럼 NoSQL은 어떨까요?

 

NoSQL은 데이터를 테이블로 관리하지 않습니다. JSON 형식 또는 트리 구조와 같은 형태로 데이터를 관리합니다.

 

그리고 데이터베이스 수준에서 데이터 형식 규제가 없습니다. 위에서 기존 방식이 age에는 int형 자료만 넣을 수 있는 것과 달리 개발자가 원하는 어떤 형식의 데이터든 넣을 수 있습니다.

 

 

그림 1. NoSQL 데이터 구조 예제

 

만약 앱이 업데이트를 해서 noise-level이라는 소음의 정도를 나타내는 항목을 추가했다고 생각해봅시다. 기존 데이터베이스 방식은 이를 위해 기존의 noise-level 항목이 없는 데이터들에게도 noise-level 필드를 만들어줘야 합니다.

 

NoSQL은 기존 데이터에 새 필드를 만들어줄 필요가 없습니다. 그림 1과 같이 식당의 필드가 서로 다르더라도 전혀 문제없이 작동합니다. 더 나아가 각 필드의 내용이 모두 다르더라도 문제 없이 작동합니다. 이런 유연함은 NoSQL의 장점 중 하나입니다.

 

NoSQL은 non-SQL이라 하였습니다. 즉 SQL을 사용할 수 없습니다. 기존 방식에서 보여드렸던 것처럼 SQL을 이용해 각 테이블의 정보를 가져와 병합할 수 없습니다. 그럼 어떻게 데이터베이스로부터 데이터를 가져와야 할까요?

 

또다시 식당 평점 앱을 예로 들겠습니다. 아래 그림처럼 각 리뷰 문서마다 식당의 정보와 유저의 정보를 저장합니다. 

 

그림 2. NoSQL 트리 방식 데이터베이스

 

리뷰에 유저 정보와 유저의 썸네일 이미지를 띄우고 싶다면 어떻게 해야 할까요? 매번 리뷰 페이지로 갈 때마다 유저의 ID를 이용해 유저 문서를 요청해야 할까요? 매번 리뷰 페이지를 열때마다 유저 정보를 request 하는 것은 바람직하지 않습니다. 불필요한 request를 줄이기 위해 NoSQL은 리뷰 문서에 유저의 이름과 썸네일 이미지 정보를 저장해 놓습니다.

 

그림 3. NoSQL 데이터 중복

 

만약 기존 데이터베이스를 사용하는 분들에게 위와 같은 방식을 제안한다면 뺨을 한대 맞을 지도 모릅니다. 데이터 노멀라이제이션(Data Normalization)은 모든 데이터는 어떤 장소에 한 번만 저장되어야 한다는 프로그래밍의 기본 규칙이며 매우 중요한 개념이지만 NoSQL에서는 이를 무시합니다.

 

그림 3과 같은 방식을 사용한다면 데이터가 중복이 발생해 불필요한 용량을 사용하게 됩니다. 그리고 어떤 유저가 썸네일 이미지를 바꾼다면 그 유저가 작성한 모든 리뷰의 썸네일 이미지를 다 바꿔줘야 하는 귀찮은 일이 발생합니다. 이 경우에 모든 리뷰를 검토하지 못했다면 데이터 일관성에 문제가 발생할 수도 있습니다.

 

이렇게 끔찍한 일이 발생하는데 NoSQL은 왜 이런 방식을 사용하며, 왜 NoSQL은 현재 가장 hot한 데이터 저장방식일까요? 이를 알기 위해서는 위 그림 3처럼 데이터 중복을 했을때 얻을 수 있는 이점에 대해 알아봐야 합니다.

 

이 방식을 채용하면 리뷰 데이터를 얻을 때는 훨씬 간단해 집니다. 모든 데이터가 한 곳에 있으니까 MySQL 등의 기존 방식처럼 매번 테이블에서 데이터를 모아 병합할 필요가 없습니다.

 

앱 사용자가 리뷰를 읽는 경우가 많을까요? 아니면 유저가 썸네일 이미지를 바꾸는 경우가 많을까요? 제 생각엔 전자가 훨씬 많을것 같습니다. 많은 경우의 수고를 덜고 적은 경우에 더 수고하는게 낫다는 것입니다.

 

거기다 또 다른 장점이 있습니다. NoSQL 방식은 데이터를 분산 저장할 수 있습니다. MySQL등의 기존 방식은 데이터가 늘어나면 데이터베이스 크기를 늘려야 하지만(Scailing vertically), NoSQL 방식은 저장 장치를 추가하기만 하면 됩니다(Scailing horizontally).

 

 

Cloud Firestore의 기본 구조

 

여기까지 NoSQL 방식의 기본 작동 원리를 알아보고, 이를 사용하는 이유에 대해 알아보았습니다. 이제 NoSQL 방식을 사용하는 데이터베이스인 Cloud Firestore에 대해 알아보도록 합시다.

 

Cloud Firestore는 컬렉션(collection)과 다큐먼트(document)로 구성된 트리구조를 갖습니다. 컬렉션은 다큐먼트를 저장하는 공간이라고 생각하시면 되고 큐먼트는 딕셔너리 형태로 자료를 저장하는 저장공간이라고 생각하시면 됩니다. 

 

그림 4. Cloud Firebase의 구조

 

그림 5. 다큐먼트의 구조

 

큐먼트는 맵(map)과 유사하게 키(key), 값(value)의 쌍들로 구성됩니다. Cloud Firestore는 맵에서 키에 해당하는 것을 필드(field)라고 부릅니다. 필드의 값으로는 어떤 데이터 타입도 넣을 수 있고 맵 또는 배열(array)도 들어갈 수 있습니다.

 

컬렉션은 다큐먼트들을 저장하는 공간입니다. 컬렉션과 다큐먼트는 다음과 같은 규칙을 따릅니다.

 

  1. 컬렉션은 다큐먼트만 가질 수 있다.
  2. 다큐먼트는 1MB 이하의 크기만 허용된다.
  3. 다큐먼트는 다른 콜렉션을 가리킬 수 있지만 다른 다큐먼트를 가리킬 수 없다.
  4. Cloud Firestore의 root(트리의 가장 위쪽)는 오직 컬렉션만 가질 수 있다.

그림 6. 컬렉션과 다큐먼트 규칙을 보여주는 예제

 

그림 6과 같이 컬렉션이 있고 그 속에 다큐먼트 들이 존재하며, 각 다큐먼트는 1MB이상의 용량을 가질 수 없고, 컬렉션 속에는 다큐먼트만 들어갈 수 있으며, 다큐먼트는 서브컬렉션을 가리킬 수 있습니다. 마지막으로 root 위치에는 컬렉션 만이 올 수 있습니다.

 

해당 데이터를 불러오려면

 

firebase.collection('User').document('Kane').collection('Schedules').document('Study').collection('History').document('200818')

 

처럼 컬렉션과 다큐먼트를 반복함으로써 원하는 데이터에 접근할 수 있습니다. 또는 

 

firestore.document('/User/Jose/Scedules/Studyt/History/200818’) 

 

과 같이 디렉토리 주소로 데이터에 접근할 수도 있습니다.

 

여기서 항상 기억하셔야 할 것은 '컬렉션 -> 다큐먼트 -> 컬렉션 -> 다큐먼트 -> ...' 처럼 컬렉션과 다큐먼트의 반복으로 원하는 데이터에 접근할 수 있다는 것입니다.

 

 

Cloud Firestore를 이용한 식당 평점 앱 데이터 구조

 

이제 다시 식당 평점앱으로 돌아가서 데이터 구조를 어떻게 정할 것인지 생각해봅시다.

 

그림 7. 식당 평점 앱 데이터 구조 예제

 

그림 7과 같이 root 레벨에 Restaurants 컬렉션을 만들어주고 각 다큐먼트에 식당 정보를 기입합니다. 

 

Restaurants 컬렉션의 다큐먼트들은 Reviews라는 서브컬렉션을 가지고, Reviews 컬렉션은 리뷰 내용을 담고 있는 다큐먼트들을 가집니다.

 

그리고 root 레벨에 Users라는 다른 컬렉션도 추가해주도록 합시다.

 

리뷰는 작성 유저에 대한 특정 데이터(유저 이름이나 유저 썸네일 이미지 등)를 가집니다. 추후 리뷰에 포함된 유저 데이터들을 일관성 있게 관리하는 법에 관해 배우도록 하겠습니다.

 

데이터 구조를 정하는 방법은 여러가지 있습니다. 기본 규칙만 지킨다면 그림 7의 방식이 아닌 원하는 다른 구조를 사용해도 좋습니다.

 

 

이로써 Cloud Firestore #1을 마치도록 하겠습니다.

 

NoSQL 데이터 베이스의 구조와 작동원리를 간단하게 알아보고 Cloud Firestore의 기본 구조에 대해 알아보았습니다. 다음 시간에는 Cloud Firestore에서 쿼리(query)가 어떻게 작동하는지에 대해 알아보도록 하겠습니다.