我正在分析一个 webapi 应用程序,该应用程序在负载下速度严重减慢(每秒 100 个请求)
应用程序调用第三方 WCF 服务。
我正在使用 dottrace,请注意 Autofac.Integration.Wcf.RegistrationExtensions.CloseChannel(T)
在我的测试期间被调用 > 22k 次(100 个客户端/秒,持续 1 分钟)
DotTrace 已将此识别为热点。
我按照 Autofac WCF 集成文档注册我的 WCF:
var bookingManagerFactory = new ChannelFactory<IBookingManager>("IBookingManager");
builder.Register(c => bookingManagerFactory).SingleInstance();
builder.Register(c => c.Resolve<ChannelFactory<IBookingManager>>().CreateChannel()).UseWcfSafeRelease();
这种行为是预期的吗?
在整个应用程序中,有许多类依赖于 IBookingManager
据我了解InstancePerDependency
是默认的生命周期 - 这适合我的场景吗? .InstancePerRequest() 是否更适用(在 CreateChannel() 方法上?)
最佳答案
简短的回答:这是预料之中的,而且我认为这不是问题。
深入研究一下:
Autofac 保留一次性对象,直到生命周期范围被释放,此时任何一次性对象都被释放。 (如果将对象注册为 Owned
,则可以手动处置对象,但对于 WCF 内容,我会保留它。)
WCF channel 是一个臭名昭著的挑战,因为它们是一次性的,但是 IDisposable
如果 channel 出现故障(例如,如果收到错误响应),实现将抛出异常,这实际上是非常糟糕的处置设计。无论如何,这就是UseWcfSafeRelease
句柄 - 它通过根据 channel 的状态正确关闭和/或中止 channel 来确保你的 channel 得到正确处理。 CloseChannel
只是处理正确清理的方法。
如果您要解析一堆 channel ,那么这些 channel 都必须以某种方式进行清理。如果您看到CloseChannel
被调用 22,000 次,这意味着您解决了 22,000 个需要安全清理的实例。
我不知道我会更改生命周期范围。另一个 WCF 问题是,如果 channel 发生故障,则无法重用(或重新打开)客户端代理。您已经完成了,您需要一个新 channel 。
优化解决方案的更好选择是解决 Func<IBookingManager>
在你的构造函数中。每当你需要代理时,调用该函数来获取一个新代理。
public class MyConsumer
{
private Func<IBookingManager> _factory;
public MyConsumer(Func<IBookingManager> factory)
{
this._factory = factory;
}
public void DoWork()
{
this._factory().CallOperation(input);
}
}
这有两个好处:
- 如果类上的方法不需要需要解析 channel ,则可以保存 channel 的创建(和处置)。
- 如果您处理错误(例如超时/重试),则可以在旧代理出现故障时创建新代理,并且您的类可以具有更高的容错能力。
除此之外,我认为我不会担心试图避免这种情况 CloseChannel
称呼。如果您需要优化,请优化您创建的 channel 数量。
关于wcf - Autofac WCF - CloseChannel 在负载测试下被多次调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23766670/