我们将如何拥有一个允许更新和同步的分布式数据存储网络?
这些问题实际上是web3分布式部分的核心。Web3还有其他部分:不变性、加密安全性等。但这些其他元素不回答如何在分布式数据存储上执行更新*
在寻找这些问题的答案时,我看到了一个相当简单的工具作为基础:JSON diff和patch。
JSON,因为JSON是web的结构化数据格式。对于Web3来说,这种情况将继续存在。在我们的web架构中,几乎所有人都使用JSON。其他格式将越来越多地被用作JSON的优化。关联数组具有(合理的)人类可读性之美,加上现代计算机编程语言中广泛的本机支持。电脑和人类都能读,这不是爱!
git分布式管理源代码策略中的一个基本工具是diff和补丁的概念。这些基本操作使git成为可能。Diff用于构造可应用于对象的面片,从而使最终状态对某些值有意义。
应用补丁是因为我们希望将某个前状态提升到某个后状态。补丁并没有指定所有内容。只有源代码的预期正确,以及更新后的预期正确。
这样,就可以对源文本的不同部分执行分布式更新。冲突会导致需要采取一些补救措施,但如果没有冲突,则可以合并所有内容以获得最终状态,该状态尊重所有更新,无论它们来自何时何地。
这使得git可以完全多主,而不需要或强制使用任何复杂的协议(如RAFT)进行同步。
逆包器Mark 2";id";:13234,";名称";";描述";";";描述";";";";逆包器Mark II是逆包器的最新发展,用于为单侧相位分配器产生反向无功电流。, "价格";:{";价值";";3430.23";";货币";";欧元";}"股票";:32 , "供应商";:[";供应商/123";,";供应商/4332";]
如果Alice在应用程序中打开对象并将项目名称更改为";复古建筑标志II";,BOB应该可以同时更新供应商名单,而无需相互干涉';脚趾。
在应用中,这种策展操作通常通过锁定对象来实现。这意味着只有一个人能赢。锁是巨大的痛苦来源,不仅因为你可以';无法实现其他完全合理的并发操作,但因为您可能会遇到过时的锁,并且必须确定何时释放它们。
但如果萨莉没有';Don’我不能提交她的整个对象进行更新,但只提交她想更改的部分?鲍勃也这么做了?
现在我们可以在三个不同的地方执行更新,本地为Lice,本地为Bob,最后在共享服务器资源上执行。
结构化补丁可以通过在Alice提交之前查看对象来确定,然后使用diff从Alice'构建补丁;s diff可能是这样的:
{";姓名";:{";前";";复古装潢师标志2";";";";复古装潢师标志II";}
现在,两者都可以清晰地应用于上面列出的原始文档。我们可以毫无困难地按任何顺序堆叠任何一个补丁。也许我们要求KBOB和Alice就应用程序顺序达成一致(使用git完成拉/推操作)。但也许我们只是允许他们在他们来的时候申请。答案取决于工作流程。
{";姓名";:{";前";";复古装潢师标志2";";";";复古装潢师标志2";
我们有个问题。但我们立即发现,这两者存在冲突,爱丽丝可以被要求通过浮出水面来解决这个问题。在数据整理的情况下,这是一个完全合理的工作流程。我们可以用JSON diff最简单的版本来解决这个数据整理问题。
这种冲突可以向爱丽丝浮出水面,鲍勃可以被允许继续他的生意。这个特殊的问题能用CRDT自动解决吗?当然,但它可能不会产生你想要的结果。最后一步当然会奏效,但接下来哪一步更正确可能需要人工审查,更糟糕的是,这可能会导致两种结果交错(一种可能的结果!)。
然而,我们可以使用文本差异将前后的内容制作成基于文本的补丁。可能gits基于行的方法不是我们想要的,而是将单词作为原子的方法。它不会解决这个特定的冲突,但它可以使文本字段更加灵活。
然而,您想要哪一个,需要DIFF算法的语义方向。虽然许多结构化的差异问题将通过最简单的算法来解决,但最终我们需要一个有助于指导差异含义的模式。字符串字段可以是基于最佳行的、基于单词的,或者它们必须始终是原子的(就像标识符一样)。
补丁实际上是更简单的操作。补丁应用程序基本上只是检查读取状态是否匹配,然后替换写入。
相比之下,Diff必须进行计算,而且在实践中经常需要猜测从读状态到写状态的良好转换。diff提供的补丁的具体调整取决于应用程序的需要。有一些通用算法可以在一系列应用中正常工作,但没有一种通用算法。这就是为什么我们需要模式提供的语义方向。
Diff在计算上也要昂贵得多。找到最小的变化意味着找到最大的相似性。事实证明,这对于JSON字典的框架来说非常简单,但对于列表和字符串来说却非常困难。对于列表列表。。。嗯,我';我待会儿再谈。
让';就这么说吧';毫不夸张地说,你可以轻易地陷入宇宙的热寂之中。因此,启发式必须是任何全自动差异的一部分。
但也有其他工作流可能需要更灵活的方法来确保数据完整性。before状态正在重新设置以指定读取对象模型。它告诉我们,当我们应用补丁时,我们希望什么是真实的。
对于git,这可能是一行行文本。例如,更改一个非常简单的自述文件。txt最初是向一个向松鼠问好的人问好,git将生成一个如下所示的补丁:
这不是';它不是最紧凑的补丁,如果hello被改成其他单词,比如“问候语”,它就会发生冲突。它对git很有效的原因是,对于编程语言来说,文本行是一种合理的粒度。
但是唐的前后';不必是台词或文字。before可以是读取状态的任何规范。对于银行账户提款,我们可能会要求前状态大于后状态,或与后状态相等。这将是一个很好的小交易,以确保我们不';不要透支。
或者我们希望用正则表达式指定before状态?或者,我们读取了很多值,以便计算对象中的进一步值,在这种情况下,我们希望知道这些值都不会改变。
这种方法为我们提供了一种读隔离,它根据我们使用的用例进行调整';我们真的在一起工作。将补丁作为更新的单位,为我们的应用程序提供了恰到好处的粒度,这实际上可以';我们不能提前知道。
这是一个超越了通常由数据库提供的隔离选项的进步,并且自然地扩展到了对象或互连对象的组织图(如USDB中存在的)。
我';我们在TerminusX中实现了一个简单的JSON差异和补丁。但我们';realso正在将其扩展到aschema指定的版本。它';它也很容易实现,而且想象一个完整的补丁空间非常有趣,其中许多补丁永远无法由adiff确定,但对于通过文档存储进行分布式传输来说,这将非常方便。我们将在实践中遇到用例时添加这些不同的操作,但我们';我们也很高兴听到人们在野外已经遇到的用例。一定要告诉我!
*CRDT针对特定类型的数据结构回答了这个问题,但不是针对所有类型的数据结构。这些方法只能更新某些类型的数据结构。此外,许多更新需要人工辅助审查,并且永远不需要aCRDT。还有一些将具有无法在CRDT中指定的对象读取模型条件。最终,我们的数据库应该支持一系列分布式数据类型,包括CRDT。
如果您对JSON diff&;感兴趣;帕奇,我们';将于2月17日格林威治标准时间下午3点在Twitch上播放。