性能的对比分析(后台)

持久化的数据源特性:总体上看,单个指标的数据应该按时间顺序进入持久化。可扩展的持久化框架包括:数据库持久化,文档持久化,RRD持久化。数据库持久化:只保留最新一条数据,主要用于自定义型界面;文档持久化:保留原始的历史数据;RRD持久化:主要用于历史曲线图绘制,通过图形引导进入原始数据等,可考虑和“统计类指标的实时ETL”功能进行整合。数据访问方式主要以提供对历史数据的访问为主,考虑以Restful WebServcie的方式提供界面。
1.功能定义:
(1)持久化控制流程:控制采集数据流向和启动每天的定时服务。
(2)数据库持久化:只保留最新一条数据,主要用于自定义型界面。
(3)文档持久化:按定义的格式写入文档中。
(4)RRD持久化:每天定时把数据持久化到RRD中。使用JRobin。
(5)数据访问:提供最新数据的访问和历史数据访问。
术语:
(1)时间周期:dateCycle,规定的对比时间范围的单位。
(2)对比区间:contrastArea,曲线绘制所需数据的所在时间范围。
(3)数据粒度:dataSize,表示数据汇总的时间间隔。
(4)显示记录数 topn、排序列 sortColum。
3.对比分析
(1)定义:对多监管对象多指标指定时间,范围内的数据绘制曲线,绘制后的曲线图可让用户更加直观的对比出所选指标在所选时间范围内的走势。
(2)功能:分析数据须具有连续性。可以选择多个管理对象的多个指标在同一时间段上比较分析得到图表。可选择单个管理对象的单个指标在不同时间上比较分析得到图表。可以在1或2的分析结果上继续添加对比。
数据接口
对比分析参数json格式和URL示例如下
var params = = {
anaType : 'dbfx',
contrastArea : 'week', //对比区间 year、month、week、day、selfDef
dataSize : 'hour', //数据粒度 month、day、hour、30m、15m、5m、selfSuit
items : [ {
alias : '1',
MOSN : '102500003',
kpiCode : '40006',
startTime : '2010-08-02 00:00',
endTime : '2010-08-08 23:59',
scale : '1'
}, {
alias : '2',
MOSN : '102500003',
kpiCode : '40006',
startTime : '2010-08-09 00:00',
endTime : '2010-08-15 23:59',
scale : '1'
} ]
};
url="${pageContext.request.contextPath}/perfAna/dbfx.action?params="+encodeURIComponent(params);
contrastArea为selfDef时,dataSize必须设置为selfSuit,并且所有对比项的开始时间与结束时间相同。

5.指标自身对比分析
指标自身对比近期3日数据:
Params为:{ "anaType":"dbfx","contrastArea":"day","dataSize":"30m","items":[ {"alias":"1","MOSN":"100500001","kpiCode":"40008","startTime":"2010-11-14 00:00","endTime":"2010-11-14 23:59","scale":"1" },{"alias":"2","MOSN":"100500001","kpiCode":"40008","startTime":"2010-11-15 00:00","endTime":"2010-11-15 23:59","scale":"1" },{"alias":"3","MOSN":"100500001","kpiCode":"40008","startTime":"2010-11-16 00:00","endTime":"2010-11-16 23:59","scale":"1" }]}

DbfxCondtion condition = JsonTransform.parseDb(params);

DbfxCondtion :private String contrastArea; //对比区间
private String dataSize; //数据粒度
private List<DbfxItem> items = new ArrayList<DbfxItem>();

DbfxItem item = (DbfxItem) JSONObject.toBean(jsonItem, DbfxItem.class);
condtion.addItem(item);

ContrastAnalysis dbfx = (ContrastAnalysis) getRequest().getSession().getAttribute("dbfx");
dbfx.proccess(condition);

对比分析流程控制方法 1 由于对比分析的特殊性,会把上次的分析结果缓存,避免两个相同对比项的重复分析:
condition.reCalc();
doClear(condition.getContrastArea(), condition.getDataSize());
List<DbfxItem> items = condition.getItems();
对于每个items:if (!item_dataset.containsKey(item)) { // 缓存有,则不分析
doAnalysis(item);
}else{
/* 改变缓存的 别名和色彩*/
String[] array = item_anaResults.get(item);
array[0] = AmStock.getColor(item.getAlias()); // nodePath
array[1] = item.getAlias(); // nodePath
}
对比分析主类:ContrastAnalysis(总和分支)
总: private String contrastArea; // 对比区间
private String dataSize; // 数据粒度
private Date baseDate;

private Map<DbfxItem, String[]> item_anaResults = new HashMap<DbfxItem, String[]>(); // item项映射到分析结果的显示项
private Map<DbfxItem, String> item_dataset = new HashMap<DbfxItem, String>(); // 保存分析的结果数据,给xml的data标签。每行记录格式:日期,数据-2008-12-12

