Pulsar與Rocketmq、Kafka、Inlong-TubeMQ,誰才是消息中間件的王者?

導(dǎo)語?|?Pulsar作為下一代消息中間件的典型代表,在設(shè)計(jì)和實(shí)現(xiàn)上面都具備很好的前瞻性,綜合考量了業(yè)界現(xiàn)存的一些比較常用的、優(yōu)秀的消息中間的架構(gòu)設(shè)計(jì)、適用場景、運(yùn)營中的問題等,如目前用的比較多的Kafka、Rocketmq、Inlong-TubeMQ等。本文僅從設(shè)計(jì)角度出發(fā),說明下Pulsar與Kafka、Rocketmq及騰訊開源的Inlong-TubeMQ在實(shí)現(xiàn)上的幾點(diǎn)區(qū)別和可能遇到的問題,供大家參考。
一、云原生多租戶設(shè)計(jì)
(一)分級命名
Pulsar原生支持多租戶設(shè)計(jì),非常適合作為云產(chǎn)品進(jìn)行管理。Pulsar的topic名稱如下圖所示:
persistent://tenant/namespaces/topic分為四個部分:
第一部分:Domain,表示存儲方式,分為nonpersistent和persistent,對應(yīng)非持久化和持久化存儲;
第二部分:tenant,表示租戶名稱,公司或團(tuán)隊(duì)內(nèi)部使用時,也可以作為部門名稱、業(yè)務(wù)分類等;
第三部分:namespace,表示命名空間,作為租戶內(nèi)部的一個層級劃分;
第四部分:topic名稱,具體的topic。Pulsar支持分區(qū)和非分區(qū)topic。但是,在業(yè)務(wù)側(cè)視角,很難看出是否是分區(qū)topic,需要查看元數(shù)據(jù)或者日志信息。
Kafka/Rocketmq/Inlong-TubeMQ,從設(shè)計(jì)上和管理的角度看,對上云并不是特別友好。Topic管理上完全是平級的,如果需要區(qū)分不同的用戶、不同的部門的topic,需要在運(yùn)營層面做一定的設(shè)計(jì)支持。
(二)多級流控
Pulsar支持Broker級別、Namespace級別、Topic級別的流控,包括生產(chǎn)、消費(fèi)的出入流控,客戶端的連接數(shù),存儲配額等。
Kafka/Rocketmq/Inlong-TubeMQ的流控措施和策略相對來說要少很多,具體可以參考相關(guān)資料。
二、計(jì)算與存儲
(一)Broker狀態(tài)
Pulsar的broker是無狀態(tài)的,這和它的計(jì)算、存儲分離的架構(gòu)設(shè)計(jì)有關(guān),broker端不需要保存任何的元數(shù)據(jù)和消息信息??梢愿鶕?jù)系統(tǒng)的需求,進(jìn)行動態(tài)的擴(kuò)/縮容處理。
Rocketmq broker具備主備的概念,且broker側(cè)本地需要存儲消息。單個broker使用一個邏輯的commitlog文件,以wal的方式寫入消息。(目前,高版本已經(jīng)引入自動主備選主能力和Dledger進(jìn)行計(jì)算與存儲分離處理,有需要的也可以關(guān)注下),所以默認(rèn)方式下,算是一個有狀態(tài)的broker。
另外,Rocketmq的備,僅在主掛掉或者主負(fù)載過高的時候才會提供讀取服務(wù),算是冷備份。這在目前逐步強(qiáng)調(diào)機(jī)器利用率的環(huán)境下,算是一個待優(yōu)化的設(shè)計(jì)點(diǎn)。
Kafka中也有主、備的概念區(qū)分,但是主備是partition維度的。Kafka broker端也需要存儲消息,它的每個分區(qū)會使用wal方式存儲消息,相對Rocketmq而言會多用很多寫FD(即會同時對應(yīng)到多個以wal方式寫入的文件句柄),這塊也是Kafka在broker端分區(qū)總數(shù)過多的時候,性能下降的一個原因。
Inlong-TubeMQ中broker沒有主備的概念,消息僅會存儲在broker本地一份,從存儲角度看Inlong-TubeMQ中的broker算是個有狀態(tài)的。由于消息只會被存儲一份,Inlong-TubeMQ的使用場景會受到一定的限制。但是,Tubemq broker也因此具備很高的處理性能,比較適合容忍少量丟失和需要高性能的應(yīng)用場景,目前公司內(nèi)部在大數(shù)據(jù)場景,有大規(guī)模的應(yīng)用。
(二)集群擴(kuò)展能力
Puslar的服務(wù)器端,分為broker和bookie兩個部署,broker負(fù)責(zé)接入、計(jì)算、拉取、分發(fā)消息等,bookie負(fù)責(zé)消息存儲存儲。broker、bookie均可以按需動態(tài)的進(jìn)行擴(kuò)縮容處理。
其中,bookie存儲過程中的多副本、數(shù)據(jù)條帶化分布處理等均在bookkeeper的客戶端sdk中實(shí)現(xiàn),是一個胖客戶端的邏輯。broker作為bookie的客戶端存在,消息數(shù)據(jù)會總體均勻的分布在bookie集群中。不會出現(xiàn)因?yàn)槟承﹖opic或著某些topic的部分分區(qū),在數(shù)據(jù)大規(guī)模傾斜時,導(dǎo)致部分存儲機(jī)器磁盤使用率過高的問題。當(dāng)然,如果系統(tǒng)需要保存的消息量比較大,擴(kuò)容時可能需要同時擴(kuò)容多臺bookie機(jī)器(寫入的副本個數(shù)的整數(shù)倍)。
此外,bookie集群擴(kuò)容后,系統(tǒng)在寫入新消息的時候會優(yōu)先選用新加入的、負(fù)載低的節(jié)點(diǎn)作為候選節(jié)點(diǎn),在存量節(jié)點(diǎn)不受影響的情況下,將新增消息寫入到新擴(kuò)容的節(jié)點(diǎn)上。
Rocketmq的broker端,擴(kuò)展能力也比較強(qiáng),只要新增主備對到集群中即可。但是需要在擴(kuò)容完畢后,在新增的broker對上面創(chuàng)建對應(yīng)的topic和訂閱組信息。
此外,Rocketmq比較強(qiáng)大的一點(diǎn)是,broker端具備讀、寫權(quán)限控制的能力,可以針對單個topic的單個Queue和broker進(jìn)行讀寫控制,非常便于運(yùn)維操作。
Kafka的broker端,在擴(kuò)所容的時候要略顯麻煩些,使用的時候需要提前評估好容量,如果在運(yùn)營的過程中進(jìn)行擴(kuò)容,需要做部分?jǐn)?shù)據(jù)的遷移操作。
InLong-TubeMQ的broker端,由于是單副本方式,擴(kuò)容非常容易。只需要對新增的broker節(jié)點(diǎn),分配topic即可。這種設(shè)計(jì)可以很好的處理部分topic數(shù)據(jù)比較多,對broker集群產(chǎn)生壓力的場景。也可以針對單個topic擴(kuò)容broker。
三、分區(qū)與存儲、消費(fèi)
(一)分區(qū)與消息存儲
Pulsar、Kafka、Rocketmq、InLong-TubeMQ四者的topic均支持分區(qū)配置,但四者的分區(qū)又有所不同。
Pulsar中Topic的分區(qū)是Topic內(nèi)針對整個集群范圍的,每個分區(qū)topic的分區(qū)數(shù)編號在集群內(nèi)遞增。而每個分區(qū)在內(nèi)部生產(chǎn)、消費(fèi)處理的時候均被作為最小單位的topic進(jìn)行處理,sdk內(nèi)部會針對每個分區(qū)單獨(dú)的創(chuàng)建一個producer/consumer進(jìn)行處理。此外,用戶也可以直接的使用某個分區(qū),給某個具體的分區(qū)生產(chǎn)或消費(fèi)某個具體分區(qū)的消息。
例如,使用客戶端sdk直接訂閱分區(qū)TopicA中的第n個分區(qū),需要使用topic名稱為:persistent://tenant/namespaces/TopicA-paritition-n
當(dāng)然,如無特殊的業(yè)務(wù)場景需求,不建議業(yè)務(wù)方直接這樣使用。可以通過sdk中自定義router的方式進(jìn)行處理。
Pulsar中的每個topic的每個分區(qū)與broker的關(guān)聯(lián)關(guān)系是通過Namespace的bundle機(jī)制進(jìn)行關(guān)聯(lián)的,可以通過loadbalance機(jī)制自動進(jìn)行l(wèi)oad/unload的操作的,也可以通過命令進(jìn)行unload操作,如圖所示:

Namespace下的每個bundle區(qū)間會關(guān)聯(lián)一個broker(這個關(guān)聯(lián)關(guān)系會被loadbalance邏輯修改,同時也可以通過運(yùn)維命令進(jìn)行unload處理),每個topic的每個分區(qū)通過hash運(yùn)算落到相應(yīng)的bundle區(qū)間,進(jìn)而找到當(dāng)前區(qū)間關(guān)聯(lián)的broker。在broker與bundle的關(guān)系發(fā)生變化時,客戶端會有重連操作,會有相應(yīng)的鏈接斷開和重建建立鏈接的日志,這個現(xiàn)象是正常的。
當(dāng)集群內(nèi)broker節(jié)點(diǎn)的個數(shù)比較多的時候,可以通過增加topic的分區(qū)數(shù),同時調(diào)整namespace的bundle數(shù),將topic的分區(qū)更加均勻的分布到所有或者大多數(shù)的broker節(jié)點(diǎn)上,來提升集群針對這個topic的生產(chǎn)/消費(fèi)性能。
此外,Pulsar中的每個Topic下的每個分區(qū)會對應(yīng)一系列的ledger(ledger id是全局唯一的),邏輯的將消息組織起來,存儲到bookie中。
由此可見,Puslar的分區(qū)是個物理上面的劃分,每個分區(qū)單獨(dú)的處理消息的生產(chǎn)、消費(fèi)和存儲。
Rocketmq中的分區(qū)(實(shí)際上是Queue的概念,邏輯劃分)是針對單個broker主/備關(guān)系對的(Rocketmq 的broker 有主/備的區(qū)分),在單個主/備關(guān)系下的broker 內(nèi)遞增。如果需要在集群內(nèi)的多個主/備關(guān)系對的broker間使用相同的topic,需要針對每個主/備關(guān)系對下的broker單獨(dú)創(chuàng)建相同的topic。每個主/備對關(guān)系下的broker上面,相同名稱的topic 的分區(qū)數(shù)可以不同。
Rocketmq的消息數(shù)據(jù)是通過索引方式,被邏輯的劃分到每個Queue的,消費(fèi)者需要通過索引文件從pagcache或者wal方式寫入的commitlog文件中獲取消息。
Kafka中的分區(qū),是針對一組broker的,因?yàn)镵afka中也具有主/備的概念。但是,Kafka的主備關(guān)系是分區(qū)級別的,相同topic的不同分區(qū)的主可能是不同的broker。這樣集群下的每個broker 均可交叉的對外提供讀寫服務(wù)。
InLong-TubeMQ中的分區(qū),與Kafka的類似,但是在存儲的處理上又有很大的不同。Kafka是針對每個分區(qū)單獨(dú)進(jìn)行處理的,而Inlong-TubeMQ是針對每個topic進(jìn)行存儲處理的。
這里對存儲的具體處理的區(qū)別小結(jié)一下:
Pulsar,broker上面不存儲消息,消息使用bookkeeper集群進(jìn)行存儲。
Rocketmq,單個broker采用wal的方式使用邏輯上唯一的一個commitlog文件存儲消息數(shù)據(jù)(高版本支持存儲分離)。
Kafka,單個broker采用wal的方式,針對每個分區(qū)在邏輯上使用一個文件存儲這個分區(qū)上的消息。
InLong-Tubemq,單個broker采用wal的方式,針對每個Topic在邏輯上使用一個文件存儲這個Topic下所有分區(qū)上的消息。
(二)分區(qū)與消費(fèi)者
Pulsar中,每個topic下的每個分區(qū)會與每個訂閱組下的所有消費(fèi)者進(jìn)行關(guān)聯(lián)。這里與Kafka/Rocketmq/InLong-TubeMQ有很大的區(qū)別,如圖下圖所示。

