1.背景转转基于Prometheus实现了一个集成监控系统,并自行开发了告警系统。而研发同学每天都会收到大量告警,导致重要告警不堪重负,部分同学会选择直接屏蔽所有告警,进一步加剧问题。警报太多等于没有警报。另外,多个告警之间通常存在一定的相关性,例如SQL执行错误导致异常日志过多的告警。面对杂乱无章的告警,很难快速分析出告警的根源。报警降噪管理很重要。在此背景下,我们基于Alertmanager的扩展开发了转转报警中心。2.规范与SDK2.1发送告警Alertmanager提供了发送告警的OpenAPI,其中告警的标签用于识别同一告警,并对告警进行去重去噪,相同标签告警的标注将被覆盖。startsAt和endsAt分别是报警发生时间和结束时间。[{"labels":{"":"",...},"annotations":{"":"",},"startsAt":"","endsAt":"","generatorURL":""},...]一个alert从提交到发送给接收者的流程大致如下图所示,其中Alertmanager需要集群部署,保证高可用。需要注意的是,在发送告警时,集群无法进行负载均衡。警报必须发送到集群中的所有警报管理器以确保高可用性。2.2公共标签Alertmanager是基于标签的告警降噪,需要提前对告警的公共标签进行标准化。ENV:环境,如:线上环境、测试环境APP:服务名称SOURCE:告警来源,如:日志告警、JVM告警NAME:告警名称LEVEL:告警级别,如:P0告警、P5告警INSTANCE:告警实例IPRECEIVER_TYPE:报警接收者类型RECEIVER:报警接收者,与RECEIVER_TYPE配合使用,如RECEIVER_TYPE=mail,RECEIVER为邮箱地址。Alertmanager标签名称的规则规则是[a-zA-Z_][a-zA-Z0-9_]*。实际发送通知时,最好对标签名称进行中文映射转换。2.3SDK我们为Alertmanager开发了一个SDK来发送警报。如下所示,发送警报非常简单。默认情况下,SDK会自动为每个告警添加服务名称、环境、IP、告警级别,并根据接收者拆分为多个告警。发送。每一项都是一个标签,其中值比较特殊,放在注释中,其他放在标签中,唯一标识一条告警。AlertManageralertManager=AlertManager.builder()//告警名称,mandatory.name("AlarmDemo")//告警标签,扩展信息,optional.label("label1","value1").label("label2","value2")//报警值,optional.value("123")//指定为企业微信报警,并指定发送者.wechat("zhangsan","lisi").build();//同步发送报警alertManager.send();//异步发送,默认线程池alertManager.sendAsync();//自定义线程池发送ThreadPoolExecutorexecutor;executor.execute(alertManager);3.告警降噪3.1分组去重分组机制可以将多条告警消息合并为一条通知。例如,当集群中有数百个正在运行的服务实例时,如果此时发生网络故障,则会因此向Alertmanager发送数百个警报。作为用户,您可能只想在一个通知中看到哪些服务实例受到影响。此时可以根据服务所在的集群或者告警名称对告警进行分组,将这些告警聚合为一个通知。Alertmanager可以根据特定的标签对接收到的告警进行分组和去重,并根据以下参数决定何时在组内发送告警通知。Alertmanager的每个通知都会包含当前组中的所有警报。初始等待时间(group_wait):一组告警第一次发送前的等待时间,用于等待更多同组告警一起发送。变化等待时间(group_interval):一组发送过初始通知的告警在收到新告警或恢复告警后,等待再次发送通知的时间。重复等待时间(repeat_interval):对于一组发送过初始通知的告警,该组告警都没有恢复,也没有添加新的告警,再次发送通知之前的等待时间。下图展示了从告警产生到合并到某个集合再到发送通知的全过程。三角形和圆形代表不断产生的告警,矩形代表实际通知时间和告警内容。3.2恢复通知Alertmanager自带恢复通知。默认情况下,如果在5m内没有收到警报,警报将被视为恢复,并在等待group_interval后通知用户。也可以在发送告警时指定告警恢复时间,如下://告警发生时间DatestartTime=newDate();//告警结束时间,如果startTime~endTime之间没有告警,则告警视为恢复DateendTime=newDate(newDate().getTime()+5*60*1000);AlertManager.builder().startsAt(startTime).endsAt(endTime)。需要注意的是,如果endTime小于当前时间,则在发出该告警时会认为该告警已经恢复,不会通知该告警。3.3报警分类我们将报警分为六个级别:P0~P5。默认情况下,警报级别取决于服务的重要性。中转服务按重要性分为A、B、C、D、E五个级别。服务重要性与告警对应等级:A→P1、B→P2、C→P3、D→P4、E→P5。还可以在发送告警时指定告警级别,如下:尽可能低级别的警报减少用户中断的次数。不同级别告警的分组和去重时间不同。例如:P4/P5告警一开始会等待3m收集告警,将当前告警接收者的所有告警汇总为一个通知;,告警源,告警名称分为维度的多个通知。route:group_by:['...']receiver:'web.hook'routes:-group_by:['_RECEIVER','_RECEIVER_TYPE']group_wait:3mgroup_interval:10mrepeat_interval:4hmatchers:-_LEVEL=~"P4|P5"continue:false-group_by:['_RECEIVER','_RECEIVER_TYPE','_ENV']group_wait:2mgroup_interval:10mrepeat_interval:2hmatchers:-_LEVEL="P3"continue:false#...省略P3,P2,P1、P0降噪策略报警级别分组标签group_waitgroup_intervalrepeat_intervalP0报警接收者、环境、服务名称、报警源、报警名称15s1m30mP1报警接收者、环境、服务名称、报警源30s5m1hP2报警接收者、环境、服务名称1m5m1hP3报警接收者、环境2m10m2hP4/P5Alarmreceiver3m10m4h3.4Notificationmerging统一使用Alertmanagerwebhooknotification,一个notification内容会包含group中的多个alarms,我们会根据alarms的相似度来合并alarms,如下:6个alarms合并为一个Notification,其中一个larm值与服务实例一一对应。定义相似度:对于多个告警标签,只有一个标签值不同,其余标签键和标签值相同,则认为相似,合并;一个Alertmanagerwebhook通知可以根据相似度拆分成多个告警,不同告警提取公共标签,最后推送到一个通知中。如下,将4条告警合并为一条通知,可以明显看出两台机器日志告警异常的原因是Druid执行SQL出错。3.5告警抑制抑制是指在某个告警发出后,可以停止重复发送由该告警引起的其他告警的机制。当同一服务、环境、告警源、IP、接收者、告警名称同时发生多级告警时,高级别告警将抑制低级别告警的通知。例如告警名称为FGCcount,P1告警阈值为20,P2告警为10。当某个实例的FGC计数超过20时,只会发送P1告警,不会发送P2告警.inhibit_rules:-source_matchers:-_LEVEL="P4"target_matchers:-_LEVEL="P5"equal:['_APP','_ENV','_SOURCE','_INSTANCE','_RECEIVER','_RECEIVER_TYPE','_NAME']-source_matchers:-_LEVEL="P3"target_matchers:-_LEVEL=~"P4|P5"等于:['_APP','_ENV','_SOURCE','_INSTANCE','_RECEIVER','_RECEIVER_TYPE','_NAME']#...省略P2、P1、P0抑制策略4.多通知机制支持企业微信、企业微信群、短信、邮件、电话、WebHook,一次告警可以同时指定多种接收方式,并且我们会自动按照收件人拆分成多个告警。企业微信、企业微信群、邮箱、WebHook:最详细,发送告警和恢复通知。SMS:相对于上述,除了不会发送恢复通知。电话:不发送恢复通知,只公布报警名称和报警服务名称。AlertManager.builder()//企业微信.wechat("zhangsan","lisi")//指定消息通道的企业微信.wechat(Arrays.asList("zhangsan","lisi"),"10")//企业微信群聊robot.wechatRobot("企业微信群机器人钥匙")//Mail.mail("zhangsan@zhuanzhuan.com","lisi@zhuanzhuan.com")//Httpcallback.webhook("http://www.baidu.com")//SMS.sms("188xxxxxxxx","180xxxxxxxx")//语音phone.phone("188xxxxxxxx","180xxxxxxxx")..5.未恢复告警防止泛洪alarms每个告警结束后,提供未恢复告警链接,可实时查询当前未恢复告警。未恢复的告警有三种状态:激活、静默和抑制。其中active状态可以设置为silent,silent状态可以由谁来勾选。6.静音报警基于AlertmanagerOpenAPI,支持基于标签的静音报警。每个告警通知都提供了一个快速静音的链接,您还可以对未恢复的告警进行静音。点击AddSilence后,会自动添加Silence匹配的标签项,也可以添加或删除标签项,如:去掉INSTANCE标签维度匹配所有机器,修改_RECEIVER为其他人等。应该是注意,添加静音时必须指定RECEIVER。添加完成后,会自动跳转到静默列表,显示刚刚添加的静默项。在静默列表中可以查询到所有活跃的和过期的静默项,可以编辑、删除和查看受影响的告警。查看受影响的告警是一个实时查询。如果没有匹配到当前静默的告警,则查询结果为空。7、报警历史报警通知用户后,我们将保留三个月的历史报警记录清单。8.总结Alertmanager提供了告警降噪策略。基于Alertmanager,我们制定了标签规范,告警分类降噪,分级抑制,告警合并。基于AlertmanagerOpenAPI,我们扩展了未恢复告警、静默告警、告警历史。Alertmanager虽然不是告警降噪的灵丹妙药,但也可以解决大部分问题。如果你也面临警报轰炸的问题,可以试试看。作者简介袁崇,转转架构部存储服务负责人,主要负责MQ、监控系统、Redis、KV存储等。热爱学习,喜欢用辩证思维和变革思维思考。