简体   繁体   English

SQL Server CLR线程

[英]SQL Server CLR Threading

I have been struggling with a SQL Server CLR stored procedure. 我一直在努力使用SQL Server CLR存储过程。

Background: 背景:

We are using SQL Server 2014 and a CLR stored procedure has been implemented which calls a customer's web service. 我们正在使用SQL Server 2014,并且已实现调用客户Web服务的CLR存储过程。

The threading was initially used not to slow the main thread of SQL Server CLR. 最初使用线程不会减慢SQL Server CLR的主线程。

Although, now, I know that using threading under CLR is no best idea, it has been working correctly for 6 years (since SQL Server 2008). 虽然,现在,我知道在CLR下使用线程并不是最好的主意,但它已经正常工作了6年(自SQL Server 2008以来)。 It has been migrated to SQL Server 2014 recently. 它最近已迁移到SQL Server 2014。

The problem 问题

On my development machine, same as on test system we have no problem with the solution. 在我的开发机器上,与测试系统一样,我们对解决方案没有任何问题。

On the customer system, the thread, which calls the web service, is never executed for some reason. 在客户系统上,调用Web服务的线程由于某种原因从不执行。

I can see from the log files that everything is working correctly till the thread execution. 我可以从日志文件中看到一切正常,直到线程执行。

There is no specific error, nothing. 没有特定的错误,没有。

We have been trying to change the permissions, but without a success. 我们一直在尝试更改权限,但没有成功。 Therefore I think its not a permission issue. 因此,我认为这不是一个许可问题。

Questions 问题

  1. Does anyone know how to change the behavior? 有谁知道如何改变行为? We couldn't find any configuration which might does the trick. 我们找不到任何可能起作用的配置。

  2. Would it be good idea to remove the threading completely, and having the calling of web services directly on SQL Server main thread? 完全删除线程,并直接在SQL Server主线程上调用Web服务是否是个好主意?

Thank you for any advice, Petr 谢谢你的任何建议,彼得

Not sure about Question #1, though it might not matter given the recommendation for Question #2. 对问题#1不确定,但考虑到问题#2的建议可能无关紧要。 Still, one difference between SQL Server 2008 (where it is working) and SQL Server 2014 (where it is not working) is the CLR version that SQL Server is linked to. 尽管如此,SQL Server 2008(它工作的地方)和SQL Server 2014(它不工作的地方)之间的一个区别是SQL Server链接到的CLR版本。 SQL Server 2005 / 2008 / 2008 R2 are linked to CLR v2.0 while SQL Server 2012 and newer are linked to CLR v 4.0. SQL Server 2005/2008 / 2008 R2链接到CLR v2.0,而SQL Server 2012和更新版本链接到CLR v 4.0。 Since you are not seeing the error and your client is, I would make sure that their system has been updated to the same .NET Framework version that you are running. 由于您没有看到错误而您的客户端是,我将确保他们的系统已更新为您正在运行的相同.NET Framework版本。

For Question #2, I would recommend removing the multi-threading. 对于问题#2,我建议删除多线程。 That has too much potential for problems, and requires the Assembly to be UNSAFE . 这有太多潜在的问题,需要大会UNSAFE If you remove the threading, you can set the Assembly to EXTERNAL_ACCESS . 如果删除线程,则可以将Assembly设置为EXTERNAL_ACCESS

If you want to reduce contention, then assuming the Web Service calls are to the same URI, then you need to increase the number of allowed concurrent web requests. 如果要减少争用,那么假设Web服务调用属于同一URI,则需要增加允许的并发Web请求数。 That can be done by setting the ServicePointManager.DefaultConnectionLimit Property . 这可以通过设置ServicePointManager.DefaultConnectionLimit属性来完成。 The default value is 2. Which means, any additional requests will wait and wait until one of the current 2 is closed. 默认值为2.这意味着,任何其他请求将等待并等待当前2之一关闭。

Also, be sure to properly Dispose of the WebRequest . 另外,请务必正确Dispose WebRequest


The concern about making external calls (ie the Web Service) that can potentially not complete quickly is that SQL Server uses Cooperative Multitasking wherein each thread is responsible for "yielding" control back to the Scheduler (effectively pausing it) at various points so that the Scheduler can shuffle things around and run other things that are currently "sleeping". 关于进行可能无法快速完成的外部调用(即Web服务)的担忧是SQL Server使用协作式多任务处理,其中每个线程负责在各个​​点处“控制”控制回到调度程序(有效地暂停它),以便调度程序可以随机播放并运行其他正在“休眠”的内容。 This concern with regards to SQLCLR code can typically be mitigated by doing at least one of the following: 通常可以通过执行以下至少一项来减轻对SQLCLR代码的关注:

  • Perform data access / querying the instance 执行数据访问/查询实例
  • Calling thread.sleep(0); 调用thread.sleep(0);

However, an external call is not doing data access, and you cannot easily call thread.sleep(0) while waiting for the WebResponse to complete. 但是,外部调用不进行数据访问,并且在等待WebResponse完成时无法轻松调用thread.sleep(0) Yes, you can call the WebService on a separate thread and while waiting for it to finish, assuming you are just looping and checking, the sleep(x) will allow for the yield. 是的,您可以在单独的线程上调用WebService,并在等待它完成时,假设您只是循环和检查, sleep(x)将允许yield。

But is doing the Web Service call asynchronously necessary? 但是异步进行Web服务调用是否必要? It certainly has the downside of requiring the Assembly to be marked as WITH PERMISSION_SET = UNSAFE . 它的缺点当然是要求将程序集标记为WITH PERMISSION_SET = UNSAFE It greatly depends on how long the call usually takes, and how frequently it is being called. 这在很大程度上取决于呼叫通常需要多长时间,以及呼叫的频率。 The more frequent the call, the more likely it is that any delays are, at least in part, caused by the low default value for how many concurrent connections are allowed per each URI. 调用越频繁,任何延迟的可能性越大,至少部分是由每个URI允许的并发连接数的低默认值引起的。 This relates to the recommendation I made at the top. 这与我在顶部提出的建议有关。

But if you want to see how SQL Server actually works, this should be fairly easy to test. 但是如果你想看看SQL Server实际上是如何工作的,那么这应该很容易测试。 On my laptop, I went to the Server "Properties" in Object Explorer, went to "Processors", unchecked the "automatically set processor affinity..." option, selected only a single CPU under "Processor Affinity" in the tree view in the middle of the dialog, clicked "OK", and then restarted the service. 在我的笔记本电脑上,我去了对象浏览器中的服务器“属性”,转到“处理器”,取消选中“自动设置处理器关联...”选项,在树视图中的“处理器关系”下只选择了一个CPU。在对话框的中间,单击“确定”,然后重新启动该服务。 I then set up a web page that did nothing but call "sleep" for 60 seconds. 然后,我建立了一个网页,除了呼叫“睡眠”60秒之外什么也没做。 I have a SQLCLR TVF that calls web pages so I ran that concurrently in two different tabs / sessions. 我有一个调用网页的SQLCLR TVF,所以我在两个不同的标签/会话中同时运行它。 In a 3rd tab / session, I ran: 在第3个标签/会话中,我跑了:

SELECT SUM(so1.[schema_id]), so1.[type_desc], so2.[type_desc]
FROM sys.objects so1
CROSS JOIN sys.objects so2
CROSS JOIN sys.objects so3
CROSS JOIN sys.objects so4
CROSS JOIN sys.objects so5
WHERE so3.[create_date] <> so4.[modify_date]
GROUP BY so1.[type_desc], so2.[type_desc], so5.[name]
ORDER BY so2.[type_desc], so5.[name] DESC;

And finally, in a 4th tab, after kicking off the first 3, I ran the following to monitor the system: 最后,在第4个选项卡中,在开始前3个后,我运行以下命令来监控系统:

SELECT * FROM sys.dm_os_schedulers WHERE [scheduler_id] = 0;

SELECT *
FROM sys.dm_exec_requests
WHERE [scheduler_id] = 0
AND [status] <> N'background'
ORDER BY [status] DESC, session_id;

The status for the 2 sessions running the SQLCLR function was always "running" and the status for the session running that ugly query in tab 3 was always "runnable". 运行SQLCLR函数的2个会话的状态始终为“正在运行”,并且在选项卡3中运行该丑陋查询的会话的状态始终为“可运行”。 But just to be sure, running that ugly query again, when neither of the SQLCLR functions was executing, took the same 1 minute and 14 seconds that it did when running concurrently with the 2 sessions running the SQLCLR call to the web page that was sleeping for 60 seconds. 但只是为了确定,当两个SQLCLR函数都没有执行时再次运行那个丑陋的查询,与运行SQLCLR调用的2个会话同时运行时所执行的1分14秒相同。持续60秒。

Please do not infer that there is no cost to running the SQLCLR code to make the web calls. 请不要推断运行SQLCLR代码进行Web调用没有任何成本。 Since those threads were busy the whole time, if the system was busy then it would have reduced the ability for SQL Server to allocate those threads to complete other queries faster. 由于这些线程一直很忙,如果系统繁忙,那么它会降低SQL Server分配这些线程以更快地完成其他查询的能力。 But it does seem safe to conclude that, at least on systems with low to moderate load, the benefit gained by adding the threading doesn't seem to be worth the cost of increased complexity (especially since now there is a not-yet-reproducable problem to debug). 但似乎可以肯定地得出结论,至少在负载低到中等的系统上,通过添加线程获得的好处似乎不值得增加复杂性的成本(特别是因为现在还有一个尚未重现的调试问题)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM