实时告警架构优化实战

简介

线上有一个告警服务采用sparkstreaming+kafka的模式实时处理数据进行布控告警,10s一个批次,34个executor,每个4core,kafka有260个分区,采用直读的方式并且打开了慢执行推测。

运行一段时间后,都没有延迟,目前布控任务有1000个左右,每天4000万的数据需要处理,昨晚业务突然添加了2000个布控任务,导致任务有积压,导致告警延迟两个多小时,经过排查,发现慢在获取mpp的布控任务。

原处理流程

                                                    

通过上述流程图可以看出,每个task都需要获取一个mpp的布控任务,因为布控任务会被更新,所以每次处理数据的时候都需要全量获取布控任务,这样每一个批次,会有260个task,就需要读取mpp260次,这肯定慢啊。写代码的小兄弟说,这个不这样搞,那每个executor怎么获取布控任务,我说:用广播变量啊,小兄弟说:我这布控任务是动态变化的啊,你这广播变量是静态不变的,,,,,,

如果spark这么呆,估计早死了,我们其实可以动态的更新广播变量,众所周知,广播变量是driver端独有的,executor只有只读权限,所以每次只能在driver端更新,所以原流程发现了两个问题,均在生产环境遇到:

问题一:为了更新布控信息,每个批次,每个task都读取一遍mpp,一个批次读取260,导致mpp压力很大

解决方案:spark为分布式而生,分布式协调是基本功,采用dirver端读取定时更新布控信息,动态广播变量,这样每个executor都可以通过rpc获取布控信息。

问题二:告警服务强依赖mpp,在mpp异常,或者cpu高的情况下,会阻塞告警,导致告警延迟

解决方案:采用缓存的机制,在dirver端采取内存缓存,一分钟定时更新,可以设置jdbc查询超时为10s,如果遇到mpp异常,查询不到数据的情况下,继续使用上次的缓存信息,类似cap理论,在分布式容错的场景下吗,保持服务可用,牺牲数据一致性。

优化后处理流程

                                                  

// 动态广播变量代码

 

补充知识点

foreachRDD、foreachPartition和foreach的不同之处主要在于它们的作用范围不同,foreachRDD作用于DStream中每一个时间间隔的RDD,foreachPartition作用于每一个时间间隔的RDD中的每一个partition,foreach作用于每一个时间间隔的RDD中的每一个元素。