OrbitDB:在浏览器中部署分布式IPFS数据库

OrbitDB解析以及今天如何利用它来存储去中心化的应用程序数据
原文地址:OrbitDB: Deploying the Distributed IPFS Database in the Browser

序言:分布式网络正全速前进

分布式协议的发展速度很快,进入2019年后只会加速发展,这一年对去中心化来说是非常令人兴奋的一年。数据库的发展在这场不断演进的软件运动中也不例外,因此本文将重点分析。

内部协议开发的时代已经过去了。开源生态系统和新兴的去中心化经济正在为塑造软件的未来的更多合作努力铺平前进的道路。正因为如此,我们今天可以通过部署最新的开源成果来领略未来。OrbitDB就是在分布式数据库领域做出的努力;它是在IPFS上运行的对等数据库。

OrbitDB令人印象深刻的是,它在浏览器中的IPFS Javascript实现之上运行。这样做允许我们在每个用户的基础上复制和管理数据库。我们将进一步探讨这实际上意味着什么,以及它提供的用例。

什么是OrbitDB?

OrbitDB Github页面称该软件包是一个用于去中心化网络的点对点数据库。为了实现这种去中心化的性质,该数据库运行在IPFS之上,如上所述。

但与传统的集中式数据库不同,传统的集中式数据库将数据存储在一个中心位置(可能会复制或分片到其他集中式位置),OrbitDB数据库是无服务器的,并复制到所有使用它的对等方。由于IPFS的散列协议不允许重复一个内容,这样的数据库没有中心点。

哈希值是真正的来源,它可能存在于整个网络的数百或数千的节点上。考虑到这一点,数据库的高层次特征如下:

  • OrbitDB在服务器端和浏览器中都兼容。
  • OrbitDB是无服务器的。它不需要一个中心节点服务器,但是,它需要至少一个IPFS节点愿意持久化数据库,以便在浏览器断开连接时不会丢失数据库,或者使用 go-ipfs 进行垃圾收集。
  • 数据库在各对等体之间自动同步。IPFS pubsub协议自动使各对等方的数据库保持最新。Pubsub是publish-subscribe的缩写,它是一种可靠地跨对等点处理事件和更新的模型。
  • OrbitDB数据库最终是一致的,通过无冲突数据库合并(CRDT)实现。简言之,跨对等点的数据库副本可以同时更新,而不需要它们之间的协调机制。因此,可以保证数据库的每个对等方最终将拥有与其他所有人相同的数据库、相同的记录、相同的顺序等。这是非常好的后台管理,前端开发人员不必考虑。
  • 由于OrbitDB数据库由对等方复制并存储在本地,因此应用程序将变得脱机兼容。这提供了更多的可访问性,但会牺牲可靠性;应用程序脱机时间越长,数据就越过时。
  • OrbitDB支持写权限。我们可以根据一个特殊的哈希键来限制对数据库的写入权限,这个哈希键对每个对等体都是唯一的,我们将在文章中进一步介绍。

注意:在撰写本文时,我们仅限于在首次启动数据库时定义写入权限。然而,OrbitDB核心开发人员正在开发更灵活的权限管理功能,包括读取权限,这些功能将在将来的更新中推出。

  • OrbitDB数据是公开的。私有IPFS协议正在研究中,尽管处于早期阶段,因此在此不进行探讨。目前,确保OrbitDB上没有存储任何敏感数据——坚持使用你想让全世界知道的数据。
  • OrbitDB提供了5种开箱即用的数据类型。让我们下一步去看看。

OrbitDB数据结构

OrbitDB提供了一系列开箱即用的数据类型,以及添加自定义数据类型的能力。我们定义了初始化数据库时要遵循的数据类型。我们将进一步访问该代码。

我们现成的数据类型有:

  • log——具有可遍历历史的日志(仅附加,不可变)结构。用于排队和记录不想删除条目的应用程序。
  • feed——具有可遍历历史的日志(可变)结构。可以添加和删除条目。用于购物车、评论、文章回复。
  • keyvalue——键值对。顾名思义,一个简单的键值结构。适用于持久化应用程序配置或应用程序状态。
  • document——文档。与基于文档的数据库(如MongoDB)类似,文档数据类型允许我们将JSON文档存储为条目。_id字段可用于查找文档的条目。这种更灵活的数据类型可用于描述产品和文章等项目。
  • counter——计数器。计数器是最简单的数据类型,它带有一个inc()函数,我们可以在其中传递正整数和负整数来操作计数器。计数器对于与log或feed数据库一起计算事件非常有用。

安装需要的软件包

