Couchbase Lite機能解説：Couchbase Serverとの同期②〜レプリケーション設定

## はじめに

ここでは、Couchbase Liteにおけるレプリケーション設定について解説します。

なお、Couchbase Mobileについては、[Couchbase Mobileアプリケーション開発へのロードマップ](https://qiita.com/yoshiyuki_kono/items/6a5bbad1b02196a25417)に記事をまとめている他、（これらの記事を元に構成した）以下の電子書籍を無償で頒布しています。

https://techbookfest.org/product/5074954942939136?productVariantID=5042865933647872

また、Couchbase Mobileは、Couchbase LiteとCouchbase Serverとのデータ同期機能を提供します。Couchbase Serverの存在意義、機能詳細、利用方法等については、拙著[NoSQLドキュメント指向データベースCouchbase Serverファーストステップガイド(インプレスR&D刊)](https://www.amazon.co.jp/-/en/%E6%B2%B3%E9%87%8E-%E6%B3%B0%E5%B9%B8/dp/429560030X/ref=tmm_pap_swatch_0?_encoding=UTF8&qid=1636588872&sr=1-1)や、[NoSQL/JSONデータベースCouchbase Server理解・活用へのロードマップ](https://qiita.com/yoshiyuki_kono/items/4c9cd1115efc5807b49f)にまとめてある記事をご参考ください。


## レプリケーション設定


### ターゲットの構成
`ReplicatorConfiguration`オブジェクトを使用して、レプリケーション構成を定義します。

`ReplicatorConfiguration`コンストラクターは、以下の引数をとります：

- 同期するローカルデータベースの名前
- サーバーのURL（ポート番号と同期するリモートデータベースの名前を含む）

```JAVA
// initialize the replicator configuration
final ReplicatorConfiguration thisConfig
   = new ReplicatorConfiguration(
      thisDB,
      URLEndpoint(URI("wss://10.0.2.2:8954/travel-sample"))); 
```

サーバーのURLには、WebソケットURLスキーム、`ws:`（非TLS）または`wss:`（SSL / TLS）プレフィックスを使用します。

クリアテキストの暗号化されていないネットワークトラフィック（`http:`または`ws:`）を使用するには`android:usesCleartextTraffic="true"`をマニフェストの要素に含めます。これは本番環境では推奨されません。

### 同期モード
開始するレプリケーションの方向と挙動を定義します。

`ReplicatorConfiguration`クラスの`replicatorType`と `continuous`パラメーターを使用して、レプリケーターに次のことを伝えます。

- レプリケータータイプ: `PUSH_AND_PULL`,`PULL`,`PUSH`

- レプリケーションモード（`continuous`）：

 - 継続的(デフォルト):無期限にアクティブなレプリケーション（`continuous=true`）

 - アドホック:ワンショットレプリケーション（`continuous=false`）



```JAVA
// レプリケータータイプ設定
thisConfig.setReplicatorType(
  ReplicatorConfiguration.ReplicatorType.PUSH_AND_PULL);

// 同期モードをアドホックに設定
thisConfig.setContinuous(false);
```

### 構成の再試行
Couchbase Liteは、レプリケーション再試行ロジックを持ちます。これによって、復元力のある接続が実現されます。

レプリケーターは、ハートビートを維持することにより、接続が切断される可能性とその影響を最小限に抑えます。
基本的に、接続が存続していることを確認するために、一定の間隔でSync Gatewayにpingを実行します。この間隔の長さは設定可能です。

一時的なエラーを検出した場合、レプリケータは再接続を試み、接続が再確立されたとき、または再試行回数が再試行制限（ワンルショットレプリケーションの場合は9回、連続レプリケーションの場合は無制限）を超えた場合にのみ停止します ）。

再試行のたびに、試行間の間隔が最大待機時間制限（5分）まで指数関数的に増加します（指数バックオフ）。

REST APIは、構成可能なプロパティのセットを使用して、このレプリケーション再試行ロジックに対する構成可能なコントロールを提供します。

以下の、レプリケーションの再試行に関する設定プロパティ説明を参照してください。



#### setHeartbeat()

- ハートビートパルス間の間隔（秒単位）。
- デフォルト：レプリケーターは300秒ごとにSync Gatewayにpingを実行します。


接続エラーをより早く検出するためには、この値を削減します。
ロードバランサーまたはプロキシのkeep-alive間隔に合わせる必要がある場合があります。

#### setMaxAttempts()

- 再試行の最大回数
- 再試行を防ぐには、これをゼロ（0）に設定します
- レプリケータが接続して複製できるようになると、再試行回数はリセットされます。
- デフォルト値は次のとおりです。
 - シングルショットレプリケーション= 9;
 - 連続レプリケーション=最大整数値
- 負の値はCouchbase例外を生成します `InvalidArgumentException`

再試行の回数を制限または延長します。

#### setMaxAttemptWaitTime()

- デフォルト値：300秒（5分）
- ゼロまたは負の値は、Couchbase例外を生成します`InvalidArgumentException`。


これは再試行の最大間隔です。最大許容待機時間を設定することはできますが、個々の間隔はレプリケーターの指数バックオフアルゴリズムによって計算され、設定することはできません。

これによって、再試行の間隔を調整します。

#### 実装例

```JAVA
URLEndpoint target =
new URLEndpoint(new URI("ws://localhost:4984/mydatabase"));

ReplicatorConfiguration config =
new ReplicatorConfiguration(database, target);

//  other config as required . . .
config.setHeartbeat(150L); ①
config.setMaxattempts(20L); ②
config.setMaxAttemptWaitTime(600L); ③

Replicator repl = new Replicator(config);
```

①`setHeartbeat()`を使用して、ハートビートパルス間に必要な間隔（秒単位）を設定します。
②`setMaxAttempts()`を使用して、必要な再試行回数を設定します
③`setMaxAttemptWaitTime()`を使用して、再試行の間に必要な間隔を設定します。



### カスタムヘッダー
カスタムヘッダーを、設定できます。レプリケーターはすべてのリクエストで設定されたヘッダーを送信します。
利用例として、この機能は、プロキシサーバー（Couchbase LiteとSync Gatewayの間にある）によって認証または承認ステップが実行されている場合に、追加の資格情報を渡すのに役立ちます。


```JAVA
ReplicatorConfiguration config = new ReplicatorConfiguration(database, endpoint);
Map<String, String> headers = new HashMap<>();
headers.put("CustomHeaderName", "Value");
config.setHeaders(headers);
```




### レプリケーションフィルター
レプリケーションフィルターという、コールバック関数定義を使用して、プッシュレプリケーションやプルレプリケーションの結果として保存されるドキュメントをコントロールできます。


注意点として、コールバックされる関数は純粋関数のセマンティクスに従う必要があります。そうしないと、長時間実行される関数によってレプリケーターの速度が大幅に低下します。さらに、コールバックは、呼び出されているスレッドについて想定してはなりません。

#### プッシュフィルター
プッシュフィルターを使用すると、アプリはデータベースのサブセットをサーバーにプッシュできます。これは、状況によっては非常に便利です。たとえば、優先度の高いドキュメントを最初にプッシュしたり、「ドラフト」状態のドキュメントをスキップしたりできます。

```JAVA
URLEndpoint target = new URLEndpoint(new URI("ws://localhost:4984/mydatabase"));

ReplicatorConfiguration config = new ReplicatorConfiguration(database, target);
config.setPushFilter((document, flags) -> flags.contains(DocumentFlag.DocumentFlagsDeleted)); 

// Create replicator (be sure to hold a reference somewhere that will prevent the Replicator from being GCed)
replicator = new Replicator(config);
replicator.start();
```


#### プルフィルター
プルフィルターを使用すると、アプリはプルされているドキュメントを検証し、失敗したドキュメントをスキップできます。

これは、完全に信頼されていないピアを使用するピアツーピアトポロジの重要なセキュリティメカニズムです。

プルレプリケーションフィルターは、チャネルの代わりにはなりません。Sync Gatewayチャネルはスケーラブルになるように設計されています（ドキュメントはサーバー上でフィルタリングされます）が、プルレプリケーションフィルターはダウンロードされるドキュメントに適用されます。


```JAVA
URLEndpoint target = new URLEndpoint(new URI("ws://localhost:4984/mydatabase"));

ReplicatorConfiguration config = new ReplicatorConfiguration(database, target);
config.setPullFilter((document, flags) -> "draft".equals(document.getString("type"))); 

// Create replicator (be sure to hold a reference somewhere that will prevent the Replicator from being GCed)
replicator = new Replicator(config);
replicator.start();
```


ドキュメントへのアクセスが失われると、プルレプリケーションフィルターもトリガーされます。

### チャネル
デフォルトでは、Couchbase Liteは、構成されたユーザーアカウントがアクセスできるすべてのチャネルを取得します。この動作は、ユーザー認証と同期機能に依存して、ユーザーごとにプルするデータを指定するほとんどのアプリに適しています。

オプションで、Couchbase Liteのレプリケーター構成オブジェクトでチャネル名のコンマ区切りリストを指定することもできます。この場合、Sync Gatewayからのレプリケーションは、それらのチャネルでタグ付けされたドキュメントのみをプルします。

### チャネルアクセス失効事の自動パージ

デフォルトでは、ユーザーがチャネルにアクセスできなくなると、チャネル内のすべてのドキュメント（ユーザーの他のチャネルにも属していない）がローカルデータベース（ユーザーに属するデバイス内）から自動パージされます。

リリース2.xでは、これらのドキュメントはローカルデータベースに残ります。

2.xでは、CBLは、ユーザーが所有するすべてのチャネルからドキュメントを削除することによってユーザーがドキュメントにアクセスできなくなった場合にのみ、自動パージを実行します。3.0では、2.xの自動パージに加えて、Couchbase Liteは、ユーザーがチャネルアクセスの取り消しによってドキュメントにアクセスできなくなったときに、ドキュメントを自動パージします。この機能はデフォルトで有効になっていますが、設定で無効にすることが可能です。

#### 構成
自動パージの動作は、`ReplicationConfiguration`オプション`setAutoPurgeEnabled()`によって制御されます。この状態を変更すると、将来のレプリケーションにのみ影響します。レプリケータは、チャネルアクセスの削除時に自動パージされたリビジョンの同期を試みません。以前に削除されたドキュメントを同期したいクライアントは、resetCheckpoint APIを使用して最初から再同期する必要があります。

以下は、自動パージの設定例です。


```JAVA
// set auto-purge behavior (here we override default)
thisConfig.setAutoPurgeEnabled(false); 
```

ここでは、自動パージ動作をオフにすることを選択しました。デフォルトでは、これはオン（true）です。

#### チャネルアクセス失効のケース
ユーザーは、さまざまな方法でチャネルにアクセスできなくなる可能性があります。

- ユーザーはチャネルに（直接的に）アクセスできなくなる
- ユーザーがチャネルにアクセスできるロールから削除される
- ユーザーが割り当てられているロールがチャネルにアクセスできなくなる



複数のチャネルに存在するドキュメントは、ユーザーがすべてのチャネルにアクセスできなくなるまで、自動パージされません。

チャネルアクセスが取り消されたためにドキュメントアクセスが失われた場合、ユーザーは`DocumentListener`から`AccessRemoved`通知を受け取ります。これは、現在の自動パージ設定に関係なく送信されます。

#### アクセスが回復した場合の動作

ユーザーが失われたチャネルへのアクセスを回復した場合、以前に自動パージされたドキュメントは、チャネルのいずれかにまだ割り当てられている場合、次に更新されるときに自動的にプルダウンされます。




##  関連情報

https://docs.couchbase.com/couchbase-lite/3.0/android/replication.html#lbl-cfg-repl

https://docs.couchbase.com/couchbase-lite/current/android/replication.html#lbl-cfg-repl