最近做了指标监控系统的后台,包括需求调研、代码coding、调试调优测试等,穿插其他杂事等前后花了一个月左右。

  指标监控指的是用户通过接口上传某些指标信息,并且通过配置阈值公式和告警规则等信息监测自己上传指标的准确性。程序方面,接口和前台采用go + redis + mysql,后台python + mysql。

  这个系统的难度主要在于数据量较大,需要在1分钟处理5w+个指标,对接口和后台程序处理并发的性能要求较高。前台则是展示问题,包括核心指标、我的订阅、指标列表、异常列表等。
  系统设计:  

1、指标的判断只支持数值的判断

2、指标的阈值公式包括对当前值V的判断,根据上一次值L求环比数据,根据历史数据求同比数据

3、告警规则采用fibonacci告警规则,分为F0,F1,F2,F3,F5,O1,O2,O5等N种规则

  程序主要代码:

1、心跳判断根据经验设置异常公式


## hbtChannel = 0, 10, 30, 60, 360, 720


## hbtDiffer = 5, 20, 45, 60, 180, 240

@classmethod
def checkHbtInfo(cls):
    """检查心跳异常公式配置"""
    if len(cls.hbtChannelList) != len(cls.hbtDifferList) or len(cls.hbtChannelList) <= 1:#至少2种阶梯
        return -1
    min = 0
    for i in range(len(cls.hbtChannelList)):#层层递增
        try:
            sum = int(cls.hbtChannelList[i]) + int(cls.hbtDifferList[i])
            if 0 == i and 0 != int(cls.hbtChannelList[i]): #从0开始
                return -1
            if min > sum:
                return -1
            min = sum
        except ValueError:
            return -1
    return 0

2、获取告警规则(fibonacci)

def getAlertChannel(self, alertRule):
    """获取告警通道"""
    channel = []
    maxNum = CMyConf.MAX_ALERT_COUNT + 1
    if "F0" == alertRule:#前20次告警
        channel = [i for i in range(1, maxNum)]
    elif "F1" == alertRule:
        channel = [self.getFibonacciNum(i) for i in range(2, maxNum)]
    elif "F2" == alertRule:
        channel = [self.getFibonacciNum(i) for i in range(3, maxNum)]
    elif "F3" == alertRule:
        channel = [self.getFibonacciNum(i) for i in range(4, maxNum)]
    elif "F5" == alertRule:
        channel = [self.getFibonacciNum(i) for i in range(5, maxNum)]
    elif "O1" == alertRule:#第1次告警
        channel = [1]
    elif "O2" == alertRule:
        channel = [2]
    elif "O5" == alertRule:
        channel = [5]
    elif "O10" == alertRule:
        channel = [10]
    else:
        channel = []
    return channel                                                            

3、解析模块

def analyzerThreshold(self, itemId, indexId, threshold, period, periodUnit, value, lastValue):
    """得到自定义公式的值, code, results, global, warnCount"""
    if "" == threshold.strip():#空阈值处理
        return 0, False, {}
    retTh, globalVar = self.checkThreshold(itemId, indexId, threshold, period, periodUnit, value, lastValue)
    if "" != retTh:
        try:
            results = eval(retTh, {}, globalVar)
        except Exception, e:
            errMsg = ("WARNING:自定义公式配置错误! "
                    "详细:itemId=%d, indexId=%d, period=%d%s, threshold=%s, Exception=%s" %
                    (itemId, indexId, period, periodUnit, threshold, e))
            g_logFd.writeFormatMsg(CMyLog.LEVEL_WARN, errMsg)
            return -1, False, {}
        return 0, results, globalVar
    errMsg = ("WARNING:自定义公式配置错误! "
            "详细:itemId=%d, indexId=%d, period=%d%s, threshold=%s" %
            (itemId, indexId, period, periodUnit, threshold))
    g_logFd.writeFormatMsg(CMyLog.LEVEL_WARN, errMsg)
    return -1, False, {}
    

其中 checkThreshold 这个函数比较麻烦,用来将自定义公式转换成python公式,当然自定义公式每个人都可以设立不同的规则,只要能求到同比、环比的值自然可以。例如我的规则是支持 V>0 || ((+H < 0.5) && T>0.5, 1d, 5, MAX )这种公式,则需要根据公式求出H,T,abs(T)等值,然后转成python可以解析的公式,通过eval来解析结果。当然上面的程序中的globalVar其实是local这个形参,只是懒得修改名字而已。最后通过这个结果来判断是否需要告警。

4、多进程模块

pool = multiprocessing.Pool(CMyConf.processNum)
server = multiprocessing.Manager()

indexIdList = []
warnChangeIndexList = server.list()
alertIndexList = server.list()
indexCount = server.dict() #测试是否全部进程都跑完整
hbtItemInfo = server.list()
#print len(self.indexInfo)
handleResults = []

i = 0
for indexId in self.indexInfo:
    indexIdList.append(indexId)
    i += 1
    if i == CMyConf.PROCESS_INDEX_NUM:#5000个
        handleResults.append(pool.apply_async(handlePartIndex,
                args=(self, indexIdList, warnChangeIndexList, hbtItemInfo, alertIndexList, indexCount)))
        indexIdList = []
        i = 0
handleResults.append(pool.apply_async(handlePartIndex,
        args=(self, indexIdList,  warnChangeIndexList, hbtItemInfo, alertIndexList, indexCount)))
pool.close()
pool.join()

其中handlePartIndex是一个进程处理函数,作用比较单纯,就是调用前面的函数解析指标,判断是否信息出错和心跳、数值异常等。

进程池在这个程序中发挥的作用其实并不怎么多,相反为了测试这个多进程花了几天的时间,真的是得不偿失,最后速度也就比单进程提高几秒,因为几万个数据解析的瓶颈并不是在解析模块,而是在数据库的写模块。其实当时本意也是想借这个机会用下进程池,既然都写了就还是用着吧,反正进程数才开了那么几个,不占资源。相信以后数据达到十几万个多进程的优势就会显现出来了。不过用完这个多进程模块,觉得python在进程共享方面做得还是比较不错的,以后发挥的空间还比较大。至少比多线程好用多,那个GIL也真是坑。

5、mysql load命令

cmd = ("mysql -u%s -p%s -h%s itemMonitor --local-infile=1 -e \"load data local infile '%s' "
         "replace into table myCurrentWarning character set utf8 fields terminated by ',' enclosed by '\\\"' lines terminated by '\\n'\"" %
       (CMyConf.dbIMUser, CMyConf.dbIMPass, CMyConf.dbIMHost, sqlFileName))
g_logFd.writeFormatMsg(CMyLog.LEVEL_INFO, cmd)

这个命令替换一个for循环直行replace into真是太棒了,尝试了两三个钟才写出这个命令,也要感谢万能的google.hk。本来30s的replace into语句,瞬间变成3s,性能虽然没有网上说的20倍那么多,也是杠杠的。估计是因为replace一次等于两句sql吧,速度缩减到10倍。哈哈。赞一个。

6、求N个月以前的时间

curTime_t = datetime.datetime.now()
targetMonth = curTime_t.month - num #num个月前
if 0 == targetMonth:
    tmpMon = 12
elif targetMonth > 0:
    tmpMon = targetMonth
else:
    tmpMon = (abs(targetMonth)/12*12 + 12 + targetMonth)
targetMonthNext = targetMonth + 1#保存下个月的
if 0 == targetMonthNext:
    tmpMonNext = 12
elif targetMonthNext > 0:
    tmpMonNext = targetMonthNext
else:
    tmpMonNext = (abs(targetMonthNext)/12*12 + 12 + targetMonthNext)

endTime = curTime_t
try:
    endTime = endTime.replace(year = endTime.year if targetMonth > 0 else endTime.year - int(-targetMonth/12) -1,
            month = tmpMon, day = endTime.day)
except:
    endTime = endTime.replace(year = endTime.year if targetMonth > 0 else endTime.year - int(-targetMonth/12) -1,
            month = tmpMonNext, #下个月1号
            day = 1)#12月31,11月份没31
    endTime += datetime.timedelta(days=-1) # 时间减1天

比较麻烦的是timedelta里面没有月的,只能自己写,还需要考虑某一天可能不存在。

总体后台就这么几个模块比较重要,虽然不难,但花在调试的时间还真是不少,主要在自定义公式设计和多进程吧。效果是现在30s前后能跑5w个数据左右,以后10w+的数据估计多进程就该发挥作用了。

  可以后续优化:告警规则优化、告警内容支持发报表等。

业务监控-指标监控(v1)的更多相关文章

  1. prometheus自定义监控指标——实战

    上一节介绍了pushgateway的作用.优劣以及部署使用,本机通过几个实例来重温一下自定义监控指标是如何使用的. 一.监控容器启动时间(shell) 使用prometheus已经两个月了,但从未找到 ...

  2. prometheus自定义监控指标——入门

    grafana结合prometheus提供了大量的模板,虽然这些模板几乎监控到了常见的监控指标,但是有些特殊的指标还是没能提供(也可能是我没找到指标名称).受zabbix的影响,自然而然想到了自定义监 ...

  3. 系统服务监控指标--load、CPU利用率、磁盘剩余空间、磁盘I/O、内存使用情况等

    介绍 大型互联网企业的背后,依靠的是成千上万台服务器日夜不停的运转,以支撑其业务的运转.宕机对于互联网企业来说,代价是沉重的,轻则影响用户体验,重则直接影响交易,导致交易下跌,并且给企业声誉造成不可挽 ...

  4. K8S Canal基于Prometheus进行实时指标监控

    文章来源于本人的印象笔记,如出现格式问题可访问该链接查看原文 部署canal的prometheus监控到k8s中 1.grafana的docker部署方式:https://grafana.com/gr ...

  5. SpringBoot第十二集:度量指标监控与异步调用(2020最新最易懂)

    SpringBoot第十二集:度量指标监控与异步调用(2020最新最易懂) Spring Boot Actuator是spring boot项目一个监控模块,提供了很多原生的端点,包含了对应用系统的自 ...

  6. 图解JanusGraph系列 - JanusGraph指标监控报警(Monitoring JanusGraph)

    大家好,我是洋仔,JanusGraph图解系列文章,实时更新~ 图数据库文章总目录: 整理所有图相关文章,请移步(超链):图数据库系列-文章总目录 源码分析相关可查看github(码文不易,求个sta ...

  7. spark的运行指标监控

    sparkUi的4040界面已经有了运行监控指标,为什么我们还要自定义存入redis? 1.结合自己的业务,可以将监控页面集成到自己的数据平台内,方便问题查找,邮件告警 2.可以在sparkUi的基础 ...

  8. 【03】SpringBoot2核心技术-核心功能—数据访问_单元测试_指标监控

    3.数据访问(SQL) 3.1 数据库连接池的自动配置-HikariDataSource 1.导入JDBC场景 <dependency> <groupId>org.spring ...

  9. 【转载】apache kafka系列之-监控指标

    原文地址:http://blog.csdn.net/lizhitao/article/details/24581907 1.监控目标 1.当系统可能或处于亚健康状态时及时提醒,预防故障发生 2.报警提 ...

随机推荐

  1. gnuplot: 一种更为简洁的曲线,柱状图绘图软件

    gnuplot: 一种更为简洁的曲线,柱状图绘图软件 gnuplot: 一种更为简洁的曲线,柱状图绘图软件 Zhong Xiewei Wed Jun 25 gnuplot简单介绍 关于gnuplot的 ...

  2. 关于客户端接口分页sql语句

    今天突然翻到为客户端写分页数据的sql,发现其实逻辑不对.列表是按照id降序的 当时这样写的: #翻上一页: select 字段 from 表 where id>lastId order by ...

  3. mybatis入门基础(四)----输入映射和输出映射

    一:输入映射 通过parameterType指定输入参数的类型,类型可以是简单类型.hashmap.pojo的包装类型. 1.1.传递pojo的包装对象 1.1.1.需求描述 完成用户信息的综合查询, ...

  4. Windows Server 2008 R2 安装 media Service 部分更新没有安装 KB963697

    1.下载安装包 Windows6.1-KB963697-x64.msu 2.安装过程失败,提示未安装更新 我是阿里云的服务器,一直出现下面提示 经过反复研究,确定系统问题,重新恢复了初始系统,再进行安 ...

  5. 在DOS使用SVN之执行命令整理(TortoiseProc.exe)

    原文链接: http://www.cnblogs.com/andrew-blog/archive/2012/08/21/SVN_DOS_Commands.html TortoiseSVN因为所有的命令 ...

  6. 背水一战 Windows 10 (22) - 绑定: 通过 Binding 绑定对象, 通过 x:Bind 绑定对象, 通过 Binding 绑定集合, 通过 x:Bind 绑定集合

    [源码下载] 背水一战 Windows 10 (22) - 绑定: 通过 Binding 绑定对象, 通过 x:Bind 绑定对象, 通过 Binding 绑定集合, 通过 x:Bind 绑定集合 作 ...

  7. 【转】Mysql联合查询union和union all的使用介绍

    Mysql的联合查询命令UNION和UNION ALL,总结了使用语法和注意事项,以及学习例子和项目例子,需要的朋友可以参考下 一.UNION和UNION ALL的作用和语法 UNION 用于合... ...

  8. 仿饿了点餐界面2个ListView联动

    如图是效果图 是仿饿了的点餐界面 1.点击左侧的ListView,通过在在适配器中设置Item来改变颜色,再通过notifyDataSetInvalidated来刷新并用lv_home.setSele ...

  9. iOS面试用到的一些知识点和技术

    1.APP的生命周期和viewcontroler的生命周期? 答:APP的生命周期:在APP的代理中分为七个阶段: 1.将要启动 2.已经启动 3.将要进入非活动状态 4.进入后台 5.从后台进入前台 ...

  10. php中防止SQL注入的方法

    [一.在服务器端配置] 安全,PHP代码编写是一方面,PHP的配置更是非常关键. 我们php手手工安装的,php的默认配置文件在 /usr/local/apache2/conf/php.ini,我们最 ...