Kafka/Rocketmq/InLong-TubeMQ每個分區(qū)會負(fù)載到一個comsumer上,多出partition個數(shù)的consumer將不會起作用(即多出的消費(fèi)者不能消費(fèi)任何的消息)。而Pulsar這面,每個分區(qū)會與訂閱下的所有消費(fèi)者客戶端進(jìn)行關(guān)聯(lián),broker端會根據(jù)每個消費(fèi)者客戶端的能力,將消息推送給客戶端進(jìn)行消費(fèi)。Pulsar的這種設(shè)計(jì),在很大程度上提高了系統(tǒng)可承載的消費(fèi)能力。業(yè)務(wù)方可以根據(jù)自己的消費(fèi)需求,并行的部署多于分區(qū)個數(shù)的消費(fèi)者。
但是,這種設(shè)計(jì),有利也有弊,不但提高了系統(tǒng)實(shí)現(xiàn)的復(fù)雜度,也為broker端的客戶端管理埋下了隱患,需要運(yùn)營過程中,做好消費(fèi)客戶端個數(shù)、流量等的流控配置,避免因業(yè)務(wù)方使用不當(dāng),引起broker端負(fù)載壓力過大,進(jìn)一步導(dǎo)致broker oom、宕機(jī)等。
此外,Pulsar支持shared、key_share、failover、exclusice四種模式消費(fèi),但不支持廣播模式消費(fèi)消息,這一點(diǎn)與Kafka/Rocketmq/InLong-TubeMQ有比較大的區(qū)別。
(三)分區(qū)與順序消息
目前業(yè)界,如Kafka/Rocketmq/InLong-TubeMQ等實(shí)現(xiàn)順序消息的大致方法是將順序消息,按照順序分組關(guān)鍵字(或?qū)?yīng)的key),在生產(chǎn)的時候,將順序消息分發(fā)到同一個partition中。消費(fèi)時,因?yàn)閜artition與consumer是一對一的關(guān)系,通過簡單的處理即可保證消費(fèi)的順序性。如下圖所示:

