Stateful Functions 2.0 基於Apache Flink的事件驅動數據庫


Stateful Functions 2.0 基於Apache Flink的事件驅動數據庫

原文:https://flink.apache.org/news/2020/04/07/release-statefun-2.0.0.html#event-driven-database-vs-requestresponse-database

應用流式處理的事件驅動應用替換CRUD數據庫應用

2020-4-7, Apache Flink 團隊,宣布了Stateful Functions (StateFun) 2.0正式發布--Stateful Functions第一次作為Apache Flink項目一部分的發布。這是個巨大的里程碑: Stateful Functions 2.0不僅僅是一個API升級,而是基於第一版基於Apache Flink之上構建的事件驅動數據庫(event-driven database)。

Stateful Functions 2.0 使有狀態性和彈性有效的結合在一起,實現了類似AWS Lambada和Kubernetes資源編排工具的快速縮放/縮放到零以及滾動升級的特性。

通過這些特性, Stateful Functions 2.0有效的解決了FaaS被詬病的兩個缺點:狀態一致性和函數間消息交換效率。

事件驅動數據庫

Stateful Functions年初剛加入Apache Flink時,這個項目作為基於Flink的類庫,用於構建通用的事件驅動應用。用可以實現接受和發送消息的函數,並且管理持久化的變量狀態。Flink提供了一個高效的exactly-once狀態和消息的基礎運行時。Stateful Functions 1.0受到FaaS的啟發,結合了流式處理和Actor編程。

Fig.1: A ride-sharing app as a Stateful Functions example.

在2.0版本中,Stateful Functions已經從Flink與JVM中解耦出來,只需通過服務調用他們。這可以使在Faas平台,K8S部署或其他(微)服務上運行函數變為可行。

Flink根據接收的事件通過HTTP或gRPC調用函數,並提供狀態訪問。系統保證每個實體在任何狀態下僅會被消費一次,這樣通過隔離保證了狀態一致性。通過提供狀態訪問作為函數的一部分,函數本身可以被當做無狀態的,函數的管理變得更為簡單,並且帶來了快速縮放,縮放到零,無縫滾動升級等優點。

Fig.2: In Stateful Functions 2.0, functions are stateless and state access is part of the function invocation.

函數可以用任何能處理HTTP請求或者啟動gRPC服務的編程語言。StateFun project 包含了一個輕量級的Python SDK,它能處理請求並分發到聲明的函數。我們的目標是微誒其他語言提供想死的SDK,如Go,JavaScript或者Rust。用戶無需寫任何Flink代碼(或是JVM代碼)。數據的輸入、輸出和函數入口可以通過YAML規范定義。

Fig.3: A module declaring a remote endpoint and a function type.

Fig.4: A Python implementation of a simple classifier function.

Flink進程(Flink JVM)不必執行任何用戶代碼,當然為了優化應用程序性能也可以通過Embedded Functions使用進程。Flink中只需要保存函數的狀態並提供函數間消息傳遞的消息面,小心地分發這些消息/調用事件驅動函數,並保證一致性。而無需執行用戶應用特定的數據流。

實際上,Flink取代了數據庫的角色,但是它更適用於事件驅動的函數和服務。它通過集成狀態存儲,保證了函數或服務間傳遞消息的有狀態性。因此,Stateful Functions 2.0也可以被當做基於Apache Flink的事件驅動數據庫。

事件驅動數據庫與請求/響應數據庫的對比

在傳統的數據庫或者Key/Value存儲(這里稱之為請求/響應數據庫)中,應用需主動發送一個查詢到數據庫(如SQL via JDBC,GET/PUT via HTTP)。然而,在StateFun這類事件驅動數據庫中,這個關系被反轉了:數據庫根據到達的消息來調用函數或服務。這個特性非常適合FaaS或者事件驅動架構的應用。

Fig.5: Stateful Functions 2.0 inverts the relationship between database and application.

基於請求/響應數據庫的應用中,數據庫只負責保存狀態。函數或服務間的通訊通常一個獨立的服務層進行處理。相反,事件驅動數據庫以緊密集成的方式既保存了狀態的存儲,又承擔了消息的傳輸。

與Actor編程模型類似,狀態函數使用了可尋址實體(addressable entities)的概念,這里的實體被定義為一類具有唯一ID的函數。這些可尋址實體擁有這些狀態,它是也消息傳遞的目標。與Actor系統不同的是這些應用邏輯在系統外部,可尋址實體也不在物理內存中存儲,而是Flink中管理的狀態。

狀態和一致性

事件驅動數據庫除了滿足了無狀態應用和FaaS的需求,同時也簡化了一致性狀態的管理。

想想以下這個例子,一個具有兩個入口的的應用,如兩個微服務(Service1, Service2)。Service1被調用更新了數據庫中的狀態,同時發送請求到Service2。 假設這個調用請求失敗。 那么通常情況下,Service1很難知道Service2是否正確的處理並更新了它的狀態。為了解決這個問題,我們引入了很多種技術,如保證服務的冪等性或者重試機制,使用commit/rollback協議,或者其他外部事務調度系統。在應用層解決這些問題就已經足夠復雜了,如果再引入數據庫到這些場景中,應用將變得難以維護。

