最近做了指标监控系统的后台,包括需求调研、代码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. 【LeetCode】Palindrome Pairs(336)

    1. Description Given a list of unique words. Find all pairs of distinct indices (i, j) in the given ...

  2. [WCF编程]7.实例上下文模式

    一.实例上下文模式概述 实例上下文(IntanceContext Mode)表示服务端的服务实例与客户端的服务代理的绑定方式. 在实例化服务器对象时,WCF采用了3种不同的模式:单调(Per-Call ...

  3. ASP.NET MVC Notes - 01

    inetmgr 进入IIS ViewBag和ViewData在run-time的时候检查错误,View中的用法如下: @*ViewBag传递的是动态对象*@ @foreach (string item ...

  4. Spring工作原理

    一. IoC(Inversion of control): 控制反转1.IoC:概念:控制权由对象本身转向容器:由容器根据配置文件去创建实例并创建各个实例之间的依赖关系核心:bean工厂:在Sprin ...

  5. jquery css属性练习

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  6. IOS应用内存释放机制

    这是由iOS系统管理决定的,但APP退出在后台后,只有10秒的持续运行时间,然后暂停.但该APP还在内存中,当出现内存警告,也就是别的APP要运行,而此时内存又不足的情况下,系统会回收停在后台APP所 ...

  7. 十一个行为模式之访问者模式(Visitor Pattern)

    定义: 提供一个作用于某对象结构(通常是一个对象集合)的操作的接口,使得在添加新的操作或者在添加新的元素时,不需要修改原有系统,就可以对各个对象进行操作. 结构图: Visitor:抽象访问者类,对元 ...

  8. javascript执行环境(执行期上下文)详解

    javascript执行环境(执行期上下文) 当js控制器(control)进入可执行代码时,控制器会进入一个执行环境,活动的多个执行环境构成执行环境栈,最上面的是正在运行的执行环境,当控制器进入一个 ...

  9. 前端Demo常用库文件链接

    <!doctype html><html><head> <meta charset="UTF-8"> <title>前端 ...

  10. JavaScript小细节点罗列

    共勉! 属性访问表达式 众所周知,JavaScript为属性的访问定义了两种语法方式: 表达式.标识符 // 表达式(指定对象) 标识符(指定需要访问的属性的名称) 表达式[表达式] //表达式1(指 ...