2020-12-22 11:05:52 +08:00
|
|
|
|
package we.stats;
|
|
|
|
|
|
|
|
|
|
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
|
|
|
|
|
|
|
|
|
|
import java.util.List;
|
|
|
|
|
|
import java.util.concurrent.ExecutorService;
|
|
|
|
|
|
import java.util.concurrent.Executors;
|
|
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
|
|
|
|
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
|
|
|
|
|
|
|
|
import we.util.JacksonUtils;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
*
|
|
|
|
|
|
* @author Francis Dong
|
|
|
|
|
|
*
|
|
|
|
|
|
*/
|
|
|
|
|
|
public class FlowStatTests {
|
|
|
|
|
|
|
|
|
|
|
|
private FlowStat stat = new FlowStat();
|
|
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
|
public void testIncr() throws Throwable {
|
2020-12-28 17:06:05 +08:00
|
|
|
|
long curTimeSlotId = stat.currentTimeSlotId();
|
|
|
|
|
|
long slotId = curTimeSlotId + 1000;
|
2020-12-25 10:34:59 +08:00
|
|
|
|
String resourceId = "a";
|
2020-12-22 11:05:52 +08:00
|
|
|
|
|
2020-12-28 17:06:05 +08:00
|
|
|
|
stat.incrRequest(resourceId, curTimeSlotId, null, null);
|
2020-12-25 10:34:59 +08:00
|
|
|
|
TimeWindowStat tws = stat.getPreviousSecondStat(resourceId, slotId);
|
2020-12-22 11:05:52 +08:00
|
|
|
|
assertEquals(1, tws.getTotal());
|
|
|
|
|
|
|
2020-12-28 17:06:05 +08:00
|
|
|
|
stat.incrRequest(resourceId, curTimeSlotId, null, null);
|
|
|
|
|
|
stat.addRequestRT(resourceId, curTimeSlotId, 100, false);
|
|
|
|
|
|
stat.addRequestRT(resourceId, curTimeSlotId, 300, true);
|
|
|
|
|
|
|
2020-12-25 10:34:59 +08:00
|
|
|
|
tws = stat.getPreviousSecondStat(resourceId, slotId);
|
2020-12-22 11:05:52 +08:00
|
|
|
|
assertEquals(2, tws.getTotal());
|
|
|
|
|
|
assertEquals(200, tws.getAvgRt());
|
|
|
|
|
|
assertEquals(100, tws.getMin());
|
|
|
|
|
|
assertEquals(300, tws.getMax());
|
|
|
|
|
|
assertEquals(2, tws.getRps().intValue());
|
|
|
|
|
|
assertEquals(1, tws.getErrors());
|
2020-12-28 17:06:05 +08:00
|
|
|
|
|
|
|
|
|
|
stat.decrConcurrentRequest(resourceId, curTimeSlotId);
|
|
|
|
|
|
Long con = stat.getConcurrentRequests(resourceId);
|
|
|
|
|
|
assertEquals(1, con);
|
2020-12-22 11:05:52 +08:00
|
|
|
|
|
2020-12-25 10:34:59 +08:00
|
|
|
|
// System.out.println(JacksonUtils.writeValueAsString(stat.resourceStats));
|
2020-12-22 11:05:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-12-25 17:45:26 +08:00
|
|
|
|
@Test
|
2020-12-28 17:06:05 +08:00
|
|
|
|
public void testIncrRequest() throws Throwable {
|
2020-12-25 17:45:26 +08:00
|
|
|
|
long curTimeSlotId = stat.currentTimeSlotId();
|
|
|
|
|
|
long nextSlotId = curTimeSlotId + 1000;
|
|
|
|
|
|
String resourceId = "b";
|
2020-12-28 17:06:05 +08:00
|
|
|
|
Long maxCon = 10l;
|
|
|
|
|
|
Long maxRPS = 20l;
|
2020-12-25 17:45:26 +08:00
|
|
|
|
|
2020-12-28 17:06:05 +08:00
|
|
|
|
stat.incrRequest(resourceId, curTimeSlotId, maxCon, maxRPS);
|
2020-12-25 17:45:26 +08:00
|
|
|
|
|
|
|
|
|
|
TimeWindowStat tws = stat.getTimeWindowStat(resourceId, curTimeSlotId, nextSlotId);
|
2020-12-28 17:06:05 +08:00
|
|
|
|
long peakCon = tws.getPeakConcurrentReqeusts();
|
|
|
|
|
|
assertEquals(1l, peakCon);
|
2020-12-25 17:45:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
|
public void testBlockedByMaxCon() throws Throwable {
|
|
|
|
|
|
long curTimeSlotId = stat.currentTimeSlotId();
|
|
|
|
|
|
long nextSlotId = curTimeSlotId + 1000;
|
2020-12-28 17:06:05 +08:00
|
|
|
|
Long maxCon = 10l;
|
|
|
|
|
|
Long maxRPS = 20l;
|
2020-12-25 17:45:26 +08:00
|
|
|
|
int threads = 100;
|
|
|
|
|
|
int requests = 10000;
|
|
|
|
|
|
int totalRequests = threads * requests;
|
|
|
|
|
|
String resourceId = "c";
|
|
|
|
|
|
|
|
|
|
|
|
ExecutorService pool = Executors.newFixedThreadPool(threads);
|
|
|
|
|
|
long t1 = System.currentTimeMillis();
|
|
|
|
|
|
for (int i = 0; i < threads; i++) {
|
2020-12-28 17:06:05 +08:00
|
|
|
|
pool.submit(new ConcurrentJob(requests, curTimeSlotId, resourceId, maxCon, maxRPS));
|
2020-12-25 17:45:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
pool.shutdown();
|
|
|
|
|
|
if (pool.awaitTermination(20, TimeUnit.SECONDS)) {
|
|
|
|
|
|
long t2 = System.currentTimeMillis();
|
|
|
|
|
|
TimeWindowStat tws = stat.getTimeWindowStat(resourceId, curTimeSlotId, nextSlotId);
|
|
|
|
|
|
assertEquals(maxCon, tws.getPeakConcurrentReqeusts());
|
|
|
|
|
|
assertEquals(totalRequests - maxCon, tws.getBlockRequests());
|
2020-12-28 17:06:05 +08:00
|
|
|
|
System.out.println("testBlockedByMaxCon total elapsed time for " + threads * requests + " requests:" + (t2 - t1) + "ms");
|
2020-12-25 17:45:26 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
System.out.println("testIncrConcurrentRequest timeout");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
|
public void testBlockedByMaxRPS() throws Throwable {
|
|
|
|
|
|
long curTimeSlotId = stat.currentTimeSlotId();
|
|
|
|
|
|
long nextSlotId = curTimeSlotId + 1000;
|
2020-12-28 17:06:05 +08:00
|
|
|
|
Long maxCon = Long.MAX_VALUE;
|
|
|
|
|
|
Long maxRPS = 20l;
|
2020-12-25 17:45:26 +08:00
|
|
|
|
int threads = 100;
|
|
|
|
|
|
int requests = 10000;
|
|
|
|
|
|
int totalRequests = threads * requests;
|
|
|
|
|
|
String resourceId = "c";
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < maxRPS; i++) {
|
2020-12-28 17:06:05 +08:00
|
|
|
|
stat.incrRequest(resourceId, curTimeSlotId, maxCon, maxRPS);
|
2020-12-25 17:45:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ExecutorService pool = Executors.newFixedThreadPool(threads);
|
|
|
|
|
|
long t1 = System.currentTimeMillis();
|
|
|
|
|
|
for (int i = 0; i < threads; i++) {
|
2020-12-28 17:06:05 +08:00
|
|
|
|
pool.submit(new ConcurrentJob(requests, curTimeSlotId, resourceId, maxCon, maxRPS));
|
2020-12-25 17:45:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
pool.shutdown();
|
|
|
|
|
|
if (pool.awaitTermination(20, TimeUnit.SECONDS)) {
|
|
|
|
|
|
long t2 = System.currentTimeMillis();
|
|
|
|
|
|
TimeWindowStat tws = stat.getTimeWindowStat(resourceId, curTimeSlotId, nextSlotId);
|
|
|
|
|
|
assertEquals(maxRPS, tws.getRps().intValue());
|
|
|
|
|
|
assertEquals(totalRequests, tws.getBlockRequests());
|
2020-12-28 17:06:05 +08:00
|
|
|
|
System.out.println("testIncrConcurrentRequest total elapsed time for " + threads * requests + " requests:" + (t2 - t1) + "ms");
|
2020-12-25 17:45:26 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
System.out.println("testIncrConcurrentRequest timeout");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-12-22 11:05:52 +08:00
|
|
|
|
@Test
|
|
|
|
|
|
public void testStat() throws Throwable {
|
2020-12-25 10:34:59 +08:00
|
|
|
|
// requests per slot per resource
|
2020-12-22 11:05:52 +08:00
|
|
|
|
int requests = 100;
|
|
|
|
|
|
int threads = 10;
|
2020-12-25 10:34:59 +08:00
|
|
|
|
int resources = 10;
|
2020-12-22 11:05:52 +08:00
|
|
|
|
int slots = 100;
|
|
|
|
|
|
long rt = 100;
|
|
|
|
|
|
long t1 = System.currentTimeMillis();
|
|
|
|
|
|
long start = (t1 / FlowStat.INTERVAL) * FlowStat.INTERVAL;
|
|
|
|
|
|
|
2020-12-25 10:34:59 +08:00
|
|
|
|
int totalRequests = requests * threads * resources * slots;
|
2020-12-22 11:05:52 +08:00
|
|
|
|
|
|
|
|
|
|
ExecutorService pool = Executors.newFixedThreadPool(10);
|
|
|
|
|
|
for (int i = 0; i < threads; i++) {
|
2020-12-25 10:34:59 +08:00
|
|
|
|
pool.submit(new Job(requests, resources, slots, start, rt));
|
2020-12-22 11:05:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
pool.shutdown();
|
|
|
|
|
|
if (pool.awaitTermination(20, TimeUnit.SECONDS)) {
|
|
|
|
|
|
long t2 = System.currentTimeMillis();
|
|
|
|
|
|
|
|
|
|
|
|
long end = start + slots * FlowStat.INTERVAL;
|
|
|
|
|
|
long nsecs = (end - start) / 1000;
|
|
|
|
|
|
|
|
|
|
|
|
System.out.println("total requests:" + totalRequests);
|
|
|
|
|
|
System.out.println("total elapsed time:" + (t2 - t1) + "ms");
|
|
|
|
|
|
System.out.println("Testing Time Window:" + (end - start) + "ms");
|
|
|
|
|
|
|
2020-12-25 10:34:59 +08:00
|
|
|
|
int resource1 = 1;
|
|
|
|
|
|
int resource2 = 2;
|
2020-12-22 11:05:52 +08:00
|
|
|
|
int rtBase1 = 1;
|
|
|
|
|
|
int rtBase3 = 3;
|
2020-12-25 10:34:59 +08:00
|
|
|
|
TimeWindowStat tws1 = stat.getTimeWindowStat("resource-" + resource1, start, end);
|
|
|
|
|
|
TimeWindowStat tws2 = stat.getTimeWindowStat("resource-" + resource2, start, end);
|
2020-12-22 11:05:52 +08:00
|
|
|
|
|
2020-12-25 10:34:59 +08:00
|
|
|
|
assertEquals(totalRequests / resources, tws1.getTotal());
|
2020-12-22 11:05:52 +08:00
|
|
|
|
assertEquals(rt * rtBase1, tws1.getAvgRt());
|
|
|
|
|
|
assertEquals(rt * rtBase1, tws1.getMin());
|
|
|
|
|
|
assertEquals(rt * rtBase1, tws1.getMax());
|
2020-12-25 10:34:59 +08:00
|
|
|
|
assertEquals(totalRequests / resources / nsecs, tws1.getRps().intValue());
|
|
|
|
|
|
assertEquals(totalRequests / resources / 10, tws1.getErrors().intValue());
|
|
|
|
|
|
System.out.println("RPS of resource1: " + tws1.getRps().intValue());
|
2020-12-22 11:05:52 +08:00
|
|
|
|
|
2020-12-25 10:34:59 +08:00
|
|
|
|
assertEquals(totalRequests / resources, tws2.getTotal());
|
2020-12-22 11:05:52 +08:00
|
|
|
|
assertEquals(rt * rtBase3, tws2.getAvgRt());
|
|
|
|
|
|
assertEquals(rt * rtBase3, tws2.getMin());
|
|
|
|
|
|
assertEquals(rt * rtBase3, tws2.getMax());
|
2020-12-25 10:34:59 +08:00
|
|
|
|
assertEquals(totalRequests / resources / nsecs, tws2.getRps().intValue());
|
|
|
|
|
|
assertEquals(totalRequests / resources / 10, tws2.getErrors().intValue());
|
|
|
|
|
|
System.out.println("RPS of resource2: " + tws2.getRps().intValue());
|
2020-12-22 11:05:52 +08:00
|
|
|
|
|
|
|
|
|
|
// performance of getTimeWindowStat
|
|
|
|
|
|
for (int n = 0; n < 10; n++) {
|
|
|
|
|
|
long t3 = System.currentTimeMillis();
|
|
|
|
|
|
int times = 100000;
|
|
|
|
|
|
for (int i = 0; i < times; i++) {
|
2020-12-25 10:34:59 +08:00
|
|
|
|
stat.getTimeWindowStat("resource-" + resource1, start, end);
|
2020-12-22 11:05:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
long t4 = System.currentTimeMillis();
|
|
|
|
|
|
System.out.println("performance of getTimeWindowStat: " + (t4 - t3) + "ms " + times + " times");
|
|
|
|
|
|
try {
|
|
|
|
|
|
Thread.sleep(10);
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-12-25 10:34:59 +08:00
|
|
|
|
// System.out.println(JacksonUtils.writeValueAsString(stat.resourceStats));
|
2020-12-22 11:05:52 +08:00
|
|
|
|
|
2020-12-25 10:34:59 +08:00
|
|
|
|
List<ResourceTimeWindowStat> list = stat.getResourceTimeWindowStats("resource-" + 1, start, end, 10);
|
2020-12-25 10:55:01 +08:00
|
|
|
|
assertEquals(nsecs / 10, list.get(0).getWindows().size());
|
2020-12-22 11:05:52 +08:00
|
|
|
|
System.out.println(JacksonUtils.writeValueAsString(list));
|
|
|
|
|
|
} else {
|
|
|
|
|
|
System.out.println("timeout");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class Job implements Runnable {
|
|
|
|
|
|
|
2020-12-25 10:34:59 +08:00
|
|
|
|
public Job(int requests, int resources, int slots, long startSlotId, long rt) {
|
2020-12-22 11:05:52 +08:00
|
|
|
|
this.requests = requests;
|
2020-12-25 10:34:59 +08:00
|
|
|
|
this.resources = resources;
|
2020-12-22 11:05:52 +08:00
|
|
|
|
this.slots = slots;
|
|
|
|
|
|
this.startSlotId = startSlotId;
|
|
|
|
|
|
this.rt = rt;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int requests = 0;
|
2020-12-25 10:34:59 +08:00
|
|
|
|
private int resources = 0;
|
2020-12-22 11:05:52 +08:00
|
|
|
|
private int slots = 0;
|
|
|
|
|
|
private long startSlotId = 0;
|
|
|
|
|
|
private long rt = 0;
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void run() {
|
|
|
|
|
|
for (int m = 0; m < slots; m++) {
|
|
|
|
|
|
for (int i = 0; i < requests; i++) {
|
2020-12-25 10:34:59 +08:00
|
|
|
|
for (int j = 0; j < resources; j++) {
|
2020-12-28 17:06:05 +08:00
|
|
|
|
stat.incrRequest("resource-" + j, startSlotId + (m * FlowStat.INTERVAL), null, null);
|
2020-12-22 11:05:52 +08:00
|
|
|
|
// 10% error
|
|
|
|
|
|
boolean isSuccess = i % 10 == 1 ? false : true;
|
|
|
|
|
|
// rt will be triple while even
|
2020-12-28 17:06:05 +08:00
|
|
|
|
stat.addRequestRT("resource-" + j, startSlotId + (m * FlowStat.INTERVAL),
|
2020-12-22 11:05:52 +08:00
|
|
|
|
rt * (j % 2 == 0 ? 3 : 1), isSuccess);
|
|
|
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
|
|
|
// Thread.sleep(1);
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-12-25 17:45:26 +08:00
|
|
|
|
class ConcurrentJob implements Runnable {
|
|
|
|
|
|
|
2020-12-28 17:06:05 +08:00
|
|
|
|
public ConcurrentJob(int requests, long curTimeSlotId, String resourceId, Long maxCon, Long maxRPS) {
|
2020-12-25 17:45:26 +08:00
|
|
|
|
this.requests = requests;
|
|
|
|
|
|
this.resourceId = resourceId;
|
|
|
|
|
|
this.maxRPS = maxRPS;
|
|
|
|
|
|
this.maxCon = maxCon;
|
|
|
|
|
|
this.curTimeSlotId = curTimeSlotId;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int requests = 0;
|
|
|
|
|
|
private String resourceId;
|
2020-12-28 17:06:05 +08:00
|
|
|
|
private Long maxCon = 0l;
|
|
|
|
|
|
private Long maxRPS = 0l;
|
2020-12-25 17:45:26 +08:00
|
|
|
|
private long curTimeSlotId = 0;
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public void run() {
|
|
|
|
|
|
for (int i = 0; i < requests; i++) {
|
2020-12-28 17:06:05 +08:00
|
|
|
|
stat.incrRequest(resourceId, curTimeSlotId, maxCon, maxRPS);
|
2020-12-25 17:45:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-12-22 11:05:52 +08:00
|
|
|
|
}
|