[英]apache flink session support
我正在調查Apache Flink Streaming,用於我們的ETL和機器學習平台。 我還沒想到的是如何將事件流式傳輸到“會話”中。 更具描述性:所有事件都包含會話ID,為了豐富數據,我需要將屬於會話的所有事件組合在一起。 請注意事件是連續流入的(因此沒有批量支持,之后您可以簡單地執行groupBy例如)
一種可能的解決方案是維護會話的LRU緩存並將所有傳入事件排序到其關聯會話。 然后,在每個會話不活動X分鍾后,可以從緩存中“關閉”或逐出會話。 問題是如何在多租戶系統中處理此緩存; flink是否具有分布式緩存的概念,還是包含某種智能負載均衡器,其中事件被定向到網格中的同一分區?
更一般地說:使用流式api建立會話支持的最佳方式(用例和陷阱)是什么? 這有可能嗎? 以及如何處理重放流? (即從事件流入不完整會話的特定時間點開始(即在時間點之前發生事件)
對任何反饋,想法和/或指針感興趣。
提前致謝
我創建了一個可能非常接近您需要的示例: https : //gist.github.com/aljoscha/91b6422114eac814479f
我使用Tuple2<Integer,String>
來模擬數據。 整數是會話ID,而String是我們鍵入 (分區)數據的字段。
我建議你先看看main()
方法,在那里你看到程序的流程。 其他位是自定義窗口定義SessionWindow
窗口分配器和SessionTrigger
。 這基本上實現了您建議的緩存的想法。 窗口根據指定的窗口和密鑰保存在緩沖區中。 觸發器觸發后,我們處理窗口並清除內容。
當觸發器接收到一個元素時,它將來會注冊一個計時器10秒鍾。 如果到那時沒有新元素到達,則觸發器將觸發。 如果新元素到達該時間窗口內,它將注冊一個新的定時器,這將取代舊定時器,因為觸發器一次只能有一個活動定時器。
此外,這使用所謂的處理時間窗口 。 這也可以根據事件時間 (即元素的時間戳)更改為觸發。
可以使用EventTimeSessionWindows
從事件流中提取會話。 它組合了一個接一個地形成會話窗口的所有事件,直到它們之間的間隙大於指定的值。 如果流包含許多會話(可以在每個事件中由sessionId
標識),則應首先按會話ID分組,以便分別為每個會話保持會話窗口。
在下面的代碼示例中,表單的事件
case class Event(
createdat: Timestamp,
session: String
)
變成了
case class SessionEvent(
sessionId: String,
start: Instant,
end: Instant,
`type`: String
)
當最近20分鍾沒有事件( sessionTimeout
)時發出SessionEvent
。
// Apache Flink 1.1.4 with Kafka connector
import java.util.Properties
import org.apache.flink.streaming.api.scala._
import org.apache.flink.streaming.api.windowing.assigners.ProcessingTimeSessionWindows
import org.apache.flink.streaming.api.windowing.time.Time
import org.apache.flink.streaming.api.windowing.windows.TimeWindow
import org.apache.flink.streaming.connectors.kafka.{FlinkKafkaConsumer09, FlinkKafkaProducer09}
import org.apache.flink.streaming.util.serialization.SimpleStringSchema
import org.apache.flink.util.Collector
object Main extends App {
val sessionTimeout = Time minutes 20
val kafkaCluster = "localhost:9092"
val inputTopic = "events"
val outputTopic = "sessions"
val env = StreamExecutionEnvironment.getExecutionEnvironment
val properties = new Properties
properties.setProperty("bootstrap.servers", kafkaCluster)
properties.setProperty("group.id", "sessions")
val consumer = new FlinkKafkaConsumer09[String](inputTopic, new SimpleStringSchema, properties)
val producer = new FlinkKafkaProducer09[String](kafkaCluster, outputTopic, new SimpleStringSchema)
val stream =
env
.addSource(consumer)
.map(Formats.readEvent _)
.keyBy(_.session)
.window(ProcessingTimeSessionWindows withGap sessionTimeout)
.apply[SessionEvent] {
(key: String, window: TimeWindow, values: Iterable[Event], out: Collector[SessionEvent]) ⇒
val session =
SessionEvent(
key,
values.head.createdat.toInstant,
values.last.createdat.toInstant,
"end"
)
out.collect(session)
}
.map(Formats.writeSessionEvent _)
.addSink(producer)
env.execute("sessions")
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.