복제의 개념

동일한 IBM® Cloudant® for IBM Cloud® 계정에 있거나, 서로 다른 계정에 있거나, 서로 다른 데이터 센터에 있는 한 데이터베이스에서 다른 데이터베이스로 데이터를 복사할 수 있습니다.

IBM Cloudant 계정과 모바일 기기 간에 데이터를 복제할 수도 있으며, 이를 위해서는 다음과 같이 PouchDB 를 사용하여 xml-ph-0000@deepl.internal 계정과 모바일 기기 간에 데이터를 복제할 수도 있습니다. 복제는 단방향 또는 양방향 모두에서 "단일 샷" 또는 연속 오퍼레이션으로 실행될 수 있으며 매개변수를 사용하여 세부적으로 조정할 수 있습니다.

IBM Cloudant의 복제 프로토콜은 다양한 데이터베이스 및 라이브러리와 호환되므로 IoT(Internet of Things) 및 모바일 애플리케이션에 적합합니다.

IBM Cloudant는 HTTP API를 사용하는 분산 JSON 데이터 저장소입니다. IBM Cloudant는 여러 클라우드 또는 사용자의 서버 랙에서 서비스로 실행될 수 있습니다. 문서는 데이터베이스에 저장되며 IBM Cloudant가 해당 데이터를 여러 노드에 분산시키는 경우 문서의 크기를 늘릴 수 있습니다. 복제는 소스 데이터베이스에서 대상 데이터베이스로 데이터를 복제하는 것입니다. 소스 및 대상 데이터베이스가 동일한 IBM Cloudant 계정 또는 동일한 데이터 센터에 속해야 할 필요는 없습니다.

그래픽은 데이터베이스 A와 B의 그림을 보여줍니다. 데이터베이스 B에는 문서가 하나 있습니다. 복제 후, 데이터베이스 a의 문서가 데이터베이스 b에 표시됩니다.
그림으로 보는 복제

소스에 있는 각 문서의 최신 버전이 대상 데이터베이스에 전송되면 복제가 완료됩니다. 전송에는 새 문서, 기존 문서에 대한 업데이트, 삭제가 포함됩니다. 문서의 최신 버전만 복제 후에 남아 있습니다. 이전 버전은 생략됩니다.

소스 데이터베이스는 마지막으로 알려진 위치에서 부분 복제가 재개될 수 있도록 체크포인트 데이터가 기록되는 것을 제외하면 복제에 의해 변경되지 않습니다. 대상 데이터베이스의 기존 데이터는 유지됩니다.

대시보드를 사용하여 복제를 시작하는 방법

IBM Cloudant 대시보드는 복제를 트리거할 수 있는 편리한 사용자 인터페이스를 제공합니다. IBM Cloudant 대시보드의 Replication을 클릭하고 Start Replication을 클릭하십시오. 다음 복제 양식을 완료하십시오.

이 화면 캡처는 적절한 필드가 모두 채워진 복제 양식의 모습을 보여줍니다. 로컬 데이터베이스인 소스 섹션과 새 데이터베이스 및 인증인 대상 섹션이 있습니다. ‘옵션’ 섹션에서 일회성 복제 또는 반복 복제를 선택하고, 복제 문서를 추가합니다.
복제 양식

보안을 이유로 IBM Cloudant 팀에서는 복제 작업을 위해 계정 레벨 인증 정보가 아닌 IAM API 키 또는 IBM Cloudant 레거시 인증 API 키를 사용할 것을 권장합니다. 자세한 정보는 액세스 관리 또는 레거시 인증권한 문서를 참조하십시오.

이 양식을 사용하여 소스 및 대상 데이터베이스를 정의한 후 Start Replication을 클릭하십시오.

각 복제 태스크의 상태는 Replication을 클릭하여 볼 수 있습니다. 각 작업의 상태는 진행됨에 따라 Running에서 Completed로 변경됩니다. 다음 스크린샷은 ‘ Completed ’ 상태를 보여줍니다.

표의 ‘상태’ 열 아래에 ‘완료’라고 표시되어 있습니다.
완료 상태

서로 다른 IBM Cloudant 계정 사이에서 복제하는 방법

복제의 소스 및 대상은 다음 예에 표시되어 있는 바와 같이 IBM Cloudant 데이터베이스의 URL입니다.

복제를 위한 소스 및 대상 URL을 정의하는 예는 다음과 같습니다.

{
  "source": {
    "url": "https://myfirstaccount.cloudant.com/a",
    "auth": {
      "basic": {
        "username": "$USERNAME",
        "password": "$PASSWORD"
      }
    }
  },
  "target": {
    "url": "https://mysecondaccount.cloudant.com/b",
    "auth": {
      "basic": {
        "username": "$USERNAME",
        "password": "$PASSWORD"
      }
    }
  }
}

소스 및 대상이 동일한 계정에 속해야 할 필요는 없습니다. 소스 및 대상 데이터베이스 이름이 일치해야 할 필요도 없습니다. 사용자는 소스 및 대상에 모두 액세스할 수 있도록 권한 부여되어야 하며, 대상에 쓸 수 있는 권한이 부여되어야 합니다.

복제의 실행 위치(소스 또는 대상)

복제는 소스 또는 대상에서 시작될 수 있습니다. 이 선택사항은 계정 A가 계정 B로 데이터를 전송하는지, 또는 계정 B가 계정 A로부터 데이터를 가져오는지를 사용자가 결정할 수 있음을 의미합니다. 한 계정이 방화벽으로 차단되어 있는 경우와 같이 두 구성 모두 복제를 실행할 수 없는 경우도 있습니다. 복제는 HTTPS 를 통해 이루어지므로 비표준 포트를 열 필요가 없습니다. 복제를 시작하는 디바이스는 사용자가 결정합니다.

복제가 변경사항 목록에 미치는 영향

_changes 엔드포인트를 사용하여 문서에 수행된 변경사항의 목록을 가져올 수 있습니다. 그러나 IBM Cloudant 데이터베이스의 분산 특성은 _changes 피드에서 제공하는 응답이 단순히 특정 날짜 및 시간 이후 발생한 변경사항의 목록이 아님을 의미합니다.

