事务是恢复和并发控制的基本单位,保证 ACID:原子性、一致性、隔离性、持久性。

对于全是异步的 Nodejs 而言, 并不适合做事务操作:

  1. 代码书写上:

    • try ... catch ... 是写给人看的,但是属于同步方法,局限性很大。

    • callback 简直是噩梦。

    • Promise.then(...).catch(...) 相对而言好一点。

    • ES7 的 async ... await ... 比较清爽,使用 Babel 编译,这是笔者目前找到的最人类的方式,但是和原来的 Promise 混合使用的时候有时候会出问题,因为编译之后的代码没法看,最后还得重构回 Promise

  2. 异步:

    • 异步导致有可能有意料之外的 uncaughtExceptionError

    • 对于 JAVA/C++ 这样语言,出错能直接转到 catch 中,但是 Node 不是,uncaughtExceptionError 将直接导致处理链断掉,你只能通过其他方式保证数据一致性。

虽然 Node 做事务相当非人类,但是考虑开发效率 / 成本,使用 Node 进行开发并不比换语言开差,毕竟事务只有核心业务需要用到。

单点

单机的事务相当容易保证,特别在依赖 MySQL 或者其他关系数据库时。

Nodejs 有 ORM (如 Sequelize ) 支持事务,也可以直接使用 PROCEDURE/FUNCTION

两者各有优势:

  • ORM 适合复杂逻辑的事务;

  • 存储过程可以有效减少 IO 次数,防止使用 ORM 时回滚失败。

实际开发过程中可以将两者结合起来一起使用,使用 ORM 完成逻辑,使用存储过程减少 IO 次数。

分布式

对于分布式系统,相信很多人都知道 CAP 理论,即任何一个分布式系统无法同时满足:

  • Consistency (一致性)

  • Availability (可用性)

  • Partition tolerance (分区容错性)

但是实际上 Consistency 是任何一个系统都不可能放弃的,分布式事务亦是为了保证数据一致性,有时候为了妥协另外两个特性,会放弃强一致性,保证最终一致性

解决方式

目前业界有很多解决分布式事务的方案,根据对数据一致性的强弱要求,可以选择不同的方案,但是解决思路大致如下:

  1. 两阶段提交

如 XA 协议(TM(事务管理器)和RM(资源管理器)之间的接口)。

假设有 A、B、C 三个操作,第一阶段,等待 A B C 均就绪,第二阶段,提交 A B C;如果第一阶段 A 失败了,则第二阶段回滚 B C。

  1. 本地事务

使用本地消息表,将远程事务拆分成一个个本地事务,写入本地表中,然后 定时 / 使用 MQ 通知事务方。

两者各有利弊,定时扫描可能大部分时候都在做无用功,而只使用 MQ 可能会有失败 / 多次消费的问题。

  1. 使用回滚接口

如 A B 两个接口,串行处理,B 失败了回滚 A ,但是回滚也可能失败,所以也需要使用本地事务表 / MQ。

使用 Node 开发,1 比较重型,不适合;2 和 3 是比较好的选择:

  1. 选择一款可靠的 MQ 服务(单次消费 / 失败重试);

  2. 拆分本地事务;

  3. 不能拆分的事务,保证回滚。

举个栗子

做一个抢购系统,用户使用虚拟币进行抢购,虚拟币是另外一套系统。为了考虑到公平,每个用户还可能要限制购买上限。

这样用户一次抢购的完整流程如下:

  1. 检查购买上限

  2. 检查总数

  3. 扣除虚拟币

  4. 写入数据库

需要事务保证的地方就是 3 和 4,3 是远程事务,4 是本地事务,此栗子中必然是串行操作,3 在前,4 在后。

0x0001

这个时候流量很少,并发不高,将 3 和 4 作为一个事务,保证一起成功,而失败一起回滚。

事务 4 即使使用 ORM 完成,也能完成功能,这个时候系统能很好的工作。

0x0010

流量上升中,抢购的商品变多,并发也变大,这个时候,考虑使用 Redis 来提高性能了(牺牲强一致性):

将 购买上限 与 总数 写入 Redis,在压力转嫁到数据库之前就挡掉,由于 Redis 的强大性能,可以假设 Redis 等同于内存操作,做好回滚就可以了。

同时可以将事务 4 重构成 PROCEDURE 防止 ORM 可能回滚失败。

0x0011

流量大到数据库扛不住了,加入 MQ 服务:

使用 Redis 抗住流量,使用 MQ 抗住压力,使用 PROCEDURE 降低 IO 。

0x0011 看起来像一个可靠的系统了,但是还有一个隐患: uncaughtExceptionError 或者 程序宕掉了,这个会影响最终一致性,导致 Redis 数据与 Database 中的数据在抢购临界结束的时候不一致。

0x0100

增加最终一致性保证。

抢购的栗子有个很特别的地方,就是 total limit ,达到总数上限之后,就只有 MQ 中的部分需要处理了,因此可以很巧妙的利用时间差,即考虑在达到上限之后,取一次数据库快照,延迟一段时间之后,再对比一次数据库,判断是数据不一致还是正常逻辑。

这是一个投机取巧的处理方式,一定程度上可以保证最终一致性。当然,还是人最靠谱了,程序搞不定,人工修复嘛,ORZ~。

