我们正在将Service Stack用于Web服务API。我们编写了一个“获取文件”例程来获取文件而不是让IIS直接提供文件,因为我们需要服务器端身份验证逻辑。
我们通过返回RestServiceBase<Foo>.OnGet
从IStreamWriter
返回一个文件,其实现方式如下:
public void WriteTo(Stream responseStream)
{
Stream filedata = File.OpenRead(_filepath);
filedata.CopyTo(responseStream);
}
问题:这比直接提供文件的IIS慢大约50%到100%。
我是否错误地从Service Stack返回了一个文件?我有什么办法可以加快速度吗?
或者,是否有某种方法可以将我们的身份验证方案(我们希望完全无状态,因此服务器计算机上没有缓存凭据)插入IIS,以便IIS以某种方式调用我们的服务器来验证每个请求然后提供服务文件本身?
答案 0 :(得分:2)
IIS将使用本机代码来提供静态文件,并且可能会采用一些积极的内存缓存来实现其性能。
由于ServiceStack是一个.NET库,代码直接写入ASP.NET的响应流,因此在托管.NET代码中流式传输文件更加困难。您可以通过将文件加载到内存中并写入原始字节来进一步提高性能。
这就是为什么如果必须执行托管代码,您应该尽最大努力利用HTTP缓存,这就是我们在StaticFileHandler中所做的 - 即ServiceStack用于提供其静态内容的内容,例如css / js / html pages。
尽管ServiceStack的请求管道已经过大量优化(即不会增加很多开销),但您仍然可以通过注册自己的自定义IHttpHandler
来绕过它并处理原始ASP.NET请求你自己 - 这将是.NET代码中最快的选择,例如:
SetConfig(new EndpointHostConfig {
RawHttpHandlers = { MiniProfilerHandler.MatchesRequest },
});
这就是内置MiniProfiler用于提供静态内容的功能。 MatchesRequest只需要一个IHttpRequest
来解决它是否应该处理请求(通过返回IHttpHandler的实例)或不处理(返回null):
public static IHttpHandler MatchesRequest(IHttpRequest request)
{
var file = Path.GetFileNameWithoutExtension(request.PathInfo);
return file != null && file.StartsWith("ss-")
? new MiniProfilerHandler()
: null;
}
除此之外,独立版本的ServiceStack(即HttpListener主机)应提供比ASP.NET更好的原始吞吐量。
答案 1 :(得分:0)
IIS I / O线程的上下文切换到CLR线程池上的线程有一个惩罚,如果你将(asp config)MaxConcurrentRequestsPerCPU设置为0你的CLR代码你应该能够减轻它(可能还有其他后果)
见 http://blogs.msdn.com/b/tmarq/archive/2007/07/21/asp-net-thread-usage-on-iis-7-0-and-6-0.aspx
我不知道windows是否允许“零复制”:文件(永远不会离开内核模式并将套接字上的缓冲区跳转到文件句柄操作)但是如果支持IIS则肯定会使用它(使其快于用户模式下的CLR ..)