마이그레이션 문제 해결

이 섹션에서는 Datastream 및 Dataflow 파이프라인을 만들고 관리할 때 발생할 수 있는 일반적인 문제를 해결하는 방법을 설명합니다.

Datastream 연결 프로필 문제 해결

마이그레이션 절차에서는 두 개의 Datastream 연결 프로필을 만들어야 합니다. 하나는 소스 MongoDB 호환 데이터베이스에서 데이터를 읽기 위한 것이고 다른 하나는 Cloud Storage 버킷에 데이터를 쓰기 위한 것입니다.

이 단계에서는 gcloud datastream connection-profiles create 명령어를 사용합니다. 이 명령어로 Datastream 연결 프로필을 만들면 다음 예와 유사한 메타데이터가 반환됩니다.

metadata:
  '@type': type.googleapis.com/google.cloud.datastream.v1.OperationMetadata
  apiVersion: v1
  createTime: '2025-05-15T21:49:05.022509533Z'
  requestedCancellation: false
  target: projects/PROJECT_ID/locations/LOCATION/connectionProfiles/SRC_CONNECTION_PROFILE_NAME
  verb: create
name: projects/PROJECT_ID/locations/LOCATION/operations/operation-1747345744961-63533a26d9ee6-b2386fbf-204c28d6

operation-로 시작하는 강조 표시된 식별자를 사용하여 지정된 데이터 스트림 작업의 상태를 가져올 수 있습니다. 위의 출력 예시에서 다음 gcloud CLI 명령어는 연결 프로필 생성 요청에 관한 세부정보를 가져옵니다.

gcloud datastream operations describe \
operation-1747345744961-63533a26d9ee6-b2386fbf-204c28d6 \
--location="$LOCATION"

Google Cloud 콘솔에서 Datastream 연결 프로필 및 기타 Datastream 아티팩트를 검사할 수 있습니다.

Google Cloud 콘솔에서 Datastream 페이지로 이동합니다.

Datastream으로 이동

Datastream 스트림 문제 해결

gcloud datastream streams create 명령어로 Datastream 스트림을 만들면 다음 예시와 유사한 메타데이터가 반환됩니다.

metadata:
  '@type': type.googleapis.com/google.cloud.datastream.v1.OperationMetadata
  apiVersion: v1
  createTime: '2025-05-14T19:31:20.209503095Z'
  requestedCancellation: false
  target: projects/PROJECT_ID/locations/LOCATION/streams/DATASTREAM_NAME
  verb: create
  name: projects/PROJECT_ID/locations/LOCATION/operations/operation-1747251080085-6351d97f63eb8-43204f78-35c87474

operation-로 시작하는 강조 표시된 식별자를 사용하여 지정된 데이터 스트림 작업의 상태를 가져올 수 있습니다. 위의 출력 예시에서 다음 gcloud CLI 명령어는 스트림 생성 요청에 관한 세부정보를 가져옵니다.

gcloud datastream operations describe \
operation-1747345744961-63533a26d9ee6-b2386fbf-204c28d6 \
--location="$LOCATION"

기존 스트림의 상태를 조회하려면 다음을 사용하세요.

gcloud datastream streams describe $DATASTREAM_NAME --location=$LOCATION

Google Cloud 콘솔에서 Datastream 스트림 및 기타 Datastream 아티팩트를 검사할 수 있습니다.

Google Cloud 콘솔에서 Datastream 페이지로 이동합니다.

Datastream으로 이동

Dataflow 파이프라인 문제 해결

Google Cloud 콘솔에서 Dataflow 파이프라인 실행을 모니터링할 수 있습니다.

Google Cloud 콘솔에서 Dataflow 페이지로 이동합니다.

Dataflow로 이동

재시도 가능한 오류 문제 해결

재시도 가능한 오류는 결국 성공하는 일시적인 오류입니다. 일반적인 재시도 가능한 오류는 다음과 같습니다.

  • 네트워크 또는 연결 문제
  • 트랜잭션 경합
  • 부하 분산으로 인해 연결이 닫힘

