Week 07- 作业一:性能测试

发布于: 2020 年 07 月 19 日

以下两题,至少选做一题

  • 性能压测的时候,随着并发压力的增加,系统响应时间和吞吐量如何变化,为什么?

  • 用你熟悉的编程语言写一个 web 性能压测工具,输入参数:URL,请求总次数,并发数。输出参数:平均响应时间,95% 响应时间。用这个测试工具以 10 并发、100 次请求压测 ***。

性能压测时响应时间和吞吐量的变化

1)在最佳运行区间内,随着并发用户的增加,由于系统资源充足,

所以系统响应时间变化不大, 根据吞吐量计算公式:吞吐量=(1000/响应时间(ms))*并发数

可以看出 吞吐量成线性增加.

2)继续增加并发用户,由于系统资源被大量占用,但是还能逐步释放,

系统响应时间基本成线性增加,吞吐量缓慢增加

3)当达到系统最大负载点后,由于系统资源被大量占用,而且不能及时释放,

系统响应时间急剧增大,吞吐量急剧下降,直至系统崩溃

web 性能压测工具

基于c# net core实现

基本思路

1)使用TPL,借助系统线程池来实现对线程的控制。

2)将总请求次数平均分配至每个线程

3)使用线程安全队列记录每个请求使用的时间(ms),并计算平均值

4)去除重复时间,排序后查找95%响应时间

public partial class Form1 : Form
{
private int _totalRequest = 0;//记录请求数(使用原子操作)
private ConcurrentQueue<long> _allRequestTime;//记录所有请求执行时间
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
}
private void btnRequest_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(txtUrl.Text))
{
MessageBox.Show("URL不能为空");
return;
}
else if (string.IsNullOrEmpty(txtHeaders.Text.Trim()))
{
MessageBox.Show("Headers不能为空");
return;
}
//init
_totalRequest = 0;
_allRequestTime = new ConcurrentQueue<long>();
//set headers
Dictionary<string, string> headers = new Dictionary<string, string>();
string[] headerData = Regex.Split(txtHeaders.Text.Trim(), "\r\n", RegexOptions.IgnoreCase);
foreach (var data in headerData)
{
if (!headers.Keys.Contains(data.Split(':')[0]))
headers.Add(data.Split(':')[0], data.Split(':')[1]);
}
//start main thread record
Stopwatch watch = new Stopwatch();
watch.Start();
Console.WriteLine("*********************************btnRequest_Click Start*********************************************");
Console.WriteLine($"btnRequest_Click main threadid:{Thread.CurrentThread.ManagedThreadId}");
TaskFactory taskFactory = new TaskFactory();
int threads = int.Parse(txtParllal.Text);
int totalRequest = int.Parse(txtRequest.Text);
List<Task> taskList = new List<Task>(threads);
//开N个Task,具体线程数量根据线程池实际情况产生,每个线程指定具体访问数量
for (int i = 0; i < threads; i++)
{
int temp = totalRequest / threads;
if (i == threads - 1)
temp += totalRequest % threads;
ActInfo actInfo = new ActInfo
{
Index = i,
//StopwatchAct = watchAct,
RequestCont = temp
};
Action<object> act = t =>
{
ActInfo actTransfer = t as ActInfo;
int reqCount = 0;
while (reqCount < actTransfer.RequestCont)
{
Stopwatch watchAct = new Stopwatch();
watchAct.Start();
SendRequestData(this.txtUrl.Text.Trim(), headers, this.txtBodys.Text.Trim());
watchAct.Stop();
Console.WriteLine($"threadid:{Thread.CurrentThread.ManagedThreadId},task index={actTransfer.Index},request count of task index:{reqCount + 1},_totalRequest:{_totalRequest}," +
$"current time:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:ffff")},totalmills:{watchAct.ElapsedMilliseconds};"
);
reqCount++;
_allRequestTime.Enqueue(watchAct.ElapsedMilliseconds);
}
};
Task task = taskFactory.StartNew(act, actInfo);
taskList.Add(task);
}
taskFactory.ContinueWhenAll(taskList.ToArray(), taskArray =>
{
watch.Stop();
List<long> ninetyfivePer = new List<long>();
long totalMills = 0L;
foreach (var item in _allRequestTime)
{
totalMills += item;
if (!ninetyfivePer.Contains(item))
ninetyfivePer.Add(item);
}
ninetyfivePer.Sort();
double index = ninetyfivePer.Count * 0.95;
int realIndex = int.Parse(Math.Floor(index).ToString());
Console.WriteLine($"!!!!!!!!!!!!!!!!!!!!average time {totalMills / _allRequestTime.Count} mills,95% time:{ninetyfivePer[realIndex]} mills!!!!!!!!!!!!!!!!!");
Console.WriteLine($"*********************************btnRequest_Click End {watch.ElapsedMilliseconds} ********************************************");
});
}
#region request methods
/// <summary>
/// SendRequestData
/// </summary>
/// <param name="strurl"></param>
/// <param name="strPost"></param>
/// <param name="context"></param>
/// <param name="strLang"></param>
/// <returns></returns>
private void SendRequestData(string strurl, Dictionary<string, string> headers, string strPost, string strLang = "utf-8")
{
try
{
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(CheckValidationResult);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(strurl);
{
foreach (var item in headers)
{
SetHeaderValue(request.Headers, item.Key, item.Value);
}
if (string.IsNullOrEmpty(strPost))
request.Method = "GET";
else
{
request.Method = "POST";
byte[] buffeSr = Encoding.GetEncoding(strLang).GetBytes(strPost.ToString());
request.ContentLength = buffeSr.Length;
request.GetRequestStream().Write(buffeSr, 0, buffeSr.Length);
}
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
using (System.IO.Stream respStream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(respStream, Encoding.UTF8))
{
string content = reader.ReadToEnd();
txtResults.AppendText($"\r\n{strurl}\r\n{content}");
txtResults.ScrollToCaret();
}
}
}
Interlocked.Increment(ref _totalRequest);//记录请求次数
}
catch (Exception ex)
{
txtResults.AppendText(strurl + "\r\n" + ex.Message + "\r\n");
txtResults.ScrollToCaret();
}
}
protected bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
{
return true;
}
public void SetHeaderValue(WebHeaderCollection header, string name, string value)
{
var property = typeof(WebHeaderCollection).GetProperty("InnerCollection",
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
if (property != null)
{
var collection = property.GetValue(header, null) as NameValueCollection;
collection[name] = value;
}
}
#endregion
}
public class ActInfo
{
public Stopwatch StopwatchAct { get; set; }
public int Index { get; set; }
public int RequestCont { get; set; }
}

发布于: 2020 年 07 月 19 日 阅读数: 14
用户头像

dean

关注

还未添加个人签名 2019.11.06 加入

还未添加个人简介

评论

发布
暂无评论
Week 07- 作业一:性能测试