CAP 정리 논의를 통해 IBM Cloudant에서 "결과적으로 일관된" 모델을 사용함이 명백합니다. 이 모델은 동시에 특정 문서에 대한 두 개의 서로 다른 데이터베이스 복제본을 요청하는 경우 서로 다른 결과를 가져올 수 있음을 의미합니다. 이 문제는 데이터베이스 사본 중 하나가 여전히 복제 완료를 기다리는 중인 경우에 발생할 수 있습니다.

결과적으로 데이터베이스 사본이 복제를 완료하므로 문서에 대한 모든 변경사항이 각 사본에 반영됩니다.

이 "결과적 일관성" 모델에는 변경 목록에 영향을 주는 두 가지 특성이 있습니다.

  1. 특정 문서에 영향을 주는 변경사항은 거의 확실하게 서로 다른 시간에 데이터베이스의 각 사본에 적용됩니다.
  2. 문서에 영향을 주는 변경사항의 순서는 복제가 발생한 시점과 위치에 따라 데이터베이스의 각 사본 간에 서로 다를 수 있습니다.

첫 번째 특성의 영향은, 변경사항의 목록을 요청할 때 특정 시점 이후의 변경사항 목록을 요청하는 것이 무의미하다는 것입니다. 이는 변경사항 목록이 서로 다른 시간에 업데이트되는 서로 다른 데이터베이스 사본에 의해 제공될 수 있기 때문입니다. 그러나 시퀀스 ID를 사용하여 지정되는, 특정 변경사항 이후의 변경사항 목록을 요청하는 것은 의미가 있습니다.

첫 번째 특성의 추가 결과에 의하면 변경 목록에 동의하기 위해 이전 변경사항에서 "돌아보기"를 수행해야 할 수도 있습니다. 즉, 사용자는 변경사항 목록을 가져오기 위해 각 데이터베이스 사본이 일치하는 최신 변경사항부터 시작합니다. 데이터베이스 사본 간의 계약 지점은 IBM Cloudant 내에서 식별되며, 이는 데이터베이스 사본 간 복제의 동기화를 가능하게 해주는 체크포인트 메커니즘을 사용하여 수행됩니다.

마지막으로 변경사항 목록을 검색하는 경우 후속 요청에서 해당 목록이 다른 순서로 표시될 수 있습니다. 이 순서는 서로 다른 데이터베이스 사본 간에 문서가 변경된 방법에 따라 달라집니다. 예를 들면, 첫 변경사항 목록이 A, B, C의 순서로 변경사항을 보고합니다. 그러나 후속 변경사항 목록은 C, A, B의 순서로 변경될 수 있습니다. 모든 변경사항이 나열되었지만 순서는 서로 다릅니다. 이 차이는 복제 중에 수신한 변경사항의 순서가 데이터베이스의 각 사본에서 서로 다를 수 있기 때문에 발생합니다.

변경 목록에 대한 "결과적 일관성"은 무엇을 의미합니까?

변경사항 목록을 요청했을 때, 목록을 제공하는 데이터베이스에 따라 받게 되는 응답이 달라질 수 있습니다.

since 옵션은 특정 업데이트 순서 ID 이후의 변경사항 목록을 가져옵니다. 이 목록에는 항상 업데이트 이후의 변경사항이 포함되지만 업데이트 이전의 변경사항이 포함될 수도 있습니다. 이는 목록 요청에 응답하는 데이터베이스 사본에서, 자신이 다른 모든 복제본과 일치하는 변경사항을 나열하는지 확인해야 하기 때문입니다. 이러한 일관성을 달성하기 위해, 데이터베이스 사본은 모든 사본이 일치했던 지점부터 변경사항 목록을 시작해야 할 수 있습니다. 이 지점은 체크포인트를 사용하여 식별됩니다.

따라서, _changes 피드를 사용하는 애플리케이션은 ‘이뎀포텐트’해야 합니다 . 이뎀포텐시(idempotency)란 애플리케이션이 동일한 데이터를 여러 번 안전하게 수신할 수 있어야 하며, 반복되는 요청의 경우 데이터의 순서가 달라질 수도 있음을 의미합니다.

체크포인트

내부적으로, 복제 프로세스는 소스 및 대상 데이터베이스에 모두 저장되는 "체크포인트" 문서에 해당 상태를 기록합니다. 체크포인트를 통해 복제 태스크를 처음부터 다시 시작할 필요 없이 중지된 지점부터 재개할 수 있습니다. 다음 매개변수를 지정하면 체크포인트 생성을 방지할 수 있습니다 "use_checkpoints": false 옵션을 선택하면 복제를 요청할 수 있습니다. 복제가 마지막으로 알려진 위치부터 효율적으로 재개될 수 있게 하려면 이 기능을 설정된 채로 두는 것이 좋습니다.

권한

_replicator 데이터베이스에 문서를 삽입하려면 관리자 액세스 권한이 필요합니다. 소스 및 대상 매개변수에 제공된 로그인 인증 정보는 전체 관리자 권한을 필요로 하지 않습니다. 인증 정보에서 다음과 같은 태스크를 수행하면 충분합니다.

  • 대상 데이터베이스에 문서를 기록합니다.
  • 두 데이터베이스 모두에 체크포인트 문서를 기록합니다.

IBM Cloudant에는 특수 _replicator 사용자 권한이 있습니다. 이 권한은 데이터베이스에서의 체크포인트 문서 작성을 허용하지만 다른 일반 문서 작성은 허용하지 않습니다. 일반적으로는 다음 권한이 있는 API 키를 작성하십시오.

  • 소스 측의 _reader_replicator 액세스 권한
  • 대상 측의 _reader_writer 액세스 권한

API 키는 IBM Cloudant 대시보드에서 데이터베이스별로 작성하고 구성할 수 있습니다.

API 키는 IBM Cloudant 대시보드 내에서 데이터베이스별로 생성 및 구성할 수 있습니다
IBM Cloudant 권한이 있는 사용자 및 API

또한 IBM Cloudant API를 사용하여 프로그래밍 방식으로 생성할 수도 있습니다.

보안을 이유로 IBM Cloudant 팀에서는 복제 작업을 위해 계정 레벨 인증 정보가 아닌 IAM API 키 또는 IBM Cloudant 레거시 인증 API 키를 사용할 것을 권장합니다. 자세한 정보는 액세스 관리 또는 레거시 인증권한 부여 문서를 참조하십시오.

양방향 복제

데이터는 양방향 복제 또는 동기화라고 하는 프로세스에서 양방향으로 복사될 수 있습니다. 사용자는 두 개의 개별 복제 프로세스(A에서 B로 데이터를 가져가는 프로세스와 B에서 A로 데이터를 가져가는 프로세스)를 설정하여 이 동기화를 가능하게 합니다. 두 복제 프로세스는 모두 독립적으로 작동하며 데이터가 양방향으로 이동됩니다.

그래픽은 데이터베이스 A와 B를 보여줍니다. 데이터베이스 A에는 4개의 문서가 있고 하나는 줄이 그어져 있습니다. 데이터베이스 B에는 문서가 하나 있습니다. 데이터베이스 A를 데이터베이스 B로 복제하면 데이터베이스 B에는 5개의 문서가 있고 하나는 삭제됩니다. 데이터베이스 b를 데이터베이스 a로 복제한 후, 데이터베이스 a에도 5개의 문서가 있으며 그중 하나는 취소선으로 표시되어 있습니다.
양방향 복제

연속 복제에 대한 논의

지금까지는 모든 소스 데이터가 대상 데이터베이스에 작성되면 완료되는 일회성 복제에 대해 다뤘습니다. 연속 복제를 사용하면 데이터가 지속적으로 이동하게 됩니다. 소스 데이터베이스에 대한 모든 후속 변경사항이 대상 데이터베이스에 실시간으로 전송됩니다.

IBM Cloudant 대시보드에서 복제 작업을 정의할 때 ‘ Make this replication continuous ’ 확인란을 클릭하거나, API에서 continuousIBM Cloudant 플래그를 설정함으로써 트리거됩니다

양방향 복제는 continuous 플래그를 설정하여 단방향 또는 양방향으로 지속되도록 설정할 수 있습니다.

연속 복제를 시작하기 위해 HTTP를 사용하는 예는 다음과 같습니다.

POST /_replicator HTTP/1.1
Content-Type: application/json
Host: $SERVICE_URL
Authorization: ...

지속적 복제를 시작하려면 다음 예제를 참조하십시오:

curl -X POST \
    -H "Content-type: application/json" \
    "$SERVICE_URL/_replicator" \
    -d '{ "_id": "repldoc-example",
          "continuous": true,
          "create_target": true,
          "source": { "url": "'"$SOURCE_SERVICE_URL/source"'" },
          "target": {
            "auth": { "iam": { "api_key": "'"$API_KEY"'" } },
            "url": "'"$TARGET_SERVICE_URL/target"'"
          }
        }'
import com.ibm.cloud.cloudant.v1.Cloudant;
import com.ibm.cloud.cloudant.v1.model.DocumentResult;
import com.ibm.cloud.cloudant.v1.model.PutReplicationDocumentOptions;
import com.ibm.cloud.cloudant.v1.model.ReplicationDatabase;
import com.ibm.cloud.cloudant.v1.model.ReplicationDatabaseAuth;
import com.ibm.cloud.cloudant.v1.model.ReplicationDatabaseAuthIam;
import com.ibm.cloud.cloudant.v1.model.ReplicationDocument;
Cloudant service = Cloudant.newInstance();
ReplicationDatabase sourceDb = new ReplicationDatabase.Builder()
    .url("<your-source-service-url>/source")
    .build();
ReplicationDatabaseAuthIam targetAuthIam =
    new ReplicationDatabaseAuthIam.Builder()
        .apiKey("<your-iam-api-key>")
        .build();
ReplicationDatabaseAuth targetAuth = new ReplicationDatabaseAuth.Builder()
    .iam(targetAuthIam)
    .build();
ReplicationDatabase targetDb = new ReplicationDatabase.Builder()
    .auth(targetAuth)
    .url("<your-target-service-url>/target")
    .build();
ReplicationDocument replDocument = new ReplicationDocument();
replDocument.setSource(sourceDb);
replDocument.setTarget(targetDb);
replDocument.setContinuous(true);
PutReplicationDocumentOptions replicationDocumentOptions =
    new PutReplicationDocumentOptions.Builder()
        .docId("repldoc-example")
        .replicationDocument(replDocument)
        .build();
DocumentResult response =
    service.putReplicationDocument(replicationDocumentOptions).execute()
        .getResult();
System.out.println(response);
const { CloudantV1 } = require('@ibm-cloud/cloudant');
const service = CloudantV1.newInstance({});
const sourceDb: CloudantV1.ReplicationDatabase = {
  url: '<your-source-service-url>/source'
};
const targetDb: CloudantV1.ReplicationDatabase = {
  auth: {
    iam: {
      'api_key': '<your-iam-api-key>'
    }
  },
  url: '<your-target-service-url>/target'
};
const replDocument: CloudantV1.ReplicationDocument = {
  id: 'repldoc-example',
  continuous: true,
  create_target: true,
  source: sourceDb,
  target: targetDb
}
service.putReplicationDocument({
  docId: 'repldoc-example',
  replicationDocument: replDocument
}).then(response => {
  console.log(response.result);
});
from ibmcloudant.cloudant_v1 import CloudantV1, ReplicationDocument, ReplicationDatabase, ReplicationDatabaseAuthIam, ReplicationDatabaseAuth
service = CloudantV1.new_instance()
source_db = ReplicationDatabase(
  url='<your-source-service-url>/source'
)
target_auth_iam = ReplicationDatabaseAuthIam(
  api_key='<your-iam-api-key>'
)
target_auth = ReplicationDatabaseAuth(
  iam=target_auth_iam
)
target_db = ReplicationDatabase(
  auth=target_auth,
  url='<your-target-service-url>/target'
)
replication_document = ReplicationDocument(
  id='repldoc-example',
  continuous=True,
  create_target=True,
  source=source_db,
  target=target_db
)
response = service.put_replication_document(
  doc_id='repldoc-example',
  replication_document=replication_document
).get_result()
print(response)
source, err := service.NewReplicationDatabase(
  "<your-source-service-url>/source",
)
if err != nil {
  panic(err)
}
target, err := service.NewReplicationDatabase(
  "<your-target-service-url>/target",
)
if err != nil {
  panic(err)
}
auth, err := service.NewReplicationDatabaseAuthIam(
  "<your-iam-api-key>",
)
if err != nil {
  panic(err)
}
target.Auth = &cloudantv1.ReplicationDatabaseAuth{Iam: auth}
replicationDoc, err := service.NewReplicationDocument(
  source,
  target,
)
if err != nil {
  panic(err)
}
replicationDoc.Continuous = core.BoolPtr(true)
replicationDoc.CreateTarget = core.BoolPtr(true)
putReplicationDocumentOptions := service.NewPutReplicationDocumentOptions(
  "repldoc-example",
  replicationDoc,
)
documentResult, response, err := service.PutReplicationDocument(putReplicationDocumentOptions)
if err != nil {
  panic(err)
}
b, _ := json.MarshalIndent(documentResult, "", "  ")
fmt.Println(string(b))

