Salesforce中并发问题案例分析及解决方案

前言】:早前在通过public access site page让终端2C客户与Campaign进行数据交互时,就已经触及到高并发的问题,但那时很难理解它内部的过程,由此也只是简单的认识了For Update这个SOQL关键字。直到这个问题再次浮出水面,终于意识到这是个重新认识它的最佳时机,希望能把这个思考过程和解决思路与大家娓娓道来。在此特别感谢和我一起探讨我的问题以及伴我最终思考出结果的同事。

业务背景】:做Campaign的时候,需要通过MC将携带Site Page的链接以Email的形式发送给目标客户,当客户点击链接时,系统会自动为该客户分配礼品券Reward Code,同时更新Campaign Member的状态。此次活动目标客户数量为8w,Reward Codes库存有1.1w。

问题】:由于对高并发及恶意访问这两点认识不够,造成了如下2类问题:
1. 多人同时访问同一资源,造成Code被分给后访问的人,因此资源竞争的不公平性就暴露出来了;
2. 同一人开多窗口同时点击链接,造成一人被分配多个Code。

过程描述】:

1. 高并发

假如库存只剩下1个Code,这时A和B同时(A先来,B后来,间隔时间很短)点击链接,代码逻辑中,俩人主要干3件事:查可用Code(如果分配过就直接显示QR Code),做其他操作,最后填充Code对象上的Contactid字段并Update Code。

现实中,很可能出现A执行到上图位置1,B执行到位置2,在都没有执行3 Commit到DB时,俩人都查询到了仅存的Code,即资源Available,这时B网速快,先执行了3,最后一个Code的Contactid被填充了B的Id,因此B页面上能正常显示仅存Code的QR Code;紧接着A执行了第三步,由于第一步查询时Code Id不变,所以update code时,A的Id被最终填充到了Code记录,即最终(当下次A/B再试图点击链接时,A展示已分配给的Code QR Code;B显示配额不足页面)Code分给了A。

我们把问题再延伸下,假如Code在量很足的情况下,依然可能出现n个人同时Update同一条记录,导致大家在第一次点击时,都能看到同一个Code,如果这时n个人都将含QR Code的页面截图去线下消费,问题就麻烦了......

注意:上述提到的网速在前端通过ajax请求后端数据时体现比较明显,这里我们也可以将其理解的更广义一点,如假定二人同时进入到apex执行片段,资源最终分配结果还与DB的连接速度,托管apex服务的硬件状况等复杂因素也有关系。

解决方案:要解决这个问题,由于sf无法做到到通知共同访问资源的人这个资源已占用,所以思路就锁定在如何将"资源被占用,请再试一次"的消息抛到界面上了

方案1Locking Statements | 临时锁 + 再查一次
在上图第1步的soql加limit 1 for update(1个人分1个Code;假如分n个Code,limit n),同时紧接着再查询一次资源是否可用 - 前提是第1步的soql中不含order by关键词;
解析:使用for update记录锁,最多锁10s,10s后B还未处理完,A就会收到QueryException,这时异常被捕获,再试一次被抛出;如果B在10s内更新完Code,这时A就可以继续执行方案1.5步中提到的再查一次,从而避免竞争同一资源,保证线程的安全。

方案2:Validation Rule法 - 首推[影响最小]
我们通过写如下Validation Rule来保证一个Code只被分配一次:

解析:由于无法在B Commit DB后通知A再查一次,我们就需要借助Update DML所引发的一系列sf内部Salesforce Execute Order里边的流程来将错误抛出来——Code Contact从无到有,正常分配;从有到其他,报错。

同理我们也能使用Trigger,通过加addError()的方式来实现

方案3:Approval.lock()记录锁
通过记录锁来永久锁住记录,防止被修改;
解析:当B Update Code后,立即追加Approval.lock(recId)来锁定记录,这样A再更新时,就会报错;难点在于如何通过Sharing关键字设计,来确保Guest User A/B在能够访问Approval.lock方法的同时,也能将A Update Record时的错误抛出。

2. 恶意访问

假如A打开两个窗口,并同时点击Link,过程有如下两种情况:

 

情况A:win1走到第一步,win2走到第2步骤,二者在被assign code前都通过了没有分配过code的验证,因为库存中contactid为A的不存在。这时假设win2先执行完就领到了code2,随后win1执行完就领到了code1;
情况B:二者几乎同时做update操作;

方案update后再查一次
解析:A在win1/win2执行完第三步后,再做一次查询,如果分给A的Code >= 2,则回滚。这样情况1由update record到再查一次有时间差,win2成功分配code显示QR Code,win2则回滚,即取消code分配;情况2几乎win1/win2同时执行完update,这时再查询A被分配的code为2,因此这次全部回滚,抛出"网络繁忙,再试一次!"。

结语】:如果大家有更经典的案例和更好的解决方案,不要吝啬笔墨哟~

相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页