【问题标题】:COM+ hang when calling a COM object under load在负载下调用 COM 对象时 COM+ 挂起
【发布时间】:2011-09-16 10:56:49
【问题描述】:

我们有一些用每个人都喜欢的语言(?)——VB6 编写的 COM+ 代码。该 COM+ 组件调用由第三方编写的标准 COM 组件,该组件执行对 SQL Server 数据库的调用。我们在 COM+ 中没有做任何花哨的事情——仅此而已(这只是一个示例;我们并没有真正调用我们的函数 doStuff :-)):

Function doStuff
   Dim o As Library.Object
   Set o = New Library.Object
   str = o.DoSomething()
   Set o = Nothing
   doStuff = str
End Function

作为一个非常快速的压力测试,我们将调用封装在一个非常简单的 VBScript 中,它简单地创建对象、循环调用方法、将对象设置为空,然后重复几次。然后我们在命令提示符下同时运行其中的四个。

我们所经历的是四个 COM+ 窗口停止死机,就好像它们以某种方式相互阻塞一样。根据输出的行为,看起来不同的窗口在沿途某处共享对象的实例:例如,输出出现在窗口之间的速度在窗口之间同步......所以两个窗口可能会以速度起泡,而另外两个每秒吐出一行(当他们吐出一行时,他们同时这样做)。

然后最终,所有四个窗口似乎都停止了 - 在组件服务中,我们看到调用时间开始攀升(因此从每次调用的几毫秒开始,它攀升至 30、40 秒)。有时 dllhost.exe 失败,我们会出现 COM Surrogate 错误对话框(此时窗口会随着新的 dllhost 生成而恢复)。

数据库上没有活动,所以我们已经排除了数据库层的阻塞。通过将 COM+ 组件设置为“事务:禁用”,我们似乎取得了更好的结果,但挂起并没有消失。而不是new,我们将尝试使用CreateObject 创建COM 对象,看看它做了什么(如果有的话)。一旦在 COM+ 和 VBScript 层完成,对象就会设置为 Nothing。

值得注意的是,如果直接从 VBScript(绕过 COM+)调用 3rd 方库,则不会出现任何问题。因此,这似乎与 COM+ 与 COM 对象交互的方式有关,但除了在组件服务中的对象属性下摆弄不同的设置之外,不确定还发生了什么。

关于导致这种情况的幕后原因有什么建议吗?还是要调整的设置?

额外信息
回答中的问题:

进一步的工作...... 看起来这是 COM+ 或 COM 深处某处的同步问题。在我们的测试脚本中,如果我们在每次迭代中添加 10-50ms 的随机延迟,问题就会消失。如果我们有一个固定的延迟,我们锁定。一些谷歌搜索似乎表明在带有 STA 的重负载 COM+ 上可能是一个问题,即documented here on an MS blog。回到 Server 2000 机器或 Server 2003 SP1 机器会很好:这可能是接下来要看的东西......

【问题讨论】:

    标签: com vb6 com+


    【解决方案1】:

    也许COM+ Object Pooling ConceptsConfiguring a Component to Be Pooled 等相关文章会有所帮助。

    池化对象必须满足某些要求,才能使单个对象实例能够被多个客户端使用。例如,它们不能保持客户端状态或具有任何线程亲和性。

    【讨论】:

    • 由于这是一个 VB6 COM+ 对象,因此无法设置池选项,因为 VB6 COM+ 对象仅适用于 STA。第 3 方组件未在 COM+ 中注册——它是标准 COM 组件。
    • 那是真的。可能与VB6代码中全局变量的使用有关吗? support.microsoft.com/kb/815053
    • 不——检查了。我们还根据support.microsoft.com/kb/264957 仔细检查了无人值守执行标志和内存保留是否正确设置
    【解决方案2】:

    想到两件事:

    1. 您是否尝试过将o 变量设为本地变量而不是模块级别?

      函数doStuff 暗淡为 Library.Object
      设置 o = New Library.Object str = o.DoSomething() 设置 o = 无 doStuff = str 结束函数

    2. 你是说Library.Object组件和.DoSomething方法不包含全局变量(或MessageBox语句)吗?

    3. 您能否在每行之后抛出日志语句以查看代码阻塞的位置?

    4. 点击ProcMon 以查看它何时停止访问注册表。最后一次通话失败了吗?如果有,去哪里?

    【讨论】:

    • 1.确实存在,只是缺少[已修复]; 2. 没有 MessageBox - DLL 不是为直接与 UI 交互而设计的 - 全局变量不知道; 3. 和 4. 我们可能需要做的事情:我的怀疑是它是对 3rd 方库的调用...顺便说一句,只是在问题中添加了更多信息:看起来带有 STA 的 COM+ 可以锁定在某些重载情况下...
    【解决方案3】:

    听起来您可能会遇到 COM+ 和 STA 超出公寓呼叫的问题。

    Microsoft 曾经有一篇由 Michael McKeown 发表的很棒的文章“从 MTS 移植到 COM+ 时保持应用程序性能”对此进行了讨论,但它看起来已被删除(有一个存档版本 here)。

    基本上,COM+ STA 线程池将最多 5 个活动绑定到每个 STA 线程。当您进行单元外调用(第 3 方组件或 SQL Server)时,COM+ 允许将其他请求作为 STA 线程上的另一个活动提供服务。最多 5 个活动(每个线程)会发生这种情况。同样,一旦将控制权授予另一个活动,原始活动将无法重新获得控制权,直到第二个活动完成。在重负载下和/或如果调用“长时间运行”,则第一个活动完成的时间是所有其他活动(在线程上)完成的时间的总和。这会影响你的表现。

    如果您能够切换整个 COM+ 服务器的设置,您可以将 COM+ 配置为使用旧的 MTS 100 STA 线程方法。有关详细信息,请参阅Registry key for tuning COM+ thread and activity。你可以看看这是否有助于你的表现。另一种方法是避免使用 STA 组件。

    【讨论】:

    • 这几乎是我根据谷歌和实验得出的结论......虽然很高兴得到证实。通常,调用应该长时间运行(并且不在正常操作中)——所以我们遇到了一些基本上破坏线程池编组的限制。需要审查将服务器放入旧方法是否是继续进行的最佳方法:我怀疑我们会尝试通过不锤击服务器来避免它(毕竟,我们只在潜在的人为负载测试期间击中它),除非我们达到没有其他选择。
    猜你喜欢
    • 1970-01-01
    • 2016-08-07
    • 2011-05-29
    • 1970-01-01
    • 2014-02-05
    • 2020-10-20
    • 1970-01-01
    • 2010-10-02
    • 1970-01-01
    相关资源
    最近更新 更多