이전 Go 예제에서는 다음 가져오기 블록이 필요합니다.

import (
   "encoding/json"
   "fmt"
   "github.com/IBM/cloudant-go-sdk/cloudantv1"
)

모든 Go 예제에서는 service 오브젝트가 초기화되어야 합니다. 자세한 정보는 API 문서 인증 섹션 예제를 참조하십시오.

연속 복제를 정의하는 JSON 문서의 예는 다음과 같습니다.

{
    "_id": "weekly_continuous_backup",
    "source": {
      "url": "https://$SOURCE_SERVICE_DOMAIN/source",
      "auth": {
        "basic": {
          "username": "$USERNAME",
          "password": "$PASSWORD"
        }
      }
    },
    "target": {
      "url": "https://$TARGET_SERVICE_DOMAIN/target",
      "auth": {
        "basic": {
          "username": "$USERNAME",
          "password": "$PASSWORD"
        }
      }
    },
    "continuous": true
}

기타 복제 유스 케이스

IBM Cloudant의 복제 프로토콜은 실제 상황에서의 다양한 활용을 위해 다른 데이터베이스 및 라이브러리와 호환됩니다.

Apache CouchDB

Apache CouchDBIBM Cloudant 와 연동할 수 있으며, 설정 과정이 매우 간단한 오픈 소스 데이터베이스입니다. 다음 애플리케이션이 포함되어 있습니다.

  • 백업 - IBM Cloudant 의 데이터를 사용자의 CouchDB 데이터베이스로 복제하세요 그리고 아카이빙을 위해 매일 밤 데이터의 스냅샷을 생성하십시오. 데이터를 안전하게 보관하기 위해 Amazon Glacier 와 같은 백업 서비스로 전송하십시오.
  • 로컬 우선 데이터 수집 - 데이터를 먼저 로컬 Apache CouchDB 에 기록한 다음, 그런 다음 장기 보관을 위해 IBM Cloudant 에 복제하고, 집계, 및 분석.

PouchDB

PouchDB 브라우저와 IBM Cloudant 간에 데이터를 양방향으로 복제할 수 있는 오픈 소스 브라우저 내 데이터베이스입니다. 클라이언트 측의 웹 브라우저에 데이터를 저장하면 인터넷 연결 없이도 웹 애플리케이션이 작동할 수 있습니다. PouchDB는 인터넷 연결이 있는 경우 IBM Cloudant와의 사이에 변경된 데이터를 동기화할 수 있습니다. 클라이언트 측에서 복제를 설정하려면 JavaScript 코드 행이 필요합니다.

복제를 사용으로 설정하기 위해 PouchDB를 사용하는 JavaScript 예는 다음과 같습니다.

var db = new PouchDB("myfirstdatabase");
var URL = "https://$USERNAME:$PASSWORD@$SERVICE_DOMAIN/my_database");
db.sync(URL, { live: true });

필터링된 복제

다음 예제와 같이 하나의 데이터베이스를 다른 데이터베이스에 복제할 때 복제 프로세스 중에 일부 데이터를 제거할 수 있을 경우 유용합니다.

  • 삭제된 문서의 모든 흔적을 제거하면 대상 데이터베이스의 크기가 소스보다 작아집니다.
  • 데이터를 더 작은 단위로 나누는 것, 예를 들어 영국 데이터는 한 데이터베이스에, 미국 데이터는 다른 데이터베이스에 저장하는 것과 같은 방식입니다.

복제 필터 기능

IBM Cloudant의 필터링된 복제를 통해 데이터베이스의 각 문서를 필터링할지 결정하기 위해 리턴값을 사용하는 JavaScript 함수를 정의할 수 있습니다. 필터 함수디자인 문서에 저장됩니다.

삭제되지 않은 문서를 복제하는 필터 함수 예는 다음과 같습니다.

function(doc, req) {
    if (doc._deleted) {
        return false;
    }
    return true;
}

복제 작업이 시작되면, 필터 함수의 이름이 해당 함수가 저장된 디자인 문서와 해당 필터 함수 이름의 조합으로 지정됩니다. query_params 값을 지정할 수도 있습니다. 이 값은 필터 함수에 전달되는 특성을 포함하는 오브젝트이며, 이는 함수의 두 번째(query) 인수의 req 필드에서 전달됩니다.

필터링된 복제를 시작하기 위해 HTTP를 사용하는 예는 다음과 같습니다.

POST /_replicator HTTP/1.1
Content-Type: application/json
Host: $SERVICE_URL
Authorization: ...

필터링된 복제를 시작하기 위해 명령행을 사용하는 예는 다음과 같습니다.

curl -X POST \
    -H "Content-type: application/json" \
    "$SERVICE_URL/_replicator" \
    -d @filtered-replication.json
