모듈 6: Cloud Datastore에서 Cloud Firestore로 마이그레이션

1. 개요

이 Codelab 시리즈 (자기 주도형 실습 튜토리얼)는 Google App Engine (표준) 개발자가 일련의 이전을 안내하여 앱을 현대화하도록 돕는 것을 목표로 합니다. 이러한 마이그레이션의 대부분은 차세대 런타임이 더 유연하여 사용자에게 더 다양한 서비스 옵션을 제공하기 때문에 원래 런타임 번들 서비스에서 이동하는 것입니다. 앱을 현대화하는 또 다른 방법은 최신 제품으로 업그레이드하는 것입니다. 이 Codelab에서 이 내용을 다룹니다.

Cloud Dataplex 또는 Cloud Datastore 클라이언트 라이브러리로 Datastore에 액세스하는 App Engine 사용자는 그냥 두면 됩니다. 따라서 더 이상 마이그레이션할 필요가 없습니다. 하지만 Cloud FirestoreFirebase 실시간 데이터베이스의 기능을 갖춘, 확장성과 가용성이 높은 최신 NoSQL 데이터 스토어입니다.

Firestore의 기능을 활용하고 싶다면 Firestore를 사용해야 한다고 생각하거나 적어도 마이그레이션에 관한 내용을 살펴볼 만큼 충분한 관심을 갖고 싶은 개발자라면 제대로 찾아오셨습니다. 이 가이드에서는 Cloud Datastore를 사용하는 App Engine 앱을 Cloud Firestore로 마이그레이션하는 방법을 설명합니다.

학습 목표

  • Datastore와 Firestore의 차이점 인식
  • Cloud Datastore에서 Cloud Firestore로 마이그레이션

필요한 항목

설문조사

이 Codelab을 어떻게 사용할 예정인가요?

<ph type="x-smartling-placeholder"></ph> 읽어보기만 해도 됩니다. 읽고 연습 활동을 완료하세요

2. 배경

App Engine의 Datastore는 2013년에 자체 제품으로 출시되었으며, Google Cloud Datastore는 현재 App Engine 외부 개발자들도 액세스할 수 있습니다. 그다음 해에 Google이 Firebase를 인수했습니다. 당시에는 실시간 데이터베이스로 유명했습니다.

이후 몇 년에 걸쳐 Firebase팀과 Cloud Datastore팀은 일부 Firebase 기능을 Datastore에 통합하는 작업을 진행했습니다. 이에 따라 2017년에 차세대 Cloud Datastore가 출시되었습니다. 일부 Firebase 기능 상속을 반영하기 위해 Cloud Firestore로 리브랜딩했습니다.

Cloud Firestore는 Google Cloud 프로젝트의 기본 NoSQL 스토리지 메커니즘이 되었습니다. 신규 앱은 기본적으로 Cloud Firestore를 사용할 수 있지만, 기존 Datastore 데이터베이스는 내부적으로 Firestore로 전환되어 이제 'Datastore 모드의 Firestore'로 작동합니다. Datastore 작업과의 호환성을 유지합니다. 따라서 애플리케이션은 이러한 모드 중 하나에서만 Cloud Firestore를 작동할 수 있으며 설정한 후에는 변경할 수 없습니다.

현재는 사용자가 새 프로젝트를 만들고 NoSQL 솔루션을 선택할 때 Datastore 모드의 Firestore 또는 네이티브 모드의 Firestore를 선택하라는 메시지가 표시됩니다. 사용자가 Datastore 항목을 추가하면 Firestore로 변경할 수 없으며 마찬가지로 Firestore 기본 모드가 선택되면 더 이상 Datastore (또는 Datastore 모드의 Firestore)로 다시 전환할 수 없습니다. 자세한 내용은 문서의 Datastore 모드의 Cloud Firestore 또는 네이티브 Firestore 모드 페이지 중 선택을 참조하세요. 앱을 Firestore로 마이그레이션하려면 새 프로젝트를 만들고 Datastore를 내보낸 다음 Firestore로 가져와야 합니다. 이 튜토리얼의 목적은 개발자에게 Cloud Datastore와 Cloud Firestore 사용의 차이점에 대한 아이디어를 제공하는 것입니다.

이러한 이전은 Google에서 사용자가 수행할 것으로 예상되는 이전이 아니므로 선택적으로 이전할 수 있습니다. Cloud Firestore를 기본적으로 사용하면 클라이언트 인증, Firebase 규칙 통합, Firebase 실시간 데이터베이스와 같은 분명한 이점이 있지만 마이그레이션 단계가 '불편'합니다.

  • 현재 앱의 프로젝트와 다른 프로젝트를 사용해야 합니다.
  • 앱에서 Datastore 항목을 추가한 프로젝트는 기본 모드의 Firestore로 전환할 수 없습니다.
  • 마찬가지로 네이티브 모드의 Firestore를 선택한 프로젝트는 Datastore 모드의 Firestore로 되돌릴 수 없습니다.
  • 한 프로젝트에서 다른 프로젝트로 데이터를 스트리밍할 수 있는 이전 도구는 없습니다.
  • 네임스페이스 및 높은 쓰기 처리량(>10k/s) 등 일부 중요한 Datastore 기능은 Firestore에서 사용할 수 없습니다.
  • 내보내기 및 가져오기 도구는 '기본' '전부 혹은 전무' 있습니다
    • 앱에 Datastore 항목이 많은 경우 내보낸 후 Firestore로 가져오는 데 몇 시간이 걸릴 수 있습니다.
    • 그동안 애플리케이션/서비스에서 데이터를 쓰거나 업데이트할 수 없습니다.
    • 이전 활동은 정상 사용으로 집계됩니다. 가능한 경우 일일 할당량에 걸쳐 분산하여 비용을 최소화할 수 있습니다.
    • 새 서비스는 다른 프로젝트에서 실행되므로 DNS 업데이트가 적용될 기간이 필요합니다.
  • Datastore와 Firestore에는 비슷하지만 다른 데이터 모델이 있으므로 이전하려면 앱/서비스의 작동 방식을 업데이트해야 합니다.
    • 이제 Datastore의 상위 쿼리가 Firestore 컬렉션 쿼리 (기본값)입니다.
    • Datastore의 광범위한 유형 쿼리는 Firestore 컬렉션 그룹 쿼리입니다.
    • 색인과 처리가 다릅니다.

그렇더라도 이전을 고려하거나 그러한 이전을 시뮬레이션하기 위해 고려할 만한 매우 간단한 앱이 있거나 Datastore와 Firestore에 대해 알아보고자 한다면 계속 진행하시기 바랍니다.

Python 2 사용자: 이 선택적 이전 Codelab은 Python 3에서만 제공되지만 Cloud Firestore는 2.x도 지원하므로 사용상의 차이를 보간할 수 있습니다. 예를 들어 Firestore 레코드는 바이트 문자열 대신 유니코드 문자열을 사용하므로 Python 2 문자열 리터럴에는 u'' 선행 표시기가 필요합니다. 즉, 2.x store_visit() 함수는 다음과 같습니다.

def store_visit(remote_addr, user_agent):
    doc_ref = fs_client.collection(u'Visit')
    doc_ref.add({
        u'timestamp': datetime.now(),
        u'visitor': u'{}: {}'.format(remote_addr, user_agent),
    })

그 외에는 클라이언트 라이브러리가 비슷하게 작동해야 합니다. 고려해야 할 다른 유일한 문제는 2.x Cloud Firestore 라이브러리가 '고정'되었다는 것입니다. 개발이 이루어지는 한 3.x Firestore 클라이언트 라이브러리에서만 점점 더 많은/새로운 기능을 사용할 수 있게 됩니다.

마이그레이션을 진행하기 위해 이 가이드의 기본 단계는 다음과 같습니다.

  1. 설정/사전 작업
  2. Cloud Firestore 라이브러리 추가
  3. 애플리케이션 파일 업데이트

