簡體   English   中英

如何編寫並發REST請求計數器

[英]How to write concurrent REST requests counter

我從事REST服務器的壓力測試。 我的目標是創建一個模擬控制器方法,該方法將每100個請求拋出404錯誤(其他結果為200 OK),並檢查已發送請求和失敗請求的總數。

問題是,即使我使用ConcurrentHashMap和AtomicInteger來計數這些數字,失敗請求的數量也會變化+ -20。 RequestCounter.addFailed()的同步沒有幫助。 我發現的唯一方法是同步控制器的方法,但這不是選項。

我通過Jmeter使用20個線程運行220_000壓力測試請求。 這是我的控制器:

@RequestMapping(value = "/items/add", method = RequestMethod.POST)
public ResponseEntity addGDT(@RequestBody String data, Principal principal) {
    RequestCounter.add();
    if ((RequestCounter.getCounts().get("ADD").longValue() % 100) == 0) {
        RequestCounter.addFailed();
        return ResponseEntity.notFound().build();
    } else {
        return ResponseEntity.ok().build();
    }
}

請求數在此處計算:

public class RequestCounter {
static Map<String, AtomicInteger> counts = new ConcurrentHashMap<>();
static {
    counts.put("ADD", new AtomicInteger(0));
    counts.put("ADD_FAILED", new AtomicInteger(0));
}

public static void add(){
    counts.get("ADD_GDT").incrementAndGet();
}

public static void addFailed(){
    counts.get("ADD_FAILED").incrementAndGet();
}

更新我遵循了javaguy的建議,並通過刪除映射並直接使用AtomicInteger變量來重構代碼。 但是結果仍然是不可預測的:failedRequestCount仍為+ -3

public class RequestCounter {
static AtomicInteger failedRequestsCounter = new AtomicInteger(0);
...
public static void addGDTFailed(){
    failedRequestsCounter.incrementAndGet();
}

UPDATE2無法通過直接調用線程安全變量或通過分離和同步獲取模數的方法來解決這種情況

問題是由於以下兩行,所以RequestCounter類不是threadsafe的:

counts.get("ADD_GDT").incrementAndGet(); 
counts.get("ADD_FAILED").incrementAndGet();

這些不是原子操作,也就是說,計算實際上涉及兩個步驟(從Map讀取值,然后寫入)。 盡管ConcurrentHashMapAtomicInteger分別是線程安全的,但是當您一起使用它們時,需要進行同步或鎖定。

但是,您可以使用更簡單的代碼來實現測試所需的功能,而無需使用ConcurrentHashMap本身。

要使RequestCounter類具有線程安全性,只需刪除Map,然后直接訪問AtomicInteger引用,如下所示:

public class RequestCounter {

        private final AtomicLong addInt = new AtomicLong();
        private final AtomicLong addFailed = new AtomicLong();

        public static long get() {
            return addInt.get();
        }

        public static long add() {
            return addInt.incrementAndGet();
        }

        public static long addFailed(){
            return addFailed.incrementAndGet();
        }
}

UPDATE1:請求變化3%的問題:

您需要確保only once per request調用only once per request RequestCounter.add RequestCounter.add() ,請看下面的控制器代碼:

@RequestMapping(value = "/items/add", method = RequestMethod.POST)
public ResponseEntity addGDT(@RequestBody String data, Principal principal) {

    if ((RequestCounter.get() % 100) == 0) {
        RequestCounter.addFailed();
        return ResponseEntity.notFound().build();
    } else {
        RequestCounter.add();
        return ResponseEntity.ok().build();
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM