【问题标题】:IN SQL Server is CLR ThreadsafeIN SQL Server 是 CLR 线程安全的
【发布时间】:2010-08-05 12:28:04
【问题描述】:

我在 SQL Server 和 Exchange Web 服务之间有一个 CLR 接口,用于在应用程序之间同步和发送电子邮件。在对此进行测试时,它可以正常工作(编辑);我们在生产环境中看到零星的问题,较长的 Web 服务任务似乎重叠。

我的问题很简单,我无法通过阅读 MSDN 上的 CLR 详细信息来决定 - CLR 线程安全还是开箱即用。

如果不是对 CLR 进行线程安全调用的最佳方法是围绕我的过程进行应用锁定,或者是否有不那么激烈的替代方案。


感谢您的回复;我们正在解决这是一个 EWS / 模拟问题,而不是 SQL 问题。我们在几个小时内对系统进行了一组新的负载测试,即使在大负载下(比应用程序迄今为止看到的高 1000 倍)我们也看不到内存泄漏/线程问题,这就是我们现在寻找其他地方的原因..

【问题讨论】:

  • 此链接不是完全相同的问题,但它可能会提供一些见解:stackoverflow.com/questions/663124/…
  • 请回答您自己的问题并详细说明您的解决方案,并(在两天内)接受该答案。

标签: sql-server thread-safety sqlclr


【解决方案1】:

不要使用进程内 CLR 连接外部、Web 服务或交换或其他任何东西。使用 SQL Server 外部的普通进程。您将看到的不仅仅是“零星”问题:您将在 CLR 事件上耗尽工作池,并且 SQL Server 将冻结

【讨论】:

  • 你真的见过被 SQL CLR 程序集锁定的 SQL Server 吗? SQLCLR 确实与数据库引擎共享一个公共线程池,但这是否意味着调度程序无法以避免完全冻结的方式管理线程?我觉得这很令人惊讶。
  • 是的,我见过。我也创建了连接到远程机器的 CLR 程序(用于性能计数器采样),并且在两周内 3 台服务器冻结后,不得不用外部进程替换解决方案。 x64 服务器。
  • Remus 有趣的是,微软推荐了这种使用 EWS / CLR 处理电子邮件的方法。 AM 将关闭日志;我们已将系统置于大量负载下(每 30 秒 5000 封带附件的出站电子邮件)并且无法重现错误,这导致我们质疑它是否是 EWS/DC 中的交换/身份验证问题,而不是 SQL 中的线程安全问题服务器
  • Remus:谢谢,这是很好的信息。我可以要求澄清一下:您是说整个 SQL Server 进程冻结了,还是只是 SQLCLR 线程冻结了?
  • 整个 SQL,没有工人。当您说“Microsoft 推荐”时,您的意思是 SQL Server 字段 MCS 推荐使用 in-proc CLR?
【解决方案2】:

答案实际上取决于您如何编写 .Net 代码以及如何注册您的程序集。默认情况下,按照一般偏好,SQLCLR 程序集被创建为 SAFE,这意味着 SQL Server 在创建程序集时会扫描它(实际的 CREATE ASSEMBLY 语句)以确定它是否符合安全程序集的规则。 SAFE 程序集没有任何非只读实例变量。意思是,所有变量都是实例变量,如果你声明了一个静态变量,你必须使用“readonly”修饰符。这可确保您不会跨线程共享数据。

但是,您可以在类中创建静态变量并对其进行修改,但程序集必须创建为 UNSAFE。尝试将其创建为 SAFE 会出现以下错误:

CREATE ASSEMBLY 失败,因为安全程序集“AssemblyName”中类型“ClassName”的方法“MethodName”正在存储到静态字段。安全程序集中不允许存储到静态字段。

存储到静态变量不是线程安全的,因此您必须授予程序集 UNSAFE 权限。但在这种情况之外,SQLCLR 是线程安全的。

【讨论】:

  • 如果您的static readonly 变量设置了反射怎么办?这是否真的破坏了 SAFE 程序集,还是 System.Reflection 的存在足以将程序集标记为 UNSAFE
  • @Seph,使用反射一定没问题,因为我正在这样做;-)。我有以下代码:“public static readonly int Major = Assembly.GetExecutingAssembly().GetName().Version.Major;”并且程序集被标记为安全,没有安装或运行时问题。
  • 我认为静态变量必须标记为只读的原因是因为静态变量通常可以同时被多个线程修改。通过使它们只读,这不会发生。但是,对象本身可以被多个线程访问/修改,在这种情况下,您必须使用某种无锁同步。
【解决方案3】:

您在 SQL CLR 代码中看到的主要问题是内存不足,这会导致 AppDomain 重置。从代码的角度来看,这相当于操作系统崩溃。使用 SQLCLR 时,您使用的是由 SQL Server 管理的单独内存池,该内存池比您习惯的要小得多且灵活性较差。我被告知 SQLCLR 团队正在解决这个问题。

一个重要提示:如果您确实重置了 SQLCLR AppDomain,那么您的服务器在其他方面的稳定性应该不会受到影响。崩溃的 SQLCLR 过程只会向调用者返回一个 TSQL 错误。

【讨论】:

  • 保罗感谢您的回答;我们已经通过一次又一次地发送 5000 条并发消息数小时来对用于发送邮件消息的 Web 服务进行负载测试。我们没有在应用程序中看到内存泄漏;我们也没有在日志中看到任何应用程序重新启动。负载测试消息交付没有问题的事实使我们认为我们可能有 DC / EWS 问题,因此我们已经编写了几千个错误处理并将事件记录到代码中以暂时跟踪事情。
【解决方案4】:

如果您的 CLR 代码编写正确,现在已经对 CLR 进行了很多独立测试(故意尝试使其失败) - 用初始化值很好地声明变量,看起来 CLR 是线程安全的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-20
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    • 2019-08-08
    • 2012-10-24
    • 1970-01-01
    相关资源
    最近更新 更多