import com.ibm.cloud.cloudant.v1.Cloudant;
import com.ibm.cloud.cloudant.v1.model.DocumentResult;
import com.ibm.cloud.cloudant.v1.model.PutReplicationDocumentOptions;
import com.ibm.cloud.cloudant.v1.model.ReplicationDatabase;
import com.ibm.cloud.cloudant.v1.model.ReplicationDatabaseAuth;
import com.ibm.cloud.cloudant.v1.model.ReplicationDatabaseAuthIam;
import com.ibm.cloud.cloudant.v1.model.ReplicationDocument;
Cloudant service = Cloudant.newInstance();
ReplicationDatabase sourceDb = new ReplicationDatabase.Builder()
    .url("<your-source-service-url>/source")
    .build();
ReplicationDatabaseAuthIam targetAuthIam =
    new ReplicationDatabaseAuthIam.Builder()
        .apiKey("<your-iam-api-key>")
        .build();
ReplicationDatabaseAuth targetAuth = new ReplicationDatabaseAuth.Builder()
    .iam(targetAuthIam)
    .build();
ReplicationDatabase targetDb = new ReplicationDatabase.Builder()
    .auth(targetAuth)
    .url("<your-target-service-url>/target"))
    .build();
ReplicationDocument replDocument = new ReplicationDocument();
replDocument.setSource(sourceDb);
replDocument.setTarget(targetDb);
replDocument.setFilter("mydesigndoc/myfilter");
Map queryParams = new HashMap<>();
queryParams.put("foo", "bar");
queryParams.put("baz", 5);
replDocument.setQueryParams(queryParams);
PutReplicationDocumentOptions replicationDocumentOptions =
    new PutReplicationDocumentOptions.Builder()
        .docId("repldoc-example")
        .replicationDocument(replDocument)
        .build();
DocumentResult response =
    service.putReplicationDocument(replicationDocumentOptions).execute()
        .getResult();
System.out.println(response);
const { CloudantV1 } = require('@ibm-cloud/cloudant');
const service = CloudantV1.newInstance({});
const sourceDb: CloudantV1.ReplicationDatabase = {
  url: '<your-source-service-url>/source'
};
const targetDb: CloudantV1.ReplicationDatabase = {
  auth: {
    iam: {
      'api_key': '<your-iam-api-key>'
    }
  },
  url: '<your-target-service-url>/target'
};
const replDocument: CloudantV1.ReplicationDocument = {
  id: 'repldoc-example',
  filter: 'mydesigndoc/myfilter',
  query_params: {'foo': 'bar', 'baz': 5},
  source: sourceDb,
  target: targetDb
}
service.putReplicationDocument({
  docId: 'repldoc-example',
  replicationDocument: replDocument
}).then(response => {
  console.log(response.result);
});
from ibmcloudant.cloudant_v1 import CloudantV1, ReplicationDocument, ReplicationDatabase, ReplicationDatabaseAuthIam, ReplicationDatabaseAuth
service = CloudantV1.new_instance()
source_db = ReplicationDatabase(
  url='<your-source-service-url>/source'
)
target_auth_iam = ReplicationDatabaseAuthIam(
  api_key='<your-iam-api-key>'
)
target_auth = ReplicationDatabaseAuth(
  iam=target_auth_iam
)
target_db = ReplicationDatabase(
  auth=target_auth,
  url='<your-target-service-url>/target'
)
replication_document = ReplicationDocument(
  id='repldoc-example',
  filter='mydesigndoc/myfilter',
  query_params={'foo': 'bar', 'baz': 5},
  source=source_db,
  target=target_db
)
response = service.put_replication_document(
  doc_id='repldoc-example',
  replication_document=replication_document
).get_result()
print(response)
source, err := service.NewReplicationDatabase(
  "<your-source-service-url>/source",
)
if err != nil {
  panic(err)
}
target, err := service.NewReplicationDatabase(
  "<your-target-service-url>/target",
)
if err != nil {
  panic(err)
}
auth, err := service.NewReplicationDatabaseAuthIam(
  "<your-iam-api-key>",
)
if err != nil {
  panic(err)
}
target.Auth = &cloudantv1.ReplicationDatabaseAuth{Iam: auth}
replicationDoc, err := service.NewReplicationDocument(
  source,
  target,
)
if err != nil {
  panic(err)
}
replicationDoc.Filter := "mydesigndoc/myfilter"
replicationDoc.QueryParams := map[string]interface{}{"foo": "bar", "baz": 5}
putReplicationDocumentOptions := service.NewPutReplicationDocumentOptions(
  "repldoc-example",
  replicationDoc,
)
documentResult, response, err := service.PutReplicationDocument(putReplicationDocumentOptions)
if err != nil {
  panic(err)
}
b, _ := json.MarshalIndent(documentResult, "", "  ")
fmt.Println(string(b))

이전 Go 예제에서는 다음 가져오기 블록이 필요합니다.

import (
   "encoding/json"
   "fmt"
   "github.com/IBM/cloudant-go-sdk/cloudantv1"
   "github.com/IBM/go-sdk-core/core"
)

모든 Go 예제에서는 service 오브젝트가 초기화되어야 합니다. 자세한 정보는 API 문서 인증 섹션 예제를 참조하십시오.

필터링된 복제를 정의하는 JSON 문서의 예는 다음과 같습니다.

{
    "_id": "weekly_backup",
    "source": {
      "url": "https://$SOURCE_SERVICE_DOMAIN/source",
      "auth": {
        "basic": {
          "username": "$USERNAME",
          "password": "$PASSWORD"
        }
      }
    },
    "target": {
      "url": "https://$TARGET_SERVICE_DOMAIN/target",
      "auth": {
        "basic": {
          "username": "$USERNAME",
          "password": "$PASSWORD"
        }
      }
    },
    "filter": "mydesigndoc/myfilter",
    "query_params": {
        "foo": "bar",
        "baz": 5
    }
}

변경사항 피드

IBM Cloudant는 _changes 엔드포인트로부터의 단일 HTTP 피드를 통해 데이터베이스에 영향을 주는 추가, 편집 및 삭제 항목을 공개합니다. 사용자의 애플리케이션은 이 피드를 사용하여 이벤트를 트리거할 수 있습니다. 사용자는 예에 표시된 바와 같이 HTTP 또는 curl을 사용하여 이 피드에 액세스할 수 있습니다. feed=continuous 옵션 사용은 스트림이 데이터베이스에 있는 모든 문서의 최신 버전을 가져오기 위해 필요한 모든 변경사항을 제공함을 의미합니다.

자세한 정보는 IBM Cloudant 변경 피드 사용 FAQ를 참조하십시오.

변경사항 피드를 조회하기 위해 HTTP를 사용하는 예는 다음과 같습니다.

GET /$DATABASE/_changes?feed=continuous HTTP/1.1
Host: $SERVICE_URL
Authorization: ...

변경사항 피드를 조회하기 위해 명령행을 사용하는 예는 다음과 같습니다.

curl "$SERVICE_URL/$DATABASE/_changes?feed=continuous"

변경사항은 각 변경사항마다 하나의 행을 사용하여 표시됩니다. 각 변경사항은 다음 항목으로 구성됩니다.

  1. 순서 번호(seq)를 포함하는 문자열
  2. 변경된 문서의 ID를 포함하는 문자열
  3. 변경사항의 배열

문서 본문 자체를 보려면 curl 명령에 &include_docs=true를 추가하십시오.

각 변경사항은 다음 예(축약됨)에 표시된 형식을 사용하여 표시됩니다.

_changes 피드의 예는 다음과 같습니다.

{
    "seq":"11-g1A...c1Q",
    "id":"6f8ab9fa52c117eb76240daa1a55827f",
    "changes":[
        {
          "rev":"1-619d7981d7027274a4b88810d318a7b1"
        }
    ]
}

알려진 위치부터 변경사항 피드를 결합하려면 시작할 순서 번호와 함께 since 인수를 전달하십시오.

알려진 위치의 since 피드와 결합하기 위해 HTTP를 사용하여 _changes 옵션을 제공하는 예(축약됨)는 다음과 같습니다.

GET /$DATABASE/_changes?feed=continuous&include_docs=true&since=11-g1A...c1Q HTTP/1.1
HOST: $SERVICE_URL
Authorization: ...

알려진 위치의 since 피드와 결합하기 위해 명령행을 사용하여 _changes 옵션을 제공하는 예(축약됨)는 다음과 같습니다.

curl "$SERVICE_URL/$DATABASE/_changes?feed=continuous&include_docs=true&since=11-g1A...c1Q"

현재 시간의 변경사항 피드와 다시 결합하려면 since=now를 설정하십시오.

현재 시간의 since=now 피드와 결합하기 위해 HTTP를 사용하여 _changes를 제공하는 예는 다음과 같습니다.

GET /$DATABASE/_changes?feed=continuous&include_docs=true&since=now HTTP/1.1
Host: $SERVICE_URL
Authorization: ...

현재 시간의 since=now 피드와 결합하기 위해 명령행을 사용하여 _changes를 제공하는 예는 다음과 같습니다.

curl "$SERVICE_URL/$DATABASE/_changes?feed=continuous&include_docs=true&since=now"

_changes 데이터에 대한 프로그래밍 방식의 액세스는 직관적입니다. 예를 들어 의 SDK 예제를 참조하여 IBM Cloudant API docs 의 SDK 예제를 참조하여 몇 줄의 코드로 변경 사항을 따르세요.

다음 목록에는 몇 가지 유스 케이스 예가 포함되어 있습니다.

  • 고객 이메일 발송과 같은 애플리케이션 내 조치를 트리거하기 위해 메시지 큐에 항목을 추가합니다.
  • 실시간 활동 수를 기록하기 위해 인메모리 데이터베이스를 업데이트합니다.
  • SQL 데이터베이스에 데이터를 전송하기 위해 텍스트 파일에 데이터를 기록합니다.

변경사항 피드는 복제 중 필터링과 유사한 기법을 사용하여, 필터 함수를 사용해 필터링할 수 있습니다.

변경사항 피드를 필터링하기 위해 HTTP를 사용하는 예는 다음과 같습니다.

GET /$DATABASE/_changes?feed=continuous&include_docs=true&since=now&filter=mydesigndoc/myfilter HTTP/1.1
Host: $SERVICE_URL
Authorization: ...

변경사항 피드를 필터링하기 위해 명령행을 사용하는 예는 다음과 같습니다.

curl "$SERVICE_URL/$DATABASE/_changes?feed=continuous&include_docs=true&since=now&filter=mydesigndoc/myfilter"

_changes 피드 내 문서의 순서 지정이 항상 동일하지는 않습니다. 즉, 변경사항이 정확한 시간 순서대로 표시되지 않을 수 있습니다. 이는 데이터가 여러 IBM Cloudant 노드로부터 리턴되며 결과적으로 일관성 규칙이 적용되기 때문입니다.

복제의 위험성

복제에 성공하려면 문서 크기와 모든 첨부 파일 크기의 합이 대상 클러스터의 최대 요청 크기보다 작아야 합니다. 예를 들어, 최대 HTTP 요청 크기가 11MB인 경우 다음 시나리오가 적용됩니다.

HTTP 요청의 최대 크기인 11MB를 기준으로 한 다양한 시나리오
문서 크기 첨부 파일 크기 총 크기 복제 여부
1MB 다섯 개의 2MB 첨부 파일 11MB
1MB 한 개의 10MB 첨부 파일 11MB
1MB 백 개의 1MB 첨부 파일 101 MB 아니오

복제를 사용할 때는 몇 가지 사항을 고려해야 합니다.

올바르지 않은 사용자 권한

데이터베이스 "a"에서 데이터베이스 "b"로 복제할 때 복제가 최적의 상태로 진행되도록 하려면 제공되는 인증 정보에 다음 항목이 포함되어 있어야 합니다.

  • 데이터베이스 "a"의 _reader_replicator 권한
  • 데이터베이스 "b"의 _writer 권한.

API 키는 IBM Cloudant 대시보드에서 또는 API 를 통해 생성됩니다. 각각의 키에는 특정 IBM Cloudant 데이터베이스와 관련된 개별 권한을 부여할 수 있습니다. IBM Cloudant는 복제 작업 중 "읽기" 부분에서 자신의 체크포인트 문서를 쓸 수 있어야 하며, 그렇지 않으면 상태가 저장되지 않아 복제를 중지된 지점에서 재개할 수 없게 됩니다. 상태가 저장되지 않은 경우에는 대형 데이터 세트의 복제가 재개되는 경우 성능 문제가 발생할 수 있습니다. 이는 체크포인트가 없는 경우 복제 프로세스가 재개될 때마다 처음부터 다시 시작하기 때문입니다.

