計算差值和計算速率的簡單實現
對於SNMPv1/v2定義的32位計數器(Counter32)是一個非負整數,其值只能增加,但不能減少,達到最大值232-1後回零,主要用於計算收到的分組數或位元組數等場合。注意,Counter32沒有定義初始值,所以單個Counter32的資料是沒有意義的。
對Counter32型別的資料,要做差值計算。
針對某裝置的指標A,按週期採集的資料,要用本次值減去上次的值做差值。需要有個快取上次值的快取佇列,記錄採集例項的具體到指標的每次採集值。做本次值減去上次的值計算時,要先判斷本次值是否大於或等於上次值,否則本次資料丟棄不處理,但要快取本次值。
速率計算就是在本次值 – 上次值後,還要再除以兩次值的採集時間差的秒數,計算公式:
(本次值 – 上次值) / (本次值採集時間 – 上次值採集時間)
另外,有的採集oid還需要和其它oid的值一起做計算,才能得到有效資料,就要做公式計算,通過一個或多個OID的採集值,計算出新的指標值。
舉例某例項的一個指標的值,在3次採集時間中的值是增大的,
值200, 採集時間1536517079401 (2018/9/10 2:17:59)
值210, 採集時間1536520679042 (2018/9/10 3:17:59)
值218, 採集時間1536524279089 (2018/9/10 4:17:59)
計算差值
3:17:59 的差值計算210 – 200,得到結果值是10
4:17:59 的差值計算218 – 210,得到結果值是8
計算速率
3:17:59 的速率計算(210 – 200)/( (1536520679042 – 1536517079401)/1000),得到結果值是0.00277
4:17:59 的差值計算(218 – 210)/( (1536524279089 – 1536520679042)/1000),得到結果值是0.00222
下面通過程式碼,來做一個通用的類,能把每次採的資料送到這個類中, 直接計算差值或速率。
上程式碼
import java.util.HashMap; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; /** * @Title: 計算差值和速率 */ public class PMDataCache { private Logger log = LogManager.getLogger(PMDataCache.class); //快取值不存在時返回這個值 public static final double NULL = -99.99d; //單例項 private static PMDataCache _instance = null; /** 計算差值 */ private static HashMap<String, Double> dataMap = null; /** 計算速率 */ private static HashMap<String, KeyAnyValue> speedMap = null; private PMDataCache() { dataMap = new HashMap<String, Double>(); speedMap = new HashMap<String, KeyAnyValue>(); } /** * 獲得單例項 * @return */ public static PMDataCache getInstance() { if (_instance == null) { _instance = new PMDataCache(); } return _instance; } /** * 取上次值 * @param key * @return */ public double getLastData(String key) { if(dataMap.containsKey(key)) return (Double) dataMap.get(key); return -1.0d; } /** * 儲存上次值 * @param key * @param value */ public void putLastData(String key, double value) { dataMap.put(key, value); } /** * 儲存上次值 * @param key * @param value */ public void putLastData(String key, String value) { putLastData(key, Double.parseDouble(value)); } /** * 當前值-上次值 * @param key * @param currentValue * @return */ public String delta(String key, double currentValue) { double deltaValue = 0.0d; double lastValue = getLastData(key); try { if(lastValue != -1.0d) { if(currentValue >= lastValue) { deltaValue = currentValue - lastValue; log.debug("Delta compute " + currentValue + " - " + lastValue + " = " + deltaValue); } else { log.warn(key + " " + currentValue + " < " + lastValue); return null; } } else return null; } catch(Exception e) { log.error("Delta compute error " + key, e); } finally { putLastData(key, currentValue); } return deltaValue + ""; } /** * 計算差值 * @param key * @param value * @return 如果上次快取值不存在, 返回-99.99d; */ public double getDeltaValue(String key, String value) { double dValue = 0.0d; String sValue = delta(key, Double.parseDouble(value)); if(sValue != null) dValue = Double.parseDouble(sValue); else return PMDataCache.NULL; return dValue; } /** * 儲存上次值 * @param key * @param value 值 * @param dcTime 資料採集時間 */ public void putLastDataAndTime(String key, String value, long dcTime) { KeyAnyValue kav = new KeyAnyValue(); kav.setKey(value); kav.setValue(new Long(dcTime)); speedMap.put(key, kav); } /** * 取上次值 * @param key * @return */ public KeyAnyValue getLastDataAndTime(String key) { if(speedMap.containsKey(key)) return (KeyAnyValue) speedMap.get(key); return null; } /** * 速率 * @param key * @param currentValue * @param currentTime * @return */ public String speed(String key, double currentValue, long currentTime) { double speedValue = 0.0d; KeyAnyValue last = getLastDataAndTime(key); try { if(last != null) { long lastTime = ((Long)last.getValue()).longValue(); //上次採集時間 double lastValue = Double.parseDouble(last.getKey()); //上次值 if(currentValue >= lastValue && currentTime > lastTime) { double secTime = (currentTime - lastTime) / 1000; speedValue = (currentValue - lastValue) / secTime; log.debug("Speed compute (" + currentValue + " - " + lastValue + ")/" + secTime + " = " + speedValue); } else { log.warn(key + " " + currentValue + " < " + lastValue); return null; } } else return null; } catch(Exception e) { log.error("Speed compute error " + key, e); } finally { putLastDataAndTime(key, currentValue + "", currentTime); } return speedValue + ""; } /** * 計算速率 * @param key * @param value * @param currentTime * @return 如果上次快取值不存在, 返回-99.99d; */ public double getSpeedValue(String key, String value, long currentTime) { double dValue = 0.0d; String sValue = speed(key, Double.parseDouble(value), currentTime); if(sValue != null) dValue = Double.parseDouble(sValue); else return PMDataCache.NULL; return dValue; } class KeyAnyValue implements java.io.Serializable{ public String key; public Object value; public String getKey() { return this.key; } public Object getValue() { return this.value; } public void setKey(String key) { this.key = key; } public void setValue(Object value) { this.value = value; } public String toString() { return key + " | " + value.toString(); } } }
測試類
/**
* @Title:計算差值和計算速率的測試
*/
public class PMDataCacheTest {
/**
* 計算差值
* @param key
* @param value
* @return 如果上次快取值不存在, 返回-99.99d;
*/
private double getDeltaValue(String key, String value) {
double dValue = 0.0d;
String sValue = PMDataCache.getInstance().delta(key,
Double.parseDouble(value));
if (sValue != null)
dValue = Double.parseDouble(sValue);
else
return PMDataCache.NULL;
return dValue;
}
/**
* 計算速率
* @param key
* @param value
* @param currentTime
* @return 如果上次快取值不存在, 返回-99.99d;
*/
private double getSpeedValue(String key, String value, long currentTime) {
double dValue = 0.0d;
String sValue = PMDataCache.getInstance().speed(key,
Double.parseDouble(value), currentTime);
if (sValue != null)
dValue = Double.parseDouble(sValue);
else
return PMDataCache.NULL;
return dValue;
}
/**
* 測試
* @param args
*/
public static void main(String[] args) {
PMDataCacheTest test = new PMDataCacheTest();
String key = "NE-1";
String readIO = "1000";
//取網元裝置NE-1的readIO差值
double dReadIODelta = test.getDeltaValue(key + "_readIO", readIO);
//取網元裝置NE-1的readIO速率
long thisTime = System.currentTimeMillis();
double dReadIOSpeed = test.getSpeedValue(key + "_readIO", readIO, thisTime);
}
}