Cloud Firestore

내위키

구글에서 클라우드 Firebase 서비스의 일부로 제공하는 NoSQL 기반 클라우드 데이터베이스. 원래 제공하던 NoSQL 데이터 베이스인 Realtime 데이터베이스와 병행 제공하고 있으나, 구글은 웬만하면 Firestore를 쓰라고 권하고 있다. Realtime 쪽은 앞으로 기능을 개선시킬 계획이 없는 반면, Firestore 쪽은 앞으로 계속 발전시킬 것이라고 일단 장담은 하고 있다.

특징

문서(document) 기반으로[1] NoSQL이므로 관계형 데이터베이스와 같은 엄격한 스키마를 필요로 하지 않는다. 각각의 문서는 키-값 형식 필드를 묶은 것으로 JSON 형식으로 표현할 수 있으며, 이러한 문서를 묶은 것이 컬렉션이다. 굳이 관계형 데이터베이스와 엮어 보자면 컬렉션은 테이블, 각각의 문서는 레코드로 볼 수 있지만 엄격한 스키마를 요구하지 않으며, 문서가 컬렉션을 가질 수 있다는 점에서 관계형 데이터베이스와는 큰 차이를 보인다. 이전 리얼타임 데이터베이스도 JSON 형식으로 표현할 수 있는 문서지만 리얼타임 데이터베이스는 전체를 하나의 큰 JSON 문서 트리로 표현하는 구조라면 Firestore는 컬렉션 → 문서 → 컬렉션 → 문서와 같은 구조를 계속해서 이어나갈 수도 있다. Firestore 역시 JSON 형식으로 표현해서 데이터베이스 루트 아래에 컬렉션들이 하위로 있고 그 아래에 문서들이 있는 하나의 큰 트리 구조로 나타낼 수는 있지만 Firestore의 문서는 컬렉션에 완전히 종속된 형태가 아니다. 따라서는 한 문서가 여러 컬렉션에 속해 있을 수도 있고, 더 중요한 것은 컬렉션을 지웠을 때 그에 속한 문서는 함께 지워지지 않는다. 컬렉션과 그에 속한 문서를 모두 지우려면 서버 함수를 따로 만들어서 붙이거나, 먼저 컬렉션에 속한 문서들을 지워야 한다.[2]

자료형으로는 문자열, 숫자, 부울(참/거짓), 시간(타임스탬프), 위치(위도/경도), 이진값, 다른 문서의 참조값[3]을 지원한다. 문서 한 개의 크기는 1 메가바이트까지 지원하므로 용량이 적은 이진 파일을 그대로 포함시킬 수도 있지만 보통은 Firebase의 저장소(storage)에 넣어두고 Firestore에는 URL[4]만 저장하는 방식을 많이 쓴다.

장점과 단점

최대 장점이라면 서버와 클라이언트 사이의 실시간 동기화로, 구글의 가이드라인 대로 라이브러리를 가져와서 코딩하면 별다른 걸 안 해도 서버의 변경 내용이 실시간으로 클라이언트에도 반영된다. 인터넷 연결이 끊어졌을 때에는 자동으로 로컬 캐시에 있는 내용을 사용하므로 초기에 서버에서 아무 데이터도 받지 못했을 때를 제외한다면 어쨌든 로컬 캐시의 내용으로 돌아는 간다. 서버/클라이언트의 연결을 관리하고 연결에 오류가 났을 때 처리해 주고... 이런 데 들어가는 코드를 대폭 줄일 수 있다. 처음에 데이터베이스를 설정할 때 메인 서버가 있는 지역을 선택하도록 하지만 NoSQL답게 분산 처리가 뛰어나므로 글로벌 서비스에도 문제가 없다.

이러한 편리한 기능에도 불구하고 거지 같은 질의 기능으로 뒷목 잡게 만든다. 원래 NoSQLSQL은 아주 쉽게 되는 갖가지 조인 연산이 안 되고 해서 관계형 데이터베이스에 익숙한 사람들에는 머리에 쥐나게 만들지만 Firestore는 몽고DB와 같은 NoSQL과 비교해도 더 짜증나는 부분이 많다. 또한 완전히 일치하는 비교가 아닌, 예를 들어 필드의 값이 기준값보다 큰가 작은가를 비교하는 경우 한 가지 질의에서는 한 가지 필드만 검사할 수 있다. 예를 들어 어떤 문서가 일정에 관한 내용을 담고 있고, 시작 날짜(startDate)와 끝나는 날짜(endDate) 필드가 있다고 가정했을 때, 오늘(today)이 이 일정 사이에 있는지 조회하려면 today >= startDate and today <= endDate와 같은 식으로 질의를 해야 하는데, 그러면 한 가지 질의에 startDate 필드와 비교하는 조건과 endDate 필드와 비교하는 조건이 같이 들어 있으므로 질의를 거부 당한다. 할 수 없이 한 개 필드의 조건만 가지고 질의를 해서 문서를 받아온 다른 조건은 앱에서 걸러내야 하는데, 그만큼 읽어와야 하는 문서의 양이 많아지므로 앱에 부담도 될 뿐더러 비용도 발생한다.

