How to Simulate Realistic Traffic with Segment Randomization in Java Performance Tests
This article explains how to combine traffic replay and custom request generation using a segment‑random approach, provides two Java implementations (CPU‑heavy and memory‑heavy), shows test scripts and a full project example, and demonstrates that the generated load matches the configured request distribution.
In everyday performance testing, traffic replay (e.g., using goreplay ) offers a quick way to build test cases that closely mirror real scenarios, while reconstructing test requests from scratch gives finer control but struggles to stay realistic, especially for full‑load tests.
Segment‑Random Concept
The author introduces a "segment random" technique: analyze online traffic to obtain a model consisting of request‑type ratios and parameter‑value ratios, then generate requests according to those probabilities so that the load better reflects actual traffic.
Implementation
Two Java methods are presented. The first, randomCpu, is CPU‑intensive; the second, randomMem, trades CPU for memory.
public static <F> F randomCpu(Map<F, Integer> count) {
List<F> keys = new ArrayList<>();
List<Integer> values = new ArrayList<>();
count.entrySet().forEach(f -> {
keys.add(f.getKey());
values.add(f.getValue());
});
int t = 0;
for (int i = 0; i < values.size(); i++) {
t = t + values.get(i);
values.set(i, t);
}
int r = getRandomInt(values.get(values.size() - 1));
for (int i = 0; i < values.size(); i++) {
if (r <= values.get(i)) return keys.get(i);
}
return null;
}The algorithm works by splitting the input map into parallel keys and values lists, converting values into a cumulative sum array, picking a random integer within the total sum, and locating the interval that contains the random number to return the corresponding key.
public static <F> F randomMem(Map<F, Integer> count) {
List<F> keys = new ArrayList<>();
List<Integer> values = new ArrayList<>();
count.entrySet().forEach(f -> {
keys.add(f.getKey());
values.add(f.getValue());
});
for (int i = 0; i < values.size(); i++) {
for (int j = 0; j < values.get(i) - 1; j++) {
keys.add(keys.get(i));
}
}
return random(keys);
}This version expands the keys list according to each weight (weight‑1 extra copies) and then selects a random element, which consumes more memory but avoids the cumulative‑sum search.
Test Script
A simple test creates a map of five strings with different weights, runs one million iterations, records each random selection, and prints the count for each element.
public static void test0() {
Map<String, Integer> map = new HashMap<>();
map.put("a", 10);
map.put("b", 20);
map.put("c", 30);
map.put("d", 1);
map.put("e", 2);
List<String> aa = new ArrayList<>();
for (int i = 0; i < 1000000; i++) {
String random = randomMem(map);
aa.add(random);
}
CountUtil.count(aa);
}The console output shows counts close to the configured ratios (e.g., a≈159 066, b≈318 615, c≈474 458, d≈16 196, e≈31 665), confirming that the method respects the weight distribution.
Project‑Level Example
The author builds a dummy project class with three interfaces, each accepting an int parameter. Two static maps store method‑selection probabilities ( ms) and parameter‑selection probabilities ( ps). The online() method picks a method via randomMem(ms), then calls the corresponding test method with a randomly chosen parameter from ps. Results are collected in three static List<Integer> fields.
package com.funtest.javatest;
import com.funtester.frame.SourceCode;
import com.funtester.utils.CountUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.*;
/**
* FunTester test segment‑random class
*/
public class R_FunTester extends SourceCode {
private static final Logger logger = LogManager.getLogger(R_FunTester.class);
public static List<Integer> ts1 = new ArrayList<>();
public static List<Integer> ts2 = new ArrayList<>();
public static List<Integer> ts3 = new ArrayList<>();
public static Map<Integer, Integer> ms = new HashMap<>() {{
put(1, 10);
put(2, 20);
put(3, 40);
}};
public static Map<Integer, Integer> ps = new HashMap<>() {{
put(10, 10);
put(20, 20);
put(30, 40);
}};
public void test1(int a) { ts1.add(a); }
public void test2(int a) { ts2.add(a); }
public void test3(int a) { ts3.add(a); }
public void online() {
Integer m = randomMem(ms);
switch (m) {
case 1: test1(randomMem(ps)); break;
case 2: test2(randomMem(ps)); break;
case 3: test3(randomMem(ps)); break;
default: break;
}
}
}The driver runs one million online() calls, then prints the sizes of the three result lists and the distribution of recorded parameters. The console output matches the expected weighted distribution, demonstrating that the segment‑random approach scales to realistic, full‑load scenarios.
INFO-> 当前用户:oker,工作目录:/Users/oker/IdeaProjects/funtester/,系统编码格式:UTF-8,系统Mac OS X版本:10.16
INFO-> 142168 286236 571596
INFO-> 元素:20,次数:40563
INFO-> 元素:10,次数:20468
INFO-> 元素:30,次数:81137
INFO-> 元素:20,次数:81508
INFO-> 元素:10,次数:40873
INFO-> 元素:30,次数:163855
INFO-> 元素:20,次数:163643
INFO-> 元素:10,次数:81117
INFO-> 元素:30,次数:326836
Process finished with exit code 0Overall, the segment‑random technique provides a practical way to generate load that mirrors real traffic while keeping test construction manageable; the CPU‑heavy version is faster for small weight sets, whereas the memory‑heavy version simplifies the lookup at the cost of higher memory usage.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