3. 설정/사전 작업

이 가이드의 주요 부분을 진행하기 전에 프로젝트를 설정하고 코드를 가져온 후 기본 앱을 배포하여 작동하는 코드로 시작할 수 있도록 준비합니다.

1. 프로젝트 설정

모듈 3 Codelab을 완료할 때 사용한 것과 동일한 프로젝트를 재사용하는 것이 좋습니다. 또는 완전히 새로운 프로젝트를 만들거나 다른 기존 프로젝트를 다시 사용할 수도 있습니다. 프로젝트에 활성 결제 계정이 있고 App Engine(앱)이 사용 설정되어 있는지 확인합니다.

2. 기준 샘플 앱 가져오기

이 Codelab의 기본 요건 중 하나는 모듈 3 샘플 앱이 작동하는 것입니다. 이러한 도구가 없으면 모듈 3 튜토리얼 (위의 링크)을 완료한 후 여기로 이동하세요. 그렇지 않고 이미 콘텐츠에 익숙하다면 아래의 모듈 3 코드를 가져와 시작할 수 있습니다.

여러분의 것이든 우리의 것이든, 모듈 3 코드에서 시작합니다. 이 모듈 6 Codelab에서는 각 단계를 진행하며 완료되면 FINISH 지점의 코드와 유사해야 합니다. 이 가이드는 Python 3에서만 사용할 수 있습니다.

모듈 3 파일의 디렉터리는 다음과 같습니다 (개발자의 파일 또는 우리가 만든 파일).

$ ls
README.md               main.py                 templates
app.yaml                requirements.txt

3. 모듈 3 앱 (재)배포

이제 남은 사전 작업 실행 단계는 다음과 같습니다.

  1. gcloud 명령줄 도구 사용 방법을 다시 숙지합니다(필요한 경우).
  2. 필요한 경우 모듈 3 코드를 App Engine에 (다시) 배포합니다.

이러한 단계를 성공적으로 실행하고, 작동하는지 확인한 후에는 이 가이드로 이동하여, 구성 파일 작업을 시작합니다.

Python 2 요구사항

  • app.yaml (여전히)가 서드 파티 번들 패키지인 grpciosetuptools를 참조하는지 확인합니다.
  • appengine_config.py가 여전히 pkg_resourcesgoogle.appengine.ext.vendor를 사용하여 앱이 서드 파티 리소스를 가리키도록 합니다.
  • requirements.txt를 업데이트하는 다음 섹션에서는 Python Firestore 클라이언트 라이브러리의 최종 2.x 호환 버전인 google-cloud-firestore==1.9.0를 사용해야 합니다.
    • requirements.txtgoogle-cloud-core 항목이 있다면 그대로 두세요.
    • lib를 삭제하고 pip install -t lib -r requirements.txt로 다시 설치합니다.

4. 구성 파일 업데이트 (Cloud Firestore 라이브러리 추가)

설정 외에도 구성을 업데이트한 후 애플리케이션 파일을 업데이트해야 합니다. 전자의 경우 유일한 구성 변경은 requirements.txt 파일의 사소한 패키지 스왑이므로 지금 해 보겠습니다.

다음과 같이 requirements.txt에서 google-cloud-datastore 줄을 google-cloud-firestore로 바꿉니다.

Flask==1.1.2
google-cloud-firestore==2.0.2

각 라이브러리의 최신 버전을 사용하는 것이 좋습니다. 위의 버전 번호는 이 문서의 작성 시점을 기준으로 최신 버전입니다. FINISH 저장소 폴더의 코드는 더 자주 업데이트되며 최신 버전을 포함할 수 있습니다.

다른 구성 변경사항은 없으므로 app.yamltemplates/index.html는 그대로 유지됩니다.

5. 애플리케이션 파일 업데이트

애플리케이션 파일(main.py) 하나만 있으므로 이 섹션의 모든 변경사항은 해당 파일에만 영향을 미칩니다.

