Files
fizz-gateway-node/src/main/java/we/stats/FlowStat.java

296 lines
8.5 KiB
Java
Raw Normal View History

2020-12-22 11:05:52 +08:00
package we.stats;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Flow Statistic
*
* @author Francis Dong
*
*/
public class FlowStat {
private static final Logger log = LoggerFactory.getLogger(FlowStat.class);
/**
* Time slot interval in millisecond
*/
public static long INTERVAL = 1000;
/**
2020-12-25 10:34:59 +08:00
* Resource ID for all resources entry
2020-12-22 11:05:52 +08:00
*/
2020-12-25 10:34:59 +08:00
public static String ALL_RESOURCES = "_ALL_RESOURCES";
2020-12-22 11:05:52 +08:00
/**
2020-12-25 10:34:59 +08:00
* A string Resource ID as key
2020-12-22 11:05:52 +08:00
*/
2020-12-25 10:34:59 +08:00
public ConcurrentMap<String, ResourceStat> resourceStats = new ConcurrentHashMap<>();
2020-12-22 11:05:52 +08:00
private ExecutorService pool = Executors.newFixedThreadPool(1);
public FlowStat() {
runHousekeepJob();
}
private void runHousekeepJob() {
pool.submit(new HousekeepJob(this));
}
/**
* Returns the current time slot ID
*
* @return
*/
public long currentTimeSlotId() {
return (System.currentTimeMillis() / INTERVAL) * INTERVAL;
}
/**
* Returns the time slot ID of the specified time
*
* @param timeMilli
* @return
*/
public long getTimeSlotId(long timeMilli) {
return (System.currentTimeMillis() / INTERVAL) * INTERVAL;
}
/**
2020-12-25 10:34:59 +08:00
* Increment concurrent request counter of the specified resource
2020-12-22 11:05:52 +08:00
*
2020-12-25 10:34:59 +08:00
* @param resourceId Resource ID
2020-12-22 11:05:52 +08:00
*/
2020-12-25 10:34:59 +08:00
public void incrConcurrentRequest(String resourceId) {
ResourceStat ResourceStat = getResourceStat(resourceId);
ResourceStat allResourceStat = getResourceStat(ALL_RESOURCES);
ResourceStat.incrConcurrentRequest();
allResourceStat.incrConcurrentRequest();
2020-12-22 11:05:52 +08:00
}
/**
2020-12-25 10:34:59 +08:00
* Returns the current concurrent requests of the specified resource<br/>
2020-12-22 11:05:52 +08:00
* <br/>
2020-12-25 10:34:59 +08:00
* Returns the current concurrent connections of all resources:<br/>
* getConnection(FlowStat.ALL_RESOURCES)
2020-12-22 11:05:52 +08:00
*
2020-12-25 10:34:59 +08:00
* @param resourceId Resource ID
2020-12-22 11:05:52 +08:00
*/
2020-12-25 10:34:59 +08:00
public int getConcurrentRequests(String resourceId) {
ResourceStat ResourceStat = getResourceStat(resourceId);
return ResourceStat.getConcurrentRequests().get();
2020-12-22 11:05:52 +08:00
}
/**
* Add request to current time slot and decrement concurrent connection counter
*
2020-12-25 10:34:59 +08:00
* @param resourceId Resource ID
* @param rt Response time of request
* @param isSuccess Whether the request is success or not
2020-12-22 11:05:52 +08:00
*/
2020-12-25 10:34:59 +08:00
public void incrRequest(String resourceId, long rt, boolean isSuccess) {
incrRequestToTimeSlot(resourceId, currentTimeSlotId(), rt, isSuccess);
2020-12-22 11:05:52 +08:00
}
/**
* Add request to the specified time slot and decrement concurrent connection
* counter
*
2020-12-25 10:34:59 +08:00
* @param resourceId Resource ID
2020-12-22 11:05:52 +08:00
* @param timeSlotId TimeSlot ID
* @param rt Response time of request
* @param isSuccess Whether the request is success or not
* @return
*/
2020-12-25 10:34:59 +08:00
public void incrRequestToTimeSlot(String resourceId, long timeSlotId, long rt, boolean isSuccess) {
if (resourceId == null) {
2020-12-22 11:05:52 +08:00
return;
}
2020-12-25 10:34:59 +08:00
ResourceStat ResourceStat = getResourceStat(resourceId);
ResourceStat allResourceStat = getResourceStat(ALL_RESOURCES);
ResourceStat.incrRequestToTimeSlot(timeSlotId, rt, isSuccess);
allResourceStat.incrRequestToTimeSlot(timeSlotId, rt, isSuccess);
2020-12-22 11:05:52 +08:00
}
2020-12-25 10:34:59 +08:00
private ResourceStat getResourceStat(String resourceId) {
ResourceStat ResourceStat = null;
if (resourceStats.containsKey(resourceId)) {
ResourceStat = resourceStats.get(resourceId);
2020-12-22 11:05:52 +08:00
} else {
2020-12-25 10:34:59 +08:00
ResourceStat = new ResourceStat(resourceId);
ResourceStat rs = resourceStats.putIfAbsent(resourceId, ResourceStat);
2020-12-22 11:05:52 +08:00
if (rs != null) {
2020-12-25 10:34:59 +08:00
ResourceStat = rs;
2020-12-22 11:05:52 +08:00
}
}
2020-12-25 10:34:59 +08:00
return ResourceStat;
2020-12-22 11:05:52 +08:00
}
/**
2020-12-25 10:34:59 +08:00
* Returns current TimeWindowStat of the specified resource
2020-12-22 11:05:52 +08:00
*
2020-12-25 10:34:59 +08:00
* @param resourceId
2020-12-22 11:05:52 +08:00
* @return
*/
2020-12-25 10:34:59 +08:00
public TimeWindowStat getCurrentTimeWindowStat(String resourceId) {
2020-12-22 11:05:52 +08:00
long startTimeMilli = currentTimeSlotId();
2020-12-25 10:34:59 +08:00
return getTimeWindowStat(resourceId, startTimeMilli, startTimeMilli + 1000);
2020-12-22 11:05:52 +08:00
}
/**
* Returns the TimeWindowStat of previous second
*
* @param timeMilli
* @return
*/
2020-12-25 10:34:59 +08:00
public TimeWindowStat getPreviousSecondStat(String resourceId, long timeMilli) {
2020-12-22 11:05:52 +08:00
long endTimeMilli = (timeMilli / INTERVAL) * INTERVAL;
2020-12-25 10:34:59 +08:00
return getTimeWindowStat(resourceId, endTimeMilli - 1000, endTimeMilli);
2020-12-22 11:05:52 +08:00
}
/**
2020-12-25 10:34:59 +08:00
* Returns the timeWindowStat of the specific resource in the specified time
* window [startTimeMilli, endTimeMilli)
2020-12-22 11:05:52 +08:00
*
* @param startTimeMilli included
* @param endTimemilli excluded
* @return
*/
2020-12-25 10:34:59 +08:00
public TimeWindowStat getTimeWindowStat(String resourceId, long startTimeMilli, long endTimeMilli) {
2020-12-22 11:05:52 +08:00
long startSlotId = (startTimeMilli / INTERVAL) * INTERVAL;
long endSlotId = (endTimeMilli / INTERVAL) * INTERVAL;
if (startSlotId == endSlotId) {
endSlotId = endSlotId + INTERVAL;
}
2020-12-25 10:34:59 +08:00
if (resourceStats.containsKey(resourceId)) {
ResourceStat ResourceStat = resourceStats.get(resourceId);
return ResourceStat.getTimeWindowStat(startSlotId, endSlotId);
2020-12-22 11:05:52 +08:00
}
return null;
}
/**
2020-12-25 10:34:59 +08:00
* Returns the ResourceTimeWindowStat list in the specified time window
2020-12-22 11:05:52 +08:00
* [startTimeMilli, endTimeMilli), The time slot unit is one second
*
2020-12-25 10:34:59 +08:00
* @param resourceId optional, returns ResourceSlot list of all resources
* while resourceId is null
2020-12-22 11:05:52 +08:00
* @param startTimeMilli
* @param endTimeMilli
* @return
*/
@SuppressWarnings("unused")
2020-12-25 10:34:59 +08:00
public List<ResourceTimeWindowStat> getResourceTimeWindowStats(String resourceId, long startTimeMilli,
long endTimeMilli) {
return this.getResourceTimeWindowStats(resourceId, startTimeMilli, endTimeMilli, 1);
2020-12-22 11:05:52 +08:00
}
/**
2020-12-25 10:34:59 +08:00
* Returns the ResourceTimeWindow list in the specified time window
2020-12-22 11:05:52 +08:00
* [startTimeMilli, endTimeMilli)
*
2020-12-25 10:34:59 +08:00
* @param resourceId optional, returns ResourceTimeWindowStat list of all
* resources while resourceId is null
2020-12-22 11:05:52 +08:00
* @param startTimeMilli
* @param endTimeMilli
* @param slotIntervalInSec interval of custom time slot in millisecond, such as
* 60 for 1 minutes
* @return
*/
@SuppressWarnings("unused")
2020-12-25 10:34:59 +08:00
public List<ResourceTimeWindowStat> getResourceTimeWindowStats(String resourceId, long startTimeMilli,
long endTimeMilli, long slotIntervalInSec) {
List<ResourceTimeWindowStat> list = new ArrayList<>();
2020-12-22 11:05:52 +08:00
long startSlotId = (startTimeMilli / INTERVAL) * INTERVAL;
long endSlotId = (endTimeMilli / INTERVAL) * INTERVAL;
if (startSlotId == endSlotId) {
endSlotId = endSlotId + INTERVAL;
}
if (slotIntervalInSec < 1 || (endSlotId - startSlotId) / 1000 < slotIntervalInSec) {
return list;
}
long slotInterval = slotIntervalInSec * 1000;
2020-12-25 10:34:59 +08:00
if (resourceId == null) {
Set<Map.Entry<String, ResourceStat>> entrys = resourceStats.entrySet();
for (Entry<String, ResourceStat> entry : entrys) {
2020-12-22 11:05:52 +08:00
String rid = entry.getKey();
2020-12-25 10:34:59 +08:00
ResourceTimeWindowStat resourceWin = new ResourceTimeWindowStat(rid);
2020-12-22 11:05:52 +08:00
for (long i = startSlotId; i < endSlotId;) {
2020-12-25 10:34:59 +08:00
TimeWindowStat tws = getTimeWindowStat(resourceId, startSlotId, endSlotId);
2020-12-22 11:05:52 +08:00
if (tws != null) {
2020-12-25 10:34:59 +08:00
resourceWin.getWindows().add(tws);
2020-12-22 11:05:52 +08:00
}
i = i + slotInterval;
}
2020-12-25 10:34:59 +08:00
if (resourceWin.getWindows().size() > 0) {
list.add(resourceWin);
2020-12-22 11:05:52 +08:00
}
}
} else {
2020-12-25 10:34:59 +08:00
ResourceTimeWindowStat resourceWin = new ResourceTimeWindowStat(resourceId);
2020-12-22 11:05:52 +08:00
for (long i = startSlotId; i < endSlotId;) {
2020-12-25 10:34:59 +08:00
TimeWindowStat tws = getTimeWindowStat(resourceId, startSlotId, endSlotId);
2020-12-22 11:05:52 +08:00
if (tws != null) {
2020-12-25 10:34:59 +08:00
resourceWin.getWindows().add(tws);
2020-12-22 11:05:52 +08:00
}
i = i + slotInterval;
}
2020-12-25 10:34:59 +08:00
if (resourceWin.getWindows().size() > 0) {
list.add(resourceWin);
2020-12-22 11:05:52 +08:00
}
}
return list;
}
class HousekeepJob implements Runnable {
private FlowStat stat;
public HousekeepJob(FlowStat stat) {
this.stat = stat;
}
@Override
public void run() {
long n = 2 * 60 * 60 * 1000 / FlowStat.INTERVAL * FlowStat.INTERVAL;
long lastSlotId = stat.currentTimeSlotId() - n;
while (true) {
log.debug("housekeeping start");
long slotId = stat.currentTimeSlotId() - n;
for (long i = lastSlotId; i < slotId;) {
2020-12-25 10:34:59 +08:00
Set<Map.Entry<String, ResourceStat>> entrys = stat.resourceStats.entrySet();
for (Entry<String, ResourceStat> entry : entrys) {
String resourceId = entry.getKey();
2020-12-22 11:05:52 +08:00
ConcurrentMap<Long, TimeSlot> timeSlots = entry.getValue().getTimeSlots();
2020-12-25 10:34:59 +08:00
log.debug("housekeeping remove slot: resourceId={} slotId=={}", resourceId, i);
2020-12-22 11:05:52 +08:00
timeSlots.remove(i);
}
i = i + FlowStat.INTERVAL;
}
lastSlotId = slotId;
log.debug("housekeeping done");
try {
Thread.sleep(60 * 1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}