IBM Cloud Docs
什么是复制?

什么是复制?

将数据从一个数据库复制到另一个数据库可以在同一 IBM® Cloudant® for IBM Cloud® 帐户内执行,也可以跨帐户和跨数据中心执行。

甚至可以使用 IBM Cloudant SyncPouchDB将数据复制到 IBM Cloudant 帐户和移动设备以及从中复制数据。 复制可以单向或双向进行、 单次 "或连续运行、 并可通过参数进行微调。

IBM Cloudant 的复制协议与一系列其他数据库和库相兼容,因此非常适合物联网 (IoT) 和移动应用程序。

IBM Cloudant 是一个具有 HTTP API 的分布式 JSON 数据存储。 IBM Cloudant 可以在多种云上或在服务器机架中作为服务运行。 文档存储在数据库中,随着 IBM Cloudant 跨多个节点对数据分片,文档可增大到任意大小。 复制是将数据从源数据库复制到目标数据库的过程。 源数据库和目标数据库不需要位于同一 IBM Cloudant 帐户上,甚至不需要位于同一数据中心。

此图显示数据库 a 和 b 的图片。 数据库 b 有一个文档。 复制后,数据库 a 中的文档将显示在数据库 b 中。
Replication in pictures

源数据库中每个文档的最新版本传输到目标数据库后,复制即完成。 传输包含新文档、对现有文档的更新以及删除项。 复制后仅保留文档的最新版本; 将省略旧版本。

复制不会改变源数据库,只是会向其写入检查点数据,以允许部分复制从最后一个已知位置恢复。 目标数据库中预先存在的所有数据都会保留。

如何开始使用仪表板进行复制

IBM Cloudant“仪表板”提供了一个用户界面,可方便地触发复制。 在 IBM Cloudant 仪表板上单击 Replication,然后单击 Start Replication。 完成以下复制表单:

此截屏显示填写了所有正确字段的复制表单。 有一个源部分是本地数据库,还有一个目标部分是新数据库和认证。 在“选项”部分中,选择一次复制或重复,然后添加复制文档。
Replication form

出于安全考虑,"IBM Cloudant团队建议您使用 IAM API 密钥或 "IBM Cloudant传统身份验证 "API 密钥,而不是复制作业的账户级凭证。 有关更多信息,请参阅 管理访问权 或旧的 认证授权 文档。

使用该表单定义源数据库和目标数据库,然后单击Start Replication

点击 "Replication 可查看每个复制任务的状态。 随着每个作业的进展,其状态将从 Running更改为Completed。 下面的屏幕截图显示了 "Completed 状态。

在表中的“状态”字段下,您将看到“已完成”。
Completed state

如何跨不同 IBM Cloudant 帐户进行复制

复制的源和目标是 IBM Cloudant 数据库的 URL,如以下示例所示。

请参阅定义用于复制的源 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. 这些更改对文档发生影响的顺序在数据库的不同副本之间可能不同,具体取决于执行复制的时间和位置。

第一个特征的一个结果是,请求更改列表时,请求特定时间点之后的更改列表没有意义。 原因是更改列表可能由不同的数据库副本提供,从而产生不同时间的文档更新。 但是,请求特定更改(通过使用序列标识来指定)之后的更改列表 有意义的。

第一个特点的另一个后果是 可能有必要“回顾”之前的修改,以便就修改清单达成一致意见。 换言之,要获取更改列表,您将从数据库副本达成一致的最新更改开始。 数据库副本之间的协议点在 IBM Cloudant 通过使用 检查点 机制,使数据库副本之间的复制能够同步。

最后,当您查看更改列表时,这些更改可能会在后续请求中以不同的顺序显示。 顺序取决于文档在不同数据库副本之间的更改方式。 换言之,更改的初始列表可能会报告更改 AB,然后按该顺序显示 C。 但是,后续更改列表可能会报告更改 CA,然后按该顺序显示 B。 所有更改都会列出,但顺序不同。 造成这种差异的原因是,在复制期间数据库两个不同副本收到更改的顺序可能不同。

最终一致性 "对变更清单意味着什么?

请求更改列表时,获得的响应可能会有所不同,具体取决于是哪个数据库副本提供该列表。

since 选项获取特定更新序列标识后的更改列表。 列表始终包含更新后的更改,但也可能包含更新前的更改。 原因是对列表请求作出响应的数据库副本必须确保自己列出与所有副本一致的更改。 为了实现这种一致性,数据库副本可能必须使更改列表从所有副本达成一致的点开始。 此点通过使用检查点进行确定。

因此、 使用 "_changes 的应用程序必须是 是 "empotent "的。 闲置性是指应用程序必须能够安全地多次接收相同的数据、 而且在重复请求时有可能以不同的顺序接收。

检查点

在内部,复制过程会将其状态写入存储在源数据库和目标数据库中的“检查点”文档中。 检查点允许从其停止的位置恢复复制任务,而不必从头开始。 可以通过提供 请求复制时的 "use_checkpoints": false 选项。 如果复制要从最后一个已知位置高效地恢复,那么使此功能保持开启非常有用。

许可权

要将文档插入到 _replicator 数据库中,需要管理访问权。 在 source 和 target 参数中提供的登录凭证不需要完全管理许可权。 如果凭证执行以下任务就足够了:

  • 在目标端写入文档。
  • 在两端写入检查点文档。

