实时告警架构优化实战

简介

线上有一个告警服务采用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理论,在分布式容错的场景下吗,保持服务可用,牺牲数据一致性。

优化后处理流程

                                                  

// 动态广播变量代码

JavaInputDStream<ConsumerRecord<String, String>> stream = KafkaUtils.createDirectStream(jssc, locationStrategy,
                consumerStrategy);

        stream.foreachRDD(rdd -> {
            // 获取offset
            OffsetRange[] offsetRanges = ((HasOffsetRanges) rdd.rdd()).offsetRanges();
            // 设置广播变量
            final Broadcast<List<ShinyDisposition>> instance = rdd.context().broadcast(QueryDataUtil.queryShinyDisposition(), ClassManifestFactory.classType(List.class));
            List<ShinyDisposition> ShinyDispositionList = instance.value();
            rdd.foreachPartition(new VoidFunction<Iterator<ConsumerRecord<String, String>>>() {
                public void call(Iterator consumerRecordIterator) throws Exception {
                //业务逻辑    
                
                }
            });
            // offset更新
            ((CanCommitOffsets) stream.inputDStream()).commitAsync(offsetRanges);
            // 广播更新
            instance.unpersist(true);
        });
 

QueryDataUtil.queryShinyDisposition()方法获取mpp的数据,一分钟更新一次内存缓存。

补充知识点

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值