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 日 阅读数: 41
版权声明: 本文为 InfoQ 作者【dean】的原创文章。
原文链接:【http://xie.infoq.cn/article/dcc5abc8fe58a2d661edd9383】。文章转载请联系作者。
dean
关注
还未添加个人签名 2019.11.06 加入
还未添加个人简介
评论