IBM Cloudant 具有特殊的 _replicator 用户许可权。 此许可权允许创建检查点文档,但不允许在数据库中创建普通文档。 通常, 创建符合以下条件的 API 密钥

  • 具有对源端的 _reader_replicator 访问权。
  • 具有对目标端的 _reader_writer 访问权。

可以在 IBM Cloudant“仪表板”中逐个数据库创建和配置 API 密钥。

API keys can be created and configured within the IBM Cloudant Dashboard, on a per-database basis.
IBM Cloudant users and API keys with permissions

也可使用IBM CloudantAPI 以编程方式 创建。API 创建。

出于安全考虑,"IBM Cloudant团队建议您使用 IAM API 密钥或 "IBM Cloudant传统身份验证 "API 密钥,而不是复制作业的账户级凭证。 有关更多信息,请参阅 管理访问权 或旧的 认证授权 文档。

双向复制

可以在一个过程中双向复制数据,此过程称为双向复制或同步。 您可通过设置两个单独的复制过程来启用此同步:一个过程将数据从 A 复制到 B,另一个过程将数据从 B 复制到 A。 这两个复制过程独立运行,数据在两个方向无缝移动。

此图显示数据库 a 和 b。 数据库 a 有四个文档,一个文档被划掉。 数据库 b 有一个文档。 将数据库 a 复制到数据库 b 后,数据库 b 有五个文档,一个文档被划掉。 将数据库 b 复制到数据库 a 后,数据库 a 还有五个文档,一个被划掉。
双向复制

关于持续复制的讨论

到目前为止,讨论仅涉及的是单次复制,它在所有源数据都写入目标数据库之后即完成。 通过持续复制,数据可持续流动。 对源数据库的所有后续更改都将实时传输到目标数据库。

在IBM Cloudant中定义复制任务时,单击“Make this replication continuous 复选框即可触发连续复制。控制面板、 或在IBM CloudantAPI 中设置”continuous标记。API 中设置 "code2 "标志。

通过设置 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 CouchDB是一个开放源码数据库 可以与 "IBM Cloudant通信、 只需极少的设置。 包括以下应用程序:

  • 备份 - 将数据从IBM Cloudant复制到您自己的CouchDB数据库。 中的数据复制到您自己的 CouchDB 数据库,并每晚拍摄数据快照用于归档。 将数据发送到备份服务,如 Amazon Glacier 等备份服务。
  • 本地优先数据收集 - 先将数据写入本地Apache CouchDB、 然后复制到IBM Cloudant进行长期存储、 聚合、 和分析。

PouchDB

PouchDB是一个开源的浏览器内数据库、 是一个开放源码的浏览器内数据库,可在浏览器和 "IBM Cloudant之间双向复制数据。 通过在客户端的 Web 浏览器中存储数据,Web 应用程序可以在没有因特网连接的情况下运行。 当有互联网连接时,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 通过单个 HTTP 订阅源从 _changes 端点发布影响数据库的添加、编辑和删除操作。 应用程序可以使用此订阅源来触发事件。 您可以使用 HTTP 或 curl(如示例中所示)来访问订阅源。 使用 feed=continuous 选项意味着流会提供获取数据库中每个文档最新版本所需的每个更改。

有关更多信息,请参阅 使用 IBM Cloudant 更改订阅源常见问题解答

请参阅以下使用 HTTP 来查询更改订阅源的示例:

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

请参阅以下使用命令行来查询更改订阅源的示例:

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

描述更改时,每个更改一行。 每个更改由以下部分组成:

  1. 包含序号 (seq) 的字符串。
  2. 包含已更改文档的标识的字符串。
  3. 更改数组。

要查看文档主体本身,请将 &include_docs=true 附加到 curl 命令。

使用以下示例(缩略版)中显示的格式来描述每个更改。

请参阅以下示例 _changes 订阅源:

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

要从已知位置连接 changes 订阅源,请传递 since 自变量以及要从其开始的序号。

请参阅下面的示例(缩写),该示例使用 HTTP 提供“since 选项,在已知位置加入”_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"

要在此刻重新连接 changes 订阅源,请设置 since=now

请参阅下面的示例,该示例使用 HTTP 提供“since=now,以便在当前时刻加入”_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 数据十分简单。 例如,请参阅 IBM Cloudant API 文档 中的 SDK 示例,以遵循带有几行代码的更改。

以下列表包含一些示例用例:

  • 将项添加到消息队列以触发应用程序中的操作,例如发送客户电子邮件。
  • 更新内存中的数据库以记录活动的实时计数。
  • 将数据写入文本文件以将数据推送到 SQL 数据库。

changes 订阅源可以通过类似于在复制期间过滤的方法,使用过滤函数进行过滤。

请参阅以下使用 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 请求大小为 11 MB,那么以下场景适用:

基于最大 HTTP 请求大小的各种方案 11 MB
文档大小 附件大小 总大小 是否复制?
1 MB 5 个 2 MB 的附件 11 MB
1 MB 1 个 10 MB 的附件 11 MB
1 MB 100 个 1 MB 的附件 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 值。 如果该值指示大小超过 1 GB,请转至 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 数据库。

请参阅以下 HTTP 以除去并重新创建 _replicator 数据库:

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 请求返回的修订版。 此选项是高级选项,因为它会废弃有冲突的文档修订版。 谨慎使用该选项。