1. 가져오기

패키지 가져오기는 datastore에서 firestore로 약간 변경되었습니다.

  • 이전:
from google.cloud import datastore
  • 이후:
from google.cloud import firestore

2. Firestore 액세스

Flask를 초기화한 후 Firestore 클라이언트를 만듭니다. 위와 비슷하게 변경합니다. 하지만 클라이언트 초기화의 경우는 다음과 같습니다.

  • 이전:
app = Flask(__name__)
ds_client = datastore.Client()
  • 이후:
app = Flask(__name__)
fs_client = firestore.Client()

Cloud Firestore에서 Cloud Datastore로 마이그레이션을 수행하면 Cloud Firestore로 이동하기 위한 복잡한 과정이 이미 완료되었을 것입니다. Datastore를 사용하면 공통 속성으로 구성된 항목 형태로 데이터 레코드를 만들고 이를 키로 그룹화할 수 있습니다. Firestore의 데이터 레코드는 문서로서 키-값 쌍으로 구성되며 컬렉션으로 그룹화됩니다. Datastore에서 이전하려면 이러한 차이점에 대해 생각해 보아야 합니다. 데이터 레코드를 만들고 쿼리할 때 이러한 차이점이 구체화되기 때문입니다. 결과는 Datastore 코드의 복잡도에 따라 달라질 수 있습니다.

Datastore의 경우 필터링 및 정렬 기준과 함께 항목 유형을 기준으로 쿼리를 수행합니다. Firestore의 경우 데이터 쿼리도 비슷합니다. 이러한 쿼리 값인 클라이언트 (각각 ds_client 또는 fs_client) 및 가져오기라고 가정하고 간단한 예를 살펴보겠습니다.

from datetime import datetime
from firestore.Query import DESCENDING

OCT1 = datetime(2020, 10, 1)
LIMIT = 10

Datastore의 경우 2020년 10월 1일 이후인 최근 Visit 항목 10개를 내림차순으로 쿼리해 보겠습니다.

query = ds_client.query(kind='Visit')
query.add_filter('timestamp', '>=', datetime(2020, 10, 1))
query.order = ['-timestamp']
return query.fetch(limit=LIMIT)

Visit 컬렉션에서 Firestore에도 동일한 작업을 수행합니다.

query = fs_client.collection('Visit')
query.where('timestamp', '>=', datetime(2020, 10, 1))
query.order_by('timestamp', direction=DESCENDING)
return query.limit(LIMIT).stream()

샘플 앱 쿼리는 더 간단합니다('WHERE' 절 없음). 검토하자면 Cloud Datastore 코드는 다음과 같습니다.

  • 이전:
def store_visit(remote_addr, user_agent):
    entity = datastore.Entity(key=ds_client.key('Visit'))
    entity.update({
        'timestamp': datetime.now(),
        'visitor': '{}: {}'.format(remote_addr, user_agent),
    })
    ds_client.put(entity)

def fetch_visits(limit):
    query = ds_client.query(kind='Visit')
    query.order = ['-timestamp']
    return query.fetch(limit=limit)

Firestore로 마이그레이션하면 앞에서 본 것과 같이 항목과 유사한 새 문서 및 쿼리를 만들 수 있습니다.

  • 이후:
def store_visit(remote_addr, user_agent):
    doc_ref = fs_client.collection('Visit')
    doc_ref.add({
        'timestamp': datetime.now(),
        'visitor': '{}: {}'.format(remote_addr, user_agent),
    })

def fetch_visits(limit):
    visits_ref = fs_client.collection('Visit')
    visits = (v.to_dict() for v in visits_ref.order_by('timestamp',
            direction=firestore.Query.DESCENDING).limit(limit).stream())
    return visits

기본 함수 root()index.html 템플릿 파일과 동일하게 유지됩니다. 변경사항을 다시 확인하고 저장, 배포, 확인합니다.

6. 요약/삭제

애플리케이션 배포

gcloud app deploy로 앱을 다시 배포하고 앱이 작동하는지 확인합니다. 이제 코드가 모듈 6 저장소 (또는 원하는 경우 2.x 버전)에 있는 코드와 일치해야 합니다.

앞의 Codelab을 수행하지 않고 이 시리즈를 바로 시작한 경우에는 앱 자체가 변경되지 않습니다. 모든 방문을 기본 웹페이지(/)에 등록하고 사이트를 충분히 방문한 후 다음과 같이 표시됩니다.

visitme 앱

선택사항인 모듈 6 이전을 완료하신 것을 축하합니다. 이는 App Engine 데이터 스토리지에 대해 수행할 수 있는 최종 마이그레이션 중 하나일 가능성이 높습니다. 고려할 수 있는 대안 중 하나는 Cloud Run에 맞게 앱을 컨테이너화하는 것입니다 (아래에 링크된 모듈 4와 5, Codelab 참고).

선택사항: 삭제

다음 마이그레이션 Codelab으로 이동할 준비가 될 때까지 비용이 결제되지 않도록 하려면 삭제를 수행해야 합니다. 기존 개발자라면 App Engine 가격 책정 정보를 이미 잘 알고 계실 것입니다.

선택사항: 앱 사용 중지

다음 가이드로 이동할 준비가 되지 않았으면 비용 발생을 방지하기 위해 앱을 사용 중지하세요. 다음 Codelab으로 이동할 준비가 되었으면 이를 다시 사용 설정하면 됩니다. 앱이 사용 중지되면 요금이 발생하는 트래픽이 발생하지 않습니다. 하지만 무료 할당량을 초과하는 경우 Firestore 사용량도 요금이 청구될 수 있으므로 이 한도 미만으로 줄일 수 있도록 충분히 삭제하세요.

반면에 마이그레이션을 계속하지 않고 모든 것을 완전히 삭제하려면 프로젝트를 종료하면 됩니다.

다음 단계

이 튜토리얼 외에도 다음과 같은 다른 이전 모듈 Codelab을 고려할 수 있습니다.

  • 모듈 7: App Engine push 태스크 큐([push] 태스크 큐를 사용하는 경우 필요)
    • App Engine taskqueue push 태스크를 모듈 1 앱에 추가합니다.
    • 모듈 8에서 Cloud Tasks로 마이그레이션하기 위해 사용자를 준비합니다.
  • 모듈 4: Docker를 사용하여 Cloud Run으로 마이그레이션합니다.
    • Docker를 사용하여 Cloud Run에서 실행하기 위해 앱을 컨테이너화합니다.
    • 이 마이그레이션을 통해 Python 2를 계속 사용할 수 있습니다.
  • 모듈 5: Cloud Buildpacks를 사용하여 Cloud Run으로 마이그레이션
    • Cloud Buildpacks를 사용하여 Cloud Run에서 실행할 앱 컨테이너화
    • Docker, 컨테이너, Dockerfile에 대해 알 필요가 없습니다.
    • 앱이 이미 Python 3로 마이그레이션되어 있어야 합니다(Buildpacks는 Python 2를 지원하지 않음).

7. 추가 리소스

App Engine 마이그레이션 모듈 Codelab 문제/의견

이 Codelab에 문제가 발견된 경우 문제를 기록하기 전에 먼저 비슷한 기록이 있는지 검색해보세요. 검색 및 새 문제 만들기 링크:

마이그레이션 리소스

모듈 3 (START)과 모듈 6 (FINISH)의 저장소 폴더 링크는 아래 표에서 찾을 수 있습니다. 또한 클론 또는 ZIP 파일로 다운로드할 수 있는 모든 App Engine 마이그레이션 저장소에서 액세스할 수도 있습니다.

Codelab

Python 2

Python 3

모듈 3

(코드)

코드

모듈 6

(해당 없음)

코드

App Engine 리소스

다음은 이 특정 마이그레이션과 관련된 추가적인 리소스입니다.