インターネットコンピュータ:Webアプリケーション分散データベースアーキテクチャ


我々は、Webアプリケーションをポートする概念の証明を開発している.DeckDeckGo , to DFINITY's Internet Computer .
ホスティングとパスワードのない認証統合を検証した後、私たちはPOCの最後の質問に取り組みます.
途中で、2つの概念を試しました.
  • 「保守的な」1つの記憶のような単一のデータベースのデータ持続性
  • 未来派🤯” 一つは、ユーザーが作成した各デッキのオンザフライでスマート契約のようなデータベースを生成する
  • この記事ではこれら2つのアプローチを紹介します.

    導入


    このブログ記事の範囲は、単純なキー値データベース概念に制限されます.その種の永続性は、我々がDeckdeckgoで頼るものです.
    私は、誰もが既にブロックを実行して完全に機能的なSQLデータベースなどのIC(Internet Computer)で重い概念を実装しているかどうかわからない.
    もちろん、これらの課題は、ブログの投稿をコメントアウトまたは😃.

    現代


    インターネットコンピュータに掘る前に、いくつかの一般的な、古いファッションの概念を最初に確認してみましょう.
    今日では、サーバーがないかどうか、データの永続性は、すべての情報の1つのデータベースで解決されます.

    ユーザーは(Web)アプリケーションを使用します.endpoint(s)を呼び出してデータを保持し、データを読み込み、結果をユーザーに返します.
    MicroServiceアーキテクチャでは、アプリケーションがサービスのコレクションとして分割されますが、いくつかの拡張子には、結果は同じ概念に基づいています.

    ユーザーは(Web)アプリケーションを使用します.これは専用のサービスを呼び出し、エンドポイントを呼び出してデータを保持してデータを読み込み、結果をユーザーに返す.
    これらのアーキテクチャ、モノまたはマイクロサービスに関係なく、データはモノリシックデータベースに格納される.

    コードスニペット


    私はGoogleの正確なアーキテクチャを知らないFirestore しかし、ユーザーと外部の観点から、それは雲でホストされるモノラルデータベースのように見えます.
    我々が開発するならば、例えば、我々のユーザーが所有する動物の種類をリストするアプリケーションpets エントリを収集する.

    データを検索して保持するには、getter (get ) とsetter (add ) クラウドデータベースを呼び出すWebアプリケーションの機能.
    import firebase from 'firebase/app';
    import 'firebase/firestore';
    
    const firestore = firebase.firestore();
    
    const get = async (entryId) => {
      const snapshot = 
                await firestore.collection('pets').doc(entryId).get();
    
      if (snapshot.exists) {
        console.log(snapshot.data());
      }
    };
    
    const add = async (userId, dog, cat) => {
      const {id: entryId} = await firestore.collection('pets').add({
        userId,
        dog,
        cat
      });
    
      console.log(entryId);
    };
    
    すべてのユーザーは同じエントリーポイントを使用します、そして、彼らのデータも同じコレクションで保存されるでしょうfirestore.collection('pets') ).

    保守的な


    インターネットコンピュータは、Dfinity財団(私の理解)のゴールでないビルトイン、ちょうど水データベースソリューションを提供しません.彼らはまた、Webアプリケーションを実行することができる未来的なブロック網を提供しています.それはすべてです.
    それはその上に機能を構築するメーカーまでです.彼らは機能を実装し、キャニスタスマート契約を介してIC上でこれらを解き放つことができます.
    クラウド内の機能のセットを実行するコンテナとして「キャニスター」を描きます😉. これは、基本的には、コンピューティングからデータの永続性に実装することができます何かを行うことができます.
    勉強した後documentation SDKのexamples そして」linkedup ” デモは、我々の最初のアプローチは、我々は、“現代”または“モノリシック”データベースアプローチに精通しているアプローチを複製する目標をしていた.

    しかしながら、インターネット・コンピュータのブロックチェーンの性質を考えれば、ブロックの形で共有されたデータで分散的にアーキテクチャを想像するのは良いかもしれません.

    我々がブロックチェーン面(そして、地方分権)を省略するならば、それは基本的に私がよく知っているものと同じように働きます?

    コードスニペット


    我々が我々の「ペット」ウェブアプリケーションのためにそうするように、我々がキャニスターの中でデータの永続性を描くことができる方法は、以前のアーキテクチャと再び全く類似しています.

    Key Value Database Collectionの代わりに--利用できる組み込みデータベースがないので、我々の俳優は単にデータを保持する属性を持っているでしょう.
    その属性は、例えばTrie , 機能的なマップ(そのセット)はその表現が「正準」であり、操作履歴から独立しています.
    問い合わせるget ) と主張するadd ) データは、次のように俳優、キャニスターを実装することができます
    Canistersと機能は、インターネットコンピュータで解き放つ一般的にいずれかを書き込むことができますMotoko or Rust . MotokoはDfinity財団によって出版され、維持され、ドキュメントの例の大部分はその特定のプログラミング言語で提供されます.それは主に我々がモトコとの概念の証明を開発した理由です.
    import Trie "mo:base/Trie";
    import Nat32 "mo:base/Nat32";
    
    actor {
    
        type PetId = Nat32;
    
        type Data = {
            dog: Bool;
            cat: Bool;
            userId: Text;
        };
    
        private stable var entryId: PetId = 0;
    
        private stable var pets : Trie.Trie<PetId, Data> = Trie.empty();
    
        public func add(userId: Text, dog: Bool, cat: Bool): async () {
            let data = {
                userId = userId;
                dog = dog;
                cat = cat;
            };
    
            pets := Trie.replace(
                pets,
                key(entryId),
                Nat32.equal,
                ?data,
            ).0;
    
            entryId += 1;
        };
    
        public query func get(entryId: Nat32) : async ?Data {
            let result = Trie.find(pets, key(entryId), Nat32.equal);
            return result;
        };
    
        private func key(x : PetId) : Trie.Key<PetId> {
            return { hash = x; key = x };
        };
    
    };
    
    データは、我々が精通しているアプローチを使用している間、キャニスタスマート契約、複製、分散化に保存されます.
    注意:Link MOTOKOプレイグラウンドに関連して、上記の例でプレーしてください.

    未来派🤯”


    私たちの最初の“保守的な”アプローチは、インターネット計算のWebアプリケーションのためのデータ永続性が行われる可能性があるという仮説を検証しました.しかし、スケーラビリティについてはどうですか?
    最初のアプローチではTrie 例のように代わりに、データをHashMap . このように、データが大量にデータを含んでいても、データが潜在的により迅速にまだ配信されていたので、それはシステムをもう少しスケーラブルにしました.しかし、いくつかの時点で、とにかく何らかの制限を打ったかもしれません.
    さらに、キャニスターは、weBassembly実現の制限のために4 GBのメモリページだけを記憶することができますsource ).
    そういうわけで、我々は我々の最初の考えに挑戦して、よりスケーラブルなデザインを見つけようとしました.
    主演者がA Managerとして機能するアーキテクチャに帰着しました--オンザフライで、オブジェクト作成に関して--各々のユーザーの各々の単一のデータ持続性のように分散安全な単純なキー値データベースを生成します🤯.

    上の図では、2つのユーザーだけを表示し、ネットワークのブロックチェーンの性質を反映していませんでしたが、うまくいけば、それは写真をよく考えます.
    ユーザーは、Webアプリケーションを介して、マネージャを要求する/彼女の個人分散安全な単純なキーの値データ永続性キャニスターを取得します.一度取得すると、彼/彼女はクエリと彼/彼女のデータを保持するために、この専用のプライベートスペースを使用します.

    コードスニペット


    私たちはそのような解決策を実行するために2人の俳優を必要とするでしょう.つは、“マネージャー”、その場で他のキャニスターを生成するキャニスター、およびデータ永続性の世話をするキャニスターの実装、その場で生成されるものとして機能するもの.
    エンドマネージャーが彼らの側で彼らの参照を保存しない限り、「マネージャー」はそれが発生したcanistersのリストを追跡するか、または持っていないかもしれません.しかし、次のスニペットでは、何が生成されるかを追跡しなければならないと仮定します.

    Managerの基本実装は、すでに実装しているものに近い.しかし、Trie , 私はHashMap 生成されているcanistersのIDを追跡する.
    import HashMap "mo:base/HashMap";
    import Principal "mo:base/Principal";
    import Cycles "mo:base/ExperimentalCycles";
    import Iter "mo:base/Iter";
    
    import Pet "./Pet";
    
    actor {
    
      type CanisterId = Principal;
      type UserId = Principal;
    
      private func isPrincipalEqual(x: Principal, y: Principal): Bool {
        x == y 
      };
    
      private var canisters: HashMap.HashMap<UserId, CanisterId> = 
        HashMap.HashMap<UserId, CanisterId>(10, isPrincipalEqual,  
                                            Principal.hash);
    
      private stable var upgradeCanisters: [(Principal, CanisterId)] = 
        [];
    
      public shared({caller}) func create(): async (CanisterId) {
        Cycles.add(1_000_000_000_000);
        let canister = await Pet.Pet();
        let id: CanisterId = await canister.id();
        canisters.put(caller, id);
    
        return id;
      };
    
      public shared query({caller}) func get() : async ?CanisterId {
        let id: ?CanisterId = canisters.get(caller);
        return id;
      };
    
      system func preupgrade() {
        upgradeCanisters := Iter.toArray(canisters.entries());
      };
    
      system func postupgrade() {
        canisters := HashMap.fromIter<UserId, CanisterId>     
                      (upgradeCanisters.vals(), 10, 
                      isPrincipalEqual, Principal.hash);
                      upgradeCanisters := [];
      };
    
    };
    
    機能create インターネットのコンピュータで新しいユーザーのキャニスターを解き放つの世話をします.最初に、新しい俳優のために最小のサイクルカウントを割り当てます.
    The get 関数は、存在する場合、ユーザのキャニスターのIDを返す.
    両方preupgrade and postupgrade は、アップグレード間のメモリを保持するために使用されるdocumentation ).
    マネージャーが開発したら、我々はactor ユーザーの個人データの永続性に専用.
    import Principal "mo:base/Principal";
    
    actor class Pet() = this {
    
      type Data = {
        dog: Bool;
        cat: Bool;
      };
    
      private stable var myPet: ?Data = null;
      public func set(dog: Bool, cat: Bool): async () {
        myPet := ?{
          dog = dog;
          cat = cat;
        };
      };
    
      public query func get() : async ?Data {
        return myPet;
      };
    
      public query func id() : async Principal {
        return Principal.fromActor(this);
      };
    
    };
    
    その実装は、我々が以前に見たことがよく知られているように見えますentryId もう、ないTrie どちらも.
    各ユーザーは彼/彼女自身の小さな王国を持っています.そういうわけで、彼/彼女はデータの大きいポットでデータを検索するために識別子を必要としません.それは、記憶さえなければなりませんuserId .
    これは、ユーザーの王国は、その特定のユーザーの個人データのみが含まれています!

    注意:Link MOTOKOプレイグラウンドに関連して上の例をチェックしてください.

    賛否両論


    すべてのユーザーが彼自身の領域で動くので、最終的な建築は本当にスケーラブルです.また、明確な所有権の懸念を分離し、よく安全なアプローチに適しています.
    しかし、彼らのコードのアップグレードの間、または、彼らの経費を扱うかどうかに関係なく、それはより多くの管理と関係があるということに注意しなければなりません.
    それにもかかわらず、我々はこのアーキテクチャの大ファンであり、利点は完全に価値があると思います.したがって、概念の我々の証明が本当の生の生産的使用ケースに変わるならば、それは我々が使う概念です.
    結局、大きな力は、大きな責任で来ます!

    概要


    それはかなり難しい主題です.私はこれらのアーキテクチャの背後にある主な考えを伝えることができたことを願って、最も重要なのは、私は未来的な🤯”.
    無限に、そして、向こうに!
    ダビデ
    あなたは私や私に到達することができますwebsite .
    試してみるDeckDeckGo あなたの次のプレゼンテーションのために!

    グラントプログラム


    我々は信じられないほど幸運にDfinityDeveloper Grant Program 開発者のエコシステムをサポートするために、賞のチームは、インターネット上のDApps、ツール、およびインフラストラクチャを構築する.
    私は、あなたが確かに応募しなければならないすばらしいプロジェクトがあるならば、十分な事実を強調することができません.それは今までのところ、驚くべき経験にすぎなかったし、その前にある何かに参加する気がする.
    この記事のすべての数値はExcalidraw , どのような滑らかな描画ツール.