并行执行CREATE DATABASE语句会导致错误,但不会导致单独的SQL Server实例

时间:2016-04-20 03:59:28

标签: c# sql-server entity-framework

我在我的应用程序中使用最新版本的Entity Framework(但我不认为EF是这里的问题,只是陈述我们正在使用的ORM)并拥有这种多租户架构。我正在做一些用C#构建的压力测试,其中它创建了X个并行运行的任务来做一些事情。在整个过程开始的某个时刻,它将为每个任务(在这种情况下为每个租户)创建一个新数据库,然后继续处理大部分操作。但是在某些任务上,它会在我尝试创建新数据库的代码中引发2个SQL异常。

异常#1:

  

无法获取数据库' model'的独占锁定。重试   后来运作。 CREATE DATABASE失败。列出的一些文件名可以   不被创造。检查相关错误。

例外#2:

  

超时已过期。完成之前已经过了超时时间   操作或服务器没有响应。

它是这两者中的任何一个并抛出我的代码的同一行(当EF创建数据库时)。显然在SQL Server中,在创建数据库时,它一次只能执行一个数据库并锁定“模型”。数据库(参见here)因此,一些正在等待的任务会导致超时或锁定模型'错误。

这些测试是在我们的开发 SQL Server 2014实例(12.0.4213)上完成的,如果我执行100个并行任务,那么某些任务或有时甚至会抛出错误我执行的任务几乎有一半。

但这是所有这些中最令人不安的部分,当我在我的其他 SQL服务器实例(12.0.2000)上进行测试时,我已在我的PC上本地安装,没有这样的错误抛出并完全完成我执行的所有任务(甚至并行1000个任务!)。

我迄今为止尝试过的解决方案但是没有成功:

  • 将EF中对象上下文的超时更改为无限
  • 尝试在连接字符串上添加更长或无限超时
  • 尝试在EF上添加重试策略并使其更长并且更频繁地运行
  • 目前,尝试将具有类似环境的虚拟机安装到我们的Dev服务器(使用Windows Server 2014 R2)并测试特定版本的SQL Server,以尝试查看版本是否与它有关(是的,我和#39; m绝望:))

无论如何,here是一个简单的C#控制台应用程序,您可以下载并尝试复制该问题。这个测试应用程序将执行您输入的N个任务,并简单地创建一个数据库并在之后进行清理。

2 个答案:

答案 0 :(得分:1)

2观察:

  1. 由于基础问题与并发性有关,并且访问“关键点”只允许单个但不是并发访问者的“资源”,因此您可能会得到不同的结果并不令人惊讶在负载下执行高度并发的方案时,在两台不同的机器上此外,可能涉及SQL Server Engine差异。所有这些都只是试图找出并调试并发问题的过程,尤其是涉及的引擎具有自己非常强大的并发概念。

  2. 不是通过尝试使某些事情发挥作用或完全解释某种情况来反对形势,当事情在经验上不起作用时,为什么不通过设计来更清楚地处理问题来改变方法?

    • 一个选项:通过某种并发同步机制调节访问权限,确认SQL Server需要对模型数据库进行独占锁定的现实 - System.Threading.Monitor听起来对于这里发生的事情是正确的它可以让你控制超时时发生的事情with a timeout of your choosing。这将有助于防止可能在SQL Server端发生的那种锁定类型场景,这可能是对当前“超时”症状的解释(尽管压力负载可能是唯一的解释)。

    • 另一种选择:看看你是否可以设计成根本不需要同步的方式。到达您从未请求同时创建多个数据库的点。创建请求的某种队列 - 并且保证队列仅由一个线程提供服务 - 请求任务对创建的结果执行async / await模式。

  3. 无论哪种方式,你都会遇到这样的情况:在压力测试下,这种情况会变慢,超应力负荷会导致失败。关键问题是:

    • 您的设计可以处理可能的最坏情况负载的多个并且仍然显示可接受的性能吗?
    • 如果确实发生了故障,您对故障的响应是否以您设计的方式“受控制”。

答案 1 :(得分:1)

可能在用于部署数据库的SSDT(DacFx部署)的开发实例和本地实例上设置了不同的 LockTimeoutSeconds QueryTimeoutSeconds

例如 LockTimeoutSeconds 用于设置lock_timeout。如果您的电话数量很少,这就是

的原因
  

无法获得数据库“模型”的排他锁。稍后重试该操作。 CREATE DATABASE失败。列出的某些文件名无法创建。检查相关错误。

您可以使用下面的查询来确定SSDT设置了什么超时时间

select session_id, lock_timeout, * from sys.dm_exec_sessions where login_name = 'username'

要增加默认超时时间,请在此处找到要部署数据库的用户的标识符

  

HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ ProfileList

然后找到以下注册表项

  

HKEY_USERS \您的用户标识符\ Microsoft \ VisualStudio \您的版本\ SQLDB \ Database

并更改 LockTimeoutSeconds QueryTimeoutSeconds

的值