1. 程式人生 > >計算差值和計算速率的簡單實現

計算差值和計算速率的簡單實現

對於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);
	}
}