diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemRule.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemRule.java index 318f6bef..7a2ac333 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemRule.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemRule.java @@ -34,6 +34,7 @@ import com.alibaba.csp.sentinel.slots.block.AbstractRule; *

* * @author jialiang.linjl + * @author Carpenter Lee * @see SystemRuleManager */ public class SystemRule extends AbstractRule { @@ -42,6 +43,10 @@ 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; @@ -110,6 +115,24 @@ public class SystemRule extends AbstractRule { this.highestSystemLoad = highestSystemLoad; } + /** + * Get highest cpu usage. Cpu usage is between [0, 1] + * + * @return highest cpu usage + */ + public double getHighestCpuUsage() { + return highestCpuUsage; + } + + /** + * 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 boolean passCheck(Context context, DefaultNode node, int count, Object... args) { return true; @@ -132,6 +155,9 @@ public class SystemRule extends AbstractRule { 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; @@ -150,6 +176,9 @@ public class SystemRule extends AbstractRule { 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)); @@ -162,6 +191,7 @@ public class SystemRule extends AbstractRule { public String toString() { return "SystemRule{" + "highestSystemLoad=" + highestSystemLoad + + ", highestCpuUsage=" + highestCpuUsage + ", qps=" + qps + ", avgRt=" + avgRt + ", maxThread=" + maxThread + diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemRuleManager.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemRuleManager.java index f25155a1..2e2fe635 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemRuleManager.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemRuleManager.java @@ -66,6 +66,10 @@ import com.alibaba.csp.sentinel.slots.block.BlockException; public class SystemRuleManager { private static volatile double highestSystemLoad = Double.MAX_VALUE; + /** + * cpu usage, between [0, 1] + */ + private static volatile double highestCpuUsage = Double.MAX_VALUE; private static volatile double qps = Double.MAX_VALUE; private static volatile long maxRt = Long.MAX_VALUE; private static volatile long maxThread = Long.MAX_VALUE; @@ -73,6 +77,7 @@ public class SystemRuleManager { * mark whether the threshold are set by user. */ private static volatile boolean highestSystemLoadIsSet = false; + private static volatile boolean highestCpuUsageIsSet = false; private static volatile boolean qpsIsSet = false; private static volatile boolean maxRtIsSet = false; private static volatile boolean maxThreadIsSet = false; @@ -134,6 +139,12 @@ public class SystemRuleManager { result.add(loadRule); } + if (highestCpuUsageIsSet) { + SystemRule rule = new SystemRule(); + rule.setHighestCpuUsage(highestCpuUsage); + result.add(rule); + } + if (maxRtIsSet) { SystemRule rtRule = new SystemRule(); rtRule.setAvgRt(maxRt); @@ -185,9 +196,18 @@ public class SystemRuleManager { checkSystemStatus.set(false); } - - RecordLog.info(String.format("[SystemRuleManager] Current system check status: %s, highestSystemLoad: " - + highestSystemLoad + ", " + "maxRt: %d, maxThread: %d, maxQps: " + qps, checkSystemStatus.get(), maxRt, maxThread)); + RecordLog.info(String.format("[SystemRuleManager] Current system check status: %s, " + + "highestSystemLoad: %e, " + + "highestCpuUsage: %e, " + + "maxRt: %d, " + + "maxThread: %d, " + + "maxQps: %e", + checkSystemStatus.get(), + highestSystemLoad, + highestCpuUsage, + maxRt, + maxThread, + qps)); } protected void restoreSetting() { @@ -195,6 +215,7 @@ public class SystemRuleManager { // should restore changes highestSystemLoad = Double.MAX_VALUE; + highestCpuUsage = Double.MAX_VALUE; maxRt = Long.MAX_VALUE; maxThread = Long.MAX_VALUE; qps = Double.MAX_VALUE; @@ -229,6 +250,12 @@ public class SystemRuleManager { checkStatus = true; } + if (rule.getHighestCpuUsage() >= 0) { + highestCpuUsage = Math.min(highestCpuUsage, rule.getHighestCpuUsage()); + highestCpuUsageIsSet = true; + checkStatus = true; + } + if (rule.getAvgRt() >= 0) { maxRt = Math.min(maxRt, rule.getAvgRt()); maxRtIsSet = true; @@ -284,17 +311,34 @@ public class SystemRuleManager { throw new SystemBlockException(resourceWrapper.getName(), "rt"); } - // BBR algorithm. + // load. BBR algorithm. if (highestSystemLoadIsSet && getCurrentSystemAvgLoad() > highestSystemLoad) { - if (currentThread > 1 && - currentThread > Constants.ENTRY_NODE.maxSuccessQps() * Constants.ENTRY_NODE.minRt() / 1000) { + if (!checkBbr(currentThread)) { throw new SystemBlockException(resourceWrapper.getName(), "load"); } } + // cpu usage + if (highestCpuUsageIsSet && getCurrentCpuUsage() > highestCpuUsage) { + if (!checkBbr(currentThread)) { + throw new SystemBlockException(resourceWrapper.getName(), "cpu"); + } + } + } + + private static boolean checkBbr(int currentThread) { + 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(); + } } diff --git a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemStatusListener.java b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemStatusListener.java index 2ccf6c63..8cf45a37 100755 --- a/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemStatusListener.java +++ b/sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/system/SystemStatusListener.java @@ -16,11 +16,12 @@ package com.alibaba.csp.sentinel.slots.system; import java.lang.management.ManagementFactory; -import java.lang.management.OperatingSystemMXBean; +import com.alibaba.csp.sentinel.Constants; import com.alibaba.csp.sentinel.log.RecordLog; import com.alibaba.csp.sentinel.util.StringUtil; -import com.alibaba.csp.sentinel.Constants; + +import com.sun.management.OperatingSystemMXBean; /** * @author jialiang.linjl @@ -28,6 +29,7 @@ import com.alibaba.csp.sentinel.Constants; public class SystemStatusListener implements Runnable { volatile double currentLoad = -1; + volatile double currentCpuUsage = -1; volatile String reason = StringUtil.EMPTY; @@ -37,6 +39,10 @@ public class SystemStatusListener implements Runnable { return currentLoad; } + public double getCpuUsage() { + return currentCpuUsage; + } + @Override public void run() { try { @@ -44,13 +50,22 @@ public class SystemStatusListener implements Runnable { return; } - // system average load - OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean(); - currentLoad = operatingSystemMXBean.getSystemLoadAverage(); + OperatingSystemMXBean osBean = ManagementFactory.getPlatformMXBean(OperatingSystemMXBean.class); + currentLoad = osBean.getSystemLoadAverage(); + /** + * Java Doc copied from {@link OperatingSystemMXBean#getSystemCpuLoad()}:
+ * Returns the "recent cpu usage" for the whole system. This value is a double in the [0.0,1.0] interval. + * A value of 0.0 means that all CPUs were idle during the recent period of time observed, while a value + * of 1.0 means that all CPUs were actively running 100% of the time during the recent period being + * observed. All values betweens 0.0 and 1.0 are possible depending of the activities going on in the + * system. If the system recent cpu usage is not available, the method returns a negative value. + */ + currentCpuUsage = osBean.getSystemCpuLoad(); StringBuilder sb = new StringBuilder(); if (currentLoad > SystemRuleManager.getHighestSystemLoad()) { sb.append("load:").append(currentLoad).append(";"); + sb.append("cpu:").append(currentCpuUsage).append(";"); sb.append("qps:").append(Constants.ENTRY_NODE.passQps()).append(";"); sb.append("rt:").append(Constants.ENTRY_NODE.avgRt()).append(";"); sb.append("thread:").append(Constants.ENTRY_NODE.curThreadNum()).append(";"); diff --git a/sentinel-demo/sentinel-demo-basic/src/main/java/com/alibaba/csp/sentinel/demo/system/SystemGuardDemo.java b/sentinel-demo/sentinel-demo-basic/src/main/java/com/alibaba/csp/sentinel/demo/system/SystemGuardDemo.java index ac8706c4..f0e1ddff 100755 --- a/sentinel-demo/sentinel-demo-basic/src/main/java/com/alibaba/csp/sentinel/demo/system/SystemGuardDemo.java +++ b/sentinel-demo/sentinel-demo-basic/src/main/java/com/alibaba/csp/sentinel/demo/system/SystemGuardDemo.java @@ -91,6 +91,8 @@ public class SystemGuardDemo { SystemRule rule = new SystemRule(); // max load is 3 rule.setHighestSystemLoad(3.0); + // max cpu usage is 60% + rule.setHighestCpuUsage(0.6); // max avg rt of all request is 10 ms rule.setAvgRt(10); // max total qps is 20