什麼是抄寫?

可以在相同的 IBM® Cloudant® for IBM Cloud® 帳戶中、跨帳戶以及跨資料中心,將資料從某個資料庫複製到另一個資料庫。

IBM Cloudant 甚至可以透過 使用 PouchDB。 複製作業可單向或雙向進行, 可作為「單次」或「持續」操作, 並可透過參數進行精細調整。

IBM Cloudant 的抄寫通訊協定與某範圍的其他資料庫及程式庫相容,使其最適用於 Internet of Things (IoT) 及行動應用程式。

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,方法是使用 checkpoint 機制來同步化資料庫副本之間的抄寫。

最後,當您查看變更清單時,在後續要求中可能會以不同的順序呈現它們。 此順序視文件在不同資料庫副本之間的變更方式而定。 換句話說,起始變更清單可能會以 ABC 這個順序報告變更。 但是,後續的變更清單可能會以 CAB 這個順序報告變更。 所有變更都會列出,但順序不同。 這項差異的原因是,抄寫期間所收到的一系列變更在資料庫的兩個不同副本之間可能會不同。

對於變更清單而言,「最終一致性」是什麼意思?

當您要求變更清單時,您收到的回應可能會不同(視哪個資料庫副本提供清單而定)。

since 選項會取得特定更新序列 ID 之後的變更清單。 清單一律包括更新之後的變更,但也可能包括更新之前的變更。 原因在於回應清單要求的資料庫副本必須確定它列出的變更與所有抄本一致。 為了達到該一致性,資料庫副本可能需要從所有副本都一致的時間點開始變更清單。 此時間點是使用檢查點進行識別。

因此, 任何使用 _changes 饋送的應用程式都必須 具備 「冪等性」。 冪等性意指應用程式必須能夠安全地多次接收相同資料, 且在重複請求時,資料的順序可能不同。

檢查點

抄寫處理程序會在內部將其狀態寫入來源及目的地資料庫中所儲存的「檢查點」文件內。 檢查點容許從其停止位置繼續抄寫作業,而不需要從頭開始。 可以透過提供「」來防止檢查點建立 "use_checkpoints": false 選項 (當您要求抄寫時)。 如果您的抄寫是要有效率地從其上一個已知位置繼續,則這有助於開啟這項特性。

許可權

需要有管理者存取權,才能將文件插入 _replicator 資料庫。 來源及目標參數中所提供的登入認證不需要完整的管理者許可權。 如果認證執行下列作業,則已足夠:

  • 在目的地端寫入文件。
  • 在兩端寫入檢查點文件。

IBM Cloudant 具有特殊 _replicator 使用者許可權。 此許可權容許建立檢查點文件,但不容許在資料庫中建立一般文件。 一般而言,會 建立 API 金鑰,而 API 金鑰具有:

  • 來源端的 _reader_replicator 存取權。
  • 目的地端的 _reader_writer 存取權。

可以在「IBM Cloudant 儀表板」中為每個資料庫逐一建立和配置 API 金鑰。

可以在IBM Cloudant儀表板中基於每個資料庫建立和配置 API 金鑰。
具有權限的IBM Cloudant使用者和 API 金鑰

此外,也可以透過 IBM Cloudant 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」核取方塊, 或於「」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 CouchDB 這是一個開源資料庫, 能夠與 IBM Cloudant 進行通訊, 且僅需極少的設定。 以下應用程式已包含在內:

  • 備份 — 將您的資料從 IBM Cloudant 複製到您自己的 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
    }
}

changes 資訊來源

IBM Cloudant 會透過來自 _changes 端點的單一 HTTP 資訊來源,來發佈影響資料庫的新增、編輯及刪除。 應用程式可以使用此資訊來源來觸發事件。 使用 HTTP 或 curl,即可存取資訊來源,如範例所示。 使用 feed=continuous 選項表示串流提供取得資料庫中每份文件的最新版本所需的每個變更。

如需相關資訊,請參閱 使用 IBM Cloudant 變更資訊來源常見問題(FAQ)

請參閱以下使用 HTTP 查詢變更 feed 的範例:

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

請參閱下列使用指令行來查詢 changes 資訊來源的範例:

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

使用一個變更一行的方式來說明變更。 每一個變更都包含:

  1. 包含序號的字串 (seq)。
  2. 包含已變更文件 ID 的字串。
  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 篩選變更 feed 的範例:

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

請參閱下列使用指令行來過濾 changes 資訊來源的範例:

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 五個 2-MB 附件 11 MB
1 MB 一個 10-MB 附件 11 MB
1 MB 一百個 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 要求依預設傳回的修訂。 此選項是進階選項,因為它會捨棄衝突的文件修訂。 請謹慎使用此選項。