vlambda博客
学习文章列表

从架构师思维看分布式事务两种技术方案 -

程序员从无到有构建代码,应该注重组合思维,做出来的东西需要能够相互组合在一起;而架构师是从上而下的视角,因为不参与具体细节构建,但为了落地,应该具有多维度多维度视角,从程序员到架构师思维转变很重要。

下面这篇文章谈了架构师的多维度视角:

架构师应该多维度多视角地思考:https://www.jdon.com/60409

分布式事务为案例,从不同视角看这个问题,得到的解决方案可能不同。



例如如果从状态角度看分布式事务实现,那么下面这篇文章也许有启发:

如何实现跨Mysql、Redis和Mongo分布式事务?: https://www.jdon.com/60408



但是,如果从微服务和事件驱动角度看分布式事务实现,下面这篇文章也有启发:

如何设计基于事件驱动架构的销售库存微服务?: https://www.jdon.com/60410



这两种实现方案似乎都可以实现基于微服务+数据库的分布式事务,第一篇文章更加偏向数据库基础设施,从幂等性和补偿回滚两个方面来保证跨多数据源的存储一致性;而第二篇文章更倾向微服务靠前一些,因为微服务+数据库架构中,微服务总是先于数据库调用,而触发调用微服务的东西是事件。

也就是说,事件是一个全新视角,而数据库状态则是一个传统观点,事件和状态实际是同一个问题的两个方面,只是角度不同。
因为从数据库状态角度出发设计,那么就要考虑幂等性,因为状态孤立的,一个状态是覆盖前面一个状态,状态之间是没有关系的,那么就可能当前状态和前面状态是同样的重复的;那么在接受状态存储时可以通过主键等新增办法实现幂等性,幂等性实际类似重复提交问题。

其次,从状态角度考虑设计,还要考虑状态退回补偿,因为状态之间没有关系,所以需要业务程序在整个事务失败时,将之前已经存储过的状态返回到之前状态。

但是,如果从(领域)事件角度考虑设计,则可能避免上述状态设计带来的复杂性,通过引入Conductor开源工作流,能够原子性地启动一个任务,通过这个任务再更改另外一个上下文微服务中的存储状态:内存状态或数据库状态。

这种方式类似主-从复制的方式,总是一个上下文中的状态为主,其他都监控这个主状态,一旦有该状态改变,或有改变主状态的命令与事件发生,就把这个改变事件作为消息广播到所有监控者,所有监控者就同步更新自己的状态与其一致。

两种业务实际都属于一种流程操作:


  1. 用户现在正在参与促销活动:他们有余额,充值话费,促销活动将赠送商城积分。

  2. 电子商务网站:销售与仓库的库存更新。


上面两种业务都可以使用微服务+数据库实现,而且都是跨不同微服务+数据库的更新状态,前者使用所谓分布式事务,后者使用主从同步复制,这两种实现方案实际可以互换到对方业务场合。

当然,最重要的是基于 CAP定理 满足不同的实时性和并发要求。

这里提第三种解决方案:事件溯源
使用Kafka等开源工作流消息系统,能够保证事件的恰好一次传递,一系列事件直接存储起来,事件之间的先后顺序关系也保存起来了,不会相互覆盖,如果需要获得当前最新状态,只要把之前所有事件遍历一次计算即可,通过stream操作非常方便简单。

如果上述两种业务都辅助以 事件溯源,系统复杂性虽然提高了,但是可靠性大大增强,发生问题时,问题追踪得也有依据,类似建设了一套冗余系统。