基於Flink和Drools的實時日誌處理

雲棲號資訊:【點擊查看更多行業資訊
在這裏您可以找到不同行業的第一手的上雲資訊,還在等什麼,快來!


背景

日誌系統接入的日誌種類多、格式複雜多樣,主流的有以下幾種日誌:

  • Filebeat採集到的文本日誌,格式多樣
  • Winbeat採集到的操作系統日誌
  • 設備上報到Logstash的syslog日誌
  • 接入到Kafka的業務日誌

以上通過各種渠道接入的日誌,存在2個主要的問題:

  • 格式不統一、不規範、標準化不夠
  • 如何從各類日誌中提取出用戶關心的指標,挖掘更多的業務價值

爲了解決上面2個問題,我們基於Flink和Drools規則引擎做了實時的日誌處理服務。

系統架構

架構比較簡單,架構圖如下:

4

各類日誌都是通過Kafka彙總,做日誌中轉。

Flink消費Kafka的數據,同時通過API調用拉取Drools規則引擎,對日誌做解析處理後,將解析後的數據存儲到Elasticsearch中,用於日誌的搜索和分析等業務。

爲了監控日誌解析的實時狀態,Flink會將日誌處理的統計數據,如每分鐘處理的日誌量,每種日誌從各個機器IP來的日誌量寫到Redis中,用於監控統計。

模塊介紹

系統項目命名爲Eagle。

eagle-api:基於Spring Boot,作爲Drools規則引擎的寫入和讀取API服務。

eagle-common:通用類模塊。

eagle-log:基於Flink的日誌處理服務。

重點講一下eagle-log:

對接kafka、ES和Redis

對接Kafka和ES都比較簡單,用的官方的connector(flink-connector-kafka-0.10和flink-connector-elasticsearch6),詳見代碼。

對接Redis,最開始用的是org.apache.bahir提供的redis connector,後來發現靈活度不夠,就使用了Jedis。

在將統計數據寫入redis的時候,最開始用的keyby分組後緩存了分組數據,在sink中做統計處理後寫入,參考代碼如下:

String name = "redis-agg-log";
    DataStream<Tuple2<String, List<LogEntry>>> keyedStream = dataSource.keyBy((KeySelector<LogEntry, String>) log -> log.getIndex())
            .timeWindow(Time.seconds(windowTime)).trigger(new CountTriggerWithTimeout<>(windowCount, TimeCharacteristic.ProcessingTime))
            .process(new ProcessWindowFunction<LogEntry, Tuple2<String, List<LogEntry>>, String, TimeWindow>() {
                @Override
                public void process(String s, Context context, Iterable<LogEntry> iterable, Collector<Tuple2<String, List<LogEntry>>> collector) {
                    ArrayList<LogEntry> logs = Lists.newArrayList(iterable);
                    if (logs.size() > 0) {
                        collector.collect(new Tuple2(s, logs));
                    }
                }
            }).setParallelism(redisSinkParallelism).name(name).uid(name);

後來發現這樣做對內存消耗比較大,其實不需要緩存整個分組的原始數據,只需要一個統計數據就OK了,優化後:

String name = "redis-agg-log";
    DataStream<LogStatWindowResult> keyedStream = dataSource.keyBy((KeySelector<LogEntry, String>) log -> log.getIndex())
            .timeWindow(Time.seconds(windowTime))
            .trigger(new CountTriggerWithTimeout<>(windowCount, TimeCharacteristic.ProcessingTime))
            .aggregate(new LogStatAggregateFunction(), new LogStatWindowFunction())
            .setParallelism(redisSinkParallelism).name(name).uid(name);

這裏使用了Flink的聚合函數和Accumulator,通過Flink的agg操作做統計,減輕了內存消耗的壓力。

使用Broadcast廣播Drools規則引擎

1、Drools規則流通過broadcast map state廣播出去。

2、Kafka的數據流connect規則流處理日誌。

//廣播規則流
env.addSource(new RuleSourceFunction(ruleUrl)).name(ruleName).uid(ruleName).setParallelism(1)
            .broadcast(ruleStateDescriptor);

//Kafka數據流
FlinkKafkaConsumer010<LogEntry> source = new FlinkKafkaConsumer010<>(kafkaTopic, new LogSchema(), properties);
env.addSource(source).name(kafkaTopic).uid(kafkaTopic).setParallelism(kafkaParallelism);

//數據流connect規則流處理日誌
BroadcastConnectedStream<LogEntry, RuleBase> connectedStreams = dataSource.connect(ruleSource);
connectedStreams.process(new LogProcessFunction(ruleStateDescriptor, ruleBase)).setParallelism(processParallelism).name(name).uid(name);

具體細節參考開源代碼。

小結

本系統提供了一個基於Flink的實時數據處理參考,對接了Kafka、Redis和Elasticsearch,通過可配置的Drools規則引擎,將數據處理邏輯配置化和動態化。

對於處理後的數據,也可以對接到其他sink,爲其他各類業務平臺提供數據的解析、清洗和標準化服務。

【雲棲號在線課堂】每天都有產品技術專家分享!
課程地址:https://yqh.aliyun.com/live

立即加入社羣,與專家面對面,及時瞭解課程最新動態!
【雲棲號在線課堂 社羣】https://c.tb.cn/F3.Z8gvnK

原文發佈時間:2020-07-09
本文作者: aoxiang
本文來自:“dockone”,瞭解相關信息可以關注“dockone”

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章