NOSQL存储的基于事件的事务实现

                   
banq 11-08-31

NOSQL存储的基于事件的事务实现

NoSQL认为两段事务2PC容易导致每个参与者锁定一段时间,不能实现数据分区(CAP定理),但是关系数据库能够实现我们需要的原子级别事务更新。这在许多应用中是必须的。

那么在这种需要高一致性原子事务情况下一定要使用关系数据库呢?甚至有人提出关系数据库为主,NoSQL为辅助的所谓通用方案。这篇文章就提出了基于事件的NOSQL事务解决方案。

NOSQL中忽视原子事务的一个自然解决方案是:如果在分区更新失败情况下,就让数据不一致呗,如果将吞吐量因素高于一切,甚至高于数据本身的话,这是一种可接受方案。

如果非得需要事务情况下,怎么办呢,文章认为其实在4年前的Adam Heroku一篇博客已经给出答案:http://adam.heroku.com/past/2007/12/17/a_world_without_sql/

银行账户之间转帐的老式做法是使用数据库事务,这种做法比较刚性(公牛),正确做法是将转帐事件存储起来(banq注:EDA事件驱动架构,把事件当数据,Hold住事件本身,而不是事件的结果数据),如果你是一个面向函数范式的思维者,这本身没有什么奇怪的。

对于NoSQL,解决方式是使用两种不同的数据空间,一个用来写数据,一个用来读书节,还有一个Job异步地从第一个数据空间拉数据,将其传送复制到第二个空间,两个空间有不同的数据模型,读写分离架构CQRS。如下图:



写数据空间这边主要保存的是写操作事件,比如ProfileUpdateEvent,如下图:


异步的传送Job再将这些写事件获得,运行这些写事件(事件触发函数),向读数据空间里写入更新的数据。如下图:



非常重要的是,要保证读领域的更新操作是幂等的(见蒯因与引用透明),还有事件必须充分有效地保存到DB中,事件本身必须是自我独立的。

数据管理的未来: “Disk-less” 风格数据库?
[该贴被banq于2011-08-31 13:23修改过]

5
SpeedVan
2011-08-31 15:21

整体感觉就是让事件成为原子事务的承载体,通过事件队列异步更新readDomain?把事件存储起来,可以让运算过程先放下,变成简单的存储过程,异步调出再执行?就是CQRS嘛。。。

我曾想过把事务去掉,如基于不变性和函数的方式。后来只能不断缩小,最后只缩小到更新瞬间。其实演算过程是不需要事务,因为它本身就在自己的边界内运算。

过去的事务:
事务起始
实体查询
实体运算
实体更新
事务结束

我曾经的思考:

实体查询,获取实体状态
把值取出来(关键,不是对实体处理,而是对值)
值参与运算(值不可变,只有新值和旧值)
返回状态更新事件(一致性不强,可在这里直接更新实体状态)

以上都不会出现事务。不过在实体之间的一致性略弱,即需要a1,b1状态时,可能会得到a1,b2或者b1,a2,因为取数肯定分先后,所以想加强这样的一致性,只能在状态更新时把实体锁起来更新,保证同时更新效果。这些可以在执行更新事件时处理。异常回滚,既然出错了,也就不会发生更新事件。(注意,这些都是在内存中进行的)

State oldState = entity.getState();//把值取出来

State update(State oldState){//值参与运算,

return new state();
}

Queue.put(new UpdateEvent(key,state));//到这里,仍然没有对过去的状态作出修改

到此,我发现banq所说到的,和我过去所想的有很大相似点。(就是当时我对仓储上升到架构的思考)

其实真的有事务的需要么?

banq
2011-09-01 11:13

2011年08月31日 15:21 "@SpeedVan"的内容
其实真的有事务的需要么 ...


事务可以使用另外一种方式实现的,不一定是传统的数据库锁或会话事务,见老马这篇给力的文章,JdonFramework与之很像:LMAX架构