-
Notifications
You must be signed in to change notification settings - Fork 8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor the underlying model of SystemRuleManager #3158
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package com.alibaba.csp.sentinel.slots.system; | ||
|
||
/** | ||
* Metric type of system rule. | ||
* | ||
* @author guozhong.huang | ||
*/ | ||
public enum SystemMetricType { | ||
/** | ||
* Load represents system load1 in Linux/Unix. | ||
*/ | ||
LOAD(0), | ||
/** | ||
* AvgRT represents the average response time of all inbound requests. | ||
*/ | ||
AVG_RT(1), | ||
/** | ||
* Concurrency represents the concurrency of all inbound requests. | ||
*/ | ||
CONCURRENCY(2), | ||
|
||
/** | ||
* InboundQPS represents the QPS of all inbound requests. | ||
*/ | ||
INBOUND_QPS(3), | ||
|
||
/** | ||
* CpuUsage represents the CPU usage percentage of the system. | ||
*/ | ||
CPU_USAGE(4); | ||
|
||
private int type; | ||
|
||
SystemMetricType(int type) { | ||
this.type = type; | ||
} | ||
|
||
public int getType() { | ||
return type; | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A formatting mistake here. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,170 +24,87 @@ | |
* provides a measurement of system's load, but only available on Linux. | ||
* </p> | ||
* <p> | ||
* We recommend to coordinate {@link #highestSystemLoad}, {@link #qps}, {@link #avgRt} | ||
* and {@link #maxThread} to make sure your system run in safety level. | ||
* We recommend to coordinate {@link SystemMetricType#LOAD}, {@link SystemMetricType#INBOUND_QPS}, {@link SystemMetricType#AVG_RT} | ||
* and {@link SystemMetricType#CONCURRENCY} to make sure your system run in safety level. | ||
* </p> | ||
* <p> | ||
* To set the threshold appropriately, performance test may be needed. | ||
* </p> | ||
* | ||
* @author jialiang.linjl | ||
* @author Carpenter Lee | ||
* @author guozhong.huang | ||
* @see SystemRuleManager | ||
*/ | ||
public class SystemRule extends AbstractRule { | ||
|
||
/** | ||
* negative value means no threshold checking. | ||
*/ | ||
private double highestSystemLoad = -1; | ||
/** | ||
* cpu usage, between [0, 1] | ||
*/ | ||
private double highestCpuUsage = -1; | ||
private double qps = -1; | ||
private long avgRt = -1; | ||
private long maxThread = -1; | ||
|
||
public double getQps() { | ||
return qps; | ||
} | ||
|
||
/** | ||
* Set max total QPS. In a high concurrency condition, real passed QPS may be greater than max QPS set. | ||
* The real passed QPS will nearly satisfy the following formula:<br/> | ||
* | ||
* <pre>real passed QPS = QPS set + concurrent thread number</pre> | ||
* | ||
* @param qps max total QOS, values <= 0 are special for clearing the threshold. | ||
* MetricType indicates the type of the trigger metric. | ||
*/ | ||
public void setQps(double qps) { | ||
this.qps = qps; | ||
} | ||
|
||
public long getMaxThread() { | ||
return maxThread; | ||
} | ||
private SystemMetricType systemMetricType; | ||
|
||
/** | ||
* Set max PARALLEL working thread. When concurrent thread number is greater than {@code maxThread} only | ||
* maxThread will run in parallel. | ||
* | ||
* @param maxThread max parallel thread number, values <= 0 are special for clearing the threshold. | ||
* TriggerCount represents the lower bound trigger of the adaptive strategy. | ||
* Adaptive strategies will not be activated until target metric has reached the trigger count. | ||
*/ | ||
public void setMaxThread(long maxThread) { | ||
this.maxThread = maxThread; | ||
} | ||
private double triggerCount; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just use count to name it like any other rule. |
||
|
||
public long getAvgRt() { | ||
return avgRt; | ||
public SystemMetricType getSystemMetricType() { | ||
return systemMetricType; | ||
} | ||
|
||
/** | ||
* Set max average RT(response time) of all passed requests. | ||
* | ||
* @param avgRt max average response time, values <= 0 are special for clearing the threshold. | ||
*/ | ||
public void setAvgRt(long avgRt) { | ||
this.avgRt = avgRt; | ||
public SystemRule setSystemMetricType(SystemMetricType systemMetricType) { | ||
this.systemMetricType = systemMetricType; | ||
return this; | ||
} | ||
|
||
public double getHighestSystemLoad() { | ||
return highestSystemLoad; | ||
} | ||
|
||
/** | ||
* <p> | ||
* Set highest load. The load is not same as Linux system load, which is not sensitive enough. | ||
* To calculate the load, both Linux system load, current global response time and global QPS will be considered, | ||
* which means that we need to coordinate with {@link #setAvgRt(long)} and {@link #setQps(double)} | ||
* </p> | ||
* <p> | ||
* Note that this parameter is only available on Unix like system. | ||
* </p> | ||
* | ||
* @param highestSystemLoad highest system load, values <= 0 are special for clearing the threshold. | ||
* @see SystemRuleManager | ||
*/ | ||
public void setHighestSystemLoad(double highestSystemLoad) { | ||
this.highestSystemLoad = highestSystemLoad; | ||
public double getTriggerCount() { | ||
return triggerCount; | ||
} | ||
|
||
/** | ||
* Get highest cpu usage. Cpu usage is between [0, 1] | ||
* | ||
* @return highest cpu usage | ||
*/ | ||
public double getHighestCpuUsage() { | ||
return highestCpuUsage; | ||
public SystemRule setTriggerCount(double triggerCount) { | ||
this.triggerCount = triggerCount; | ||
return this; | ||
} | ||
|
||
/** | ||
* set highest cpu usage. Cpu usage is between [0, 1] | ||
* | ||
* @param highestCpuUsage the value to set. | ||
*/ | ||
public void setHighestCpuUsage(double highestCpuUsage) { | ||
this.highestCpuUsage = highestCpuUsage; | ||
@Override | ||
public String toString() { | ||
return "SystemRule{" + | ||
"systemMetricType=" + systemMetricType + | ||
", triggerCount=" + triggerCount + | ||
'}'; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) { | ||
return true; | ||
} | ||
if (!(o instanceof SystemRule)) { | ||
if (o == null || getClass() != o.getClass()) { | ||
return false; | ||
} | ||
if (!super.equals(o)) { | ||
return false; | ||
} | ||
|
||
SystemRule that = (SystemRule)o; | ||
|
||
if (Double.compare(that.highestSystemLoad, highestSystemLoad) != 0) { | ||
return false; | ||
} | ||
if (Double.compare(that.highestCpuUsage, highestCpuUsage) != 0) { | ||
return false; | ||
} | ||
|
||
if (Double.compare(that.qps, qps) != 0) { | ||
return false; | ||
} | ||
SystemRule that = (SystemRule) o; | ||
|
||
if (avgRt != that.avgRt) { | ||
if (Double.compare(that.triggerCount, triggerCount) != 0) { | ||
return false; | ||
} | ||
return maxThread == that.maxThread; | ||
return systemMetricType == that.systemMetricType; | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
int result = super.hashCode(); | ||
long temp; | ||
temp = Double.doubleToLongBits(highestSystemLoad); | ||
result = 31 * result + (int)(temp ^ (temp >>> 32)); | ||
|
||
temp = Double.doubleToLongBits(highestCpuUsage); | ||
result = 31 * result + (int)(temp ^ (temp >>> 32)); | ||
|
||
temp = Double.doubleToLongBits(qps); | ||
result = 31 * result + (int)(temp ^ (temp >>> 32)); | ||
|
||
result = 31 * result + (int)(avgRt ^ (avgRt >>> 32)); | ||
result = 31 * result + (int)(maxThread ^ (maxThread >>> 32)); | ||
result = 31 * result + systemMetricType.hashCode(); | ||
temp = Double.doubleToLongBits(triggerCount); | ||
result = 31 * result + (int) (temp ^ (temp >>> 32)); | ||
return result; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "SystemRule{" + | ||
"highestSystemLoad=" + highestSystemLoad + | ||
", highestCpuUsage=" + highestCpuUsage + | ||
", qps=" + qps + | ||
", avgRt=" + avgRt + | ||
", maxThread=" + maxThread + | ||
"}"; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package com.alibaba.csp.sentinel.slots.system; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto. |
||
|
||
import com.alibaba.csp.sentinel.Constants; | ||
import com.alibaba.csp.sentinel.EntryType; | ||
import com.alibaba.csp.sentinel.concurrent.NamedThreadFactory; | ||
import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; | ||
|
||
import java.util.Collection; | ||
import java.util.concurrent.Executors; | ||
import java.util.concurrent.ScheduledExecutorService; | ||
import java.util.concurrent.TimeUnit; | ||
|
||
|
||
|
||
/** | ||
* <p> | ||
* Sentinel System Rule makes the inbound traffic and capacity meet. It takes | ||
* average rt, qps, thread count of incoming requests into account. And it also | ||
* provides a measurement of system's load, but only available on Linux. | ||
* </p> | ||
* <p> | ||
* rt, qps, thread count is easy to understand. If the incoming requests' | ||
* rt,qps, thread count exceeds its threshold, the requests will be | ||
* rejected.however, we use a different method to calculate the load. | ||
* </p> | ||
* <p> | ||
* Consider the system as a pipeline,transitions between constraints result in | ||
* three different regions (traffic-limited, capacity-limited and danger area) | ||
* with qualitatively different behavior. When there isn’t enough request in | ||
* flight to fill the pipe, RTprop determines behavior; otherwise, the system | ||
* capacity dominates. Constraint lines intersect at inflight = Capacity × | ||
* RTprop. Since the pipe is full past this point, the inflight –capacity excess | ||
* creates a queue, which results in the linear dependence of RTT on inflight | ||
* traffic and an increase in system load.In danger area, system will stop | ||
* responding.<br/> | ||
* Referring to BBR algorithm to learn more. | ||
* </p> | ||
* <p> | ||
* Note that {@link SystemRule} only effect on inbound requests, outbound traffic | ||
* will not limit by {@link SystemRule} | ||
* </p> | ||
* | ||
* @author jialiang.linjl | ||
* @author leyou | ||
* @author guozhong.huang | ||
*/ | ||
public class SystemRuleChecker { | ||
|
||
private static SystemStatusListener statusListener = null; | ||
private final static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, | ||
new NamedThreadFactory("sentinel-system-status-record-task", true)); | ||
|
||
static { | ||
statusListener = new SystemStatusListener(); | ||
scheduler.scheduleAtFixedRate(statusListener, 0, 1, TimeUnit.SECONDS); | ||
} | ||
|
||
public static void checkSystem(Collection<SystemRule> rules, ResourceWrapper resourceWrapper, int count) throws SystemBlockException { | ||
if (resourceWrapper.getEntryType() != EntryType.IN) { | ||
return; | ||
} | ||
if (rules != null) { | ||
for (SystemRule rule : rules) { | ||
if (!canPassCheck(rule, count)) { | ||
throw new SystemBlockException(resourceWrapper.getName(), rule); | ||
} | ||
} | ||
} | ||
} | ||
|
||
|
||
public static boolean canPassCheck(SystemRule rule, int acquireCount) { | ||
SystemMetricType systemMetricType = rule.getSystemMetricType(); | ||
double threshold = rule.getTriggerCount(); | ||
switch (systemMetricType) { | ||
case LOAD: | ||
double currentSystemAvgLoad = getCurrentSystemAvgLoad(); | ||
if (currentSystemAvgLoad > threshold) { | ||
return checkBbr(); | ||
} | ||
return true; | ||
case AVG_RT: | ||
double rt = Constants.ENTRY_NODE.avgRt(); | ||
return rt <= threshold ; | ||
case CONCURRENCY: | ||
int currentThread = Constants.ENTRY_NODE.curThreadNum(); | ||
return currentThread <= threshold; | ||
case INBOUND_QPS: | ||
double currentQps = Constants.ENTRY_NODE.passQps(); | ||
return currentQps + acquireCount <= threshold; | ||
case CPU_USAGE: | ||
double currentCpuUsage = getCurrentCpuUsage(); | ||
return currentCpuUsage <= threshold; | ||
default: | ||
return true; | ||
} | ||
} | ||
|
||
|
||
private static boolean checkBbr() { | ||
int currentThread = Constants.ENTRY_NODE.curThreadNum(); | ||
if (currentThread > 1 && | ||
currentThread > Constants.ENTRY_NODE.maxSuccessQps() * Constants.ENTRY_NODE.minRt() / 1000) { | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
public static double getCurrentSystemAvgLoad() { | ||
return statusListener.getSystemAverageLoad(); | ||
} | ||
|
||
public static double getCurrentCpuUsage() { | ||
return statusListener.getCpuUsage(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please prepend the license header here?