六个可以替代传统事务解决并发问题的建议

转载 2016年05月31日 12:23:20

增删改查是大部分框架的功能,如果有两个并发请求修改同一个数据,这个时候,你会怎么办?或者插入本来应该是唯一却重复的数据时应该怎么办?再或者插入和修改时有其它辅助动作比如保存到另外的表,这些情况,有什么好的解决方案?

我想最开始,你会首先想到“事务”,事务确实能够让一组操作一起可靠安的全执行,他们要么全部执行,要么一个也别想执行。但如果有两个同时发生的并发事务怎么办?使用事务隔离级别,这是ACID中的定义,关系数据库内部机制中就是这么做的。

但是,如果使用隔离级别,比如可串行化serializable (以及可重复读),你的系统会变得很慢,依赖于不同关系数据库,同时发生的事务也许需要应用代码编码指定重试几次,这就很复杂,其他不是很严格的隔离级别则会带来更新丢失或幻读(幻读是不可重复读的一种特殊场景,当事务没有获取范围锁的情况下执行SELECT … WHERE操作就可能会发生幻读)。

即使你正确地设置了合适的隔离级别,你也能用代码正确处理了事务的失败错误情况,但是隔离并不能解决所有并发问题,比如应用级别的数据约束,也就是说,一种复杂的业务逻辑约束或规则,很难使用数据库的表键约束来实现的;单纯使用数据库技术也不能解决重复插入的问题;更不能解决应用级别的并发问题;不能解决数据并发等问题。也许你试图通过获得数据库锁来解决这些问题,但是锁是可怕的,锁有写锁、读锁和排他锁,如何避免死锁?不是每个程序员能够有经验和锁打交道的。

双重提交就是个很好的佐证,它说明了不是所有问题都可以通过数据库方式单独解决的。双重提交很多人的解决办法是:使用一个token代表每个请求,并存储在数据库,使用数据库的唯一键约束,这样,重复记录就无法插入,这种问题使用API比较复杂,因为你得根据API的用户才能产生合适的token。另外,虽然你使用数据库唯一约束,但是还得在应用代码中进行检查,因为两行记录虽然键不同但是值相同还是可能被插入的。

大部分并发是运行在单机上,这可以使用语言的并发特性来确保执行的串行化,双重重复不可能发生,但是当你部署应用在几台机器以上,并发问题变得困难。

下面是不使用事务而使用并发的解决思路:
1.类似Hazelcast之类提供分布式锁,整个集群都遵循锁语义如同单机一样,但是适用场景不多。

2.使用消息队列– 将所有请求推入消息队列,队列会被单个异步worker处理,但是可能不适合业务上需要立即返回给用户的场景。

3.使用Akka和其集群,能保证一个actor(可看成一个服务)一次只处理一个消息,但是因为akka完全改变了使用范式,难以使用和跟踪调试,而且和语言平台特点有关。

4.使用数据库的应用级别锁,比如关系数据库Postgre提供 advisory锁,MySQL也有类似的get_lock。使用关系数据库作为分布式锁机制,锁是被应用管理,不需要表库做任何事,只要请求为entityType, entityId字段请求一个锁,保证没有其他应用线程只有在获得数据库锁的情况下才能执行应用中指定一段代码,相当于用数据库锁替代语言同步锁,然后使用Spring的 @Before 之类AOP方式拦截服务的方法。

5.使用CRDT,它是一种幂等的数据结构,不管操作其之上的操作顺序,最终都是同样的结果状态。但是完全幂等的操作在实际中也是很少碰到。

6.使用“insert-only”只追加模型。像Datomic之类数据库内部使用这种模型,你可以在任何数据库中使用这种模型,只有新增追加,没有删除和更新,每次使用新的版本号插入新记录. 这样版本号的唯一性保证不会有重复记录。你不会丢失数据,相当于免费得到一个校订日志(banq注:实际是EventSourcing 事件流日志)。

上面列出的方法都是在不损失性能情况下如何串行化请求,包括了各种锁机制 队列和非堵塞I/O。

另外,与本文内容无关。再推荐一个开源的并发框架Disruptor,它能够在无锁的情况下实现网络的Queue并发操作。Martin Fowler曾在自己网站上写了一篇LMAX架构的文章,在文章中他介绍了LMAX是一种新型零售金融交易平台,它能够以很低的延迟产生大量交易。这个系统是建立在JVM平台上,其核心是一个业务逻辑处理器,它能够在一个线程里每秒处理6百万订单。业务逻辑处理器完全是运行在内存中,使用事件源驱动方式。而业务逻辑处理器的核心是Disruptor,点击阅读原文链接(送你一个很不错的PPT),了解关于Disruptor的更多信息。

今天再给大家推荐一个不错的网站Jdon.com,JDON自2002年建站以来,内容一直在持续更新,致力于跟踪国际最新软件设计前沿,吸引软件专家和思想领袖参与探索、分享、交流、解惑、传道;主要方向包括有关软件建模、领域驱动设计、设计模式、云计算架构、敏捷开发等方面实战经验和原创思想 。本文也是出自JDON创始人板桥先生之手。

事务并发问题以及处理方法

事务并发问题: 1. 第一类丢失更新(lost update): 在完全未隔离事务的情况下,两个事物更新同一条数据资源,某一事物异常终止,回滚造成第一个完成的更新也同时丢失。 2. 脏读(dirty ...
  • kenight
  • kenight
  • 2016年05月05日 14:24
  • 3394

Spring事务注解@Transactional的坑爹陷阱

生产系统凌晨定时任务处理,涉及到核心部分特别是账户处理,结果出问题了,现象很诡异: 1)程序没有按照预定步骤处理数据库相关数据 1)问题偶发,但没有规律 2)发生后也没有发现有死锁,但出现异常的锁 后...
  • hardywang
  • hardywang
  • 2016年04月23日 09:37
  • 5219

常见事务并发问题以及处理方法

1、数据库事务并发会引起那些常见问题以及对应的解决方法? 1)丢失更新:撤消一个事务时,把其它事务已提交的更新的数据覆盖了。 2)脏读:一个事务读到另一个事务未提交的更新数据。 3)幻读:一...
  • songwei128
  • songwei128
  • 2015年02月05日 21:40
  • 2320

不解决这六个问题,农商行如何去玩大数据?

  • 2015年09月07日 16:35
  • 136KB
  • 下载

magento使用过程中六个常见的问题和解决方案

  • 2017年03月27日 09:47
  • 18KB
  • 下载

不解决这六个问题,农商行怎么去玩大数据?

进入信息化时代以来,银行的生存环境发生了巨大的变化,信息化建设和大数据的应用,已经成为银行业竞争的一个筹码,也是获得竞争优势的一个方法。银行业按照形态,分为农村商业银行和城市商业银行两类。这次先随传说...
  • nayun123
  • nayun123
  • 2015年08月31日 09:42
  • 6631

六个建议防止SQL注入式攻击

  • 2011年06月30日 11:27
  • 34KB
  • 下载

基于分布式学习的大规模网络入侵检测算法(pdf)摘 要: 计算机网络的高速发展,使处理器的速度明显低于骨干网的传输速度,这使得传统的入侵检测方法无法 应用于大规模网络的检测.目前,解决这一问题的有效办法是将海量数据分割成小块数据,由分布的处理节点并行理.这种分布式并行处理的难点是分割机制,为了不破坏数据的完整性,只有采用复杂的分割算法,这同时也使分割 模块成为检测系统新的瓶颈.为了克服这个问题,提出了分布式神经网络学习算法,并将其用于大规模网络入侵检 测.该算法的优点是,大数据集可被随机分割

  • 2009年06月10日 18:34
  • 598KB
  • 下载

六个建议防止SQL注入式攻击

SQL注入攻击的危害性很大。在讲解其防止办法之前,数据库管理员有必要先了解一下其攻击的原理。这有利于管理员采取有针对性的防治措施。   一、 SQL注入攻击的简单示例。   stateme...
  • zouxistudent
  • zouxistudent
  • 2011年08月24日 11:14
  • 319

六个建议防止SQL注入式攻击(转载)

SQL注入攻击的危害性很大。在讲解其防止办法之前,数据库管理员有必要先了解一下其攻击的原理。这有利于管理员采取有针对性的防治措施。 一、 SQL注入攻击的简单示例。  statement := "SE...
  • yym154
  • yym154
  • 2011年02月09日 15:36
  • 221
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:六个可以替代传统事务解决并发问题的建议
举报原因:
原因补充:

(最多只允许输入30个字)