レプリカッシュの全体像

Patricia Arquette
リリース: 2025-01-02 20:23:39
オリジナル
913 人が閲覧しました

Replicache

Local First Softwareを実装するのに役立つフレームワークです。

Replicacheはサーバーデータの同期を後から非同期的に実行し、サーバーのラウンドトリップを排除し、即時UI変更を可能にします。

Replicache Parts

Replicacheはいくつかの要素で構成されています。

Replicache

Replicacheは内部にgitのような動作を含むIn browser Key-Valueストアと見なすことができます。

Your application

Webアプリケーションのような私たちが作ったアプリケーションである。 Replicacheに状態を保存する主体である。

Your server

最も信頼できるデータを保存するために存在します。

サーバーはpush(upstream)とpull(downstream)を実装してクライアントのReplicacheと通信する必要があります。

push(upstream): Replicache は変更を push endpoint に送る。 🎜>

pull(downstream):定期的または明示的に要求すると、Replicacheはサーバーにプル要求を送信します。サーバーはクライアントがサーバーの状態と同じになるために必要な変更を返します。 >

  • poke: 定期的にクライアントがプルリクエストを送ったが、もう少しリアルタイムで見せるためにサーバに変更があるとき、サーバがクライアントにプルリクエストをするようにヒントを与える信号だ。しないでください。

  • Sync

    アプリケーションとサーバーが最新の状態に同期する 以下の図がこの過程をよく示しています。にプッシュされる過程を見せる。
  • ソース
Clients, ClientGroups, Caches

メモリにあるReplicacheをClientと呼びます。

Replicache Big Pictureクライアントは通常1つのタブに1つ存在します。

Client Groupは、ローカルデータを共有するクライアントの集まりです。このクライアントグループ内のクライアントは、オフライン状態でも状態を共有します。

Client Groupは、Replicacheのコンストラクタのnameパラメータによって区別されるon-disk persistent cacheを使用します。同じ名前を持つクライアントグループに属するすべてのクライアントは同じキャッシュを共有します。

The Client View

Client は ordered map of key value pair を persistent cache に持っていますが、これを Client View と呼びます。 Client Viewはアプリケーションのデータであり、サーバーのデータと同期されます。 Client Viewと呼ばれる理由は、異なるクライアントごとにサーバーのデータを異なるClient Viewに持つことができるからです。各クライアントがサーバーの状態を見るのが異なるという意味だ。

Client Viewにアクセスするのは非常に高速です。 Read latency は 1ms 未満で、ほとんどのデバイスで 500MB/s の Throughput を持ちます。

React同じ場所でuseStateに別々にClient Viewをコピーしてメモリに置いて使用しないでください。 Client Viewにmutatorが変更を加えるとsubscriptionが発動され、UIが更新されるようにすればよい。

Subscriptions

Subscribe関数はReadTransaction引数を受け取り、Replicacheで読み取ることを実装します。 Replicacheのデータが変わって、このサブスクリプションがout of dateになるたびに、subscribe関数が再実行されます。この結果が変わると、値が更新され、UIも更新されます。

SubscriptionでUIを設定すれば、常に最新の状態に保つことができる。


Mutations

import {Replicache} from "replicache";

const rep = new Replicache({
  name: userID,
  ...
});

console.log(rep.clientID);
ログイン後にコピー
MutationはReplicacheのデータを変更する作業を意味します。 Mutationを受けて実際にデータを変化させる主体をMutatorという。

起動時にReplicacheに複数のMutatorを登録するが、実はただのnamed functionだ。以下のcreateTodoとmarkTodoCompleteはどちらもmutatorでWriteTransactionを介してReplicacheのデータを変更します。

Mutatorは以下のように動作させる。 Mutatorが機能するとデータが変更され、それに関連するサブスクリプションがトリガーされ、UIも変更されます。

const todos = useSubscribe(rep, async tx => {
  return await tx.scan({prefix: 'todo/'}).toArray();
});
return (
  <ul>
    {todos.map(todo => (
      <li key={todo.id}>{todo.text}</li>
    ))}
  </ul>
);
ログイン後にコピー

内部的にMutatorはmutationというものを作る。実行履歴と同じですが、Replicacheは以下のようなミューテーションを生成します。

const rep = new Replicache({
  ...
  mutators: {
    createTodo,
    markTodoComplete,
  },
});

async function createTodo(tx: WriteTransaction, todo: Todo) {
  await tx.set(`/todo/${todo.id}`, todo);
}

async function markTodoComplete(tx: WriteTransaction,
    {id, complete}: {id: string, complete: boolean}) {
  const key = `/todo/${id}`;
  const todo = await tx.get(key);
  if (!todo) {
    return;
  }
  todo.complete = complete;
  await tx.set(key, todo);
}
ログイン後にコピー
これらのミューテーションがサーバーにプッシュされ、完全に同期されるまで、これらのミューテーションはペンディング状態で表記されます。

Sync Details

これでReplicacheの核心といえるSyncの詳細な内容だ。 Syncはサーバー上で行われます。

The Replicache Sync Model

(これから「状態」という表現は、複数のkeyとvalueペアのデータ(key value space)の状態を意味する。)

Replicacheが解決しようとするSyncの問題は、複数のクライアントが同時に同じ状態を変化させる状況であり、以下のような条件を持つ場合に発生します。

    サーバーが持っている状態がsource of truthである。 canonical(標準)と表現する。
  1. クライアントのローカル状態の変化はすぐに反映されます。これをspeculative(推測)と呼ぶ。
  2. サーバーは変更を正確に一度だけ適用し、その結果が予測可能でなければなりません。サーバーに適用された変更は、クライアントのローカル変更と合理的にマージできる必要があります。
この中で最後の項目でサーバーの変化をローカル状態と「合理的にマージ」というのは興味深いテーマだ。 「合理的マージ」のためには、次の状況を考慮する必要があります。

  • ローカルの変更がまだサーバーに適用されていない場合。この場合、サーバーから新しい状態を取得しても、ローカルでの変更がアプリのUIから消えないようにする必要があります。サーバーから新しい状態を受信した後、既存のローカル変更をサーバーの状態の上に再実行する必要があります。

  • クライアントで行われたローカル変更がすでにサーバーに送信され、サーバーの状態に反映されている場合。この場合は、ローカル変更を重複して適用することに注意する必要があります。ローカル変更を再適用しないでください。

  • 同じ状態に対してサーバーの状態を変更した他のクライアントが存在する場合。この場合も、最初の場合と同様に、サーバーから受信した状態に基づいてローカル変更を再実行する必要があります。しかし、同じリソースに対して競合が発生する可能性があるため、マージロジックをよく編成する必要があります。 Mutator内にこのロジックを作成します。

Mutatorの動作過程に従いましょう。

Local execution

ローカルでMutatorが動作し、mutatorロジックによってreplicacheの値が変更される。同時に、このクライアントで sequential に増加する mutationId を持つ mutation を生成します。 mutationはpending mutationでqueuingされる。

プッシュ

Pending mutations は server に実装された push endpoint(replicache-push) に送られる。

mutation はサーバに実装された mutator を実行させて canonical 状態を変更する。 Mutationを適用しながら、このクライアントのlast mutation idを更新し、このクライアントが次のプルを行うとき、どのmutationから再適用するかを知ることができる値になる。

ローカルに適用されたpending mutationはspeculative resultを生成し、サーバに適用されたmutationはcanonical resultを生成する。サーバーに適用された mutation は confirmed され、再びローカルで実行されません。もし同じミューテーションが別の結果を返しても、サーバーの canonical result が優先されるので、クライアントの結果は変わります。

プル

Replicacheは最新の状態を取得し、UIを更新するために定期的にプルエンドポイント(replicache-pull)に要求を送信します。

Pull requestはcookie、clientGroupIdを入れて要求し、new cookie、patch、lastMutationIDChangesを返します。

cookieは、クライアントが持っているサーバーの状態を区別するために使用されます。サーバーとクライアントの状態がどれだけ変化しているかを追跡できる値です。データベースの状態が変わるたびに変更されるグローバル'version'と考えてもよい。あるいは、より特定の範囲のデータを追跡するためのクッキー戦略を使用することもできます。

lastMutationIdChangesは、各クライアントの最後にサーバーで適用されたミューテーションIDを表す値です。この値より小さい mutationID を持つ mutation は、すべて pending ではなく confirmed と見なすべきです。

Rebase

クライアントがプルを受け取ったら、ローカルの状態にパッチを適用する必要があります。しかし、pending mutationが現在ローカル状態に影響を与えているので、ローカル状態にすぐにパッチを適用することはできません。代わりに、ローカルのペンディングミューテーションを元に戻し、プルとして受け取ったパッチを最初に適用した後、再びローカルのペンディングミューテーションを適用します。

このような戻しと再適用を可能にするために、Replicacheは羽と同様に設計された。サーバーの状態がmain branch、ローカルにパンディングされたmutationに変更された状態をdevelopブランチだと考え、サーバーからmainにプルを受け取り、developをmainにrebaseすると考えればよい。

リベースしながら発生する可能性のあるコンフリクトは、以下から別々に調べる。

Poke

Pokeは、上記のように、サーバーがクライアントにプルをするように指示するヒントメッセージです。

Conflict Resolution

Replicacheのような分散システムでは、Merge conflictは避けられません。プルとプッシュプロセスでマージが必要です。マージは、マージ結果が予測可能でなければならず、アプリの目的に合った方法で行われるべきです。

もし会議室予約アプリであれば、コンフリックが発生したときに1つの要求のみ承認されなければならない。そのため、まず予約したクライアントのみを承認するマージ方法を採用しなければならない。

逆にTodoアプリなら、ツーリストは同時に追加が起こっても、両方の変更が承認されることが目的に合います。

Merge Conflictは、次の2つの状況で発生します。

    ローカル変更がサーバーに適用される時点。ローカルで適用するときの状態とサーバーで適用するときの状態が異なる場合があるからです。
  1. Rebaseするとき。やはり適用する時の状態が異なることがあるからだ。

  2. Replicacheは、アプリの目的に応じてマージ方法を異なる方法で実装する必要があることを認識しているため、開発者がそれを実装できるようにします。開発者はMutatorを介してこのロジックを実装できます。

以上がレプリカッシュの全体像の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート