解决并发问题的初学者指南

插入,更新和删除。 每个框架教程都从这些开始,它们被视为最基本的功能。

但是,如果两个并发请求尝试修改相同的数据怎么办? 还是尝试插入应该唯一的相同数据? 或者插入和更新具有副作用,必须将其存储在其他表中(例如,审核日志)。

您可能会说“交易”。 好吧,是的,不是。 事务允许将一组查询一起执行-将失败一起传递。 并发事务的处理方式取决于事务的特定属性,即它们的隔离级别。 您可以在此处阅读有关所有这些工作原理的非常详细的说明。

如果选择最安全的隔离级别–可序列化(和可重复读取),则系统可能会变得太慢。 并且取决于数据库,可能必须通过特定的应用程序代码重试同时发生的事务。 那太乱了。 使用其他隔离级别,您可能会丢失更新,幻像读取等。

即使正确实现隔离,并且正确处理了失败的事务,隔离也不能解决所有并发问题。 它没有解决具有应用程序施加的数据约束的问题(例如,不能表示为数据库唯一约束的唯一性复杂逻辑),没有解决插入精确重复项的问题,没有解决解决其他应用程序级并发问题,并且不能完美解决数据修改问题。 您可能必须进入数据库锁定,并且锁定很繁琐。 什么是写锁,读取锁,什么是排他锁,以及如何不以死锁(或活动锁)结尾? 我确信即使是经验丰富的开发人员也不会熟练使用数据库锁,因为您要么不需要它们,要么遇到更大的问题, 应该首先解决

重复提交问题有点离题,但它说明并非所有并发请求问题都可以单独由数据库解决。 正如许多人所建议的,通过为每个请求生成并使用唯一约束存储在数据库中的令牌来解决。 这样,两个相同的插入(两次提交的结果)不能同时进入数据库。 使用API​​会使情况变得更加复杂,因为您应该依靠API的用户来提供适当的令牌(而不是在后端动态生成令牌)。 至于唯一性,我读过的每篇文章都得出结论,保证唯一性的唯一正确方法是在数据库级别使用唯一性约束。 但是,对于该约束有复杂的规则时,您倾向于签入该应用程序。 在这种情况下,并发请求最终将允许插入两个具有相同值的记录。

如果应用程序在单台计算机上运行,​​大多数问题很容易解决。 您可以利用您的语言并发功能(例如Java锁,并发集合)来确保所有内容都已正确序列化,不会发生重复等。但是,当您部署到多台机器(应该是)时,困难得多的问题。

那么,除了事务之外,还有什么方法可以解决并发问题? 有很多,这里有几个(按无先后顺序排列)。

  • 有Hazelcast,可让您使用分布式锁 -整个群集都遵循Lock语义,就好像它是一台计算机一样。 那是特定于语言的,并且设置仅几个用例的hazelcast集群(因为并非所有请求都需要),这可能太多了
  • 您可以使用消息队列–将所有请求推送到由单个(异步)工作程序处理的消息队列。 在某些情况下这可能很有用,而在其他情况下则不切实际(例如,如果您必须向用户返回一些即时响应)
  • 您可以使用Akka及其群集功能-它可以确保参与者(认为“服务”)一次仅处理一条消息。 但是对所有内容使用akka可能不是一个好主意,因为它完全改变了范例,它更难阅读和跟踪,更难调试,并且是特定于平台的(只有JVM语言可以使用它)。
  • 您可以使用特定于数据库的应用程序级别锁。 这是非常有用的,即使它完全依赖于RDBMS。 Postgre有咨询锁MySQL有get_lock ,其他人可能也有类似的东西。 这里的想法是将数据库用作分布式锁定机制。 这些锁是由应用程序管理的,甚至不需要与您的表有任何关系–您只需要为(entityType,entityId)请求一个锁,然后其他任何应用程序线程都无法输入给定的锁代码,除非它成功获取该数据库锁。 这有点像榛子广播方法,但是您可以通过数据库“免费”获得它。 然后,例如,您可以拥有一个@Before(spring)方面,该方面附加到服务方法并进行适合于当前应用程序用例的锁定,而无需使用表锁。
  • 您可以使用CRDT。 这是一个幂等的数据结构–不管所应用操作的顺序是什么,它最终都处于相同状态。 本演示文稿对此进行了更详细的说明。 我没有答案,CRDT如何映射到关系数据库是一个有趣的问题,但问题是,如果您的操作是幂等的,则问题可能会更少。
  • 使用“仅插入”模型。 像Datomic这样的数据库在内部使用它,但是您可以在任何数据库中使用它。 您没有删除,没有更新-只是插入。 更新记录是在插入新记录的同时增加“版本”。 这再次依赖于数据库功能,以确保不会以相同版本的两条记录结尾,但是您绝不会丢失数据(并发更新会使其丢失,因为它不是最新版本,而是“丢失”了)它已存储并且可以还原为)。 您会免费获得审核日志。

总体问题是如何在不损失性能的情况下序列化请求。 并且所有各种锁定机制和队列(包括非阻塞IO)都可以解决该问题。 但是,使任务变得更容易的是拥有不关心并发性的数据模型。 如果适用后者,请始终坚持下去。

整本书都是关于并发的,我意识到这样的博客文章从定义上来说还很肤浅,但是我希望至少能提供一些指导。

翻译自: https://www.javacodegeeks.com/2016/04/beginners-guide-addressing-concurrency-issues.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值