복제 문서 충돌

사용자 권한을 잘못 설정하여 발생하는 또 다른 결과는 _replicator 문서의 충돌입니다. _replicator 문서는 복제 프로세스의 현재 상태를 기록합니다. 극단적인 경우에는 해결되지 않은 충돌이 다수 포함되어 문서가 매우 커질 수 있습니다. 이렇게 커진 문서는 사용 가능한 공간을 많이 사용하며 추가적인 서버 로드를 발생시킵니다.

_replicator 요청을 GET 엔드포인트에 전송하여 /_replicator 데이터베이스의 크기를 확인할 수 있습니다.

curl "$SERVICE_URL/_replicator"
import com.ibm.cloud.cloudant.v1.Cloudant;
import com.ibm.cloud.cloudant.v1.model.DatabaseInformation;
import com.ibm.cloud.cloudant.v1.model.GetDatabaseInformationOptions;
Cloudant service = Cloudant.newInstance();
GetDatabaseInformationOptions databaseInfoOptions =
    new GetDatabaseInformationOptions.Builder()
        .db("_replicator")
        .build();
DatabaseInformation response =
    service.getDatabaseInformation(databaseInfoOptions).execute()
        .getResult();
System.out.println(response);
const { CloudantV1 } = require('@ibm-cloud/cloudant');
const service = CloudantV1.newInstance({});
service.getDatabaseInformation({db: '_replicator'}).then(response => {
  console.log(response.result);
});
from ibmcloudant.cloudant_v1 import CloudantV1
service = CloudantV1.new_instance()
response = service.get_database_information(db='_replicator').get_result()
print(response)
getDatabaseInformationOptions := service.NewGetDatabaseInformationOptions(
  "_replicator",
)
databaseInformation, response, err := service.GetDatabaseInformation(getDatabaseInformationOptions)
if err != nil {
  panic(err)
}
b, _ := json.MarshalIndent(databaseInformation, "", "  ")
fmt.Println(string(b))

이전 Go 예제에서는 다음 가져오기 블록이 필요합니다.

import (
   "encoding/json"
   "fmt"
   "github.com/IBM/cloudant-go-sdk/cloudantv1"
)

모든 Go 예제에서는 service 오브젝트가 초기화되어야 합니다. 자세한 정보는 API 문서 인증 섹션 예제를 참조하십시오.

복제 문서에서 충돌 가져오기

리턴되는 JSON에서 disk_size 값을 찾으십시오. I값이 1GB이상의 크기를 표시하는 경우 IBM Cloud 지원 포털 로 이동하여 추가적인 조언을 얻을 수 있습니다.

다음 예에 표시된 바와 같이 개별 _replicator 문서의 충돌 여부를 확인할 수 있습니다.

curl "$SERVICE_URL/_replicator/$DOCID?conflicts=true"
import com.ibm.cloud.cloudant.v1.Cloudant;
import com.ibm.cloud.cloudant.v1.model.GetReplicationDocumentOptions;
import com.ibm.cloud.cloudant.v1.model.ReplicationDocument;
Cloudant service = Cloudant.newInstance();
GetReplicationDocumentOptions replicationDocOptions =
    new GetReplicationDocumentOptions.Builder()
        .conflicts(true)
        .docId("$DOCID")
        .build();
ReplicationDocument response =
    service.getReplicationDocument(replicationDocOptions).execute()
        .getResult();
System.out.println(response);
const { CloudantV1 } = require('@ibm-cloud/cloudant');
const service = CloudantV1.newInstance({});
service.getReplicationDocument({
  conflicts: true,
  docId: '$DOCID'
}).then(response => {
  console.log(response.result);
});
from ibmcloudant.cloudant_v1 import CloudantV1
service = CloudantV1.new_instance()
response = service.get_replication_document(
  conflicts=True,
  doc_id='$DOCID'
).get_result()
print(response)
getReplicationDocumentOptions := service.NewGetReplicationDocumentOptions(
  "$DOCID",
)
replicationDocument, response, err := service.GetReplicationDocument(getReplicationDocumentOptions)
if err != nil {
  panic(err)
}
replicationDocument.Conflicts = core.BoolPtr(true)
b, _ := json.MarshalIndent(replicationDocument, "", "  ")
fmt.Println(string(b))

이전 Go 예제에서는 다음 가져오기 블록이 필요합니다.

import (
   "encoding/json"
   "fmt"
   "github.com/IBM/cloudant-go-sdk/cloudantv1"
   "github.com/IBM/go-sdk-core/core"
)

모든 Go 예제에서는 service 오브젝트가 초기화되어야 합니다. 자세한 정보는 API 문서 인증 섹션 예제를 참조하십시오.

모든 복제 취소

모든 복제를 취소하고 깨끗한 새 _replicator 데이터베이스를 시작하려면 replicator 데이터베이스를 삭제한 후 다시 작성하십시오.

_replicator 데이터베이스를 삭제하고 다시 생성하려면 다음 링크( HTTP )를 참조하십시오:

DELETE /_replicator HTTP/1.1
HOST: $SERVICE_URL
Authorization: ...
PUT /_replicator HTTP/1.1
HOST: $SERVICE_URL
Authorization: ...

리플리케이터 데이터베이스 삭제

_replicator 데이터베이스를 제거하려면 다음 예제를 참조하세요:

curl -X DELETE "$SERVICE_URL/_replicator"
import com.ibm.cloud.cloudant.v1.Cloudant;
import com.ibm.cloud.cloudant.v1.model.DeleteDatabaseOptions;
import com.ibm.cloud.cloudant.v1.model.Ok;
Cloudant service = Cloudant.newInstance();
DeleteDatabaseOptions deleteDatabaseOptions = new DeleteDatabaseOptions.Builder()
        .db("_replicator")
        .build();
Ok response = service.deleteDatabase(deleteDatabaseOptions).execute()
        .getResult();