同樣的場景中,事件驅動數據庫承擔了狀態管理和消息傳遞的責任,以上問題變得很容易解決。假設數據庫的一個分片接收到了初始的消息,並更新了它的狀態,調用了Service1,並將處理過的消息路由到了另外一個分片,它將被分發到Service2。如果這個消息在傳輸過程中發生錯誤,它可能傳輸失敗或成功,然后我們並不能確定。因為數據庫負責狀態管理和消息傳遞,它可以提供通用的解決方案來保證兩個數據的一致性,例如通過事務或者consistent snapshots。應用的函數是無狀態的,他們的調用沒有任何副作用,這也就意味着我們可以重復調用它們,而不用擔心一致性問題。

Fig.6: The event-driven database integrates state access and messaging, guaranteeing consistency.

這也是過去幾年中,我們從流式處理技術開發過程中總結的寶貴經驗:狀態的訪問與更新必須與消息傳遞進行集成。它在狀態訪問和計算瓶頸等場景中帶給你一致性,可擴展性和反壓性。

盡管狀態管理和計算任務被物理的切割開,調度和分發的函數調用依然被集成在狀態管理中,也就是說為了保證一致性,它們的物理位置相同。

Remote, Co-located or Embedded Functions

函數可以根據應用的耦合性,獨立擴展性和性能開銷以不同的方式部署。每個函數模塊都可以不同,一些函數可以遠程運行,而另外一些可以使用嵌入式運行。

遠程函數(Remote Functions)

遠程函數是上文中主要討論的方式,函數被部署在Flink集群之外。狀態管理和消息傳遞層(如Flink進程)和函數層都被可以被單獨部署與縮放。所有函數通過遠程服務終結點進行遠程調用。

遠程

與數據庫提供標准化協議(如ODBC/JDBC等傳統關系數據,基於REST的Key/value存儲)訪問類似,StateFun 2.0通過一個基於HTTP或gRPC的標准協議調用函數和服務。

本地函數(Co-located Functions)

另外一種部署方式被稱為Co-located Functions,函數被運行在與Flink JVM相同的位置。在這種模式下,每個Flink TaskMananger只與“臨近”的函數通信。一個通用的方式就是使用K8S類似的系統將Flink容器和函數容器定義在同一個POD下,它們通過pod的本地網絡進行通信。

這個模式支持不同的編程語言,同時避免了通過服務/網關/負載均衡進行調用,但是無法將狀態和計算單元獨立的縮放。

本地

這個部署模式類似於 Apache Beam’s的適配層和Flink的Python API,他們被部署在無需JVM運行時的環境中。

嵌入式函數(Embedded Functions)

嵌入式函數是Stateful Functions 1.0支持的模式,支持Flink的 Java/Scala流式處理API。函數被部署在JVM中,並消息可以直接調用和訪問狀態。這是最高效的方式,然而僅允許JVM支持語言。

嵌入式函數

以數據庫作為類比, 嵌入式函數有點像存儲過程, 然而更嚴格的講:這里的函數是實現了標准接口的Java/Scala/Kotlin函數。

加載數據到數據庫

當構建一個有狀態應用時,通常不會從一個完全空的數據庫開始。通常,應用有它的初始狀態,例如一個“bootstrap”狀態,或者恢復前一個版本的狀態。當使用數據庫時,我們可以簡單的批量加載這些數據。

同樣的步驟可以通過包含初始狀態的Flink的savepoint實現。Savepoints是分布流式處理應用的狀態快照,將它傳進Flink后,Flink可以這個狀態進行恢復。可以把它們當做數據庫轉儲文件,但是是一個分布式分布式流處理數據庫。在StateFun例子中,savepoint包含了函數的狀態。

如果需要創建Stateful Functions程序的savepoint,請查看StateFun 2.0的 State Bootstrapping API。State Bootstrapping API當前使用了Flink的DataSet API,下一版本中我們計划提供SQL支持。

Try it out and get involved!

We hope that we could convey some of the excitement we feel about Stateful Functions. If we managed to pique your curiosity, try it out — for example, starting with this walkthrough.

The project is still in a comparatively early stage, so if you want to get involved, there is lots to work on: SDKs for other languages (e.g. Go, JavaScript, Rust), ingresses/egresses and tools for testing, among others.

To follow the project and learn more, please check out these resources:

Code: https://github.com/apache/flink-statefun Docs: https://ci.apache.org/projects/flink/flink-statefun-docs-release-2.0/ Apache Flink project site: https://flink.apache.org/ Apache Flink on Twitter: @ApacheFlink Stateful Functions Webpage: https://statefun.io Stateful Functions on Twitter: @StateFun_IO Thank you!

Thank you!

The Apache Flink community would like to thank all contributors that have made this release possible:

David Anderson, Dian Fu, Igal Shilman, Seth Wiesman, Stephan Ewen, Tzu-Li (Gordon) Tai, hequn8128


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM