我已经实现了一个 HttpModule,它拦截每个请求的响应流,并在每个文本/html 类型的响应上运行六到十个 Regex.Replace()。我担心我在这里会受到多大的性能影响。有什么好办法查明?我想比较运行和不运行 HttpModule 的速度。
4 回答
我有一些连接到 Response.Filter 流管道中,以提供资源文件集成、JS/CSS 打包和将静态文件重写为绝对路径。
只要您在 RegexBuddy 中测试您的正则表达式的速度超过几百万次迭代,请确保您使用 RegexOptions.Compiled,并记住通常最快和最有效的技术是使用正则表达式来广泛识别匹配,然后使用 C# 来磨练它正是你所需要的。
确保您也在缓存和配置您所依赖的。
我们在这方面取得了很大的成功。
这里有一些想法:
- 添加一些 Windows 性能计数器,并使用它们来测量和报告平均计时数据。仅当时间测量超过某个阈值时,您也可以增加计数器。和
- 结合使用跟踪失败的请求跟踪来收集和报告计时数据。您也可以仅在页面执行时间超过阈值时触发 FRT 报告。
- 编写一个单元测试,使用 Windows 操作系统时钟来测量代码执行所需的时间。
- 向您的代码添加一个标志,您可以使用测试页面打开或关闭该标志以启用或禁用您的正则表达式代码,以便轻松进行 A/B 测试。
- 使用 WCAT 之类的负载测试工具来查看在启用和不启用代码的情况下每秒可以处理多少页面请求。
Http 模块只是一段普通的代码,因此您可以测量此特定正则表达式替换内容的执行时间。就够了。将一组典型的响应流作为压力测试的输入,并使用Stopwatch
类测量替换的执行。也考虑RegexOptions.Compiled
切换。
我最近不得不对我编写的 HTTPModule 进行一些 pef 测试,并决定执行几个负载测试来模拟 Web 流量并捕获配置和不配置模块的性能时间。这是我想真正了解安装模块的影响的唯一方法。
我通常会用 Apache Bench 做一些事情(关于如何安装,如何在 windows 7 上安装 apache bench?),但我还必须使用 windows 身份验证。由于ab
只有基本身份验证,因此不适合我。ab
很漂亮,允许不同的请求场景,所以这将是第一个看的地方。另一种想法是,您也可以通过使用glimpse获得很多可见性。
由于我无法使用,ab
我编写了一些自定义内容,允许并发请求并测试不同的 url 时间。
下面是我想出的测试模块,希望对您有所帮助!
// https://www.nuget.org/packages/RestSharp
using RestSharp;
using RestSharp.Authenticators;
using RestSharp.Authenticators.OAuth;
using RestSharp.Contrib;
using RestSharp.Deserializers;
using RestSharp.Extensions;
using RestSharp.Serializers;
using RestSharp.Validation;
string baseUrl = "http://localhost/";
void Main()
{
for(var i = 0; i < 10; i++)
{
RunTests();
}
}
private void RunTests()
{
var sites = new string[] {
"/resource/location",
};
RunFor(sites);
}
private void RunFor(string[] sites)
{
RunTest(sites, 1);
RunTest(sites, 5);
RunTest(sites, 25);
RunTest(sites, 50);
RunTest(sites, 100);
RunTest(sites, 500);
RunTest(sites, 1000);
}
private void RunTest(string[] sites, int iterations, string description = "")
{
var action = GetAction();
var watch = new Stopwatch();
// Construct started tasks
Task<bool>[] tasks = new Task<bool>[sites.Count()];
watch.Start();
for(int j = 0; j < iterations; j++)
{
for (int i = 0; i < sites.Count(); i++)
{
tasks[i] = Task<bool>.Factory.StartNew(action, sites[i]);
}
}
try
{
Task.WaitAll(tasks);
}
catch (AggregateException e)
{
Console.WriteLine("\nThe following exceptions have been thrown by WaitAll()");
for (int j = 0; j < e.InnerExceptions.Count; j++)
{
Console.WriteLine("\n-------------------------------------------------\n{0}", e.InnerExceptions[j].ToString());
}
}
finally
{
watch.Stop();
Console.WriteLine("\"{0}|{1}|{2}\", ",sites.Count(), iterations, watch.Elapsed.TotalSeconds);
}
}
private Func<object, bool> GetAction()
{
baseUrl = baseUrl.Trim('/');
return (object obj) =>
{
var str = (string)obj;
var client = new RestClient(baseUrl);
client.Authenticator = new NtlmAuthenticator();
var request = new RestRequest(str, Method.GET);
request.AddHeader("Accept", "text/html");
var response = client.Execute(request);
return (response != null);
};
}