오류로 인해 대상에 쓸 수 없는 문서는 Cloud Storage 버킷의 Dataflow 템플릿의 deadLetterQueueDirectory 매개변수로 지정된 위치에 저장됩니다. 재시도 가능한 오류는 기본적으로 dlqMaxRetryCount 매개변수에 지정된 횟수만큼 재시도됩니다.

데드 레터 대기열 (DLQ)은 DLQ_LOCATION 환경 변수에 지정된 경로로 이동하여 Cloud Storage에서 직접 검사할 수 있습니다. 경로에는 MongoDB 호환성을 갖춘 Firestore 데이터베이스에 쓸 수 없는 문서 및 업데이트의 json 레코드가 포함된 타임스탬프 폴더의 계층 구조가 포함됩니다.

재시도 가능한 오류로 인해 실패한 문서만 데드 레터 대기열에 포함되어 있다고 가정하면 이 대기열에서만 작동하는 모드로 Dataflow 템플릿을 실행하여 대기열을 드레인할 수 있습니다. 이렇게 하려면 다음 예와 같이 runMode 매개변수를 retryDLQ로 설정합니다.

DLQ_START_TIME="$(date +'%Y%m%d%H%M%S')"

gcloud dataflow flex-template run "dataflow-mongodb-to-firestore-$DLQ_START_TIME" \
--template-file-gcs-location gs://dataflow-templates-us-central1/latest/flex/Cloud_Datastream_MongoDB_to_Firestore \
--region $LOCATION \
--num-workers $NUM_WORKERS \
--temp-location $TEMP_OUTPUT_LOCATION \
--additional-user-labels "" \
--parameters inputFilePattern=$INPUT_FILE_LOCATION,\
inputFileFormat=avro,\
fileReadConcurrency=10,\
connectionUri=$FIRESTORE_CONNECTION_URI,\
databaseName=$FIRESTORE_DATABASE_NAME,\
shadowCollectionPrefix=shadow_,\
batchSize=500,\
deadLetterQueueDirectory=$DLQ_LOCATION,\
dlqRetryMinutes=10,\
dlqMaxRetryCount=500,\
processBackfillFirst=false,\
runMode=retryDLQ,\
directoryWatchDurationInMinutes=10,\
streamName=$DATASTREAM_NAME,\
stagingLocation=$STAGING_LOCATION,\
autoscalingAlgorithm=THROUGHPUT_BASED,\
maxNumWorkers=$MAX_WORKERS,\
workerMachineType=$WORKER_TYPE

재시도할 수 없는 오류 문제 해결

일반적인 재시도 불가능 오류는 다음과 같습니다.

  • 지원되지 않는 BSON 유형
  • _id로 사용되는 지원되지 않는 BSON 유형
  • _id로 지원되지 않는 0L
  • 문서 크기가 Firestore의 4MB 한도를 초과함

재시도할 수 없는 오류는 Cloud Storage 버킷에 저장되며, Dataflow 템플릿의 deadLetterQueueDirectory 매개변수로 지정된 위치에 저장됩니다.

데드 레터 큐 (DLQ) 검사

모든 처리가 중지된 후(활성 트래픽이 처리되지 않고 오류가 발생한 이벤트가 다시 시도되지 않음) 오류가 발생한 이벤트가 Cloud Storage에 유지됩니다.

트랜잭션 쓰기 이벤트 검사를 통해 처리가 중지되었는지 확인하고 처리량과 새 로그 항목이 생성되지 않는지 확인합니다.

Cloud Storage에서 직접 DLQ를 검사할 수 있습니다.

  1. DLQ_LOCATION 환경 변수에 지정된 Cloud Storage 위치로 이동합니다.
  2. 타임스탬프에 따라 구성된 중첩 폴더 트리에서 폴더를 펼쳐 대기열의 최신 콘텐츠를 확인합니다. 파일이 샤딩되어 다음 예시와 같이 표시될 수 있습니다.

    DLQ의 파일

  3. 각 파일을 검사하여 대상 데이터베이스에 적용되지 않은 문서와 업데이트를 확인합니다. 각 메시지에는 원래 이벤트의 페이로드와 발생한 예외가 포함됩니다.

    특히 dlqMaxRetryCount 매개변수에 낮은 값이 사용된 경우 재시도 가능한 오류가 있을 가능성은 매우 낮지만 일반적으로 DLQ에 있는 이벤트는 앞에서 설명한 이유로 재시도할 수 없습니다.

  4. 마이그레이션을 중단하고 소스 데이터베이스로 애플리케이션 트래픽을 재개하여 소스 데이터베이스의 Firestore 데이터 제약 조건을 해결하고 전체 마이그레이션 프로세스를 다시 실행하거나, 각 DLQ 이벤트의 데이터 문제를 해결하고 이러한 이벤트의 처리를 다시 시도할 수 있습니다.

각 DLQ 파일의 각 행에 대해 다음을 수행할 수 있습니다.

  • 문서 페이로드를 수정하여 지원되지 않는 데이터 유형을 대체 데이터 유형으로 변환합니다. 문서 페이로드는 표준 확장 JSON 형식입니다. 표준 확장 JSON 형식으로 새 데이터 유형을 표현합니다.

  • 0L 문서 _id을 새 Long 또는 String과 같은 다른 데이터 유형에 재할당합니다. 기존 코드에서 _id가 모두 Long이라고 예상하는 경우 다른 데이터 유형에 재할당하려면 애플리케이션 로직을 변경해야 할 수 있습니다.

  • Firestore의 4MB 한도를 초과하는 문서는 더 작은 문서로 분리하거나 콘텐츠를 압축할 수 있습니다. 하지만 이렇게 하려면 데이터를 처리하도록 애플리케이션 로직을 변경해야 합니다.

  • DLQ 파일에서 행을 삭제하여 이벤트를 무시합니다.

DLQ 파일을 수정하려면 .json 파일을 로컬로 다운로드하고 콘텐츠를 수정한 후 원래 파일을 덮어쓰면서 동일한 Cloud Storage 위치에 다시 업로드해야 합니다. 파일에서 참조하는 모든 문서를 이전에서 안전하게 제외할 수 있는 경우 전체 파일을 삭제할 수 있습니다.

DLQ 파일을 수정한 후 retryDLQ 모드에서 이전 Dataflow 템플릿을 통해 이러한 이벤트를 다시 실행할 수 있습니다.

다음 명령어는 데드 레터 대기열의 항목만 처리하는 새 Dataflow 파이프라인을 시작합니다.

DLQ_START_TIME="$(date +'%Y%m%d%H%M%S')"

gcloud dataflow flex-template run "dataflow-mongodb-to-firestore-$DLQ_START_TIME" \
--template-file-gcs-location gs://dataflow-templates-us-central1/latest/flex/Cloud_Datastream_MongoDB_to_Firestore \
--region $LOCATION \
--num-workers $NUM_WORKERS \
--temp-location $TEMP_OUTPUT_LOCATION \
--additional-user-labels "" \
--parameters inputFilePattern=$INPUT_FILE_LOCATION,\
inputFileFormat=avro,\
fileReadConcurrency=10,\
connectionUri=$FIRESTORE_CONNECTION_URI,\
databaseName=$FIRESTORE_DATABASE_NAME,\
shadowCollectionPrefix=shadow_,\
batchSize=500,\
deadLetterQueueDirectory=$DLQ_LOCATION,\
dlqRetryMinutes=10,\
dlqMaxRetryCount=500,\
processBackfillFirst=false,\
runMode=retryDLQ,\
directoryWatchDurationInMinutes=10,\
streamName=$DATASTREAM_NAME,\
stagingLocation=$STAGING_LOCATION,\
autoscalingAlgorithm=THROUGHPUT_BASED,\
maxNumWorkers=$MAX_WORKERS,\
workerMachineType=$WORKER_TYPE

다음 단계