Nucleoid是一个低代码框架,它跟踪 JavaScript 中的给定语句,并在图中创建变量、对象和函数等之间的关系。因此,就像在 Node.js 中编写任何其他代码一样,运行时通过管理 JS 状态以及存储在内置数据存储中,将您的业务逻辑转换为完全工作的应用程序,这样您的应用程序就不需要外部数据库或其他任何东西。
const nucleoid = require("nucleoidjs"); const app = nucleoid(); class Item { constructor(name, barcode) { this.name = name; this.barcode = barcode; } } nucleoid.register(Item); // 👍 Only needed a business logic and 💖 // "Create an item with given name and barcode, // but the barcode must be unique" app.post("/items", (req) => { const barcode = req.body.barcode; const check = Item.find((i) => i.barcode === barcode); if (check) { throw "DUPLICATE_BARCODE"; } return new Item(name, barcode); }); app.listen(3000); 复制代码
差不多就是这样,多亏了 Nucleoid 运行时,只有这个👆,你才成功地用业务逻辑持久化了你的第一个对象😎
什么是链上数据存储?
Nucleoid 项目的一个重要目标是在同一运行时下组合逻辑和数据。Nucleoid 有一个内置的链上数据存储,通过区块链风格的加密来保存后续交易。每个事务都按顺序相互加密,数据存储将这些哈希值保存在托管文件中。每笔交易都在亚毫秒内完成,哈希值的任何变化都会抛出错误,从而保证对象的最终状态,并且如果没有有序的哈希值和初始密钥,对象将不可见。
对运行时的每次调用都被视为一个事务,即使它包含多个语句,如果抛出错误,它也会回滚该事务。
nucleoid.run(() => { a = 1; b = a + 2; c = b + 3; }); 复制代码
运行时返回这样的东西;结果(如果有的话)、时间戳和交易哈希。
{ "date": 1672179318252, "time": 1, "hash": "d3af6bdae8e8ff1eeb1f0f1ea8aaf02e:8b23f8ec493a16cee484f44a6e09a543a62b5e535b8c16ad5f8484766eed686d" } 复制代码
重要的不同是链上数据存储不存储值,而是像 CQRS、Event Store 等中那样持久化事务,并且预计运行时会在内存中建立值。该算法提供了具有更大空间复杂度的快速读取和快速写入,并且需要在启动时在内存中计算值作为权衡。
例如,此表作为事务的一部分构建在内存中:
内存中的值
状态 | |
var a |
1个 |
var b |
3个 |
var c |
6个 |
数据存储中的事务
但实际的数据存储看起来像这样👇(虽然这是解码的交易对象):
{ "s": "var a = 1" ... } { "s": "var b = a + 2" ... } { "s": "var c = b + 3" ... } 复制代码
哈希是如何生成的?
运行时使用硬编码的创世令牌作为链中的第一个哈希。当它收到更多交易时,数据存储使用先前的哈希以及密钥来生成链中的下一个哈希。它使用带有可配置算法的 Node.js 内置加密包。
托管文件中的链上数据示例~/.nuc/data/
:
ff2024a65a339abd3c77bb069da38717:10812ca4ed497e3167684f9b0316b5cf72992adffd9ed8bd97e08f321e117daf367b012 a1a521479a43e1b16ce0ecc1671fbd8d:1ceb5211efadecc791c22a010752ecdf626764a71c4bc80c74f9d3ba6adb88d2e7cedcf 20033f1556383ce5b911436aa76381a8:543a50ae5072aa64acb0ef7c307aa53f3aaea042023704362305bedfafd721c9f918740 ee8a894958d4bb372d1a9e63335ccee7:4834d1e04e6b234135ae896c0057186df4c820b9b25fa6ce153e03f89c63b905208ba07 dc2d6d47071db41845fa8631b131bef5:0ec5427dd957ccb46fbd6884290eb0de9696102405fc606d2acf56e059ed3e827610e6a 3ef42a5927c4e231f17323619d6a60d1:e793031d12c9e5b10708c62d49a56c77fd9ef463606609036d22af83490106c213224e5 3a016c3e71238462f8b42ebb733e5856:cb1595d06424c7e1ec3c353f5eee2d6cf1b804306dcdadb09a6be9a066b89581270464d 复制代码
可扩展性
Nucleoid 遵循单线程多进程范例。分片处理程序采用 JavaScript 函数并允许开发人员创建自己的可扩展性策略。该函数接收额外的数据,如请求标头、正文等,它还带有 Nucleoid 运行时以及内置数据存储,因此分片函数可以持久保存用户数据,以便memtable
像 Cassandra 一样支持。
npx nucleoidjs start --cluster 复制代码
此npx
命令启动专门的 Nucleoid 实例,并充当集群的前门。默认的分片功能Process
从 REST 中获取标头并在进程列表中查找 IP 和端口信息,并且可以使用调用终端添加集群实例process1 = new Process("127.0.0.1", 8448)
。
可以通过在函数中包含函数~/.nuc/handlers/cluster.js
并从函数返回进程 ID 来更改默认函数。例如:
// cluster.js const jwt = require("jsonwebtoken"); function run(req, fn) { const bearer = req.headers["authorization"]; const token = bearer.split(); const decoded = jwt.verify(token, "secret"); return decoded.company_id; // This returns company id as a process id } module.export = run; 复制代码
基准
这是我们在 Nucleoid IDE 中使用 Express.js 和 Sequelize 库的示例订单应用程序与 MySQL 和 Postgres 的比较。
性能基准在 AWS EC2 实例的 t2.micro 中运行,两个数据库都有没有索引和默认配置的专用服务器。对于平均复杂度的应用程序,由于链上数据存储、内存计算模型以及限制 IO 过程,Nucleoid 性能接近线性。