今天我要分享的内容,有这样几个方面,首先讨论在数据库运维中存在什么痛点,其次是我们为什么要做智能运维,智能运维是什么,我们在民生做得怎么样。然后会大概说说智能运维中的智能算法,最后是案例分享,也就是我们上了这套智能运维系统后到底有什么效果,在使用过程中帮助我们达成了什么样的目标。
首先聊聊运维的痛点。我是银行的从业者,我们行内对数据库运维的要求,我总结为两点。一点是银行里对数据库运维的要求是非常高的,我们自己银行内部有个“双十”红线的要求,就是说数据库如果出现问题,那么需要DBA在十分种内分析问题,十分钟解决问题。如果在十分种内没有分析完成,那么先暂停分析,救急的工作一定要开始做,争取在十分钟内把救急的工作做好。所以我们平时在运维过程中时间要求还是很紧张的。尤其是没搞清楚原因的情况下,救急的操作可能最终没有解决问题。
另外一点是我们在运维过程中,会产生很多有价值的数据,我们对于机房所有的产品,无论是系统、中间件、数据库都会监控很多东西。即便是这样,我们现在监控的数据还是比较片面的,不是说没有更详尽的运维数据,而是我们没有办法把这些把数据用起来,现在我们只是人工挑选了一些比较核心的指标,做了一些监控告警。
首先谈谈“双十”红线。如果数据库遇到bug,性能不好的SQL,我们大概会从运维系统的交易响应率,数据库的一些告警中知道现在数据库运行缓慢或者出现故障。这时候我们要赶紧去收集数据,查看日志,分析当前遇到问题是什么。
如果我们是很有经验的DBA,那我们可能会基于现有的数据和现象,能够知道说可能命中了个什么样的问题,如果以前有相关经验的话可能就能很快解决。但如果说我遇到这个问题是个新问题,那之前那种解决方式我可能就做不到。
做不到的情况下,就只能做应急处理,把数据库的应用杀一杀,重启一下数据集,能怎么做就怎么做,通过所谓万能的重启大法,先把问题试着解决,后面再复盘,再把数据上收,发送给对应的数据库厂商来帮我们分析问题。
这可能就是DBA平时的工作,收集数据,分析问题,应急处理,问题复盘。但是在这个过程中会有很多欠缺的地方,比如一开始收集的东西不够多,就会导致问题复盘的时候很难重现,这块其实有很多痛点。
引申来说,除了我们现有对故障的处理的痛点,还有问题就是我们现在拿到这些数据是不是没有什么用?比说我们从数据库这一层面可以收集成百上千个指标,那这些指标都是很奇怪的指标,你要是不查资料你根本不知道这个指标是干嘛的。对我来讲也一样, 我其实做数据库运维有很长时间了,指标也不是全部都清楚,我遇到后还是要去查一查看一看。
那这么多指标,它们都是有自己真实的含义的,大家不用起来的话是真浪费。如果我们可以做到把所有的指标管理起来,而不仅仅只是管理我们关心的那十几个重要的指标,那我们对数据库的洞察力会更强。
更进一步,如果我已经拿到这些数据了,那数据和数据之间是不是存在很多的关系呢?比如说我们经常有这样一个需求,我们遇到一个问题,说哪个东西不正常,你知不知道是什么东西引起的不正常呢?会不会是其他的什么事情?
我们平时在运维中分析告警时,总是想办法去找跟它相关的那些指标,或者是因素。这个相关性是可以从历史数据中找到的,如果我们已经把这个东西挖掘挖掘,并且形成一定的知识库,那真的遇到问题的时候,我们基于这个知识库立刻就能发现是什么情况。所以我们要挖掘运维数据的关系,并且利用起来。
再继续下去,我们不仅仅是管理了所有的指标,还理清楚了这些指标之间的关系,下一步就要汇聚体现。比方说我这么多指标,密密麻麻上千个,到处发生异常对我来说没什么意义,我想知道整个行里面几百到上千个数据库,运行得怎么样,那我怎么样去观察它们?
那这个时候就需要这样一个全局的视图,相当于说我需要数据库的运行状态通过一些有价值的数据指标综合起来,描绘出一个数据库的画像,这样能够从很多数据库运维中立刻挑出来说哪些数据库运行的状态是属于哪一种类型中,也就是把握住这个数据库的运行特点。
然后我们总结了几种类型,描述这个数据库很忙,它是一个事务性集中的数据库,它平时的业务量大但是数据量不多,它的io的承载能力或者各方面的属于中等。这就是一个数据库的画像,这个东西是我下一步会做的事情。
其实说了这么多,从我自己的理解来讲,智能运维不是靠人为定义哪些规则去发掘指标的关系,去看指标的含义,而是说我通过智能算法把指标采集起来,再把它们给训练和管理,然后智能算法自己从指标里挖关系,把关系提炼起来,最后通过智能算法把核心的指标挑出来,它们能展示我们自己想要的东西。
那做这件事情就是为了节省DBA的人力,因为我是个DBA,如果要自己手工做这些事,我相信是不可能发生的。但是自从机器学习比较流行之后,我也是看到了机器学习在数据分析上的各种能力,所以我觉得数据库这个层面,再加上机器学习,互相结合能迸发出来火花,完成一些我们之前做不到的事情。
为了做这个智能运维,我们首先要对智能运维平台进行构思,比如说我这个平台到底要做什么事情,它要监管一些什么样的指标,我这里面有哪些计算的内容,这些内容我们应该怎么去依托现有的架构去实现,还有大数据量的挖掘和处理。
这里我大概提了几个比较重要的点,比如容器化。因为我觉得现在云化容器化比较流行,我的计算节点是无状态的,通过容器化的伸缩,很快完成我的目标。事实上也确实是这样,智能运维到现在,监管的对象越来越多,内容越来越扩展,数据量越来越大,训练和实时处理的要求越来越高。自从用了容器化,把我的平台扔进去,我要扩展这方面的性能就变得比较简单。
然后关于机器学习的语言选择。其实也没有其他什么好选的,python是现在最流行的机器学习语言,比较通用,算法包比较多,接口多。我自己作为初学者,来看应该用什么平台时,python能解决很多开发上的工作,我能很快找到我想要的算法包,很快去把我想要的模型弄出来,研究它的效果。所以我最终还是选择python,没有选其他高性能的语言,毕竟我这边开发能力资源有限,没有办法去砸很多人把python里的一些算法转化为java、c++高性能语言。
选了python之后,也是要在python里找对应的处理框架,最终找的框架帮助我在容器化里做动态的扩展。系统里有很多的高性能实时运算的工作,以前我们在监控的数据,一天的时间有12个亿多,所以你想想每秒里也有一两万的的样子,我要把这些东西全部实时的处理完其实挺困难的,我只能通过分布式框架横向扩展的方式来解决。
最后一个是对象存储,这个是我计划用起来的,我们做python机器学习时,还需要一些地方存放我们的模型,那对象存储和容器化一结合,就解决了整个前后端的过程,解决了容器化无状态的需求。
下面会具体讲,我这边到底做了些什么样的智能运维场景,第一个是异常检测,这个是我们在做智能运维过程中最先想要做的事情,如何把所有的指标进行机器学习的异常检测,而不是基于人为定义规则。
第二个比较核心的场景是根因分析,如何在我检测到异常的情况下能够找到sql是什么,是哪个业务跑过来的。我知道它跑的是什么东西。不仅如此我还要去分析sql为什么这个时候跟以前是否不一样,到底触发了个什么样的问题。
最后是做了个智能场景,其实是因为我异常检测的指标太多了,产生的异常也很多,大家对于这些指标也不了解,从我这边来讲,我会把这些指标,尤其是相关性比较强的指标聚合在一起,然后分析它们在过往的过程中发生了什么事情,那我把这个事情描述起来,把场景描述起来,我未来的异常检测就会通过场景的方式来进行告警。告诉大家说我用了什么样的场景,虽然说现在是检测到许多指标的异常,这些指标的异常都是说明同一个场景,这个场景是什么,有什么样的解决办法。
首先看异常检测。异常检测我从四点描述,第一是对象,我异常检测的对象是什么,举个例子,我们现在用数据库,我异常检测的对象是数据库还是sql,那其实很好分析。如果我们对一个数据库检查到了,我肯定希望检测全局的指标,如果检测到sql这个级别,sql的对象是不定的,有的时候有有的时候没有,有的时候换一个sql进来。所以这就不太好检测。
总体来说,光从数据库全局的指标来说,已经是一个很大的对象,比如说我在做DB2的全局指标的时候,大概监控了四百个指标,然后做MySQL的全局指标的时候,大概是三百多个指标,所以这个量还挺大的,一个系统就这么多,然后每个机器每个系统都有这么多数据送过来,这个量还是挺庞大的。
在确定好了我们要监控的对象之后,下一步要挑选什么样的算法。在挑选算法的时候,其实也很简单,因为我们人力有限,所以不能挑有监督的算法,所以像那种分类算法,或者回归算法都不太适合我们。我们适合从无监督学习算法里面挑选对我们有帮助的,后面会介绍一些算法。
到底是使用时间序列算法呢,还是其他算法。这个问题我也考虑了很久,因为选时间序列算法它面临两个问题,第一个问题是时间序列算法会导致检测出的异常点更多,因为它会把整个指标基于时间来分析,而且我的训练数据也需要往前推,需要更久的历史数据。第二个问题是我用时间算法的话,计算量要比普通算法更高一些,对于我们本来要做很大量的学习指标的期望,是相悖的,所以一开始就放弃了时间序列算法。
前面谈算法的时候谈到了最关心的性能,性能主要包含两个方面,一方面是这么多的系统,这么多指标,一个系统400个指标,有400个系统,那就是16万训练对象,我要用多少资源训练才能完成呢。因此我对性能有很高的要求,我们在做整个算法的开发过程中,最关注的就是性能,一开始性能比较差,我们使用的原有的算法包里的东西,后来我们决定把算法的思想抽出来,然后把原来的算法包摒弃掉,只用我们的思想自己做算法,去求阈值的区间。
另一方面是实时处理的性能,同样这么多监控指标,每分钟采集一次,时时刻刻往这儿怼,我需要解决。最后才是展示,最简单的,展示整个指标的发展曲线是最基本的要素,在上面我们还需要做到我这么多指标怎么分层展示,让我有概念,其次刚才说的场景告警,怎么样才能把场景展示出来。
大概给大家说说我做智能检测的流程,首先我们第一步是从数据库里面获取全局的快照,快照里面主要是含指标的数据,不能说采了就往库里面存,还是要把它异步化,中间用了kafka做流处理,从kafka获取数据后,我的实时处理会对当时的快照和之前的快照做差值,把我们指标在快照间产生的数据计算出来,然后这部分数据会被我当成原始数据扔到数据库里,那定期会对数据库里的数据进行训练,历史数据,保存异常模型。原先我们保存的是模型,现在保存预值,就是因为性能问题以及对象存储的问题。
根据这个检测模型,加上前面的流处理接过来的指标,进行实时的异常检测,会最终在通过告警的方式或者邮件提醒用户,那从我的前面页面一样能看到总的异常变化量,在里面的每个指标,指标变化的情况。还会基于根因分析把指标对应的sql,影响最大的排序,列出来,分析对应的sql情况。
我们作为专业的DBA,尤其是采集了这么多专业的性能数据,sql的详情页面,也基本上就能知道sql出了什么问题。
做异常检测的时候,肯定选无监督学习,人工没法标注异常。然后在做异常检测过程中需要多用几种算法,因为每种算法思路不太一样,它的最终的效果不太一样。结合几种算法之后,结果会更准确。最后能单并发十分钟训练400+指标模型。
下面关于根因分析,根因分析主要做的事情,一种是核心指标,cpu的消耗和总的执行时间是核心指标,一种是异常指标,当前页面上爆出的异常指标,这些指标无论是哪个,我点击这些指标,然后查看我那些sql对它的贡献度,然后根据贡献度把sql找出来,在sql生成详细的分析报表。最终达到说我从发现异常到找到问题sql,并且基于提示的sql指标能定位sql的问题是什么。
问题根因模型,从监控里看到等待时间比较长,我会去看下哪些sql占的等待时间比较高,那找到这些sql之后,我回去看单独的sql它历史的执行情况,能看到有些高点,在高点里面这个时刻它的时间分布是怎样的,右边这个饼图讲执行时间的分布,分布里面会看到说,磁盘里面读或写的时间比较多,这种通常会说明问题,问题还需要分析就不继续说了。
在前面两个做完的基础上,做了后面这个智能场景。第一智能场景是属于异常指标的汇聚,我把我经常发生的指标汇聚在一起,告诉他说的这是一个什么场景。第二我给你不仅报了命中这个场景,我还基于当时已经发生问题的指标,将它所关联的sql进行排序,告诉你命中这个场景,很大可能是这个sql导致的。这就是我要做的事情。
当然做完这些事情之后,从展示、告警各方面我们会有很多可以做的东西。比如我做了个大屏展示,也做了系统排行,命中的场景,系统里面能看到异常这样,现在异常量比较多,过去一个小时有多少个指标发生异常了,异常越多的通常是数据库当前运行状况变化比较大的系统,我肯定会关注异常比较多的系统,从我自己是个dba,从管理所有数据库的角度来看的。作为应用人员来讲,他需要关心的只是自己的系统。比如说我是个emu系统的负责人,我只需要看我emu系统的数据库,它所命中的是什么场景。而我是个dba,我会挑异常量比较多的系统来看后面命中的异常场景。
针对DB2我已经做了28个异常场景,里面有日志写盘、回滚异常,锁异常,这些都很好理解,所以从不太好理解的指标我们汇聚成一个很好理解的智能场景,那我们就把这件事情做起来了。
日志写盘异常的例子:
LOG_DISK_WAITS_TOTALLOG_DISK_WAIT_TIMETOTAL_COMMIT_PROC_TIMETOTAL_commit_TIME
比如说这四个指标通常一起发生的,或者两两发生,都是为了说明同一个问题,日志写盘时间慢了还是怎么样,我这边会解释说是什么样的场景,可能需要再去分析什么东西,这相当于我最终给用户提供出来的解释。
在前面这个基础上我还做了个一键智能分析,就像我们刚才看到系统有26个异常,作为一个非DBA,或者只是个应用负责人,那你就需要我那边开发一键分析按钮,只要点这个按钮,它就把当前所有指标基于异常场景分析,告诉你说你的关联sql是什么,这就是给普通用户使用的。
对DBA来讲,我希望你们细致些,仔细看完里面的指标,比方说第一个日志写盘的场景,里面有个什么log_disk_wait,两两一块出现是相关性很高的指标,你看到之后呢,作为DBA来说会看log_disk_wait是个什么含义,怎么回事。普通用户只需要看异常的分析,解决的方案就可以了。
下面介绍一些在做智能运维过程中采用的算法。
首先谈异常检测算法,最简单的就是3σ原则,这种原则其实是我们认为,指标的数据会存在一定分布概率,假设它是符合正态分布的。事实上是不是这样呢?其实不是完全这样的,因为一个指标反馈的事情不一定是一个行为导致的,每个行为都存在自己的正态分布,合到一起后,指标数据因为受到各自的影响,正态分布就不好说了。不管怎么说,作为最基础的算法,我们还是要讲讲这个3σ。
这个算法是假定这个指标符合均值和标准差的分布,如果超过三倍标准差的话,分布的概率就是0.003%左右了。通常来说,整个数据的集合里面,千分之三外面是属于不太容易发生的,所以3σ作为最普通的算法大家可以了解一下。
这个算法很好,叫孤立森林,孤立森林的思路很简单,数据排好了之后,我通过构建孤立树的方式去来孤立样本,如果我在砍了无数次,能将样本最终孤立出来,很快并多次被孤立出来的样本,分布式应该是比较疏离的,所以它可能就是个异常点。
我第一步在整个数据里砍一刀,之后左右分,大于它的和小于它的,小于它的里面再随意砍,大于它的里面也随意砍刀,一层层往下砍,控制下砍的次数。10次或者100次,这是算法里的超参数,之后我们会发现有些部分数据量还超过多少个,有些可能砍了一两个,那个地方数据量就剩一两个,没法再砍了。所以多次很快就没法下刀的树,就是异常点,这就是算法的核心思想。
通过这个算法,砍树行为,我其实连正常数据标准化都不需要做了,因为我砍的时候,按照最大最小值中间随机砍一刀,无所谓是1到100还是0到1,好处是不需要对数据进行预处理,并且算法支持非单一指标的检测。
后面讲个很重要的dbscan算法。这个算法是我做异常检测的核心算法,dbscan是无监督的聚类算法。看这个图右下角,Dbscan将数据分为三类,除了这些分类的数据外,还有边边角角的点不属于任何一类,因为离得太远了。从这个思路来讲,因为定义好密度后,这个点落在圈里面,我的密度足够,我的点是正常的一类点,那我觉得ok,如果刚好在边上,属于临界点,也还ok,也还很靠近正常点。画的圈里面,数据点够不上这个密度,也达不到更其他点在一起,就是异常点。
结合三种算法后,做了集成效果,第一个是孤立森林,第二个是dbscan,分为黄色和蓝色两类,游离在其他地方就是异常点,第三个是3σ正态分布,很大量都是异常点,对我来说不太能接受,最后集成三种算法,如图右下角,形成最终检查出的异常点。
挖掘数据相关性,第一个是最常用皮尔逊相关系数,根据公式做数据标准化处理后,结果就是想要的相关系数。结果是1的表示正相关,同起同落,-1就是负相关,你高我就低这种,不管是哪种都是能说明互相之间是有关系,然后聚在一起,人为去看它的含义。
下一个是apriori,这种算法比相关性更不好理解和更不好处理点。因为它是基于概率的算法,不是基于离散型数据的。指标值上上下下是离散型的,那用这个算就没法做。但我们有异常检测能打标签呀,打完标签之后的标签数据给这个算法用就再合适不过了。
最后基于0和1的标签关系,计算下这些指标是不是同时发生异常,发生异常的比例怎么样,我就可以得到,他们相关性的结果,它们核心的支持度、置信度、提升度在这里可以去看一下,跟概率相关的。
最后分享案例,是近期真实的在民生做运维的过程中发生的情况。近期有系统反馈在日终跑批处理的时候老是影响在线交易,日终时有大量核销订单的操作,这个操作影响交易后,看看数据库到底发生了什么,能不能解决,问题比较突出的时间也有,通过它交易的响应率告诉我是什么时候。我去看一下。先看是不是资源问题,cpu高不高。我就找下当时的cpu,高倒是不高,但却是有个小波动。虽然资源没问题但却显示出来当时有异常现象发生。我们看看是什么。
从智能运维平台里查看数据库有什么异常,数据库看了400个指标,有10个指标发生异常,当时确实同时有多个指标发生异常,下一步看看这个指标是什么。
我自己用的话会详细看每个指标是什么。但这里为了体现工具的能力,点了一键分析的按钮,系统告诉我说有日志写盘的问题,写盘的时候业务在等待,这个业务叫create index,写日志数据占用了我的资源,是不是它影响导致的呢,还需要继续往下看。
再往下看,有多少日志写盘的行为,我们排序发现,当时为什么这么多个sql都在等。
然后继续查看,转订单的sql,看下它的占比,会发现前面等日志写盘,转订单再等日志的buffer,这个就是跟数据库技术相关性比较高。就是说我的数据是在提交,要写进日志盘。首先要先经过日志的buffer,再从buffer汇总起来写日志的盘,等待写盘结束才能提交。如果写盘在等待,那么就会影响前面交易,响应时间就会变长。
所以看了下当时核销sql,log buffer等待比较高,一堆东西等着写磁盘,一堆东西等着写日志缓存,缓存也不够,放不下提交的数据。
所以这个点业务语句是不是在等缓存呢?我看下sql受到影响的业务语句是怎样。这时候发现业务语句在这段时间也出现了很多log buffer的业务等待,平时等待时间是0,因为平时buffer有空间,就不存在等待行为。这个时间点出现了大量的等待。所以从系统里不仅仅能看sql的执行时间的历史, 而相关指标的历史也是可以观察到的,从指标历史来看,sql确实出现了问题。
详细分析下sql,能看到log buffer等待时间比较多,还有latch等和执行时间。说下latch的等待,这个latche等待时间通常是结果,因为前面sql没提交,hold住了latch,那么后面的sql都会等在latch上。所以latch不是原因,而是受影响的现象,这也是曾经发生和分析过的案例。
到这一步,基本上可以得到结论,从系统整个的异常检测里面,通过智能分析定位到了写日志的问题,从写日志的问题知道当时一堆create index语句造成日志写盘繁忙,同时大量的订单转表语句,跑的数据量大,缓存塞得满,所以也在等日志缓存,外面在线交易也是,也会等缓存,造成了业务抖动。
优化建议,在维护窗口时间里把日志缓存调大从16m到64m。从应用角度,希望事务越小越好,越分散越好,相当于错峰,减小事务的力度,让事务尽快提交。
作者介绍:
孔再华,中国民生银行信息科技部数据库专家。
本文由 dbaplus 社群授权转载。
领取专属 10元无门槛券
私享最新 技术干货