System.out.println(response);
const { CloudantV1 } = require('@ibm-cloud/cloudant');
const service = CloudantV1.newInstance({});
service.deleteDatabase({db: '_replicator'}).then(response => {
  console.log(response.result);
});
from ibmcloudant.cloudant_v1 import CloudantV1
service = CloudantV1.new_instance()
response = service.delete_database(db='_replicator').get_result()
print(response)
deleteDatabaseOptions := service.NewDeleteDatabaseOptions(
  "_replicator",
)
ok, response, err := service.DeleteDatabase(deleteDatabaseOptions)
if err != nil {
  panic(err)
}
b, _ := json.MarshalIndent(ok, "", "  ")
fmt.Println(string(b))

이전 Go 예제에서는 다음 가져오기 블록이 필요합니다.

import (
   "encoding/json"
   "fmt"
   "github.com/IBM/cloudant-go-sdk/cloudantv1"
)

모든 Go 예제에서는 service 오브젝트가 초기화되어야 합니다. 자세한 정보는 API 문서 인증 섹션 예제를 참조하십시오.

리플리케이터 데이터베이스 다시 만들기

_replicator 데이터베이스를 다시 만들려면 다음 예제를 참조하세요:

curl -X PUT "$SERVICE_URL/_replicator"
import com.ibm.cloud.cloudant.v1.Cloudant;
import com.ibm.cloud.cloudant.v1.model.Ok;
import com.ibm.cloud.cloudant.v1.model.PutDatabaseOptions;
Cloudant service = Cloudant.newInstance();
PutDatabaseOptions databaseOptions = new PutDatabaseOptions.Builder()
    .db("_replicator")
    .build();
Ok response =
    service.putDatabase(databaseOptions).execute()
        .getResult();
System.out.println(response);
const { CloudantV1 } = require('@ibm-cloud/cloudant');
const service = CloudantV1.newInstance({});
service.putDatabase({
  db: '_replicator'
}).then(response => {
  console.log(response.result);
});
from ibmcloudant.cloudant_v1 import CloudantV1
service = CloudantV1.new_instance()
response = service.put_database(db='_replicator').get_result()
print(response)
putDatabaseOptions := service.NewPutDatabaseOptions(
  "_replicator",
)
ok, response, err := service.PutDatabase(putDatabaseOptions)
if err != nil {
  panic(err)
}
b, _ := json.MarshalIndent(ok, "", "  ")
fmt.Println(string(b))

이전 Go 예제에서는 다음 가져오기 블록이 필요합니다.

import (
   "encoding/json"
   "fmt"
   "github.com/IBM/cloudant-go-sdk/cloudantv1"
)

모든 Go 예제에서는 service 오브젝트가 초기화되어야 합니다. 자세한 정보는 API 문서 인증 섹션 예제를 참조하십시오.

다수의 동시 복제

이전에 두 데이터베이스 간에 복제를 설정한 것을 잊어버려 실수로 추가 복제 프로세스를 작성하는 경우가 종종 발생합니다. 각 복제 작업은 서로 독립되어 있으며, 따라서 IBM Cloudant는 사용자가 추가 복제 프로세스를 작성하는 것을 막지 않습니다. 그러나 각 복제 태스크는 시스템 리소스를 사용합니다.

IBM Cloudant 대시보드에서 "활성 복제"를 확인하여 원치 않는 복제 태스크가 진행 중인지 확인할 수 있습니다. 더 이상 필요하지 않은 _replicator 문서는 삭제하십시오.

복제 속도 조정

By default, IBM Cloudant 복제는 적절한 비율로 실행되어 성능에 부정적인 영향을 주지 않고 소스에서 대상으로 데이터를 가져옵니다. 복제 속도와 다른 태스크를 위한 클러스터 성능은 양립할 수 없습니다. 다른 IBM Cloudant 서비스의 성능이 떨어지는 것을 감수하고 더 빠른 복제를 수행해야 하는 유스 케이스가 있을 수 있습니다. 또는, 복제를 백그라운드 프로세스로 취급하여 클러스터 성능을 우선해야 하는 경우도 있을 수 있습니다.

고급 복제 API 옵션을 사용할 수 있습니다. 이러한 옵션은 다음 예제에 표시된 것과 같이 복제 중에 사용되는 컴퓨팅 기능의 양을 늘리거나 줄일 수 있습니다.

  • 문서에 첨부 파일이 포함되어 있는 경우에는 batch_size를 줄이고 worker_processes를 늘려 일괄처리의 양을 줄이고 더 큰 문서를 처리할 수 있도록 설정할 수 있습니다.
  • 작은 문서가 많은 경우에는 worker_processhttp_connections 값을 늘릴 수 있습니다.
  • 성능에 대한 영향을 최소화하면서 복제를 실행하려면 worker_processeshttp_connections를 1로 설정하는 것이 적절합니다.
  • 자세한 내용은 복제에 의한 읽기 및 쓰기 작업의 소비를 참조하세요.

유스 케이스에 대한 최상의 구성에 대한 추가 지원을 받으려면 IBM Cloud 지원 포털로 이동하십시오.

"use_bulk_get": true" 복제 옵션을 활성화하면 복제 성능을 향상시킬 수 있습니다. 이 경우 리플리케이터는 소스에서 문서를 개별적으로 가져오지 않고 일괄적으로 가져옵니다.

{
  "_id": "rep_doc_id",
  "source": "https://account1.cloudant.com/db1",
  "target": "https://account2.cloudant.com/db2",
  "use_bulk_get": true
}

복제 속도가 증가하면 소스 및 대상 엔드포인트 계정에서 사용 가능한 읽기 또는 쓰기 속도 용량이 소모될 수 있습니다.

복제를 통해 충돌하는 문서 수정본 제거하기

복제를 통해 충돌하는 문서 수정본을 제거하는 한 가지 방법은 "winning_revs_only": true 옵션을 활성화하는 것입니다. 이 옵션은 우승한 문서 수정본만 복제합니다. 이는 GET $SERVICE_URL/$DATABASE/$DOCID 요청에 의해 기본적으로 반환되는 수정본입니다. 이 옵션은 충돌하는 문서 수정본을 삭제하므로 고급 옵션입니다. 이 옵션을 사용할 때는 주의하십시오.