일단 텍스트 검색은 거의 불가능에 가깝다. 사실상 필드 값 전체에 걸쳐서 정확히 같은 문자열인가만 비교할 수 있다. '큰지', '작은지' 비교하는 연산자도 사용할 수 있으나 효용성이 정말 많이 떨어진다. 하다 못해 특정 문자열로 시작하는 필드를 찾는다든가 하는 것도 아주 어렵다. 알파벳이라면 그나마 어떻게 하겠으나 한글이라면 거의 노답 수준... 구글은 ElasticSearch나 Algolia와 같은 텍스트 검색 엔진을 붙여서 쓰라고 하는데 이건 또 별도로 유료라서 이중으로 돈이 나간다. 따라서 검색 기능이 필요한 앱을 만들 때에는 정말로 뒷목 잡게 만드는 원흉이다.[5] NoSQL이 텍스트 검색 부분은 인덱스 문제로 관계형 데이터베이스에 비해서 약하지만 Firestore는 그 중에서도 심한 편에 속한다. 경쟁 상대인 Realm MongoDB라든가, 아마존의 DynamoDB도 역시 텍스트 검색 기능이 시원찮지만 그나마 Firestore만큼 꽝은 아니다.

데이터의 업데이트가 빈번하게 일어날 경우에는 안 쓰는 게 좋다. Firestore 공식문서에 보면 문서 하나 당 1초에 쓰기 작업이 1번을 초과하지 않도록 하라고 경고한다.

비용

기본 무료 사용량을 제공하므로 개발 단계, 혹은 소규모 서비스는 무료에 가깝게 사용할 수 있으나, 제대로 서비스를 하는 단계에서는 사용량에 따라 돈이 나갈 수 있다는 점에 유의하자.

  • 데이터 용량 : 1 기가바이트까지는 무료. 이후 매달 기가바이트 당 0.18 달러.
  • 네트워크 방출량 : 월 10 기가바이트까지는 무료. 이후에는 구글 클라우드 요금제에 준한다.
  • 읽기 : 하루 5만 문서까지는 무료. 이후 10만 문서 당 0.06 달러.
  • 쓰기/지우기 : 각각 하루 2만 문서까지는 무료. 이후 각각 10만 문서 당 0.18 달러.

요금제는 Firebase 전체에 적용하는 Spark와 Blaze가 마찬가지로 적용되며, Spark는 위의 무료 사용량까지만 서비스를 제공한다. Blaze는 Spark와 같은 무료 사용량을 제공하고, 이를 넘어가는 부분은 과금한다. 미리 예산을 설정해 놓고 그 예산 한도 안에서만 사용할 수 있도록 할 수도 있고, 설정한 예산의 일정 비율까지 사용량이 올라오면 이메일로 알려주는 기능도 제공한다.

각주

  1. 리얼타임 데이터베이스는 키-값 쌍 기반이다.
  2. 컬렉션을 먼저 지워버리면서 어느 문서가 그 컬렉션이 속했는지 알 수 없게 되므로 문서부터 먼저 지워야 한다.
  3. 그렇다고 이를 키값으로 하는 SQL 같은 조인 연산을 지원하는 것은 아니다.
  4. gs://로 시작하기 때문에 실제 파일 다운로드를 위한 URL은 한번 변환을 거쳐야 한다. https://로 시작하는 다운로드 링크를 저장하는 방법도 있지만 혹시 바뀔 수도 있기 때문에 gs:// URL을 사용하는 게 안전하긴 하다.
  5. 텍스트 검색 기능은 필요하고 다른 검색 엔진도 붙일 수 없다면 일단 문서를 다 받아서 앱 안에서 검색하는 수밖에 없다. 물론 그만큼 문서 읽기 사용량을 소모한다.