终语

分布式事务是一个很大的话题,依据业务量大小可以给出很多实现。

Nodejs 做分布式事务勉勉强强,异步里面的雷很多,不过依赖良好的设计和逻辑一样可以实现。

node.js - Nodejs 分布式事务_个人文章 - SegmentFault 思否相关推荐

  1. python之父去面试-面试题_个人文章 - SegmentFault 思否

    1 Spring Bean是什么? 在spring中由Spring创建和管理的对象称为bean, bean有相关的特性,例如懒加载,作用域,生命周期这些. 懒加载就是延迟加载,启动的时候,会创建所有对 ...

  2. java - websocket配合spring-security使用token认证_个人文章 - SegmentFault 思否

    使用框架介绍 spring boot 1.4.3.RELEASE spring websocket 4.3.5.RELEASE spring security 4.1.3.RELEASE sockjs ...

  3. python质因子分解_质因子分解_个人文章 - SegmentFault 思否

    质因子分解的问题就是给定一个n使得n能够分解为多个因子的乘积形式,并且相同因子用指数形式表示: 例如180=2^23^25; 对于这个问题,很好理解,我们的目的就是寻找其因子,通常的方法也就是从0开始 ...

  4. java9 gc log参数迁移_个人文章 - SegmentFault 思否

    序 本文主要研究一下java9 gc log参数的迁移. 统一JVM及GC的Logging java9引进了一个统一的日志框架,对gc log的输出进行了统一的配置. 相关JEP(JDK Enhanc ...

  5. node.js项目中常量的配置 - 个人文章 - SegmentFault 思否

    在项目中,我们常将一些常量信息做成配置项,如,数据库的链接配置,业务错误代码配资等等. 我们通过两种方式可以解决该问题. 系统环境变量的方式 配置文件的方式 下边,将以这两方面进行展开. 1. 系统环 ...

  6. css 高度塌陷_高度塌陷问题_前端技术文章 - SegmentFault 思否

    1. 高度塌陷 在文档流中,父元素的高度默认被子元素撑开,也就是说子元素多高,父元素就多高.但是, 当为子元素设置浮动后,子元素会完全脱离文档流.此时,将会导致子元素无法撑起父元素的高度,导致父元素的 ...

  7. java大麦_大麦大 - SegmentFault 思否

    通过这个教程,我想告诉你在 React 中如何使用 state 和 effect 这两种 hooks 去请求数据.我们将使用众所周知的 Hacker News API 来获取一些热门文章.你将定义属于 ...

  8. java表驱动法索引访问_表驱动法 - SegmentFault 思否

    在我们平时的开发中,if else是最常用的条件判断语句.在一些简单的场景下,if else用起来很爽,但是在稍微复杂一点儿的逻辑中,大量的if else就会让别人看的一脸蒙逼. 如果别人要修改或者新 ...

  9. vue项目全局配置微信分享_Vue项目history模式下微信分享总结-个人文章-SegmentFault思否...

    每回遇到微信分享都是一个坑,目前的商城项目使用vue开发,采用history的路由模式,配置微信分享又遇到了很多问题,最后终于解决了,现将解决的过程分享一下. 原文https://justyeh.to ...

最新文章

  1. C++ limits头文件
  2. BZOJ 3910 并查集+线段树合并
  3. python实现链表的删除_Python垃圾回收机制
  4. android 指示灯权限,Android实现LED灯显示效果
  5. Kubernetes-服务连接和暴露(endpoints)(二十)
  6. OpenCV3学习(10.4)基于KNN的背景/前景分割算法BackgroundSubtractorKNN算法
  7. 911计算机专业基础综合,青岛大学10数据结构911计算机专业综合
  8. 017-Centos7.6+CDH 6.2 安装和使用
  9. thinkphp mysql存储过程_MySql存储过程的创建与使用及在thinkphp中如何调用笔记
  10. [工具] Snipaste
  11. docker 镜像注册【图文教程】
  12. 向小伙伴讲讲搜索引擎?读完这个文章先
  13. 数据库select语句详解
  14. python画马鞍面_在matlab中怎么画马鞍面?
  15. oracle根据身份证号码 计算年龄、性别
  16. PTA6-1 鸡兔同笼问题 (20分)
  17. 【python 淘宝爬虫】淘宝信誉分抓取
  18. java科学计数法的基本使用与如何看科学计数法
  19. 我总结了程序员转行得最有出路5个方向
  20. cass简码大全_考考你......列出 南方cass 简码指令50个。

热门文章

  1. 1997年出生的人,现在月薪多少了?
  2. Camera2 Android相机Demo
  3. 数学归纳法 Mathematical Induction
  4. 青少年软件编程(C语言)等级考试试卷(一级)
  5. HOOK显卡驱动达到D3D游戏,c++实现人物透视完美源代码!
  6. 迁徙在互联网风口之间的年轻人
  7. 【零声教育】C/C++Linux服务器开发/高级架构师 课程
  8. 数据中心如何提高运维效率?数据中心综合能效管理解决方案——安科瑞 严新亚
  9. redash 上写 mongodb 查询语句 语法
  10. linux上不了网有两个网卡,linux上两个常见的网卡报错