【第22期】观点:IT 行业加班,到底有没有价值?

TARDiS:A Branch-and-Merge Approach To Weak Consistency

翻译 2017年01月03日 13:53:57

事务异步复制的不同存储:弱一致性的分支与合并方法

摘要:
本文叙述了一个针对弱一致性系统设计的事务型键值对存储系统——TARDIS的设计、实现和评估。
TARDIS暴露出在弱一致性系统中出现的基础的抽象概念:冲突-》分支的集合。
提出了一种新的并发控制机制:冲突-》分支。
以此来保证从一个分支继承出的执行线程看到的存储是有序的,保证应用逻辑简单。还提供了应用随时按需自动合并分支。
因为TARDIS在冲突时新建分支比较快,弱一致性系统可以采用这种方式来处理不同客户端的操作以及正确的本地冲突操作。TARDIS还减少了这类系统的代码复杂度,并且聪明的冲突-》分支可以增加客户端吞吐量2-8倍。

介绍:
TARDIS是异步复制的,多master节点,事务型键值存储系统。TARDIS是为构建在弱一致性和非事务型系统(Riak,MongoDB,Cassandra)的应用设计的。TARDIS放弃了顺序存储的抽象模型,暴露给应用一个并发和分布式的概念。
TARDIS的设计基于一个简单的概念:帮助开发人员解决这些应用程序中出现的异常,每个副本应该记录完整的上下文,以便了解异常时如何发生的。但是只在需要的时候才向应用程序暴露异常。
根据CAP理论,很多大范围服务和应用选择了放弃强一致性来换取ALPS(可用性,低延迟,网络延迟容忍,高扩展性)
很多主系统将应用于这种复杂性隔离开,依赖了两种技术:因果一致性(针对读写冲突),单对象最终收敛(针对写写冲突)。
当冲突出现时的解决方法有两种:在存储层(通过确定的解决机制强制单对象收敛),或交给应用程序通过冲突更新解决对象的状态。但是这些技术不能解决同时更新时顺序存储的抽象概念。
更糟糕的是,因果顺序和单对象收敛不能解决针对多对象的同时顺序更新。而且,这些技术摧毁了应用程序可以用来解决错误的信息。
ALPS系统中不可避免的写偏序异常,既难预防也难解决,因此,如何为ALPS系统合并冲突状态提供最好的系统支持是最主要的。
类似git,TARDIS不依赖确定的用户指令,使用了三个核心机制:(1)冲突分支(2)内部隔离分支(3)应用程序驱动的跨对象合并
(1)冲突分支让TARDIS可以在检测到冲突操作时从逻辑上进行状态的分支,并且保存冲突的分支。(2)内部隔离分支保证了存储对任何出自一个分支的线程的操作是有序的,保证了程序的逻辑简单。(3)任务可以决定是否、何时、如何将冲突的分支合并到应用程序中。而不是存储层(不适合平衡语义信息)。

TARDIS有四个特性:
(1)系统保留历史信息。每个节点存储了一个记录所有操作产生的分支的有向无环图。并且使用了新的DAG压缩算法。这些保存的上下文环境会在编程是带来好处。
(2)合并分支,不是对象。TARDIS提出了一种跟踪冲突的概念,通过将分支总结为一个分歧点和合并点的集合,这减少了使用因果一致性系统遭遇的元数据负载。
(3)良好的表现性。TARDIS支持很多隔离层次(可串行性,快照隔离,确定的读)和一致性保证(读我所写,因果一致性)。并且可以和商用数据库BerkeleyDB相比。TARDIS实现这些依赖两种重定义:隔离和一致性需求-》状态前和状态后的集合
(4)提高了本地节点的性能。TARDIS为ALPS应用程序提供了将弱一致性准则应用在端到端,通过跟踪不同节点和本地冲突操作产生的冲突分支。当这样配置时,TARDIS处理本地冲突并不通过终止/回滚和锁,而是逻辑上将本地数据库分支。这一特性并不对所有应用有利,但是对TARDIS针对的那些ALPS应用程序(弱一致性和合并时第一考虑因素),可以利用这一特性显著增加吞吐率。

