予測モニタリング、潜在的な障害アラート



この投稿は前の投稿の続きです。 予測監視は標準の監視方法ではありません。 したがって、通知は非常に標準的ではなく使用する必要があります。 これがどのように行われ、なぜそうなのかを検討してください。



通知はどうあるべきか



誰もが誰が毎日の仕事でどの監視システムを使用しているかに興味があると思います。 たとえば、 Dudeを使用します。 私たちは、最も重要なトランジットVoIPを除き、インフラストラクチャ全体を監視する方法を彼に教えました。 Dudeはデフォルトで、クライアントアプリケーションの実行時にメールとポップアップでアラートを送信する方法を知っています。 また、外部アプリケーションを使用してSMSを送信するように彼に教えました。 しかし、これはそれについてではありません。

監視システムからアラートが送信されると、アラート自体はどのノードで障害が発生したか、および監視されている値の最後の測定結果を示す必要があります。 たとえば、Router1のプロセッサの負荷が95%であるという通知を受け取る場合があります。 このようなアラート自体は、応答する必要がある速さを理解するのに十分な情報を提供します。 もう1つは、予測方法を使用して監視すると同時に、数千のパラメーターの状態を確認する場合です。

はい、アラートで最後の測定結果を報告できます。また、いくつかの最近の測定値の平均結果、またはちょうど1日前の測定値を表示することもできます。 しかし、これでは十分でない場合がよくあります。 この場合の最も効果的な通知方法は通知です。これは、一定期間の測定値のグラフを表示します。 チャートを一目見れば、潜在的な障害が重大であるかどうか、障害が実際に発生したかどうか、または誤検知であるかどうかを理解するのに十分です。



rrdtoolでの実装の詳細



以前の投稿で書いたように、rrdtoolが潜在的な障害(異常)の予測と識別を開始するには、rrdデータベースを正しく作成し、単に現在の値を入力する必要があります。 この構成では、測定値自体に加えて、ベースに別の値-FAILURESが自動的に入力されます。 FAILURESは、そのインデックスが測定が行われた時間(unixtime)である単純なハッシュです。 指標値は、測定値の異常の存在を示します。 簡単です。異常があり、FAILURESの値は1でしたが、ありませんでした-0。

ただし、最後の測定後にFAILURES値を確認するだけでは不十分です。 実際には、異常は十分長く続く可能性があるため、グラフを見てください。



ほとんどの場合、監視システムは、異常が存在する間、値を測定するたびに警告を発すべきではありません。 ただし、場合によっては、これも実行する必要があります。 さらに、異常が解消した場合、これは問題が解決したことを意味するものではなく、システムが予測を新しい値に単純に調整する可能性があります。 実際の例は次の図にありますが、ストリームの問題は解決されておらず、異常はすでに終了しています。



監視時の最も正確なIMHO予測は、異常が始まったときと終わったときに、スケジュールとともにアラートを送信することです。



どうやって



実際、スクリプトは:

#!/usr/bin/env python import os import time import rrdtool import tempfile import smtplib from email.mime.image import MIMEImage from email.mime.multipart import MIMEMultipart COMMASPACE = ', ' # Define params rrdpath = '/usr/rrdmonit/rrd/' pngpath = '/usr/local/share/cacti/rrdmonit/ width = '500' height = '200' mailsender = "alerter@my-domain.com" mailreceip = ["admins@my-domain.com", "support@my-domain.com"] mailserver = 'mx.my-domain.com' # Generate charts for last 48 hours enddate = int(time.mktime(time.localtime())) begdate = enddate - 172800 def send_alert_attached(subject, flist): """ Will send e-mail, attaching png files in the flist. """ msg = MIMEMultipart() msg['Subject'] = subject msg['From'] = mailsender msg['To'] = COMMASPACE.join(mailreceip) for file in flist: png_file = pngpath+file.split('.')[0]+'.png' print png_file fp = open(png_file, 'rb') img = MIMEImage(fp.read()) fp.close() msg.attach(img) mserver = smtplib.SMTP(mailserver) mserver.sendmail(mailsender, mailreceip, msg.as_string()) mserver.quit() def check_aberration(rrdpath,fname): """ This will check for begin and end of aberration in file. Will return: 0 if aberration not found. 1 if aberration begins 2 if aberration ends """ ab_status = 0 rrdfilename = rrdpath+fname info = rrdtool.info(rrdfilename) rrdstep = int(info['step']) lastupdate = info['last_update'] previosupdate = str(lastupdate - rrdstep - 1) graphtmpfile = tempfile.NamedTemporaryFile() # Ready to get FAILURES from rrdfile # will process failures array values for time of 2 last updates values = rrdtool.graph(graphtmpfile.name, 'DEF:f0='+rrdfilename+':val:FAILURES:start='+previosupdate+':end='+str(lastupdate), 'PRINT:f0:MIN:%1.0lf', 'PRINT:f0:MAX:%1.0lf', 'PRINT:f0:LAST:%1.0lf') fmin = int(values[2][0]) fmax = int(values[2][1]) flast = int(values[2][2]) # check if failure value had changed. if (fmin != fmax): if (flast == 1): ab_status = 1 else: ab_status = 2 return ab_status def gen_image(rrdpath, pngpath, fname, width, height, begdate, enddate): """ Generates png file from rrd database: rrdpath - the path where rrd is located pngpath - the path png file should be created in fname - rrd file name, png file will have the same name .png extention width - chart area width height - chart area height begdate - unixtime enddate - unixtime """ # 24 hours before current time, will show on chart using SHIFT option ldaybeg = str(begdate - 86400) ldayend = str(enddate - 86400) # Will show some additional info on chart endd_str = time.strftime("%d/%m/%Y %H:%M:%S",(time.localtime(int(enddate)))).replace(':','\:') begd_str = time.strftime("%d/%m/%Y %H:%M:%S",(time.localtime(int(begdate)))).replace(':','\:') title = 'Chart for: '+fname.split('.')[0] # Files names pngfname = pngpath+fname.split('.')[0]+'.png' rrdfname = rrdpath+fname # Get iformation from rrd file info = rrdtool.info(rrdfname) rrdtype = info['ds[val].type'] # Will use multip variable for calculation of totals, # should be usefull for internet traffic accounting, # or call/minutes count from CDR's. # Do not need logic for DERIVE and ABSOLUTE if rrdtype == 'COUNTER': multip = str(int(enddate) - int(begdate)) else: # if value type is GAUGE should divide time to step value rrdstep = info['step'] multip = str(round((int(enddate) - int(begdate))/int(rrdstep))) # Make png image rrdtool.graph(pngfname, '--width',width,'--height',height, '--start',str(begdate),'--end',str(enddate),'--title='+title, '--lower-limit','0', '--slope-mode', 'COMMENT:From\:'+begd_str+' To\:'+endd_str+'\\c', 'DEF:value='+rrdfname+':val:AVERAGE', 'DEF:pred='+rrdfname+':val:HWPREDICT', 'DEF:dev='+rrdfname+':val:DEVPREDICT', 'DEF:fail='+rrdfname+':val:FAILURES', 'DEF:yvalue='+rrdfname+':val:AVERAGE:start='+ldaybeg+':end='+ldayend, 'SHIFT:yvalue:86400', 'CDEF:upper=pred,dev,2,*,+', 'CDEF:lower=pred,dev,2,*,-', 'CDEF:ndev=dev,-1,*', 'CDEF:tot=value,'+multip+',*', 'CDEF:ytot=yvalue,'+multip+',*', 'TICK:fail#FDD017:1.0:"Failures"\\n', 'AREA:yvalue#C0C0C0:"Yesterday\:"', 'GPRINT:ytot:AVERAGE:"Total\:%8.0lf"', 'GPRINT:yvalue:MAX:"Max\:%8.0lf"', 'GPRINT:yvalue:AVERAGE:"Average\:%8.0lf" \\n', 'LINE3:value#0000ff:"Value \:"', 'GPRINT:tot:AVERAGE:"Total\:%8.0lf"', 'GPRINT:value:MAX:"Max\:%8.0lf"', 'GPRINT:value:AVERAGE:"Average\:%8.0lf" \\n', 'LINE1:upper#ff0000:"Upper Bound "', 'LINE1:pred#ff00FF:"Forecast "', 'LINE1:ndev#000000:"Deviation "', 'LINE1:lower#00FF00:"Lower Bound "') # List of new aberrations begin_ab = [] # List of gone aberrations end_ab = [] # List files and generate charts for fname in os.listdir(rrdpath): gen_image(rrdpath, pngpath, fname, width, height, begdate, enddate) # Now check files for beiaberrations for fname in os.listdir(rrdpath): ab_status = check_aberration(rrdpath,fname) if ab_status == 1: begin_ab.append(fname) if ab_status == 2: end_ab.append(fname) if len(begin_ab) > 0: send_alert_attached('New aberrations detected',begin_ab) if len(end_ab) > 0: send_alert_attached('Abberations gone',end_ab)
      
      





これは前回の投稿で説明したスクリプトの修正であり、異常をチェックしてメールを送信する手順を追加しただけです。



PS私は、Pythonのソリューションの容量と美しさに驚かされるのに飽きていません。



All Articles