但是,這里會有個問題,負(fù)載到同一個partition中的不同分組之間實(shí)際是可以并行消費(fèi)的,順序性僅需要保證在同一個分組內(nèi)即可。如果,消費(fèi)者與partition是一對一的對應(yīng)關(guān)系,順序消費(fèi),效率會比較低。
在Pulsar中,每個分區(qū)與多個消費(fèi)者做關(guān)聯(lián)。在順序消息的場景,生產(chǎn)的時候也是根據(jù)key,將消息負(fù)載到相同的parititon內(nèi)。而消費(fèi)的時候,則是根據(jù)key,按照key的維度,每個key關(guān)聯(lián)到固定的consumer,同一個parititon內(nèi)的不同key的消息,使用不同(如果consumer足夠多)的但唯一的一個consumer進(jìn)行推送和消費(fèi)處理,在很大的程度上提高了順序消息場景下的消費(fèi)性能。如下圖所示:

(四)消息分發(fā)機(jī)制
Puslar采用的是推模式,broker端給消費(fèi)者客戶端推送消息??蛻舳嗽趧?chuàng)建consumer的時候,會配置當(dāng)前consumer 可以接受的消息的最大能力(receiveQueueSize,默認(rèn)1000)。broker端會根據(jù)這個參數(shù),在服務(wù)端給每個consumer初始化對應(yīng)的permit參數(shù),通過對permit的控制,批量給consumer推送消息。
同時,broker端會統(tǒng)計(jì)unack狀態(tài)的消息個數(shù)并進(jìn)行流控處理,當(dāng)推送給單個consumer或整個訂閱組下的unack狀態(tài)的消息達(dá)到一定閾值后,broker端將不再推送任何消息到當(dāng)前消費(fèi)者或整個訂閱下的所有消費(fèi)者(訂閱組維度時,即使有部分的消費(fèi)者有接收能力,broker端也不會在推送消息)。分發(fā)消息時的交互流程,如下圖所示:

Consumer端會在處理的消息個數(shù)達(dá)到receiveQueueSize/2時,向broker端重新發(fā)送一條Flow命令,變更broker端對應(yīng)當(dāng)前consumer的分發(fā)permit值。
而Kafka/Rocketmq/InLong-TubeMQ,消費(fèi)者均采用拉模式獲取消息(Rocketmq是客戶端用long pull的方式實(shí)現(xiàn)的push)。具體細(xì)節(jié)這里不再做過多的敘述,有興趣的同學(xué)可以單獨(dú)查閱下相關(guān)資料。
另外,在消息過濾方面,Rocketmq/InLong-TubeMQ支持服務(wù)器端過濾消息,Kafka支持在客戶端過濾消息,Pulsar社區(qū)版本暫時不支持服務(wù)器端過濾(TDMQ版本支持),服務(wù)器端過濾消息的功能,目前在PIP規(guī)劃和實(shí)現(xiàn)中。
具體細(xì)節(jié)這里不再做過多的敘述,有興趣的同學(xué)可以單獨(dú)查閱下相關(guān)資料。
(五)消息確認(rèn)保存機(jī)制
Kafka/Rocketmq/InLong-TubeMQ在消費(fèi)確認(rèn)的時候,每次上報的是當(dāng)前已經(jīng)消費(fèi)的最小的offset值,broker端針對每個topic的每個分區(qū)下的每個訂閱,保存這個分區(qū)下當(dāng)前訂閱的最小的offset,如下圖所示:

這種實(shí)現(xiàn)方式比較簡單,但是在運(yùn)營過程中,會發(fā)現(xiàn)存在比較嚴(yán)重的缺陷。因?yàn)橄⑹潜慌坷〉娇蛻舳说?,消費(fèi)端有可能已經(jīng)消費(fèi)了后面的大量的消息,只是因?yàn)檩^小的offset的這條消息例如圖中5這個位置,消費(fèi)過程出錯或者消費(fèi)時間比較長,每次消費(fèi)確認(rèn)信息的時候只能上報到5這個位置。表面上看,有大量的消息堆積,其實(shí)可能后面的消息已經(jīng)被消費(fèi)很多了。當(dāng)消費(fèi)者重啟的時候會重新從5這個位置重新拉取一遍消息,這時消費(fèi)者可能要處理大量的重復(fù)消息,如果業(yè)務(wù)側(cè)冪等措施做的不夠健壯,可能會對業(yè)務(wù)造成很大的困擾。
Pulsar中,每個topic的每個分區(qū)是與訂閱組下的所有消費(fèi)者關(guān)聯(lián)的,broker端可以將這個分區(qū)下的消息按批次分發(fā)給每個對應(yīng)的消費(fèi)者,每個消費(fèi)者對接受到的消息進(jìn)行消費(fèi)和確認(rèn)。如果,采用Kafka/Rocketmq/InLong-TubeMQ的確認(rèn)保存方式,很難處理。因此Pulsar另辟蹊徑,如圖所示:

每個分區(qū)下的訂閱通過markDeletePosition保存當(dāng)前完全消費(fèi)的最有一個位點(diǎn)(即這個位置之前的所有消息均已經(jīng)消費(fèi)和確認(rèn)了),使用individualDeletedMessages表示當(dāng)前正在消費(fèi)的消息的確認(rèn)情況,這里不是僅僅的保存一個點(diǎn),而是保存多個范圍,表示markDeletePosition這個位置之后哪些消息范圍內(nèi)的消息已經(jīng)被確認(rèn)了。避免了重啟之后消息被重復(fù)消費(fèi)的問題。
但是,這里也有一個風(fēng)險點(diǎn)。如果,individualDeletedMessages中保存的區(qū)間信息比較多的時候,需要占用大量的內(nèi)存空間,會對broker和bookie存儲造成壓力。因此,我們在使用的時候,需要盡量的將位點(diǎn)連續(xù)的消息,連續(xù)的消費(fèi)和確認(rèn),避免出現(xiàn)大量的確認(rèn)空洞。
四、元數(shù)據(jù)存儲
Pulsar目前依賴Zookeeper做元數(shù)據(jù)的存儲。
Rocketmq使用自己實(shí)現(xiàn)的NameServer做元數(shù)據(jù)。NameServer是無狀態(tài)的、獨(dú)立的,每個節(jié)點(diǎn)之間沒有主、備區(qū)分,全部對外提供服務(wù)。broker在上報元信息的時候,需要向集群內(nèi)每個NameServer節(jié)點(diǎn)上報一份信息。
Kafka正在逐步的做去Zookeeper依賴規(guī)劃和處理。但是,目前元數(shù)據(jù)、選主這塊還是需要依賴Zookeeper。
InLong-TubeMQ使用集中式的方式管理元數(shù)據(jù),broker通過api從后臺服務(wù)器獲取元數(shù)據(jù),對zk有比較弱的依賴。
這里提一下,使用Zookeeper的一個風(fēng)險點(diǎn)。當(dāng)Zookeeper選主階段或集群不可用的時間較長時,如果是強(qiáng)依賴的場景,這個時間段內(nèi)會導(dǎo)致消息中間件集群不可用。
另外,就是Zookeeper只有主節(jié)點(diǎn)能處理寫請求,當(dāng)元數(shù)據(jù)比較多、更新操作比較頻繁時會影響系統(tǒng)的整體性能,在做大規(guī)模集群部署的時候,需要考慮這個風(fēng)險點(diǎn)。
五、小結(jié)
Pulsar作為新一代的消息中間件產(chǎn)品,在設(shè)計(jì)架構(gòu)上了順應(yīng)了當(dāng)前業(yè)界云原生的訴求。同時,Pulsar充分調(diào)研了Kafka/Rocketmq等優(yōu)秀消息中間件的優(yōu)、缺點(diǎn),在實(shí)現(xiàn)上進(jìn)行擴(kuò)展和規(guī)避。
本文主要介紹了Pulsar與Rocketmq/Kafka/InLong-TubeMQ的幾點(diǎn)設(shè)計(jì)和實(shí)現(xiàn)層面與使用方關(guān)系比較大的幾點(diǎn)區(qū)別。
Pulsar的云原生多租戶設(shè)計(jì),非常適合上云和大規(guī)模、多用戶場景下的使用和管理。
Pulsar的topic的單分區(qū)與多個消費(fèi)者關(guān)聯(lián)這種設(shè)計(jì),在很大程度上能夠提升并行的消費(fèi)能力。但是,broker端和consumer端會占用更多的資源,在使用的時候,需要做好流控策略配置和接入管理。避免因?yàn)榭蛻舳藬U(kuò)容導(dǎo)致broker集群掛掉。
Pulsar的按位點(diǎn)區(qū)間保存消費(fèi)確認(rèn)信息的方式,能夠極大的避免重復(fù)消費(fèi)消息的問題。但是,同樣存在確認(rèn)空洞的風(fēng)險,在使用的時候,消費(fèi)方需要盡量按消息的id順序連續(xù)消費(fèi),避免產(chǎn)生大量的確認(rèn)空洞,導(dǎo)致broker、bookie壓力過大。
Pulsar在順序消費(fèi)消息的設(shè)計(jì)上,細(xì)化到了key的維度,將相同partition下的相同key的消息推送給相同的consumer進(jìn)行處理。很大程度上提高了順序消息場景下的消費(fèi)能力。
Pulsar在元數(shù)據(jù)存儲上,目前還是需要依賴Zookeeper,不單單是broker集群,bookkeeper集群也對Zookeeper有很強(qiáng)的依賴性。broker、bookie集群均具備很好的可平行擴(kuò)展能力。但是,Zookeeper集群如果掛掉的話,整個Pulsar集群存在不可用的風(fēng)險,這點(diǎn)需要進(jìn)一步的優(yōu)化處理,在AP和CP之間進(jìn)行取舍。
此外,Pulsar在運(yùn)維層面,具有很好的可平行擴(kuò)展能力和豐富的admin管理接口,原生對運(yùn)維相對友好。但是,也需要進(jìn)一步的周邊生態(tài)的建設(shè)。
最后,簡單的概括下,每款消息中間件產(chǎn)品都有其自身的優(yōu)點(diǎn)、缺點(diǎn)和對應(yīng)的適用場景,選擇一款比較適合自己業(yè)務(wù)團(tuán)隊(duì)需求的產(chǎn)品比較關(guān)鍵。綜合角度來看,目前公司內(nèi)部,新的業(yè)務(wù)還是推薦使用Pulsar,不管是Pulsar的多租戶特性、生產(chǎn)/消費(fèi)設(shè)計(jì),還是內(nèi)部的實(shí)現(xiàn)細(xì)節(jié),都在考慮性能、可靠性及運(yùn)維可操作能力的不斷提升。
?作者簡介
鮑明宇
騰訊高級后臺開發(fā)工程師
騰訊高級后臺開發(fā)工程師,畢業(yè)于東北大學(xué)。目前在騰訊TEG數(shù)據(jù)平臺部,負(fù)責(zé)消息中間件Pulsar、大數(shù)據(jù)接入套件Inlong相關(guān)的開發(fā)工作。
?推薦閱讀
gRPC如何在Golang和PHP中進(jìn)行實(shí)戰(zhàn)?7步教你上手!
詳細(xì)解答!從C++轉(zhuǎn)向Rust需要注意哪些問題?
如何保證MySQL和Redis的數(shù)據(jù)一致性?10張圖帶你搞定!