2.因果性和现实的差距
一个因果一致性的例子:A在和B接触好友之后发的照片,B不应该看到,即使他们从不同的节点访问照片共享程序。但是ALPS应用程序面临另一类异常:写写冲突(因果一致性系统无法预防、检测和修复)
图1展示了双副本时的写写冲突和语义矛盾问题。这里面包含了弱一致性系统中的两个公开难题。
(1)句法冲突解决方案,很多系统采用修正的、句法的解决规则来解决写写冲突,确定的写赢解决各节点的写写冲突,但是这种解决方案无法缓解语义鸿沟,还会丢失有用的信息。
(2)缺乏跨对象语义。无法解决两个对象间的语义冲突。
从一个写写冲突产生的后续操作可能使整个数据库都不一样。
事务不能解决对象间映射的写写冲突。比如第一个写操作结束之后,第二个写操作来了,系统肯定更要先将第一个写操作诞辰给一个事务提交,并且将第二个写操作也当做一个事务。

3.填补鸿沟:分支
TARDIS的设计理念:将ALPS应用程序与各自独立的写冲突、应用需要的解决过程隔离开是一个好心的错误。
当冲突产生时,TARDIS提供了两个新功能来缓解。
(1)将结果独立的分支和这个分支产生的状态集合(fork点和merge点)暴露给应用程序。
(2)提供原子级合并分支,并且允许应用程序选择when和how来合并。

3.1状态分支和合并
将分支升到数据存储的基本抽象有两个互补的优势。
分支和他们的fork和merge点,封装了所有被合并时需要考虑的因素,以及冲突是如何发展的。

3.2点到点的弱一致性
冲突操作也可能发生在本地,由于可以立即检测,一般处理方式是加锁或回滚,在ALPS应用中,这就有问题了。第一抽象的顺序存储无法被端到端保留,在分布式系统层次就宕机了。第二设计的复杂度来解决远程冲突已经被考虑到ALPS的应用中了。
为ALPS应用提供一个数据存储,分支当做基本抽象。用来模拟端到端的冲突。这样就给了应用通过冲突-》分支处理本地冲突的可能。不可控的分支会导致推理系统很难,TARDIS允许应用调节本地分支的级别,用来平衡性能和复杂度。

3.3系统目标
(1)接口简单
(2)好的性能
(3)较小空间复杂度

4.系统架构
每个副本包含四个部分:
(1)存储层次:将记录存储在基于磁盘的B-Tree。现在每个节点存储了一个完整的数据库的副本(TARDIS也可扩展支持数据分区)。每个更新朝族都会创建一个新的记录版本,版本和key的mapping存储在内存cache中,便于快速遍历。
(2)一致性层次:通过一个DAG跟踪分支,顶点是一个数据库的逻辑状态。每个更新记录的事务产生一个新的状态。
(3)垃圾回收单元,包含一个DAG压缩子模块,和一个记录剪枝子模块。用来控制空间复杂度。
(4)复制服务器:传播提交的事务,将远程的事务正确应用。

5.使用TARDIS

5.1接口
TARDIS可以工作在单模式和合并模式下,在单模式中,编程和传统的事务型系统一样,除了需要指定一个分支。
在合并模式下,程序员可以通过合并事务解决冲突分支,允许跨对象的原子级解决方案。就像事务一样。
为了让应用解决冲突,提供了三种接口:
(1)findConflictWrites:检测冲突对象
返回选择的分支上的所有冲突的值
(2)findForkPoints:定位分支点,对于给定的状态集,返回fork点的结构化集合。
(3)getForID:确定分支点的值,允许请求任意对象的版本,将程序员从跟踪数据库演化的任务中解脱出来。应用程序需要在fork点主动调用这个方法来获得对象的值。并且用这些信息通过系统专业的方式解决冲突,之后再写回合并的分支。

begin和end的约束可以随意搭配,足够模拟传统的数据库系统中的隔离级别

5.2用TARDIS编程
传统的因果一致性系统中,计数器用两个分离的向量时钟实现,一个加一个减。应用一个远程操作需要合并本地的加减向量,将向量各元素取最大值。所有的操作,包括非冲突的读,实际上都需要merge,系统必须通过每个副本的本地视图重新构造全局视图。
TARDIS的单模式和merge模式是完全分开的。单模式中加减操作针对一个单一的属性(像非分布式场景一样)。对fork点暴露接口使得merge操作简单和灵活。

6设计和实现

6.1.1开始事务(读状态选择)
从最新的合适的状态入手,广度优先搜索叶子节点,TARDIS会选择一个满足begin约束的状态,一般来说是唯一的,如果有多个,就随机选一个。

6.1.2提交事务(提交状态选择)
事务首先检查读状态是否满足end约束,不满足则放弃事务。满足的话则继续搜索是否有更多的满足end约束的状态,直到遇到不满足的,这时在最后满足的状态下令开一个提交状态。

6.1.3读记录
逻辑上,非只读的事务每次执行都会创造数据库的新状态。保存每个状态是不可忍受的,写操作只产生记录的新版本,写时复制和最多多版本控制机制(MVCC)类似,但是有一个重要的差别:TARDIS不仅支持旧的快照,而且支持不同分支的快照。MVCC系统在读数据时事务必须确定一个最新的数据版本。但是TARDIS必须同时确定数据版本属于选择的分支。

为了快速确定一个记录的版本是否属于选择的分支,TARDIS放弃了传统的依赖检查(在因果一致性系统中的瓶颈),而是依赖fork点检查。
每一个fork出的点都记录了一个tuple(i,b),表示当前状态是状态i的第几个儿子节点。

如图,状态2是状态1的第一个儿子,状态4是状态1的第二个儿子,如果没有分支则保存父亲节点的状态,如状态3保存了状态2的tuple。
可以根据fork点的集合是否包含另一个来判断他们是否属于一个分支。比如s8包含s3,所以是一个分支。

为了保证事务选择了最近的版本。TARDIS为每个key-版本映射维护了一个版本的拓扑排序。每个key的所有版本从新到旧在链表中从头到尾连接。在事务读数据时,从头扫描链表,第一个出现在自己分支上的记录版本就是最新的。
例子:事务t10的版本有(0,1,2,3,8),A对应2,B对应8,C对应1,D对应null

6.1.4写数据
为了处理一直的分支和非分支场景,TARDIS的写逻辑保证(1)写操作在冲突或不冲突是都不block。(2)更新正确的记录在正确的分支上很容易。
写数据时需要做的仅仅是插入新的版本到跳转链表中。
只读事务不产生新的状态,不加入DAG中。

6.2合并事务
提供了三种获得需要信息的方法,如上。

6.3垃圾回收
(1)用户设置特定的状态为顶层,保证不会将此状态之前的当做读状态。
(2)路径压缩算法压缩,压缩DAG中非fork节点和非叶子节点。
(3)记录升级算法,去除记录版本中由于(1)和(2)不再被看到的版本

6.4复制
垃圾回收机制有主动和被动两种操作方式,被动则在接收所有复制品的一致同意后才操作。
乐观则允许每个节点独立进行回收。
暂不支持数据分区。但是可以扩展来支持这个功能。

6.5容错和恢复
recovery:按时间顺序遍历日志,对每条日志(1)将状态插入DAG中,并且作为匹配的父节点的子节点添加进去(2)在key-version中添加一个记录
异步刷磁盘:减轻了写磁盘负载
checkpointing:为减少日志大小,定期执行非阻塞检查点机制(1)选择一个状态(2)刷所有的outstanding写(3)保存每一个比选择状态小的DAG状态
replication:为了恢复在其他节点提交了但是本地丢失的事务,恢复进程广播一个向量,包括从每个复制器接收到的最新的状态。复制品将比这个状态新的状态发送出去。如果这些状态已经被回收了,则发送整个DAG

6.6实现注意
在TARDIS-BDB中,记录持久化是通过BerkeleyDB实现的,且没有用到并发控制。TARDIS-MDB以来MapDB。
以来protobuffers进行信息序列化

7评估
使用了分支/合并减少了一半代码行数,有效的冲突分支产生了2到8倍的加速。

跟踪状态的负载:
比较了全读和全写性能,基本与BerkeleyDB一致,比OCC好,因为OCC要确认只读事务,而TARDIS的确认阶段(提交状态检查)消耗小,只需要检查事务的写集合是否是选择的读状态的子集。

什么时候本地分支会提升性能:
所有的事务运行在开启冲突分支,并且Ancestor和Serializability作为begin和end约束。
在数据库中对象访问符合zipf分布时,由于竞争激烈,TARDIS性能较好。TARDIS的lock free实现的写跳转链表保证写不会阻塞(即使冲突时)。
在zipf分布时,由于竞争激励(锁),BDB的读写比普通的慢十倍,TARDIS只慢了一点。OCC表现最好,因为OCC保证了(1)至少一个事务总会被提交(2)读不会阻塞写。但是OCC的高弃疗率和昂贵的确认阶段使其吞吐率是TARDIS的5倍
在一致的写数据时,由于锁发生的几率小,TARDIS的垃圾回收速度不能跟上状态的产生。增加的内存使TARDIS的性能比BDB差10%。

表现层面对性能的影响:
begin的约束会对性能造成影响,但是end约束影响较小。

垃圾回收:
垃圾回收使得吞吐率维持在平稳水平,而不进行垃圾回收则会因为java的垃圾回收机制使得系统停顿。而状态和记录个数上,回收是不回收的1%,但是是BDB的100倍。尽管状态在变成垃圾可回收状态时被清除掉,但是状态提升表首先要被刷磁盘(在这之前要运行一遍记录版本提升过程),这些记录一般都不会在cache中,所以记录提升线程滞后。这个是缺点。

如何扩展成多节点:
扩展是根据节点个数线性增加的。系统保证远程事务应用不会与本地事务竞争。

7.2应用
(1)明确的状态分支和合并会简化冲突解决策略吗?
CRDTs是一种数据类型,支持懒拷贝,包含一组有语义意义的冲突解决策略。
TARDIS来实现CRDTs简单并且代码少,大概BDB是TARDIS的两到三倍。原因是两个:1.状态ID复制:保证本地执行的操作会在远端节点的同样状态上执行,避免了不活并且复制的副作用。2.冲突跟踪:为合并更新提供简单的接触需要的DAG信息。但是扁平存储的BDB系统需要明确跟踪每个副本的更新并且CRDTs的状态被复制到所有副本上。 拿计数器举例,BDB需要CRDT开发人员确保操作会全局正确。但是TARDIS会将需要的信息都给开发人员,合并就和加法一样简单,将每个分支的计数器值和当前值加起来就行。
为保证最终一致,CRDTs在顺序存储上的实现必须保证本地状态原子化和顺序性。这限制了吞吐率。冲突-》分支在不牺牲一致性的情况下避免了这些限制,TARDIS实现的CRDTs增加了4到8倍吞吐率。原因有三个:1.每个独立的操作比较简单,读或更新计数器不再需要操作向量,只需读写一个int。2.操作不用有序,冲突就分支就可以了。后面再合并。3.合并可批处理。传统的CRDTs需要为每个远程操作合并。但是TARDIS系统中不同操作记录在不同的分支上。
(2)ALPS应用程序可以用本地冲突-》分支来提升性能吗?
实现了Retwis,一个类似Twitter的,当只读时,TARDIS没有明显优势,但是在read-heavy和post-heavy时优势比较明显。因为写会阻塞读和写,但是TARDIS在冲突时直接分支,合并也不会阻塞系统。


8.Relatedwork

Branching:
其他的分支系统也暴露了分支,如git,Olive文件系统。但是他们暴露的分支太明确了,但这恰是ALPS应用程序希望避免的。TARDIS提供的分支比较隐晦。
还有一类因果一致系统,允许并发写暴露给用户。这限制了分支,其实是分支了单个对象而不是状态。这类系统没有提供跟踪冲突或分支的功能,将多个值暴露给应用增加了复杂度。在TARDIS中,开发人员只在合并模式需要是才处理多值对象。
在拜占庭问题上,SUNDR和FAUST开发了分支的一致性和线性来避免客户端看到错误客户端的不同的值。Depot系统扩展了SUNDR的模型来支持加入分支,但是Depot没有暴露分支的抽象概念,也不支持跨对象原子合并。Sporc系统支持原子合并分支,但是只针对有限的情况(协同文本应用),并且使用操作变换来解决冲突。

9future work
副本不支持分布式事务,






阅读提纲:

TARDiS:A Branch-and-Merge Approach To Weak Consistency
前提:我们把一个应用分为两部分ABA是业务逻辑处理系统,B是底层的存储系统。TARDIS是B类系统,为具有ALPS(availability,low latency,partition tolerance,scalability)特性的A类系统提供底层支持。
1.论文解决了什么问题,从business problemtechnical problem
         
Business problem:很多A系统的数据存储都是依赖BerkeleyDB或其他现有的数据库系统的,这些数据库系统将A系统与数据冲突隔离开,B系统需要自己实现全局弱一致性的保证措施和解决冲突的机制,使得B系统的实现比较复杂,而且由于B系统要解决冲突,吞吐率也会受到限制。反应到应用层面就是不能有效的支持竞争增多的情况。
Technical problemB类系统中有两个比较难解决的问题:(1)写写冲突,很多系统采用一套固定的解决策略,如保存最后写成功的值。但是不能完全符合A系统的真实想法,而且没有给A系统解决冲突的充分信息。而A系统在不同的应用场景下可能有不同的需要。(2)缺乏跨对象语义,无法解决两个对象间的语义冲突问题(A(人)和B(人)对同一个对象a的不同副本进行了修改,这两个事务完成后,C(人)和D(人)分别根据a的这两个不同副本的两种语义对其他对象cd进行了修改,这时cd就有了语义冲突,但是正常合并时只能检查出a的冲突并进行冲突解决,不能检查出cd有了冲突,这样就会出现对象间的语义冲突)
2.论文的问题是不是成立的?有哪些地方是solid的的,有哪些地方其实应用场景是存在疑问的。
         论文的问题是成立的
solid的地方:
(1)现有的大多数B系统没有保留用以解决冲突的上下文(在解决冲突后就扔掉了)。而且B系统无法根据实际需求来处理冲突,只能根据系统逻辑判断。
         (2B类系统在遇到事务之间冲突时,需要先解决冲突,使数据保持一致状态,再进行下一批事务的执行。这样就会等待。吞吐率会受到影响,如果不解决冲突,直接在不同的分支写数据可以大大提升吞吐率。
    存在疑问的地方:
  1. TARDIS提供了两类约束,begin约束和end约束,合理的选择不同的约束搭配可以
模拟出传统数据库的各种隔离级别。但是如何根据需求选择搭配不清楚。
    (2TARDIS解决的是为A类系统提供解决冲突所需信息的问题。如果这个冲突指的是多节点间副本的一致性,那么这个冲突由谁感知?状态的DAG存在哪个节点?如果这个冲突指的单节点的并发操作时产生的冲突,那么TARDIS解决就是单节点的并发控制问题。这样的话如何解决多节点间的数据不一致问题?
    (3TARDIS针对的是数据在各个节点间全备份的情况,针对不同节点间保存数据的不同部分(如hdfs)如何检测冲突并创建分支?
3.如果我沿着这个大方向研究下去,我会对这个问题做一些什么样的改变,或者衍生出一些什么样的新问题,问题和原有问题差异在哪。
我理解TARDIS是解决单个节点高并发情况下如何解决写数据冲突的问题,那么如何解决不同节点间数据冲突的问题?比如A节点写a为1,B节点写a为2。这样如何感知冲突并在不同节点间维护状态DAG图?
4.现有的技术是什么,为什么不能很好地解决这个问题。
其他的分支系统也有的暴露了分支,如git,Olive文件系统。但是他们暴露的分支太明确了,信息太多,增加了合并的复杂度,这恰是ALPS应用程序希望避免的。TARDIS提供的分支概念则比较简单,容易进行合并。
还有一类因果一致系统,将写冲突直接暴露给应用。其实是将单个对象的多个值暴露给应用。这类系统没有提供跟踪冲突或分支的功能,将多个值暴露给应用增加了复杂度。在TARDIS中,开发人员只在合并模式需要是才处理一个对象的多个值,便于掌控。
在拜占庭问题上,SUNDR和FAUST开发了分支的一致性和线性来避免客户端看到错误客户端的不同的值。Depot系统扩展了SUNDR的模型来支持加入分支,但是Depot没有暴露分支的抽象概念,也不支持跨对象原子合并。Sporc系统支持原子合并分支,但是只针对有限的情况(协同文本应用),并且使用操作变换来解决冲突。
5.作者采取的方法是什么。和baselinepre-art相比,理论上为什么会好?实验是怎么做的?实验结果是否成立(比如实验集群的规模过小…)?
    作者认为每一个副本应该完整地记录描述一个冲突是如何产生的所有信息,但是只在上层应用需要地时候再暴露出去。而且将上层应用与底层冲突隔离不是一个好的方式。
TARDIS是一个为弱一致性系统提供支持的存储系统B,为A系统提供了很好的解决端到端冲突的方法。
每个节点都保存了全部数据副本。每个副本包含四个部分:
(1)存储层次:将记录存储在基于磁盘的B-Tree。每个节点存储了一个完整的数据库的副本。每个更新操作都会创建一个新的记录版本,版本和key(记录)的mapping存储在内存cache中,便于快速遍历。
(2)一致性层次:通过一个DAG跟踪分支,顶点是一个数据库的逻辑状态。每个更新记录的事务产生一个新的状态。
(3)垃圾回收单元,包含一个DAG压缩子模块,和一个记录剪枝子模块。用来控制空间复杂度。
(4)复制服务器:传播提交的事务,将远程的事务正确应用。
TARDIS在内存中维护了一个状态DAG。在遇到写冲突时会建立新的状态分支,每个写操作都会产生一个新的状态,并且用一些压缩算法来保证一定的空间复杂度。同时将具体数据按key-version set存储为map结构,每个记录都对应一个按版本新旧顺序连接的链表,存储多个版本的数据,这样可以快速找到一个分支上的所有的数据的值。 
为A系统提供合并分支需要的所有信息(如冲突时的分支点,某一条分支路径上的所有冲突对象等)。使得A系统可以自己定义分支合并规则。简化了A系统的复杂度。
在冲突时建立分支而不是等待冲突解决使得在写数据竞争激烈时本地吞吐率比其他系统要大很多,理论上是正确的。
实验做法:
(1)首先对比了实现ALPS系统的复杂度。分别基于TARDIS和BerkeleyDB实现了几个CRDTs(一致可复制数据类型)和Retwis(Twitter的简化版),对比了他们的代码行数和吞吐率。TARDIS的代码是BerkelyDB的一半到三分之一。复杂度大大降低。吞吐率提高了2到8倍。
(2)对比负载:比较了全读和全写性能,基本与BerkeleyDB一致,比OCC好,因为OCC要确认只读事务,而TARDIS的确认阶段(提交状态检查)消耗小,只需要检查事务的写集合是否是选择的读状态的子集。
(3)接着对比不同吞吐率时的负载,在集群上模拟提交请求。分别对TARDIS、BerkeleyDB和OCC三种系统在读密集、写密集、符合zipf分布的写密集、标准的忙写情况下不同吞吐率的负载情况。在数据库中对象访问符合zipf分布时,由于竞争激烈,TARDIS性能较好。TARDIS的lock free实现的写跳转链表保证写不会阻塞(即使冲突时)。
在zipf分布时,由于竞争激励(加锁),BDB的读写比读密集或写密集时慢十倍,TARDIS只慢了一点。OCC表现最好,因为OCC保证了(1)至少一个事务总会被提交(2)读不会阻塞写。但是OCC的高召回率和复杂的提交过程使其吞吐率是TARDIS的1/5。
在一致的写数据时,由于锁发生的几率小,TARDIS的垃圾回收速度不能跟上状态的产生。增加的内存使TARDIS的性能比BDB差10%。
实验结果是成立的是对比实验,对比的内容比较有代表性而且比较大众。
    
6.作者为什么会想出这样的方法?
    因为作者在做存储系统尝试解决并发产生的冲突时总觉得少了一些信息,而这些信息只有上层应用才能获取到,这些信息就是实际需求。所以为什么不把冲突保存下来留给上层应用去解决呢?就像git一样,人工处理冲突。
7.作者在解决这个问题中是不是尝试建立了一些假设或者约束去简化问题,或者尝试把读者从一个问题引导到另一个问题。
    
    在开头举的例子是两个人,对一个网页的不同副本进行修改,之后又来了两个人,在前面的改动的基础上继续改动,由此引发的单对象多值冲突和多对象间语义冲突。但是后面解决的问题都是单节点的冲突。并没涉及多节点间冲突如何检测和解决。
8.作者的方法有什么缺陷或者可改进的空间。
    在数据存储类型上有可能进行优化,在多节点冲突时的分支状态产生。
9.如果我来仅仅从方法层面做接下来的工作,我会选择什么方向,为什么。
    本文方法是记录系统演进状态并为上层应用提供简单的获得所需信息的接口,思想是存储系统不解决冲突,交给上层应用利用专业知识合并冲突分支,类似git。
    方法上的改进主要针对数据分区存储时跨节点的冲突检测和状态分支。以及更优秀的垃圾回收机制来减少因保存状态DAG图和多个数据库版本带来的空间消耗。
    思想上没有什么问题。这个思想挺好,甩锅。
举报

相关文章推荐

SVN trunk branch concept and how to merge them(reposted)

需求一: 有一个客户想对产品做定制,但是我们并不想修改原有的svn中trunk的代码。 方法: 用svn建立一个新的branches,从这个branche做为一个新的起点来开发 <div class="cod

svn: check out a new branch , realse or tag and merge to branches.

create a new branch    In SVN, branches, realses and tags are just common directories. Creating a ne...

svn branch and merge(svn切换分支和合并)详解

下文的实践主要是参考了TortoiseSVN的帮助文档和Subversion的在线文档,Subversion的在线文档:http://svnbook.red-bean.com/en/1.5/svn-b...

Git pull from and push to server branch

1.push to server branch. git branch harry git checkout harry --modify something git push origin harry 2.pull from server branch git clone git@10.0.1.1:projectname fetch branch file git fetch git@10.0.1.1:projectname harry git pull origin harry
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)