什么是竞争条件?
我关注了寡头垄断状态的很好构成,这是我们选择的好的构成:
竟争情况是因另一个进度以与预期效果不一的方式与独享资源量人机交互而造成的交通意外习惯。
这实在是太拗口了,而且还不是很清楚Rails中的竞争条件是如何显示的。
施用Rails,企业都会加工2个流程——每位post请求或网站后台使用均是一款 用单独的流程,也可以差不多上独自于另外流程开机运行。
.我也始终保持在在采用的共亨成本。APP软件有无在在采用的感情数据文件库?很显然共亨成本。APP软件有无在在采用的某类缓存能力服务质量器?是的,这也是共亨成本。你在在采用的某类内部API吗?您猜记得——这也是共亨成本。
好想议论俩种恶性竞争前提条件的样例等级分类,那么议论怎样解決这句话。
读-修改-写
读入数据-更改-输入品目都是种竞争力状态,另外是一个速度将从共亨信息读入数据值,更改存储空间中的值,最后再试一次将其写回共亨信息。每当们从单独步奏的的视角看看时,这虽然尤其简洁明了。因为当会出现其次个速度时,很有可能会诱发一系意外事故的动作。
来考虑方式代码是什么:
class IdeasController < ActionController::Base def vote @idea = Idea.find(params[:id]) @idea.votes += 1 @idea.save! end end
这里我们正在读取( Idea.find(params[:id])
),修改( @idea.votes += 1
),然后写入( @idea.save!
)。
他们都还可以观察到,这将使个思路的从投票数增大一单。假如全是个思路实现零票,现在然后将以一单终止。不过,假如第二点个提起打不进并从数据显示表格比对库获取这款思路,而它即使有零票,并在4g内存中增大该值,他们都也许 会会出现两票的同时进行的状态 - 但然后但是是票数数据显示表格比对库只全是个。
这也称为丢失更新竞争条件。
检查然后行动
check-then-act 品目都是种竞争力先决条件,在其中数值从共享能源能源跳转,还有会根据都存在的值,我们都确实是否是都要制定进行。
Rails 中的validates_uniqueness_of
验证是这种情况的典型示例之一,如下所示:
class User < ActiveRecord::Base validates_uniqueness_of :email end
考虑到一下二维码:
User.create(email: "[email protected]")
确认完美后,Rails 将查验能否有随便现存用户组的组成为该光电email地此。比如没了别的,它将依据将用户组的组保护图片到数据文件表格分析源库贝盛实施的操作的。而且,比如第二步个請求一起实施一致的二维码,会引发任何现象?自己而使会会遇上是这样的现象:3个請求总会查验以确立能否有着反复数据文件表格分析源(实际情况上没了),之后它总会依据保护图片数据文件表格分析源来实施的操作的,而使诱发数据文件表格分析源冷库中造成反复的用户组的组。
解决竞争条件
克服市场竞争力状况没奇药,但有块些策咯还可以应用于克服其他其他状况。避免市场竞争力状况大部分分成3个品类:
1.删除关键部分
虽说这几率被视作删除图片有毛病的代碼是什么,但有的那时候您可构建代碼是什么,使其不能受过激烈竞争必要条件的应响。另外那时候,您可理论研究原子团实际操作。分子操控流程一种没另外的过程中也可以突然中断操控流程的操控流程,那么您不知道它将保持对于单一个单位施行。
在调用-编辑-拷贝样例,可不可以在大数据之中新增想方拉票,而就不是在4g内存中新增想方拉票:
@ideas.increment!(:votes)
这将实行以下几点提示的 sql:
UPDATE "ideas" SET "votes" = COALESCE("votes", 0) + 1 WHERE "ideas"."id" = 123
运用它不懂由于完全相同的寡头垄断状态的影向。
人们对 check-then-act 样例,人们能能在使用 upsert 将记录卡可以直接插入图统计db2数据库,而就不是让 Rails 校验模形:
User.where(email: "[email protected]").upsert({}, unique_by: :email)
这会将的记录进到这一领域动态数据冷库中。如果电商email留存争议(这要有电商email上的真正字段),它将简单易行地忽略掉进到这一领域。
2. 检测与恢复
有时候您没有误删关键因素要素。或许具备原子结构错施,但它并不根本依照码规定的策略的工作。在某些状况下,您还还都可以勇于尝试加测和恢复过来错施。确认这错施,还还都可以设备保护的错施,在产生争夺状况时通告您。您还还都可以普通中止审理或重试该错施。
对于读-修改-写示例,这可以通过来完成。 Rails 中内置了乐观锁定,可以检测多个进程同时对同一条记录进行操作的情况。要启用乐观锁定,您只需在表中添加一个lock_version
列,Rails 就会自动启用它。
change_table :ideas do |t| t.integer :lock_version, default: 0 end
然后,当您尝试更新记录时,只有当lock_version
与内存中的版本相同时,Rails 才会更新它。如果不是,它将引发ActiveRecord::StaleObjectError
异常,可以通过救援来处理它。处理它可能是retry
,也可能只是向用户报告的错误消息。
def vote @idea = Idea.find(params[:id]) @idea.votes += 1 @idea.save! rescue ActiveRecord::StaleObjectError retry end
针对先诊断后执行力的实例,会凭借列上的一个目录来完全此控制,最后在删去统计数据时对待无效。
add_index :users, [:email], unique: true
有了唯一索引,如果数据库中已存在该email
数据,Rails 将引发ActiveRecord::RecordNotUnique
错误,并且可以适当地挽救和处理该错误。
begin user = User.create(email: "[email protected]") rescue ActiveRecord::RecordNotUnique user = User.find_by(email: "[email protected]") end
幂等性
关键在于重试实操,另一实操一定要是幂等的,某些点非常重要要。这意示着如果次数实施就是说实操,则結果与仅应运连续重复。
举例说明,预料一下吧,倘若项上班运输了一大封光光电电邮,还有就是没次许多 打算的微信票选进行转化时会有执行程序该光光电电邮。倘若没次重试都运输1封光光电电邮,那就是太无趣了。要想使方法使用幂等,您是能够 延期运输光光电电邮,有一天整体微信票选方法使用做完。或许,您是能够 更行运输光光电电邮的方法的保证 ,能够仅在微信票选自再一次运输时进行转化时才运输光光电电邮。倘若进行行业竞争具体条件还有就是您需用重试,则1次战胜困难运输光光电电邮或许会以至于无方法使用,还有就是是能够 安全性高地再一次闪避它。
许多操作可能不是幂等的,例如对后台作业进行排队、发送电子邮件或调用第三方API 。
3. 保护代码
假若是没办法检验和恢复过来,能去尝试保护区源代码。在等你的阶段目标是創建一家誓约,在其中有一次不过一家程序流程图运行能网页防问信息共享设备资源英文性。实际的上,您时未排除高连接数性 - 是由于不过一家程序流程图运行能网页防问信息共享设备资源英文性,那么我们公司能预防基本数竞争力条件。但绝不是删除文件的高连接数性多了,使用程序流程图的网络速度就更慢,根据各种程序流程图运行将等到两者被能网页防问。
这可以使用 Rails 内置的悲观锁定来处理。要使用,您可以向正在构建的查询添加lock
,Rails 将告诉数据库在这些记录上持有行锁定。然后,数据库将阻止任何其他进程获取锁,直到完成为止。请务必将代码包装在transaction
中,以便数据库知道何时释放锁。
Idea.transaction do @idea = Idea.lock.find(params[:id]) @idea.votes += 1 @idea.save! end
如何难以完成行级冻结,则还可不可以应用许多器具,比如说 Redlock 或 with_advisory_lock。这类将支持冻结中任何代碼块。应用它还可不可以像这样一来单纯:
email = "[email protected]" User.with_advisory_lock("user_uniqueness_#{email}"} do User.find_or_create_by(email: email) end
许多方式将造成的前做出程错过,到拿到锁。从而,他还愿意有某样类型的超时来防范前做出程终究错过,和在超日日做出些许处理。
然而没了处理良性角逐标准的神丹妙药,但不少良性角逐标准会用这样策略性来处理。只不过,所有困难都明显区别,由此处理工作方案的环节很有可能会起所区别。您会看到,这当中更完整地介紹了良性角逐标准。
关于作者
凯尔·奥利维拉
凯尔青睐于将具像的观念转为为可任务的图片app软件。他是的总裁图片app软件水利项目工程师。 。当不激发时,凯尔喜爱在德国温哥华的家附近商场品尝鲜香的产品和精酿啤洒厂。
也发布了