MongoDB 호환성을 갖춘 Firestore의 변경 스트림을 사용하면 애플리케이션이 컬렉션 또는 전체 데이터베이스에 적용된 실시간 변경사항 (삽입, 업데이트, 삭제)에 액세스할 수 있습니다. 변경 스트림은 수정 시간을 기준으로 업데이트를 정렬합니다.
변경 스트림은 MongoDB 호환 API 및 기존 MongoDB 드라이버를 통해 액세스할 수 있습니다. MongoDB 호환성을 갖춘 Firestore의 변경 스트림 구현은 쓰기 및 읽기 병렬 처리에 대한 자동 파티션 나누기의 고유한 구현을 통해 모든 쓰기 및 읽기 처리량을 처리할 수 있습니다. 이를 통해 높은 처리량의 워크로드를 빌드할 수 있습니다. 또한 Cloud Firestore와 다른 스토리지 솔루션 간의 마이그레이션 및 데이터 동기화 인프라를 개선할 수 있습니다.
MongoDB 드라이버와의 호환성 외에도 Cloud Firestore 를 사용하여 변경 스트림을 병렬로 읽을 수 있습니다. 이를 통해 병렬의 높은 처리량 읽기 워크로드를 빌드할 수 있습니다. 각 스트림은 잘 분산된 결과 파티션을 나타냅니다.
변경 스트림은 다음 기능을 지원합니다.
- 데이터베이스 또는 컬렉션 범위로 구성 가능한 변경 내역
- 생성 시 지정된 변경 스트림의 보관 기간 기본 보관 기간은 7일이고 최소 보관 기간은 1일입니다. 보관 기간은 최대 7일까지 1일의 배수여야 합니다. 보관 기간은 생성 후에는 변경할 수 없습니다. 보관 기간을 변경하려면 변경 스트림을 삭제하고 다시 만들어야 합니다.
db.collection.watch()및db.watch()를 사용하여 관찰할 수 있는delete,insert,update,drop변경 이벤트updateDescription.updatedFields에는 업데이트 차이가 포함됩니다.- 모든
fullDocument및fullDocumentBeforeChange옵션- 업데이트를 위해 전체 문서 조회
- 문서가 대체, 업데이트 또는 삭제되기 전의 사전 이미지
- 문서가 대체 또는 업데이트된 후의 사후 이미지
- 1시간보다 오래된 사전 및 사후 이미지를 사용하려면 PITR (point-in-time recovery)을 사용 설정해야 합니다.
resumeAfter및startAfter를 포함한 모든 재개 옵션watch()를 사용하여 변경사항을 관찰할 때$addFields,$match,$project,$replaceRoot,$replaceWith,$set,$unset과 같은 집계 단계를 연결할 수 있습니다.
변경 스트림 구성
데이터베이스의 기존 변경 스트림을 만들거나 삭제하거나 보려면 Google Cloud 콘솔을 사용합니다.
역할 및 권한
변경 스트림을 만들고 삭제하고 나열하려면 주 구성원에게 각각 datastore.schemas.create, datastore.schemas.delete, datastore.schemas.list Identity and Access Management (IAM) 권한이 필요합니다.
예를 들어 Datastore 색인 관리자 (roles/datastore.indexAdmin) 역할은 이러한 권한을 부여합니다.
변경 스트림 만들기
해당 변경 스트림 커서를 열려면 먼저 변경 스트림을 만들어야 합니다. 컬렉션 또는 데이터베이스 생성 시 자동 변경 스트림 사용 설정은 지원되지 않습니다.
변경 스트림을 만들려면 Google Cloud 콘솔을 사용합니다.
-
Google Cloud 콘솔에서 데이터베이스 페이지로 이동합니다.
- 목록에서 MongoDB 호환성을 갖춘 Firestore 데이터베이스를 선택합니다. Firestore 스튜디오 패널이 열립니다.
- 탐색기 패널에서 변경 내역 노드를 찾고 작업 더보기를 클릭한 후 변경 내역 만들기를 선택합니다.
- 고유한 변경 스트림 이름, 범위, 보관 기간을 입력한 후 저장 을 클릭합니다.
변경 스트림 보기
Google Cloud 콘솔에서 변경 스트림에 대한 세부정보를 볼 수 있습니다.
-
Google Cloud 콘솔에서 데이터베이스 페이지로 이동합니다.
- 목록에서 MongoDB 호환성을 갖춘 Firestore 데이터베이스를 선택합니다. Firestore 스튜디오 패널이 열립니다.
- 탐색기 패널에서 변경 내역 노드를 찾습니다.
- 노드를 열거나 닫으려면 노드 전환 을 클릭합니다.
변경 스트림 삭제
변경 스트림을 삭제하려면 Google Cloud 콘솔을 사용합니다.
-
Google Cloud 콘솔에서 데이터베이스 페이지로 이동합니다.
- 목록에서 MongoDB 호환성을 갖춘 Firestore 데이터베이스를 선택합니다. Firestore 스튜디오 패널이 열립니다.
- 탐색기 패널에서 변경 내역 노드를 찾습니다.
- 노드를 열거나 닫으려면 노드 전환 을 클릭합니다.
- 탐색기에서 삭제하려는 변경 스트림을 찾습니다.
- 작업 더보기를 클릭한 후 변경 스트림 삭제를 선택합니다.
- 대화상자에서 변경 스트림 이름을 입력하여 삭제를 확인한 후 삭제 를 클릭합니다.
변경 스트림 커서 열기 또는 재개
다음 예시에서는 변경 스트림 커서를 만들고 재개하고 구성하는 방법을 보여줍니다.
변경 스트림 커서를 만들기 전에 데이터베이스 또는 컬렉션의 변경 스트림을 명시적으로 만들어야 합니다.
변경 스트림 커서 만들기
새 변경 스트림 커서를 만들려면 MongoDB 드라이버에서 watch 메서드를 사용합니다.
데이터베이스의 모든 변경사항을 수신 대기하려면 데이터베이스 범위 변경 스트림을 만들고 db 객체에서 watch 메서드를 호출합니다.
let cursor = db.watch()
컬렉션 범위 커서를 만들려면 먼저 해당 컬렉션의 변경 스트림을 만들어야 합니다. 그런 다음 해당 컬렉션에서 watch 메서드를 호출합니다.
let cursor = db.my_collection.watch()
이제 변경 스트림 커서를 만들었으므로 스트리밍을 시작할 수 있습니다.
예를 들어 문서를 삽입하고 커서에서 tryNext를 호출하면 변경 스트림에 변경사항이 표시됩니다.
let doc = db.my_collection.insertOne({value: "hello world"}) console.log(cursor.tryNext())
문서를 업데이트하고 삭제하면 변경 스트림에 이러한 변경사항이 표시됩니다.
db.my_collection.updateOne({"_id": doc.insertedId}, {$set: {value: "hello world!"}}) db.my_collection.deleteOne({"_id": doc.insertedId}}) // Prints the update event console.log(cursor.tryNext()) // Prints the delete event console.log(cursor.tryNext())
변경 스트림 재개
변경 스트림을 재개하려면 resumeAfter 또는 startAfter 옵션을 사용합니다.
resumeAfter 및 startAfter에서 재개할 변경 로그의 위치를 확인하려면 재개 토큰을 사용합니다.
// Create a cursor and add one event to the change stream. let cursor = db.my_collection.watch(); db.my_collection.insertOne({value: "hello world"}); let event = cursor.tryNext(); // Get the resume token from the event. let resumeToken = event._id; // Add a new event to the change stream. db.my_collection.insertOne({value: "foobar"}); // Create a new cursor by using the resume token as a starting point. let newCursor = db.my_collection.watch({resumeAfter: resumeToken}) // Log the change event containing the "foobar" value. console.log(newCursor.tryNext())
startAfter를 사용하려면 다음 안내를 따르세요.
// Start after the resume token. let startAfterCursor = db.my_collection.watch({startAfter: resumeToken})
업데이트 및 삭제에 사전 및 사후 이미지 포함
필요한 경우 업데이트 및 삭제 변경 이벤트에 문서의 사전 및 사후 이미지를 포함할 수 있습니다. 이미지 사용 가능 여부는 PITR (point-in-time recovery) 기간에 따라 다르며 1시간보다 오래된 문서 이미지를 읽으려면 PITR을 사용 설정해야 합니다.
변경 스트림은 PITR 기간을 활용하여 지정된 변경 이벤트 전후의 문서 뷰를 제공합니다. 기본적으로 업데이트 이벤트에는 업데이트 작업으로 수정된 필드의 델타인 updateDescription 필드가 포함됩니다.
변경 이벤트에 사전 및 사후 이미지를 포함하려면
변경 스트림 쿼리에서 fullDocumentBeforeChange 및 fullDocument 옵션을
지정해야 합니다.
let cursor = db.my_collection.watch({ "fullDocument": "required", "fullDocumentBeforeChange": "required" })
쿼리가 PITR 보관 기간 외부의 문서를 읽으려고 시도하거나 PITR이 사용 설정되지 않은 경우 required 값은 서버 측 오류 메시지를 발생시킵니다.
오류를 발생시키는 대신 whenAvailable 값을 사용하여 이미지를 더 이상 사용할 수 없는 경우 null 값을 반환할 수 있습니다.
let cursor = db.my_collection.watch({ "fullDocument": "whenAvailable", "fullDocumentBeforeChange": "whenAvailable" })
업데이트에 현재 이미지 포함
기본적으로 업데이트 이벤트에는 업데이트 작업으로 수정된 필드의 델타인 updateDescription 필드가 포함됩니다. 대신 전체 문서의 최신 버전을 조회하려면 fullDocument 옵션에서 updateLookup 값을 사용합니다.
이 기능은 PITR을 필요로 하지 않으며 문서 조회를 실행합니다.
let cursor = db.my_collection.watch({ "fullDocument": "updateLookup", })
병렬 읽기
처리량을 늘리려면 firestoreWorkerConfig 옵션을 사용하여 변경 스트림 쿼리를 여러 작업자 간에 분할할 수 있습니다. 각 작업자는 고유한 문서 집합의 변경사항을 제공합니다. runCommand 또는 aggregate 쿼리를 통해 병렬 커서를 만들어야 합니다.
예를 들어 다음과 같이 변경 스트림을 3명의 작업자에게 분산할 수 있습니다.
let cursor1 = db.my_collection.aggregate([{ "$changeStream": { "firestoreWorkerConfig": {numWorkers: 3, workerId: 0 }} }]); let cursor2 = db.my_collection.aggregate([{ "$changeStream": { "firestoreWorkerConfig": {numWorkers: 3, workerId: 1 }} }]); let cursor3 = db.my_collection.aggregate([{ "$changeStream": { "firestoreWorkerConfig": {numWorkers: 3, workerId: 2 }} }]);
변경 스트림 및 백업
백업 복원 작업에서는 변경 스트림 구성도 변경 스트림 데이터도 사용할 수 없습니다. 변경 스트림이 있는 데이터베이스를 복원하는 경우 대상 데이터베이스에서 해당 변경 스트림을 다시 만들어 데이터베이스에 커서를 열어야 합니다.
결제
- 변경 스트림에는 읽기 단위 및 스토리지 비용이 발생합니다. 변경 스트림 가격 책정을 참조하세요.
- 읽기 요청 시 1시간보다 오래된 사전 및 사후 이미지를 포함하려면 PITR 비용이 발생하는 PITR을 사용 설정해야 합니다.
동작 차이
다음 섹션에서는 MongoDB 호환성을 갖춘 Firestore와 MongoDB 간의 변경 스트림 차이점을 설명합니다.
updateDescription
updateDescription은 업데이트 작업으로 업데이트되거나 삭제된 필드
를 설명하는 update 이벤트의 문서입니다.
Cloud Firestore에서 주목할 만한 차이점은 다음과 같습니다.
updateDescription에서truncatedArrays및disambiguatedPaths필드는 채워지지 않습니다.updateDescription.updatedFields는 변경사항이 적용되기 전후의 문서 사전 및 사후 이미지 간의 정규 차이를 나타냅니다.
다음 문서의 초기 상태를 고려해 보세요.
db.my_collection.insertOne({ _id: 1, root: { array: [{a: 1}, {b: 2}, {c: 3}] } })
시나리오 1: 배열의 첫 번째 요소만 변경합니다.
이 시나리오에서 Cloud Firestore 동작은 MongoDB와 일치합니다.
db.my_collection.updateOne( {_id: 1}, {'$set': {"root.array.0.a": 100}} ) { updatedFields: {"root.array.0.a": 100}, removedFields: [] }
전체 배열로 덮어쓰기
이 시나리오에서 작업은 첫 번째 배열 필드만 업데이트하지만 전체 배열을 덮어씁니다.
Cloud Firestore 업데이트 차이는 이러한
두 시나리오를 구분하지 않으며 둘 다 동일한 updateDescription.updatedFields를 반환합니다.
db.my_collection.updateOne( {_id: 1}, {'$set': {"root.array": [{a: 100}, {b: 2}, {c: 3}]}} ) // In other implementations, updatedFields reflects the mutation itself { updatedFields: { "root.array": [{a: 100}, {b: 2}, {c: 3}] }, removedFields: [] } // Firestore updatedFields is the diff between the before and after versions of the document { updatedFields: {"root.array.0.a": 100}, removedFields: [] }