效能測試中標記每個請求
阿新 • • 發佈:2020-01-11
在做效能測試過程中,遇到一個棘手的問題,開發讓我們復現幾個請求時間較長的請求,他們看日誌進行鏈路追蹤,查詢瓶頸所在。
這裡說一下框架中的處理邏輯:每個請求有一個唯一的requestid,由幾部分組成,還有一些演算法保證其唯一性。然後這個requestID貫穿整個請求過程的日誌,服務間的相互呼叫,與資料庫中介軟體的互動都依賴於這個requestID。
以往壓測都是寫了一個請求ID,並未對這個header做處理,現在得搞起來了。
首先我先新建了一個Java interface,用於使用閉包直接完成這個功能,還有就是其他標記方法:
package com.fun.base.interfaces; import org.apache.http.client.methods.HttpRequestBase; import java.io.Serializable; /** * 用來標記request,為了記錄超時的請求 */ public interface MarkRequest extends Serializable { /** * 用來標記base,刪除header其中一項,新增一項 * * @param base * @return */ public String mark(HttpRequestBase base); }
然後我再ThreadLimitTimesCount
和ThreadLimitTimeCount
實現類中使用這個介面物件,兩個實現類的程式碼已經發過了效能測試框架第二版,這裡只寫一個:
- 中間用到了深拷貝的方法,在之前也記錄過了拷貝HttpRequestBase物件,目前是每一個執行緒對應一個
mark
物件,而不是多執行緒共享,下面會看到效果。
package com.fun.frame.thead; import com.fun.base.constaint.ThreadLimitTimesCount; import com.fun.base.interfaces.MarkRequest; import com.fun.config.Constant; import com.fun.config.HttpClientConstant; import com.fun.frame.Save; import com.fun.frame.excute.Concurrent; import com.fun.frame.httpclient.FanLibrary; import com.fun.frame.httpclient.FunRequest; import com.fun.frame.httpclient.GCThread; import com.fun.utils.Time; import org.apache.http.client.methods.HttpRequestBase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; import java.util.Vector; /** * http請求多執行緒類 */ public class RequestThreadTimes extends ThreadLimitTimesCount { private static final long serialVersionUID = -2751325651625435070L; static Logger logger = LoggerFactory.getLogger(RequestThreadTimes.class); /** * 記錄總的請求超時的情況 */ public static Vector<String> requestMark = new Vector<>(); /** * 請求 */ public HttpRequestBase request; /** * 標記物件 */ public MarkRequest mark; /** * 記錄當前執行緒超時請求 */ public List<String> marks = new ArrayList<>(); /** * 單請求多執行緒多次任務構造方法 * * @param request 被執行的請求 * @param times 每個執行緒執行的次數 */ public RequestThreadTimes(HttpRequestBase request, int times) { this.request = request; this.times = times; this.mark = new MarkRequest() { private static final long serialVersionUID = 5599842482575655279L; @Override public String mark(HttpRequestBase base) { return EMPTY; } }; } /** * 應對對每個請求進行標記的情況 * * @param request * @param times * @param mark */ public RequestThreadTimes(HttpRequestBase request, int times, MarkRequest mark) { this(request, times); this.mark = mark; } protected RequestThreadTimes() { super(); } @Override public void before() { super.before(); GCThread.starts(); } /** * @throws Exception */ @Override protected void doing() throws Exception { FanLibrary.excuteSimlple(request); } @Override protected void after() { requestMark.addAll(marks); GCThread.stop(); synchronized (RequestThreadTimes.class) { if (countDownLatch.getCount() == 0) Save.saveStringList(requestMark, Constant.DEFAULT_STRING); } } @Override public void run() { try { before(); List<Long> t = new ArrayList<>(); long ss = Time.getTimeStamp(); for (int i = 0; i < times; i++) { try { String m = this.mark.mark(request); long s = Time.getTimeStamp(); doing(); long e = Time.getTimeStamp(); long diff = e - s; t.add(diff); if (diff > HttpClientConstant.MAX_ACCEPT_TIME) marks.add(diff + CONNECTOR + m); excuteNum++; if (status()) break; } catch (Exception e) { logger.warn("執行任務失敗!", e); errorNum++; } } long ee = Time.getTimeStamp(); logger.info("執行次數:{},錯誤次數: {},總耗時:{} s", times, errorNum, (ee - ss) / 1000 + 1); Concurrent.allTimes.addAll(t); } catch (Exception e) { logger.warn("執行任務失敗!", e); } finally { if (countDownLatch != null) countDownLatch.countDown(); after(); } } @Override public RequestThreadTimes clone() { RequestThreadTimes threadTimes = new RequestThreadTimes(); threadTimes.times = this.times; threadTimes.request = FunRequest.cloneRequest(request); threadTimes.mark = deepClone(mark); return threadTimes; } }
我自己寫了一個使用Demo:
def "測試併發情況下記錄響應標記符的"() { given: HttpGet httpGet = FanLibrary.getHttpGet("https://cn.bing.com/"); MarkRequest mark = new MarkRequest() { String m; @Override public String mark(HttpRequestBase base) { base.removeHeaders("requestid"); m = m == null ? RString.getStringWithoutNum(4) : m String value = "fun_" + m + CONNECTOR + Time.getTimeStamp(); base.addHeader("requestid", value); return value; } }; FanLibrary.getHttpResponse(httpGet); HttpClientConstant.MAX_ACCEPT_TIME = -1 RequestThreadTimes threadTimes = new RequestThreadTimes(httpGet, 2, mark); new Concurrent(threadTimes, 2).start(); output(RequestThreadTimes.requestMark) }
下面是記錄的結果如下,可以看到,一共出現了兩個m
的值,後面跟的是時間戳,這樣既保證了requestID唯一性,也可以對執行緒進行歸類。
80_fun_QkhQ_1578367527661
103_fun_QkhQ_1578367527742
101_fun_zwtk_1578367527661
107_fun_zwtk_1578367527763
- 鄭重宣告:文章首發於公眾號“FunTester”,禁止第三方(騰訊雲除外)轉載、發表。
技術類文章精選
- java一行程式碼列印心形
- Linux效能監控軟體netdata中文漢化版
- 效能測試框架第二版
- 如何在Linux命令列介面愉快進行效能測試
- 圖解HTTP腦圖
- 將swagger文件自動變成測試程式碼
- 五行程式碼構建靜態部落格
- 基於java的直線型介面測試框架初探
- Selenium 4.0 Alpha更新日誌
- Selenium 4.0 Alpha更新實踐
- 如何統一介面測試的功能、自動化和效能測試用例
非技術文章精選
- 為什麼選擇軟體測試作為職業道路?
- 寫給所有人的程式設計思維
- 成為自動化測試的7種技能
- 如何在DevOps引入自動化測試
- Web端自動化測試失敗原因彙總
- 如何在DevOps引入自動化測試
- 測試人員常用藉口
- 2019年瀏覽器市場份額排行榜
- API測試基礎
- API自動化測試指南
- 未來的QA測試工程師