要启动并运行OrbitDB,请安装IPFS JS和OrbitDB,它们可以使用npm或者yarn安装:

npm i orbit-db ipfs
#or
yarn add orbit-db ipfs

注意:如果您在安装特定软件包时遇到错误,正如我在本期中介绍的tiny-secp256k1中所做的那样,解决方案需要使用自制软件重新安装新的npm。

IPFS JS还在开发阶段!慎用!

需要强调的是,IPFSJS处于alpha状态,随着项目接近公开发布,API可能确实会发生变化。但是,我们要求它与OrbitDB一起运行,以便在浏览器中运行,因此我们将在这里采用它。

通常不建议在任务关键型应用程序中包含预发布软件,但我完全建议使用预发布软件创建应用程序的原型版本,以测试稳定性并从实现中学习-您可能会惊喜地看到您的应用程序性能完美无瑕。

通过Github项目页面了解IPFS JS的最新信息:
js-ipfs GitHub page
您是否希望在IPF上缓慢推出资产、向部分用户发布beta版本,或者只是等待最终版本,然后再将其引入生产基础架构,这取决于您的决定。
考虑到这一点,现在让我们来实例化一个数据库。

实例化OrbitDB数据库

现在安装了ipfs和OrbitDB包,我们可以在浏览器中自发地实例化ipfs节点,然后启动OrbitDB数据库。

执行此操作所需的代码如下:

const IPFS = require('ipfs')
const OrbitDB = require('orbit-db')
const ipfsOptions = {
  EXPERIMENTAL: {
    pubsub: true
  }
}
const ipfs = new IPFS(ipfsOptions)
ipfs.on('ready', () => {
  //Create OrbitDB instance
  const orbitdb = new OrbitDB(ipfs);
   //orbitdb is now the OrbitDB instance we can use to interact with databases
})

在React中实例化

此时,您可能想知道如何将此代码应用到React状态管理的应用程序中。以下要点解决了这一问题。
将以下内容复制并粘贴到React项目(安装了ipfs和orbit db)中,以观察ipfs实例化的速度,然后是OrbitDB:

import React from 'react';
const IPFS = require('ipfs');
const OrbitDB = require('orbit-db');

export class OrbitDBHandler extends React.Component {

  state = {
    ipfs: null,
    orbitdb: null
  };

  constructor(props) {
    super(props);

    //connect to IPFS
    const ipfs = new IPFS({
      EXPERIMENTAL: {
        pubsub: true
      }
    })

    ipfs.on('ready', () => {
      console.log('ipfs ready');

      //Create OrbitDB instance
      const orbitdb = new OrbitDB(ipfs);

      console.log("orbitdb ready");

      //store ipfs and orbitdb in state
      this.setState({
        ipfs: ipfs,
        orbitdb: orbitdb
      });
    })
  }

  render() {
    return(
      <div>
        <h1>Connect to IPFS and OrbitDB</h1>
        <p>{this.state.ipfs === null ? `IPFS Not connected` : `IPFS Connected`}</p>
        <p>{this.state.orbitdb === null ? `OrbitDB Not Instantiated` : `OrbitDB Instantiated`}</p>
      </div>
    );
  }
}
export default OrbitDBHandler;

ipfs-orbit-db-connect.js hosted with ❤ by GitHub
在我的本地机器上,IPFS实例化只花了不到一秒钟的时间,紧接着是一瞬间,然后OrbitDB就被实例化了——因此触发了重新渲染以反映更新的状态。

数据库创建者+数据库持久性

此时,值得简要讨论一下哪个节点创建数据库的问题。如果我们允许最终用户这样做,运行基于浏览器的IPFS节点,我们将看到该节点在该用户离开网页时断开连接,或者只是失去连接。然后,刚创建的数据库将变得无法访问并被销毁。

现在需要的是一个高可用性节点来实例化数据库,并让它的对等节点复制和固定数据库,使其成为可广泛访问的。

这里的解决方案是让服务器端IPFS节点作为IPFS集群的一部分来创建数据库。IPFS集群是另一个话题,但是,作为集群对等方的IPFS节点将由所述集群中的每个对等方自动复制和固定其文件。

这可以通过IPFS的“Distributions page”页面上的ipfs-cluster-service和ipfs-cluster-ctl包来实现。

通过这篇介绍性文章了解有关安装和配置IPFS群集的更多信息:
Using IPFS Cluster Service for Global IPFS Data Persistence

创建数据库

现在,通过实例化orbitdb对象,我们现在可以在IPFS网络上创建数据库并与之交互。

创建数据库很简单-可以通过以下方式创建keyvalue数据库:

#keyvalue database
const db = await orbitdb.keyvalue('my-database')

OrbitDB方法是异步的,支持Javascript中的async、await实现。

为了完整起见,让我们基于其他现成的数据类型来运行其他数据库创建方法:

#log
const db = await orbitdb.eventlog('site.visitors')
#feed
const db = await orbitdb.feed('orbit-db.issues')
#docs
const db = await orbitdb.docs('orbit.users.shamb0t.profile')
#counter
const counter = await orbitdb.counter('song_123.play_count')

创建数据库后,将生成一个结果地址字符串,允许对等方复制和写入(如果他们具有写入权限)数据库。接下来让我们看一下地址字符串。

注意:如果我们想复制一个已经存在的数据库而不是创建一个,那么数据库的地址字符串将被传递到上述方法中,而不是名称字符串。

OrbitDB数据库地址字符串

OrbitDB数据库字符串由以下内容组成:

/<protocol>/<database_manifest_hash>/<database_name>

为了避免重复现成的可用资源,可以在GitHub上找到更多关于地址字符串的文档。

获取数据库地址

了解OrbitDB中的数据库字符串很重要,因为其他对等方需要它来与数据库交互或复制数据库。地址可以通过db.address获得。db是您的数据库实例:

const address = db.address.toString();

接下来,让我们访问可访问性,以及如何配置对等方对数据库具有写访问权限。

授予写访问权限

OrbitDB目前只支持配置写访问权限-默认情况下,写访问权限仅授予数据库创建者,而读访问权限是全局的。
为了给更多的对等方提供写访问权限,我们在创建数据库时传入了一个访问对象。是的,当前定义写访问权限的唯一方法是在创建数据库时。这无疑将在未来发生变化,但这是我们目前必须坚持的限制。

在实际使用中,通过以下方式传递访问对象:

const access = {
   // Give write access to ourselves
   write: [orbitdb.key.getPublic('hex')],
}
const db = await orbitdb.keyvalue('first-database', access);

数据库的创建方式与前面相同,但这次将access对象作为第二个参数传递。访问是一个由写字段组成的对象,写字段由需要写访问的对等方的公钥数组组成。

现在,这些公钥不是您的IPFS标识哈希。相反,它们是对等方的OrbitDB实例密钥。为了获得所需的写入特权对等方的实例密钥,它们都需要在实例化orbitdb后运行orbitdb.key.getPublic(‘hex’):

console.log(orbitdb.key.getPublic('hex'));

一旦获得,就可以将它们插入访问对象。

const access = {
   write: ['key1', 'key2', 'keyN'],
}
...

关于访问控制的官方文档可以在GitHub上找到。

数据库事件

此时,我们已经准备好与数据库交互,但您可能想知道如何监听复制数据库的更新以保持UI同步。

从本文前面的内容中我们了解到,一个数据库在对等点之间会自动保持最新,因此现在需要做的就是对来自其他可写对等点的传入更改做出反应

事件机制内置于数据库实例中。我们可以使用复制事件对传入的更新作出反应(示例取自文档):

// When the second database replicated new heads, query the database
db2.events.on('replicated', () => {
   
   const result = db2
     .iterator({ limit: -1 })
     .collect()
     .map(e => e.payload.value) {
        console.log(result.join('\n'))
     }
 });

对于复制和事件的进一步阅读,GitHub上有很好的文档。

查询数据库

现在,您可以深入了解文档并研究每种数据库类型的CRUD方法。数量不多,且易于使用:

  • keyvalue( put, set, get )here.
  • log( add, get, iterator )here.
  • feed( add, get, remove, iterator )here.
  • docs( put, get, query, del )here.
  • counter ( inc )here.
    所有OrbitDB方法都是异步的,请记住将它们视为带有await的方法。

结束语

这是对使用OrbitDB的细分。现在是开始尝试使用OrbitDB以及一般的IPFS的好时机,以了解其与你的应用程序基础设施相关的使用情况,并从其分布式架构中获益。

在生产环境中部署任何OrbitDB所需的资产之前,请记住OrbitDB仍处于积极开发阶段。根据他们在Github上的通知:

状态:处于活动开发
注意!OrbitDB是alpha stage软件。这意味着OrbitDB还没有经过安全审核,编程API和数据格式仍然可以更改。如果您计划在任务关键型系统中使用OrbitDB,我们鼓励您联系维护人员。

但考虑到这一点,已经有了一些令人印象深刻的演示,包括orbit的实时聊天应用程序https://orbit.chat,将以太坊和web3与uPort集成相结合,并将IPFS和OrbitDB用于聊天内容。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值