“Serverless(無服務(wù)器)”有很多令人興奮的地方,包括對(duì)其確切含義的爭(zhēng)論(例如,考慮到代碼仍然在某個(gè)服務(wù)器上運(yùn)行,“Serverless”是否是一個(gè)有意義的名稱)。
不管“Serverless”確切定義如何,Serverless的基本思想是通過將開發(fā)人員與執(zhí)行他們創(chuàng)建的編程邏輯的基礎(chǔ)結(jié)構(gòu)分離,達(dá)到簡(jiǎn)化開發(fā)人員生活的目的。
與傳統(tǒng)單體式應(yīng)用程序開發(fā)中的開發(fā)人員的體驗(yàn)不同,在傳統(tǒng)單體式應(yīng)用程序開發(fā)中,開發(fā)人員往往要花費(fèi)大量時(shí)間考慮其代碼如何與整個(gè)應(yīng)用程序的體系結(jié)構(gòu)和操作進(jìn)行集成和交互。
相比之下,Serverless的承諾是,開發(fā)人員只需通過一個(gè)簡(jiǎn)單的API和抽象,專心關(guān)注他們的邏輯實(shí)現(xiàn),而由基礎(chǔ)架構(gòu)和操作團(tuán)隊(duì)負(fù)責(zé)處理和執(zhí)行該邏輯的環(huán)境。
目前市場(chǎng)上已經(jīng)存在不少通用型無服務(wù)器框架,但是,相同的概念也可以應(yīng)用于更具體的技術(shù)支持方面。
現(xiàn)在我們來說一說"流處理"。流處理傳統(tǒng)上是專用流處理引擎(SPE,即“specialized stream processing engines”)的領(lǐng)域,如Apache Storm、Apache Heron 等。這些SPE提供了復(fù)雜的框架和執(zhí)行模型,能夠執(zhí)行各種各樣的處理。
流處理的方法主要基于函數(shù)編程概念(如map、flatmap等)和將處理流編譯成有向無環(huán)圖(DAG)等思想,同時(shí),流處理的方法也融入了許多混合流處理系統(tǒng),包括Apache Spark Streaming、Apache Kafka Streams和Apache Flink。盡管這些框架功能強(qiáng)大且靈活,但大多數(shù)開發(fā)人員都不熟悉這些框架,學(xué)習(xí)起來相當(dāng)繁瑣。另一方面,運(yùn)營(yíng)團(tuán)隊(duì)在生產(chǎn)中管理起來也很復(fù)雜。
總之,復(fù)雜性和開銷一直是數(shù)據(jù)處理中運(yùn)用流技術(shù)的一個(gè)重要障礙。
然而,新技術(shù)正在將無服務(wù)器概念引入流處理領(lǐng)域。在本文中,我們將探討Pulsar函數(shù)如何將無服務(wù)器概念引入Apache Pulsar消息傳遞系統(tǒng)內(nèi)的流處理中。
流處理的方法主要基于函數(shù)編程概念(如map、flatmap等)和將處理流編譯成有向無環(huán)圖(DAG)等思想,同時(shí),流處理的方法也融入了許多混合流處理系統(tǒng),包括Apache Spark Streaming、Apache Kafka Streams和Apache Flink。盡管這些框架功能強(qiáng)大且靈活,但大多數(shù)開發(fā)人員都不熟悉這些框架,學(xué)習(xí)起來相當(dāng)繁瑣。另一方面,運(yùn)營(yíng)團(tuán)隊(duì)在生產(chǎn)中管理起來也很復(fù)雜。
很多數(shù)據(jù)處理應(yīng)用的場(chǎng)景是簡(jiǎn)單和輕量級(jí)的。簡(jiǎn)單的ETL(提取、轉(zhuǎn)換和加載)操作、基于事件的服務(wù)、實(shí)時(shí)聚合和事件路由都是不需要復(fù)雜拓?fù)浠蛱幚砜蚣艿膽?yīng)用場(chǎng)景。
雖然這些應(yīng)用場(chǎng)景可以使用SPE(專用流處理引擎)實(shí)現(xiàn),但開發(fā)人員和用戶一直受到以下問題的困擾:
1.設(shè)置一個(gè)單獨(dú)的流處理集群太復(fù)雜和繁重,尤其是考慮到用戶只需要SPE功能的一小部分時(shí);
2.對(duì)于這種簡(jiǎn)單的處理來說,操作成本太高,這是因?yàn)槌墒斓腟PE有很多特性,以致于它們?cè)诓渴?、監(jiān)控和維護(hù)方面自然具有很高的復(fù)雜性;
3.對(duì)于大多數(shù)簡(jiǎn)單的應(yīng)用場(chǎng)景來說,成熟SPE的API過于復(fù)雜和復(fù)雜,許多SPE都有基于函數(shù)編程模型的API(例如map、flatmap、reduce等),這些API可能是一個(gè)強(qiáng)大的工具,但對(duì)于許多應(yīng)用場(chǎng)景,尤其是如果用戶對(duì)函數(shù)式編程范式不熟悉時(shí),這一方案可能顯得過于復(fù)雜和笨拙。
Pulsar函數(shù)的創(chuàng)建使得在流數(shù)據(jù)上開發(fā)和部署處理邏輯更加容易。其開發(fā)具有以下設(shè)計(jì)目標(biāo)。
1.簡(jiǎn)單API:任何有能力用受支持的語(yǔ)言編寫函數(shù)的人都應(yīng)該能夠在幾分鐘內(nèi)完成工作;
2.多語(yǔ)言:支持Java、Scala、Python、Go和JavaScript等流行編程語(yǔ)言;
3.內(nèi)置狀態(tài)管理功能:為了簡(jiǎn)化開發(fā)人員的體系架構(gòu),應(yīng)該允許在計(jì)算過程中,讓計(jì)算保持狀態(tài)。系統(tǒng)應(yīng)該以穩(wěn)固的方式保持這種狀態(tài),諸如遞增、獲取、存儲(chǔ)和更新功能等基本功能是必需的;
4.托管運(yùn)行時(shí):開發(fā)人員不必?fù)?dān)心在何處以及如何運(yùn)行計(jì)算,開發(fā)人員只需提交他/她的計(jì)算,系統(tǒng)就會(huì)運(yùn)行之:
5.自動(dòng)負(fù)載平衡:托管運(yùn)行時(shí)應(yīng)負(fù)責(zé)為函數(shù)分配工作線程。
6.可調(diào)整:用戶應(yīng)該能夠使用托管運(yùn)行時(shí)調(diào)整函數(shù)實(shí)例的數(shù)量。
7.容錯(cuò):托管運(yùn)行時(shí)還應(yīng)以可靠和容錯(cuò)的方式運(yùn)行開發(fā)人員的計(jì)算,以便最大限度地減少停機(jī)時(shí)間。
8.多租戶:不同的計(jì)算應(yīng)該相互隔離。開發(fā)人員應(yīng)指定其計(jì)算所需的資源量,運(yùn)行時(shí)將強(qiáng)制執(zhí)行這些資源配額。
9.靈活的部署模型:計(jì)算應(yīng)能夠作為線程、進(jìn)程、docker容器等運(yùn)行。此外,它們還應(yīng)支持在Kubernetes等外部調(diào)度程序上運(yùn)行。
什么是Pulsar函數(shù)?
Pulsar函數(shù)是一個(gè)輕量級(jí)的處理框架,位于Apache Pulsar消息傳遞和流媒體平臺(tái)內(nèi)部。Pulsar函數(shù)的靈感不僅來自Apache Heron和Apache Storm等流處理引擎,還受到AWS Lambda和Google云函數(shù)等函數(shù)即服務(wù)(FaaS)產(chǎn)品的影響。
Pulsar函數(shù)可以使用Java、Python等通用語(yǔ)言編寫處理函數(shù),并將這些函數(shù)部署到Pulsar集群,并不需要使用復(fù)雜的SDK。Pulsar負(fù)責(zé)設(shè)置函數(shù)的執(zhí)行環(huán)境,提供彈性支持,并確保遵循消息傳遞保證。處理邏輯可以是在函數(shù)中容納的任何內(nèi)容,包括數(shù)據(jù)轉(zhuǎn)換、動(dòng)態(tài)路由、數(shù)據(jù)豐富(data enrichment)、數(shù)據(jù)分析等。
總之,Pulsar函數(shù)的美妙之處在于,開發(fā)者可以享受SPE(服務(wù)資源調(diào)配環(huán)境,即“Service Provisioning Environment”)的好處,而無需部署SPE。如果開發(fā)者已經(jīng)在使用SPE或仍然需要部署SPE,那么可以輕松地將Pulsar連接到任何流處理引擎(包括Apache Spark Streaming、Apache Storm、Apache Heron或Apache Flink)。
脈沖星函數(shù)的工作原理
Pulsar函數(shù)使用來自一個(gè)或多個(gè)Pulsar主題的數(shù)據(jù),支持使用自定義邏輯處理數(shù)據(jù)。
并且,在必要時(shí)支持使用簡(jiǎn)單的API將結(jié)果寫入其他Pulsar主題。同一個(gè)Pulsar函數(shù)的一個(gè)或多個(gè)實(shí)例能夠執(zhí)行用戶定義的處理邏輯。其中,一個(gè)函數(shù)可以使用提供的狀態(tài)接口來持久化中間結(jié)果,而其他函數(shù)負(fù)責(zé)查詢?cè)摖顟B(tài)以檢索這些結(jié)果。
在最簡(jiǎn)單的情況下,您甚至不需要SDK來實(shí)現(xiàn)Pulsar函數(shù)。例如,在Java中,用戶可以僅實(shí)現(xiàn)只有一個(gè)apply方法的java.util.function.Function接口。下面是一個(gè)Pulsar函數(shù)的示例,該函數(shù)對(duì)消息應(yīng)用了一種簡(jiǎn)單的轉(zhuǎn)換操作(在字符串中添加一個(gè)字符“!”):
import java.util.Function;
public class ExclamationFunction implements Function<String, String> {
public String apply(String input) { return String.format("%s!", input); }
}
如果用戶需要與上下文相關(guān)的信息,例如函數(shù)的名稱,那么用戶可以只實(shí)現(xiàn)PulsarFunction接口而不是Java的Function接口。下面給出一個(gè)相應(yīng)的示例:
public interface PulsarFunction<I, O> {
O process(I input, Context context) throws Exception;
}
Pulsar函數(shù)可以使用多種配置來進(jìn)行部署。下面,我們將展開詳細(xì)討論。
Pulsar函數(shù)部署方案選擇
Pulsar函數(shù)由稱為實(shí)例的執(zhí)行器運(yùn)行。單個(gè)實(shí)例執(zhí)行函數(shù)的一個(gè)副本。Pulsar函數(shù)具有內(nèi)置的并行性,因?yàn)橐粋€(gè)函數(shù)可以有許多實(shí)例,這些實(shí)例的數(shù)量可以在函數(shù)的配置中設(shè)置。
為了最大限度地提高部署靈活性,Pulsar函數(shù)提供了多種執(zhí)行環(huán)境來支持多種部署選項(xiàng),并提供了大量運(yùn)行時(shí)來執(zhí)行用不同編程語(yǔ)言編寫的函數(shù)。當(dāng)前支持以下執(zhí)行環(huán)境:
運(yùn)行時(shí) | 描述? |
進(jìn)程運(yùn)行時(shí) | 每個(gè)實(shí)例都作為一個(gè)進(jìn)程運(yùn)行。 |
Kubernetes / Docker 運(yùn)行時(shí) | 每個(gè)實(shí)例都作為Docker容器運(yùn)行 |
線程運(yùn)行時(shí) | 每個(gè)實(shí)例都作為線程運(yùn)行,這種類型僅適用于Java實(shí)例,因?yàn)镻ulsar Functions框架本身是用Java編寫的 |
每個(gè)執(zhí)行環(huán)境都會(huì)產(chǎn)生不同的成本,并提供不同的隔離保證。
運(yùn)行Pulsar函數(shù)
運(yùn)行Pulsar函數(shù)最簡(jiǎn)單的方法是實(shí)例化一個(gè)運(yùn)行時(shí)和一個(gè)函數(shù),并在本地運(yùn)行它們(本地運(yùn)行模式)。有一個(gè)助手命令行工具使這一點(diǎn)非常簡(jiǎn)單。在本地運(yùn)行模式下,該函數(shù)作為獨(dú)立運(yùn)行時(shí)運(yùn)行,可以由可用的任何進(jìn)程、Docker容器或線程控制機(jī)制進(jìn)行監(jiān)視和控制。
用戶可以手動(dòng)在機(jī)器上生成這些運(yùn)行時(shí),或者使用復(fù)雜的調(diào)度程序(如Mesos/Kubernetes)將它們分布到集群中。以下是在“本地運(yùn)行”模式下啟動(dòng)Pulsar函數(shù)的命令示例:
$ bin/pulsar-admin functions localrun \
--inputs persistent://sample/standalone/ns1/test_src \
--output persistent://sample/standalone/ns1/test_result \
--jar examples/api-examples.jar \
--className org.apache.pulsar.functions.api.examples.ExclamationFunction
用戶還可以在Pulsar集群內(nèi)與代理一起運(yùn)行函數(shù)。在這種模式下,用戶可以向正在運(yùn)行的Pulsar集群“提交”其功能,Pulsar將負(fù)責(zé)在集群中分發(fā)這些功能,并監(jiān)視和執(zhí)行這些功能。
該模型允許開發(fā)人員專注于編寫他們的函數(shù),而不用擔(dān)心管理函數(shù)的生命周期。下面是提交要在Pulsar集群中運(yùn)行的一個(gè)Pulsar函數(shù)的示例:
$ bin/pulsar-admin functions create \
--inputs persistent://sample/standalone/ns1/test_src \
--output persistent://sample/standalone/ns1/test_result \
--jar examples/api-examples.jar \
--className org.apache.pulsar.functions.api.examples.ExclamationFunction \
--name myFunction
另一種選擇是將函數(shù)的整個(gè)配置放置在一個(gè)YAML文件中,如下所示:
inputs: persistent://sample/standalone/ns1/test_src
output: persistent://sample/standalone/ns1/test_result
jar: examples/api-examples.jar
className: org.apache.pulsar.functions.api.examples.ExclamationFunction
name: myFunction
如果開發(fā)者選擇通過YAML方式配置一個(gè)函數(shù)的話,則可以使用更簡(jiǎn)單的create命令:
className: org.apache.pulsar.functions.api.examples.ExclamationFunction
name: myFunction
如果開發(fā)者選擇通過YAML方式配置一個(gè)函數(shù)的話,則可以使用更簡(jiǎn)單的create命令:
Pulsar函數(shù)提供以下功能,可針對(duì)不同的函數(shù)進(jìn)行專門的指定:
1.最多一次(最多一次)
2.至少一次(至少一次)
3.有效一次(有效一次)
其中,有效的一次(Effective once)處理是通過將至少一次(A這意味著,狀態(tài)更新可以發(fā)生兩次,但狀態(tài)更新只能應(yīng)用一次,而任何重復(fù)的狀態(tài)都會(huì)在服務(wù)器端被丟棄。
小結(jié)
通過本文的介紹,我希望能夠激起讀者對(duì)Pulsar函數(shù)的興趣。此外,本文還向讀者展示了Pulsar函數(shù)的擴(kuò)展功能:如何允許開發(fā)者將Pulsar用作處理數(shù)據(jù)流的統(tǒng)一系統(tǒng)。
當(dāng)然,Pulsar函數(shù)還蘊(yùn)藏著更多的能力和可能性:讀者可以在Apache Pulsar網(wǎng)站上了解到更多有關(guān)Pulsar函數(shù)的信息。
譯者介紹
朱先忠,51CTO社區(qū)編輯,51CTO專家博客、講師,濰坊一所高校計(jì)算機(jī)教師,自由編程界老兵一枚。早期專注各種微軟技術(shù)(編著成 ASP.NET AJX、Cocos 2d-X相關(guān)三本技術(shù)圖書),近十多年投身于開源世界(熟悉流行全棧Web開發(fā)技術(shù)),了解基于OneNet/AliOS+Arduino/ESP32/樹莓派等物聯(lián)網(wǎng)開發(fā)技術(shù)與Scala+Hadoop+Spark+Flink等大數(shù)據(jù)開發(fā)技術(shù)。
參考鏈接:
https://dzone.com/articles/an-introduction-to-stream-processing-with-pulsar-f