事务是恢复和并发控制的基本单位,保证 ACID:原子性、一致性、隔离性、持久性。git
对于全是异步的 Nodejs 而言, 并不适合作事务操做:github
代码书写上:数据库
try ... catch ...
是写给人看的,可是属于同步方法,局限性很大。并发
callback
简直是噩梦。异步
Promise.then(...).catch(...)
相对而言好一点。async
ES7 的 async ... await ...
比较清爽,使用 Babel 编译,这是笔者目前找到的最人类的方式,可是和原来的 Promise
混合使用的时候有时候会出问题,由于编译以后的代码无法看,最后还得重构回 Promise
。分布式
异步:性能
异步致使有可能有意料以外的 uncaughtExceptionError
。spa
对于 JAVA/C++ 这样语言,出错能直接转到 catch
中,可是 Node 不是,uncaughtExceptionError
将直接致使处理链断掉,你只能经过其余方式保证数据一致性。设计
虽然 Node 作事务至关非人类,可是考虑开发效率 / 成本,使用 Node 进行开发并不比换语言开差,毕竟事务只有核心业务须要用到。
单机的事务至关容易保证,特别在依赖 MySQL 或者其余关系数据库时。
Nodejs 有 ORM (如 Sequelize ) 支持事务,也能够直接使用 PROCEDURE/FUNCTION
。
二者各有优点:
ORM 适合复杂逻辑的事务;
存储过程能够有效减小 IO 次数,防止使用 ORM 时回滚失败。
实际开发过程当中能够将二者结合起来一块儿使用,使用 ORM 完成逻辑,使用存储过程减小 IO 次数。
对于分布式系统,相信不少人都知道 CAP 理论,即任何一个分布式系统没法同时知足:
Consistency (一致性)
Availability (可用性)
Partition tolerance (分区容错性)
可是实际上 Consistency 是任何一个系统都不可能放弃的,分布式事务亦是为了保证数据一致性,有时候为了妥协另外两个特性,会放弃强一致性,保证最终一致性。
目前业界有不少解决分布式事务的方案,根据对数据一致性的强弱要求,能够选择不一样的方案,可是解决思路大体以下:
两阶段提交
如 XA 协议(TM(事务管理器)和RM(资源管理器)之间的接口)。
假设有 A、B、C 三个操做,第一阶段,等待 A B C 均就绪,第二阶段,提交 A B C;若是第一阶段 A 失败了,则第二阶段回滚 B C。
本地事务
使用本地消息表,将远程事务拆分红一个个本地事务,写入本地表中,而后 定时 / 使用 MQ 通知事务方。
二者各有利弊,定时扫描可能大部分时候都在作无用功,而只使用 MQ 可能会有失败 / 屡次消费的问题。
使用回滚接口
如 A B 两个接口,串行处理,B 失败了回滚 A ,可是回滚也可能失败,因此也须要使用本地事务表 / MQ。
使用 Node 开发,1 比较重型,不适合;2 和 3 是比较好的选择:
选择一款可靠的 MQ 服务(单次消费 / 失败重试);
拆分本地事务;
不能拆分的事务,保证回滚。
作一个抢购系统,用户使用虚拟币进行抢购,虚拟币是另一套系统。为了考虑到公平,每一个用户还可能要限制购买上限。
这样用户一次抢购的完整流程以下:
检查购买上限
检查总数
扣除虚拟币
写入数据库
须要事务保证的地方就是 3 和 4,3 是远程事务,4 是本地事务,此栗子中必然是串行操做,3 在前,4 在后。
这个时候流量不多,并发不高,将 3 和 4 做为一个事务,保证一块儿成功,而失败一块儿回滚。
事务 4 即便使用 ORM 完成,也能完成功能,这个时候系统能很好的工做。
流量上升中,抢购的商品变多,并发也变大,这个时候,考虑使用 Redis 来提升性能了(牺牲强一致性):
将 购买上限 与 总数 写入 Redis,在压力转嫁到数据库以前就挡掉,因为 Redis 的强大性能,能够假设 Redis 等同于内存操做,作好回滚就能够了。
同时能够将事务 4 重构成 PROCEDURE
防止 ORM 可能回滚失败。
流量大到数据库扛不住了,加入 MQ 服务:
使用 Redis 抗住流量,使用 MQ 抗住压力,使用 PROCEDURE
下降 IO 。
0x0011 看起来像一个可靠的系统了,可是还有一个隐患: uncaughtExceptionError
或者 程序宕掉了,这个会影响最终一致性,致使 Redis 数据与 Database 中的数据在抢购临界结束的时候不一致。
增长最终一致性保证。
抢购的栗子有个很特别的地方,就是 total limit
,达到总数上限以后,就只有 MQ 中的部分须要处理了,所以能够很巧妙的利用时间差,即考虑在达到上限以后,取一次数据库快照,延迟一段时间以后,再对比一次数据库,判断是数据不一致仍是正常逻辑。
这是一个投机取巧的处理方式,必定程度上能够保证最终一致性。固然,仍是人最靠谱了,程序搞不定,人工修复嘛,ORZ~。
分布式事务是一个很大的话题,依据业务量大小能够给出不少实现。
Nodejs 作分布式事务勉勉强强,异步里面的雷不少,不过依赖良好的设计和逻辑同样能够实现。