为什么Actor模型是高并发事务的终极解决方案?
首先看看道友提出的一个问题:
用户甲的操作
1.开始事务
2.访问表A
3.访问表B
4.提交事务
乙用户在操作
1.开始事务
2.访问表B
3.访问表A
4.提交事务
如果甲用户和乙用户的两个事务同时发生,甲事务锁住了表A未释放(因为整个事务未完成),正在准备访问B表,而乙事务锁住了表B未释放(因为整个事务未完成),正在准备访问A表,可是A表被甲事务锁住了,等甲事务释放,而甲事务真正等待乙事务释放B表,陷入了无限等待,也就是死锁Dead Lock。
也有道友使用多线程来模拟存储过程:http://www.jdon.com/45727,每个线程里开启一个事务,类似上述问题也会出现死锁。
问题出在哪里?
是我们的思路方向出现问题:
其实无论是使用数据库锁 还是多线程,这里有一个共同思路,就是将数据喂给线程,就如同计算机是一套加工流水线,数据作为原材料投入这个流水线的开始,流水线出来后就是成品,这套模式的前提是数据是被动的,自身不复杂,没有自身业务逻辑要求。适合大数据处理或互联网网站应用等等。
但是如果数据自身要求有严格的一致性,也就是事务机制,数据就不能被动被加工,要让数据自己有行为能力保护实现自己的一致性,就像孩子小的时候可以任由爸妈怎么照顾关心都可以,但是如果孩子长大有自己的思想和要求,他就可能不喜欢被爸妈照顾,他要求自己通过行动实现自己的要求。
数据也是如此。
只有我们改变思路,让数据自己有行为维护自己的一致性,才能真正安全实现真正的事务。
数据+行为=对象,有人问了,对象不是也要被线程调用吗?
例如下述代码,因为对象的行为要被线程调用,我们要使用同步锁synchronized :
public class A { private volatile int lower, upper; //两个状态值public int getLower() { return lower; } public int getUpper() { return upper; }public synchronized void setAUpper(int value){if (value < a.getUpper()) a.setLower(value);}public asynchronization void setALower(int value){if (value > a.getLower()) a.setUpper(value);}} |
上面这段代码业务逻辑是想实现lower<upper:
1. lower和upper的初始值是(0, 5),
2.一个客户端请求线程A: setLower(4)
一个客户端请求线程B: setUpper(3)
3. lower和upper是 (4, 3)
这个结果破坏了lower<upper这个逻辑一致性,所以,用锁并不能保证逻辑一致性,而且还带来了堵塞。锁用错了地方,不但没有得到想要的,而且还失去更多。
下图展示了锁带来堵塞,每个时刻只能允许一个线程工作,如同只能允许一个人蹲马桶一样。
从历史上看,锁的问题如鬼魂一直伴随着我们:
1.用数据表一个字段来表示状态,比如1表示已付款未发货,2表示已付款已发货,然后用户来一个请求用SQL或存储过程修改,这时使用的数据库锁。
2.用ORM实现,比如Hibernate JPA来修改状态,虽然不用SQL了,但是Hibernate的悲观锁和乐观锁也让人抓狂。
3.彻底抛弃数据库,直接在内存缓存中进行修改,使用Java的同步锁,性能还是不够,吞吐量上不去。如上图提示,只能一个厕所蹲位一个人用,其他人必须排队。
4.Actor模型。
Actor模型原理
Actor模型=数据+行为+消息。
Actor模型内部的状态由自己的行为维护,外部线程不能直接调用对象的行为,必须通过消息才能激发行为,这样就保证Actor内部数据只有被自己修改。
Actor模型如何实现?
Scala或ErLang的进程信箱都是一种Actor模型,也有Java的专门的Actor模型,这里是几种Actor模型比较
明白了Actor模型原理,使用Disruptor这样无锁队列也可以自己实现Actor模型,让一个普通对象与外界的交互调用通过Disruptor消息队列实现,比如LMAX架构就是这样实现高频交易,从2009年成功运行至今,被Martin Fowler推崇。
回到本帖最初问题,如何使用Actor模型解决高并发事务呢?
转账是典型的符合该问题的案例,转账是将A帐号到B帐号转账,使用Actor模型解决如下:
发出是否可转出消息--->消息队列--->A
A作为一个对象,注意不是数据表,对象是有行为的,检查自己余额是否可转账,如果可以,冻结这部分金额,比如转账100元,冻结100元,从余额中扣除。因为外部命令是通过消息顺序进来的,所以下一个消息如果也是扣除,再次检查余额是否足够......
具体详细流程可见:REST和DDD
那么,既然Actor模型如此巧妙,而解决方向与我们习惯的数据喂机器的方式如此不同,那么如何在实战中能明显发现某个数据修改应该用Actor模型解决呢?因为我们习惯将数据喂机器的思路啊?
使用DDD领域驱动设计或CQRS架构就能明显发现这些特殊情况,CQRS是读写分离,其中写操作是应领域专家要求编写的功能,在这类方向,我们都有必要使用Actor模型实现,因为在这个方向上,领域专家的要求都表达为聚合根实体,聚合根就是用Actor模型实现最合适不过了。而读方向,比如大数据处理,报表查询,OLTP等等都是数据喂机器的方式。
有的道友会疑问,我们经常使用SSH,也就是Spring + Hibernate架构,这个默认是哪种方向呢?很显然,默认是数据喂机器的方向,所以在实现写操作时,特别警惕高并发发生死锁等影响性能问题,当然也包括EJB架构。
有一种togaf架构,将企业软件架构分为数据架构和应用架构等,实际是EJB或SSH的变相描述,这种架构的问题我们已经一目了然了,特别这样的系统如果从面向内部管理转向到SaaS模型时,这类高并发死锁问题就特别容易发生,几乎不具备可用性。前期12306火车票系统是这类问题的典型体现。
为什么Actor模型是高并发事务的终极解决方案?相关推荐
- 高并发事务问题以及解决方案
事务的概念 事务 可以理解为一个 独立的工作单元, 在这个独立的工作单元中, 有一组操作; 放在事务(独立工作单元)中的多个操作, 要么全部执行成功, 要么全部执行失败. 不免俗套, 这还是通过最经典 ...
- MySQL高并发事务问题
事务的概念 事务 可以理解为一个 独立的工作单元, 在这个独立的工作单元中, 有一组操作; 放在事务(独立工作单元)中的多个操作, 要么全部执行成功, 要么全部执行失败. 不免俗套, 这还是通过最经典 ...
- java actor模型实例,详解Theron通过Actor模型解决C++并发编程的一种思维
现今,单台机器拥有多个独立的计算单元已经太常见了,这点在服务器的处理器上表现尤为明显,据AMD的一张2012-2013服务器路线图显示,服务器处理器的核心数将在2013年达到20颗之多,合理的利用CP ...
- MySQL - 并发事务问题及解决方案
文章目录 生猛干货 Pre 脏读 不可重复读 幻读 Solutions 搞定MySQL 生猛干货 带你搞定MySQL实战,轻松对应海量业务处理及高并发需求,从容应对大场面试 Pre MySQL - 多 ...
- 高并发系统设计——分布式锁解决方案
摘要 分布式应用进行逻辑处理时经常会遇到并发问题.比如一个操作要修改用户的状态,修改状态需要先读出用户的状态, 在内存里进行修改,改完了再存回去.如果这样的操作同时进行了,就会出现并发问题, 因为读取 ...
- 海量数据高并发的访问技术解决方案
如今数据增长远远超过机器的计算性能, ORACL RAC能满足百万千万的业务系统, 硬件成本太高, 垂直方向的发展不太现实,追求水平方向的发展, 使用普通商业服务器,多台协调完成计算 如今,能 ...
- mysql高并发和大流量_高并发-高并发和大流量解决方案
高并发架构相关概念 并发 并发,在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,并且这几个程序都是在同一个处理机上运行,担任一个时刻点上只有一个程序在处理机上运行. 我们所说的 ...
- 高并发和大流量解决方案
#高并发架构相关概念# 并发: 在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任意一个时刻上只有一个程序在处理机上运行. 我们说的高并 ...
- 高并发与大流量解决方案
1.相关概念 1.1.并发与并行 1.1.1.并发(Concurrent) 在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行 就想前面提到的 ...
最新文章
- 03-NSPredicate谓词
- 施工日志管理软件app_康智颐app下载-康智颐客户端下载v1.4.9 安卓官方版
- 来看看几篇Nature上的GNN吧~
- hdu 1046 完数
- 旅游自助系统可行性分析
- 四面体的表面积_JACS:武汉大学汪成课题组利用从平面至四面体的扭曲单体来合成COFs材料...
- python交互式和文件式_使用Python创建和自动化交互式仪表盘
- CentOS7.4中搭建lnmp环境
- 整数倒转问题的算法实现
- Tensorflow学习笔记-第二节程序结构
- Hadoop作业性能指标及參数调优实例 (二)Hadoop作业性能调优7个建议
- 详细解说“黑客”们热衷的热门抓鸡技术
- 邻接表拓扑排序算法【C/C++】
- 读养生四要有感《慎动篇》
- 手把手教你如何在Innovus中解决local congestion问题
- 下单后,订单拆单能怎拆?
- E-Prime2.0安装问题
- java毕业生设计忆居民宿管理计算机源码+系统+mysql+调试部署+lw
- 无线传感网的MAC层协议
- 使用R语言对S&P500股票指数进行ARIMA + GARCH交易策略
热门文章
- 基于java的搜索引擎系统设计与实现(项目报告+开题报告+答辩PPT+源代码+数据库+部署视频)
- Node.js毕业设计——基于Node.js+JavaScript+MongoDB的供求信息网站设计与实现(毕业论文+程序源码)——供求信息网站
- 二进制与八进制十进制十六进制之间的转换
- OpenCvSharp 学习笔记7 --绘制图形和文字
- pwnable 题目解析:[Toddler's Bottle]-lotto 逻辑漏洞
- 利用有限元法求解一维热传导问题
- 恶魔之魂重制版登陆服务器未响应,数毛社分析《恶魔之魂:重制版》 60帧运行,加载超快...
- win8默认使用IE浏览器打开QQ空间,通过如下设置可以更改浏览器
- Linux目录结构——树形目录结构
- 抽象类和接口有什么区别