我们有一个WCF方法返回一个流 - 通过REST公开。 我们比较(从网站)定期下载到WCF方法,我们发现了70MB文件如下:REST WCF - 流下载速度非常慢,无法更改65535(64KB)块
-
在正规的网站
- - 下载耗时到10秒 - 1MB块大小
- 在WCF的方法 - 花了约20秒 - 块大小总是65535字节。
我们有一个实际流入另一个产品的自定义流,这会使时代差异变得更糟 - 常规站点需要1分钟,而WCF需要2分钟。
因为我们需要支持非常大的文件 - 它变得越来越重要。
我们在调试时停下来,发现WCF调用的流的“读取”方法始终有一个块大小为65,535 - ,这导致缓慢。
我们尝试了多个服务器配置 - 是这样的:
端点:
<endpoint address="Download" binding="webHttpBinding" bindingConfiguration="webDownloadHttpBindingConfig" behaviorConfiguration="web" contract="IAPI" />
结合:
<binding name="webDownloadHttpBindingConfig" maxReceivedMessageSize="20000000" maxBufferSize="20000000" transferMode="Streamed">
<readerQuotas maxDepth="32" maxStringContentLength="20000000" maxArrayLength="20000000" maxBytesPerRead="20000000" maxNameTableCharCount="20000000"/>
<security mode="Transport">
<transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
</security>
</binding>
的客户端,它是一个REST客户端(不能使用WCF绑定 - 我们不想参考它) - 是这样构建的:
System.Net.HttpWebRequest request = (HttpWebRequest)WebRequest.Create(CombineURI(BaseURL, i_RelativeURL));
request.Proxy = null; // We are not using proxy
request.Timeout = i_Timeout;
request.Method = i_MethodType;
request.ContentType = i_ContentType;
string actualResult = string.Empty;
TResult result = default(TResult);
if (!string.IsNullOrEmpty(m_AuthenticationToken))
{
request.Headers.Add(ControllerConsts.AUTH_HEADER_KEY, m_AuthenticationToken);
}
using (var response = request.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
byte[] buffer = new byte[1048576];
int read;
while ((read = responseStream.Read(buffer, 0, buffer.Length)) > 0)
{
o_Stream.Write(buffer, 0, read);
}
}
}
基本上我们只是流入一个流。
所以,无论我们做 - 服务器始终接收的65,535块大小(我们尝试了几种客户端/服务器配置)
我们有什么缺失?
谢谢!
==编辑15年8月4日微软响应== 嗨,我们与微软有关这个案子的工作,这是他们的答案:
当WCF客户端调用返回流的WCF方法,实际上获得对MessageBodyStream实例的引用。 MessageBodyStream最终依赖于WebResponseInputStream实际读出的数据,通过该曲线图的关系:
- MessageBodyStream有一个成员,消息,引用了InternalByteStreamMessage实例
- InternalByteStreamMessage有一个成员,bodyWriter,引用一个StreamBasedStreamedBodyWriter实例
- StreamBasedStreamedBodyWriter有一个引用MaxMessageSizeStream实例的成员流
- MaxMessageSizeStream有一个引用WebResponseInputStream实例的成员流
当你在流调用Read(),WebResponseInputStream.Read()最终调用(你可以在Visual Studio中设置断点测试这个自己 - 一个警告:在Visual Studio中“仅我的代码”选项 - 必须禁用调试,才能命中断点)。 WebResponseInputStream.Read()的相关部分是以下各项:
return BaseStream.Read(buffer, offset, Math.Min(count, maxSocketRead));
其中maxSocketRead被定义为64KB。 上面的注释maxSocketRead说:“为了避免吹内核缓冲区,我们扼杀了我们的读取。 http.sys处理这个问题,但是System.Net不会做任何这样的限制。“ 这意味着如果指定的读取值太大,则会超出内核本身的缓冲区大小,并导致性能较差,因为它需要执行更多工作。
这是否会导致性能瓶颈?不,它不应该。一次读取太少的字节(比如256字节)会导致性能下降。但64KB应该是一个可以提高性能的值。在这些情况下,真正的瓶颈通常是网络带宽,而不是客户端读取数据的速度。 为了最大限度地提高性能,重要的是读取循环尽可能紧凑(换句话说,读取之间没有明显的延迟)。 我们还要记住,大于80KB的对象将转到.Net中的大对象堆,它的存储管理效率低于“正常”堆(压缩不会在正常情况下发生,因此可能会发生内存碎片) 。
检查[maxRequestLength的。 (http://msdn.microsoft.com/en-us/library/system.web.configuration.httpruntime section.maxrequestlength(v = vs.110).aspx)属性 – 2014-10-13 07:27:24
@LukasKubis - 这不是最大的请求大小吗? (默认是4MB - 不是64KB,因为我们看到块的大小) – ArielB 2014-10-13 13:45:11
http://stackoverflow.com/questions/451376/file-download-through-wcf-slower-than-through-iis – Nahum 2015-02-04 15:00:48