【问题标题】:Concurrent API requests - Database Conflicts并发 API 请求 - 数据库冲突
【发布时间】:2018-07-10 16:57:48
【问题描述】:

我对(任何)一个 API 端点(ASP.NET Web API 2)的并发请求存在问题。当第二个请求在第一个请求完成之前开始处理时,数据库实体可能会出现并发问题。

示例:
1:请求R1开始处理,将实体E1和E2读入内存
2:请求R2开始处理,将实体E2和E1读入内存
3:请求 R1 更新对象 E1
4:请求 R1 创建 E3,如果 E1 和 E2 已经更新
5:请求 R2 更新对象 E2
6:请求R2创建E3,如果E1和E2已经更新了

问题是两个请求都在另一个请求更新实体 E1 和 E2 之前读取了它。所以两者都看到过时的、未更新的版本,并且永远不会创建 E3。

所有请求都在单个数据库事务中处理(隔离级别“已提交”,SQL Server 2017 上的实体框架 6)。 以我目前的理解,我认为这个问题无法在数据访问/数据存储级别(例如更严格的数据库隔离级别或乐观锁定)上解决,但需要在代码层次结构(请求级别)中更高。

我的建议是悲观地锁定所有在进入 API 方法时可以更新的实体。当另一个 API 请求启动时,它需要对任何已锁定的实体进行写锁定,它需要等到所有先前的锁定都被释放(队列)。一个请求的处理时间通常少于 250 毫秒。
这可以通过装饰 API 方法的自定义属性来实现:[LockEntity(typeof(ExampleEntity), exampleEntityId)]。单个 API 方法可以用零到多个这些属性进行修饰。如果可能,锁定机制将与 async/await 一起使用,或者只是让线程进入睡眠状态。 锁同步需要跨多个服务器工作,所以我在这里看到的最简单的选项是应用程序数据存储中的表示(单个,全局的)。
这种方法很复杂并且有一些性能劣势(阻塞请求处理,在锁定处理期间执行数据库查询),所以我愿意接受任何建议或其他想法。

我的问题:
1. 有没有描述这个问题的术语?这似乎是一件很常见的事情,但到目前为止我还不知道。
2. 有没有解决这个问题的最佳实践?
3. 如果没有,我的提议有意义吗?

【问题讨论】:

    标签: concurrency locking asp.net-web-api2 race-condition isolation-level


    【解决方案1】:

    我不会绕过 Web 和 REST 的无状态,也不会阻止请求。 250 毫秒是四分之一秒,IMO 相当慢。例如 100 个并发请求会互相阻塞,并且至少一个流会等待 25 秒!这会大大降低应用程序的速度。

    我见过一些应用程序(包括 Atlassians Confluence)会通知用户当前数据集已同时被另一位用户更改。 (有时也提到了另一个用户。)我会使用 Websockets 以同样的方式进行操作,例如通过信号R。其他应用程序,如 service-now,正在将远程更改合并到当前开放的数据集中。

    如果您不想使用 Websockets,您也可以尝试在服务器端合并或检查,并通过特定的 HTTP 状态代码和消息通知用户。告诉用户同时发生了什么变化,尝试合并并询问合并是否正常。

    【讨论】:

      猜你喜欢
      • 2019-10-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多