private String amPath;
private List<String[]> results;
总:doAnalysis(DbfxItem item)方法。其中item可以通过get方式获得MOSN,kpiCode,startTime,endTime。

总:IDataAccess access = AccessFactory.createDataAccess(MOSN);
分支: public static IDataAccess createDataAccess(Integer MOSN){
String moType = ModelUtil.getType(MOSN);
return createDataAccess(moType);
}
在createDataAccess中判断是否为业务
分支: if (CoreModelUtil.isYewuType(moType)) {
return new InnerDataAccess();
}
总:SortedMap<String, String> map = access.search(MOSN, kpiCode, startTime, endTime,dataSize);//dataSize为30m

webservice获取数据:
分支: private static SortedMap<String, String> get(int mosn, String kpiCode, String startTime, String endTime) {
Client client = Client.create();
WebResource resource = client.resource("http://" + WebServiceConst.host + ":" + WebServiceConst.port + "/history/" + mosn + "/" + kpiCode);
MultivaluedMap queryParams = new MultivaluedMapImpl();
queryParams.add("params", "[{startTime:'" + startTime + "',endTime:'" + endTime + "'}]");
String s = resource.queryParams(queryParams).get(String.class);
JSONArray array = JSONArray.fromObject(s);
if(array!=null&&array.size()>0){
JSONArray result = array.getJSONObject(0).getJSONArray("values");
if(result!=null){
for (int i = 0; i < result.size(); i++) {
JSONObject item = result.getJSONObject(i);
String value = item.getString("value");
if (StringUtils.isNotBlank(value)) {
map.put(item.getString("time"), value);
}
}
}
}
}

Map的值为:2010-11-16 03:14:00=1.34, 2010-11-16 03:15:00=1.34, 2010-11-16 03:16:00=1.33, 2010-11-16 03:17:00=1.33, 2010-11-16 03:18:00=1.36, 2010-11-16 03:19:00=1.37, 2010-11-16 03:20:00=1.37, 2010-11-16 03:21:00=1.34, 2010-11-16 03:22:00=1.32, 2010-11-16 03:23:00=1.30 ...

long moveTime = calcMoveTime(startTime);//返回当前填充的曲线需要移动的毫秒数

protected long calcMoveTime(String startTime) throws Exception {
if (MyTimeUtil.isValideDateTime2(startTime)) {判断是否是长日期格式(yyyy-MM-dd HH:mm)及字符串的length为16
Date start = MyTimeUtil.parseDate2(startTime);
if (baseDate == null) {
baseDate = start;
return 0;
} else {
return start.getTime() - baseDate.getTime();
}
}
}

总:汇总模式huizong(),如果是"default",false。其他为true,比如本例中为"30m"。
分析:-->将标准时间字符串转换成为时间对象(java.util.Date)
private static SimpleDateFormat format2 = new SimpleDateFormat(
"yyyy-MM-dd HH:mm");
synchronized(format2){
return format2.parse(timeStr);
}
总:Date t1 = MyTimeUtil.parseDate2(startTime);
Date t2 = add(t1, dataSize);
将时间加上粒度:5m,10m,15m,30m,hour,day,week,month,quarter,year
public static Date add(Date date, String lidu){
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
if (PerfAnaConst.DATASIZE_1M.equalsIgnoreCase(lidu)) { //粒度为原始数据时
calendar.add(Calendar.MINUTE, 30);
}
}
Date d;
for (Entry<String, String> entry : map.entrySet()[Map里键值对,时间=值,每分钟采集一次的数据。]) {
d = MyTimeUtil.parseDate(entry.getKey());
if (d != null) {
String value = entry.getValue();
if(StringUtils.isBlank(value)){
//null或者空串表示没有数据,但是改点为一次采集值
}else{
double data = FloatingDecimal.readJavaFormatString(value).doubleValue();
max = Math.max(max, data);//比较最大值
min = Math.min(min, data);
sum += data;
count++;
if (d.getTime() < t2[t2为粒度为30m时的时间,从0~29次叠加算平均值。].getTime()) {
shortSum += data;
shortCount++;
} else {
if (shortCount > 0) {
dataset[Dataset保存最近30分钟的记录,第30分钟的数据比如2:30的数据划归到下一次数据记录的第一次进行分析。].append(calc(t1, moveTime));
dataset.append(",");
dataset.append(shortSum / shortCount);
dataset.append("\n");
shortSum = 0.0d;
shortCount = 0;
}
t1 = t2;
t2 = add(t2, dataSize);
while (d.getTime() >= t2.getTime()) {
/* 是否补充空数据 */
dataset.append(calc(t1, moveTime));
dataset.append(",");
dataset.append("\n");
t1 = t2;
t2 = add(t2, dataSize);
}
shortSum += data;
shortCount++;
}
}

} else {
throw new Exception("SortedMap中的时间" + entry.getKey() + "不是yyyy-MM-dd HH:mm:ss格式....");
}
}

/* 末尾补充空数据 */
d=MyTimeUtil.parseDate2(endTime);
while (d.getTime() >= t2.getTime()) {
dataset.append(calc(t1, moveTime));
dataset.append(",");
dataset.append("\n");
t1 = t2;
t2 = add(t2, dataSize);
}
} else {
/* */
// double max = Double.MIN_VALUE;//bug:Double.MIN_VALUE大于0
for (Entry<String, String> entry : map.entrySet()) {
String time = calc(entry.getKey(), moveTime);
if (time == null) {
throw new Exception("gcw___ SortedMap中的时间" + entry.getKey() + "不是yyyy-MM-dd HH:mm格式....");
} else {
// double value = Double.parseDouble(entry.getValue());
String value = entry.getValue();
dataset.append(time);
dataset.append(",");
if(StringUtils.isBlank(value)){
//null或者空串表示没有数据
}else{
double data = FloatingDecimal.readJavaFormatString(value).doubleValue();
max = Math.max(max, data);
min = Math.min(min, data);
sum += data;
count++;
dataset.append(data);
}
dataset.append("\n");
}
}
}

/* 缺少末尾数据时,添加(最后时间+1分钟)的一个空数据 */
dataset.append(calc(MyTimeUtil.parseDate2(endTime), moveTime - 60000));
dataset.append(",");

/* 统计结果 */
String unit = ModelUtil.getUnit(MOSN, kpiCode);
String[] result = new String[11];
result[0] = AmStock.getColor(item.getAlias()); // nodePath
result[1] = item.getAlias(); // nodePath
result[2] = ModelUtil.getShortPath(MOSN); // nodePath
result[3] = ModelUtil.getDisplayName(MOSN);//
result[4] = ModelUtil.getKpiName(MOSN, kpiCode);
result[5] = startTime;
result[6] = endTime;
if (count > 0) {//小数点后保留两位数字
result[7] = ItimsNumber.formatDouble(max) + unit;
result[8] = ItimsNumber.formatDouble(min) + unit;
result[9] = ItimsNumber.formatDouble(sum / count) + unit;
// result[10] = ItimsNumber.formatDouble(calcScale(max));
result[10] = RateNumber.formatDouble(calcScale(max));
} else {
result[7] = "";
result[8] = "";
result[9] = "";
result[10] = "";
}
item_dataset.put(item, dataset.toString());
item_anaResults.put(item, result);
}

分析:将item_dataset和item_anaResults的数据写入HashMap。在proccess()方法中读出使用,同时存入到amstock中。

总: /* 生成结果 */
AmStock amStock = new AmStock(IPerfAnaConst.DBFX_XML);
this.results = new ArrayList<String[]>();
int count = 0;
for (DbfxItem item : items) {
String datas = item_dataset.get(item);
if (count == 0) {
amStock.setDataset(item, datas, true);
} else {
amStock.setDataset(item, datas, false);
}
results.add(item_anaResults.get(item));
count++;
}
amStock.setFormats[通过对比区间和数据粒度设置amStock的x轴刻度上如何显示文字和date_formats的legend格式。
* 同时设置period_selector标签
](contrastArea, dataSize);
String path = IPerfAnaConst.TMP_DIR_PATH + UUID.randomUUID().toString() + ".xml";
String newPath = WebEnv.webBasePath + "/" + path;
logger.debug("生成xml的配置文件路劲" + newPath);
amStock.write[String xml = doc.asXML();
String datas = "<data_sets>" + datasets + "</data_sets>";
xml = xml.replaceFirst("<data_sets>[\\s\\S]{1,}</data_sets>", datas);
ItimsFile.writeFile(new File(newPath), xml);](newPath);
this.amPath = path;

分析: setFormats方法内容
Element periods = doc.selectSingleNode("//period_selector/periods"));
if ("day".equals(contrastArea)) { // 对比区间:天
periods.addElement("period").addAttribute("type", "hh").addAttribute("count", "1").addText("1时");
periods.addElement("period").addAttribute("type", "hh").addAttribute("count", "6").addText("6时");
this.doc.selectSingleNode("//date_formats/x_axis/minutes").setText("hh:mm");
this.doc.selectSingleNode("//date_formats/x_axis/days").setText("hh:mm");
this.doc.selectSingleNode("//date_formats/legend/minutes").setText("hh:mm");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值