flink内部计算指标的95线-99线等的实现
发表于:2025-02-04 作者:千家信息网编辑
千家信息网最后更新 2025年02月04日,15年在某电商从0设计了一个通用的API监控系统,当时只是计算了成功率+平均耗时,没有算75,90,95,99,999,9999线,这次单位需要,所以促使我去思考这个问题,问了单位CAT维护人员,大致
千家信息网最后更新 2025年02月04日flink内部计算指标的95线-99线等的实现
15年在某电商从0设计了一个通用的API监控系统,当时只是计算了成功率+平均耗时,没有算75,90,95,99,999,9999线,这次单位需要,所以促使我去思考这个问题,问了单位CAT维护人员,大致了解了计算方式,跟我在18年7月份在单位内网BBS发表的文章思路是一致的,所以就直接写了下面的代码
PercentageCalculation.java
package com.ymm.computation.udf.define;import org.apache.flink.table.functions.AggregateFunction;import org.slf4j.Logger;import org.slf4j.LoggerFactory;//批量计算95line类似的数据public class PercentageCalculation extends AggregateFunction
PercentageAccumulator.java
package com.ymm.computation.udf.define;import org.slf4j.Logger;import org.slf4j.LoggerFactory;//!只针对时间来计算95线等,其它参数不要使用本类public class PercentageAccumulator { private static final Logger LOG = LoggerFactory .getLogger(PercentageAccumulator.class); public final static double PERCENT_50 = 0.5; public final static double PERCENT_75 = 0.25; public final static double PERCENT_90 = 0.1; public final static double PERCENT_95 = 0.05; public final static double PERCENT_99 = 0.01; public final static double PERCENT_999 = 0.001; public final static double PERCENT_9999 = 0.0001; public final static int PERCENT_COUNT = 7; private final static int[] SCALE = { // 1, // 2, // 4, // 8, // 16, // 32, // 64, // 128, // 256, // 512, // 1024, // 2048, // 4096, // 8192, // 16384, // 32768, // 65536 // }; private int[] countContainer = { // 0, //<=1 0, //<=2 0, //<=4 0, //<=8 0, //<=16 0, //<=32 0, //<=64 0, //<=128 0, //<=256 0, //<=512 0, //<=1024 0, //<=2048 0, //<=4096 0, //<=8192 0, //<=16384 0, //<=32768 0 //<=65536 }; private int positionByTwoDivision(int[] array, int begin, int end, int value) { int mid = (begin + end) >> 1; int midValue = array[mid]; int halfMidValue = midValue >> 1; //判断是否可以命中mid if (value > halfMidValue && value <= midValue) { return mid; } //没法命中,则根据大小来定 if (value <= halfMidValue) { if (mid - 1 < 0) {//没路可走的边界条件 return 0; } return positionByTwoDivision(array, begin, mid - 1, value); } else { return positionByTwoDivision(array, mid + 1, end, value); } } public int positionInValueArray(int val) { int length = SCALE.length; //如果大于最大值|小于等于最小值 if (val >= SCALE[length - 1]) { return length - 1; } else if (val <= SCALE[0]) { return 0; } //采用2分法来计算 return positionByTwoDivision(SCALE, 0, length - 1, val); } public void accumulate(Object value) { //转换为long值,int值够用了 Long longValue = (Long) value; int intValue = longValue.intValue(); //找到下标 int index = positionInValueArray(intValue); countContainer[index]++; } //确保在[1,MAX]范围内, //自然顺序 private int adjust(int input, int max) { if (input <= 1) { return 1; } else if (input >= max) { return max; } else { return input; } } private static final ThreadLocalSTR_BUILDER_ThreadLocal = new ThreadLocal () { public StringBuilder initialValue() { return new StringBuilder(); } }; private static final String SEPARATOR = ":"; public String getValue() { //total int total = 0; int length = countContainer.length; for (int index = 0; index < length; index++) { total += countContainer[index]; } //如果total为0的异常情况 //注意是自然序---[1,total] int percent_9999_pos = adjust((int) (total * PERCENT_9999), total); boolean found_9999 = false; int percent_9999_value = Integer.MAX_VALUE; //999 int percent_999_pos = adjust((int) (total * PERCENT_999), total); boolean found_999 = false; int percent_999_value = Integer.MAX_VALUE; //99 int percent_99_pos = adjust((int) (total * PERCENT_99), total); boolean found_99 = false; int percent_99_value = Integer.MAX_VALUE; //95 int percent_95_pos = adjust((int) (total * PERCENT_95), total); boolean found_95 = false; int percent_95_value = Integer.MAX_VALUE; //90 int percent_90_pos = adjust((int) (total * PERCENT_90), total); boolean found_90 = false; int percent_90_value = Integer.MAX_VALUE; //75 int percent_75_pos = adjust((int) (total * PERCENT_75), total); boolean found_75 = false; int percent_75_value = Integer.MAX_VALUE; //50 int percent_50_pos = adjust((int) (total * PERCENT_50), total); boolean found_50 = false; int percent_50_value = Integer.MAX_VALUE; //开始遍历每一个元素,从后往前算 int scanned = 0; int left = PERCENT_COUNT; for (int index = length - 1; index >= 0; index--) { //当前没有值,无论如何也不会成为备选 if (0 == countContainer[index]) { continue; } //当前有值 scanned += countContainer[index]; //逐个判断 //9999线 if (false == found_9999 && scanned >= percent_9999_pos) { percent_9999_value = SCALE[index]; found_9999 = true; left--; } //999线 if (false == found_999 && scanned >= percent_999_pos) { percent_999_value = SCALE[index]; found_999 = true; left--; } //99线 if (false == found_99 && scanned >= percent_99_pos) { percent_99_value = SCALE[index]; found_99 = true; left--; } //95线 if (false == found_95 && scanned >= percent_95_pos) { percent_95_value = SCALE[index]; found_95 = true; left--; } //90线 if (false == found_90 && scanned >= percent_90_pos) { percent_90_value = SCALE[index]; found_90 = true; left--; } //75线 if (false == found_75 && scanned >= percent_75_pos) { percent_75_value = SCALE[index]; found_75 = true; left--; } //50线 if (false == found_50 && scanned >= percent_50_pos) { percent_50_value = SCALE[index]; found_50 = true; left--; } //全部都找到了就break if (0 == left) { break; } } //所有的值都算好了 //拿出来时先reset一下 StringBuilder stringBuilder = STR_BUILDER_ThreadLocal.get(); stringBuilder.delete(0, stringBuilder.length()); //开始挂各种数据,测试表明每秒几百万次执行 stringBuilder.append(percent_50_value); stringBuilder.append(SEPARATOR); stringBuilder.append(percent_75_value); stringBuilder.append(SEPARATOR); stringBuilder.append(percent_90_value); stringBuilder.append(SEPARATOR); stringBuilder.append(percent_95_value); stringBuilder.append(SEPARATOR); stringBuilder.append(percent_99_value); stringBuilder.append(SEPARATOR); stringBuilder.append(percent_999_value); stringBuilder.append(SEPARATOR); stringBuilder.append(percent_9999_value); //return return stringBuilder.toString(); } public void print() { for (int index = 0; index < this.countContainer.length; index++) { System.out.println(index + "->" + this.countContainer[index]); } }}
欢迎提出 优化建议,比如对GC更友好的优化建议!
这个函数的瓶颈在于stringbuilder.
单位
建议
数据
一致
成功
无论如何
下标
人员
代码
函数
参数
只是
够用
大小
思路
成功率
文章
方式
时间
月份
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
甘肃金融网络安全
建网站需要买服务器吗
iis没权限访问数据库
学习网络安全工程师用编程语言吗
串口联网服务器军品级
数据库的恢复与安全性控制
初级中学网络安全制度
iis安装服务器
数据库er关系图 超市
地下城与勇士服务器连接
rfid资产管理服务器
信息系统网络安全论文题目
系统应用访问不了数据库
亚马逊云服务器上传本地文件
软件开发创新创业资金规划
企业如何做好网络安全
玩游戏出现服务器暂时不可用
情咖网络技术公司怎样
百思易智能服务器不在线
启明软件开发工程师
网易我的世界自由好玩的服务器
大学网络安全知识竞赛主题
你们公司谁负责软件开发翻译
怎样赋予数据库最高权限
怎么查服务器所剩端口
相对来说查询数据库时间
网络安全何时摆脱勒索
数据库中的标签和宽表
计算机网络技术怎么做
app显示请求被服务器拒绝