蚂蚁集团网络通信框架 SOFABolt 功能介绍及协议框架解析 | 开源
,有趣實(shí)用的分布式架構(gòu)頻道。
回顧視頻以及 PPT 查看地址見(jiàn)文末。歡迎加入直播互動(dòng)釘釘群 : 30315793,不錯(cuò)過(guò)每場(chǎng)直播。
大家好,我是本期 SOFAChannel 的分享講師丞一,來(lái)自螞蟻集團(tuán),是 SOFABolt 的開(kāi)源負(fù)責(zé)人。今天我們來(lái)聊一下螞蟻集團(tuán)開(kāi)源的網(wǎng)絡(luò)通信框架 SOFABolt 的框架解析以及功能介紹。本期分享將從以下四個(gè)方面展開(kāi):
- SOFABolt 簡(jiǎn)介;
- 基礎(chǔ)通信能力解析;
- 協(xié)議框架解析;
- 私有協(xié)議實(shí)現(xiàn)解析;
SOFABolt 是什么
SOFABolt 產(chǎn)生背景
相信大家都知道 SOFAStack,SOFAStack(Scalable Open Financial Architecture Stack)是一套用于快速構(gòu)建金融級(jí)云原生架構(gòu)的中間件,也是在金融場(chǎng)景里錘煉出來(lái)的最佳實(shí)踐。
SOFABolt 則是 SOFAStack 中的網(wǎng)絡(luò)通信框架,是一個(gè)基于 Netty 最佳實(shí)踐的輕量、易用、高性能、易擴(kuò)展的通信框架,他的名字 Bolt 取自迪士尼動(dòng)畫(huà)《閃電狗》。他一開(kāi)始是怎么在螞蟻集團(tuán)內(nèi)部產(chǎn)生的,我們可以類(lèi)比一下 Netty 的產(chǎn)生原因:
- 為了讓 Java 程序員能將更多的精力放在基于網(wǎng)絡(luò)通信的業(yè)務(wù)邏輯實(shí)現(xiàn)上,而不是過(guò)多的糾結(jié)于網(wǎng)絡(luò)底層 NIO 的實(shí)現(xiàn)以及處理難以調(diào)試的網(wǎng)絡(luò)問(wèn)題,Netty 應(yīng)運(yùn)而生;
- 為了讓中間件開(kāi)發(fā)者能將更多的精力放在產(chǎn)品功能特性實(shí)現(xiàn)上,而不是重復(fù)地一遍遍制造通信框架的輪子,SOFABolt 應(yīng)運(yùn)而生;
這些年,在微服務(wù)與消息中間件在網(wǎng)絡(luò)通信上,螞蟻集團(tuán)解決過(guò)很多問(wèn)題、積累了很多經(jīng)驗(yàn)并持續(xù)進(jìn)行著優(yōu)化和完善,我們把總結(jié)的解決方案沉淀到 SOFABolt 這個(gè)基礎(chǔ)組件里并反饋到開(kāi)源社區(qū),希望能夠讓更多使用網(wǎng)絡(luò)通信的場(chǎng)景受益。目前該組件已經(jīng)運(yùn)用在了螞蟻集團(tuán)中間件的微服務(wù) (SOFARPC)、消息中心、分布式事務(wù)、分布式開(kāi)關(guān)、以及配置中心等眾多產(chǎn)品上。
同時(shí),已有數(shù)家企業(yè)在生產(chǎn)環(huán)境中使用了 SOFABolt,感謝大家的肯定,也希望 SOFABolt 可以給更多的企業(yè)帶來(lái)實(shí)踐價(jià)值。
以上企業(yè)信息根據(jù)企業(yè)用戶 Github 上反饋統(tǒng)計(jì) — 截止 2020.06。
SOFABolt:https://github.com/sofastack/sofa-bolt
SOFABolt 框架組成
SOFABolt 整體可以分為三個(gè)部分:
- 基礎(chǔ)通信能力(基于 Netty 高效的網(wǎng)絡(luò) IO 與線程模型、連接管理、超時(shí)控制);
- 協(xié)議框架(命令與命令處理器、編解碼處理器);
- 私有協(xié)議實(shí)現(xiàn)(私有 RPC 通信協(xié)議的實(shí)現(xiàn));
下面,我們分別介紹一下 SOFABolt 每個(gè)部分的具體能力。
基礎(chǔ)通信能力
基礎(chǔ)通信模型
如上圖所示,SOFABolt 有多種通信模型,分別為:oneway、sync、future、callback。下面,我們介紹一下每個(gè)通信模型以及他們的使用場(chǎng)景。
- oneway:不關(guān)注結(jié)果,即客戶端發(fā)起調(diào)用后不關(guān)注服務(wù)端返回的結(jié)果,適用于發(fā)起調(diào)用的一方不需要拿到請(qǐng)求的處理結(jié)果,或者說(shuō)請(qǐng)求或處理結(jié)果可以丟失的場(chǎng)景;
- sync:同步調(diào)用,調(diào)用線程會(huì)被阻塞,直到拿到響應(yīng)結(jié)果或者超時(shí),是最常用的方式,適用于發(fā)起調(diào)用方需要同步等待響應(yīng)的場(chǎng)景;
- future:異步調(diào)用,調(diào)用線程不會(huì)被阻塞,通過(guò) future 獲取調(diào)用結(jié)果時(shí)才會(huì)被阻塞,適用于需要并發(fā)調(diào)用的場(chǎng)景,比如調(diào)用多個(gè)服務(wù)端并等待所有結(jié)果返回后執(zhí)行特定邏輯的場(chǎng)景;
- callback:異步調(diào)用,調(diào)用線程不會(huì)被阻塞,調(diào)用結(jié)果在 callback 線程中被處理,適用于高并發(fā)要求的場(chǎng)景;
oneway 調(diào)用的場(chǎng)景非常明確,當(dāng)調(diào)用方不需要拿到調(diào)用結(jié)果的時(shí)候就可以使用這種模式,但是當(dāng)需要處理調(diào)用結(jié)果的時(shí)候,選擇使用同步的 sync 還是使用異步的 future 和 callback?都是異步調(diào)用,又如何在 future、callback 兩種模式中選擇?
顯然同步能做的事情異步也能做,但是異步調(diào)用會(huì)涉及到線程上下文的切換、異步線程池的設(shè)置等等,較為復(fù)雜。如果你的場(chǎng)景比較簡(jiǎn)單,比如整個(gè)流程就一個(gè)調(diào)用并處理結(jié)果,那么建議使用同步的方式處理;如果整個(gè)過(guò)程需要分幾個(gè)步驟執(zhí)行,可以拆分不同的步驟異步執(zhí)行,給耗時(shí)的操作分配更多的資源來(lái)提升系統(tǒng)整體的吞吐。
在 future 和 callback 的選擇中,callback 是更徹底的異步調(diào)用,future 適用于需要協(xié)調(diào)多個(gè)異步調(diào)用的場(chǎng)景。比如需要調(diào)用多個(gè)服務(wù),并且根據(jù)多個(gè)服務(wù)端響應(yīng)結(jié)果執(zhí)行邏輯時(shí),可以采用 future 的模式給多個(gè)服務(wù)發(fā)送請(qǐng)求,在統(tǒng)一對(duì)所有的 future 進(jìn)行處理完成協(xié)同操作。
超時(shí)控制機(jī)制
在上一部分的通信模型中,除了 oneway 之后,其他三種(sync、future、callback)都需要進(jìn)行超時(shí)控制,因?yàn)橛脩粜枰陬A(yù)期的時(shí)間內(nèi)拿到結(jié)果。超時(shí)控制簡(jiǎn)單來(lái)說(shuō)就是在用戶發(fā)起調(diào)用后,在預(yù)期的時(shí)間內(nèi)如果沒(méi)有拿到服務(wù)端響應(yīng)的結(jié)果,那么這次調(diào)用就超時(shí)了,需要讓用戶感知到超時(shí),避免一直阻塞調(diào)用線程或者 callback 永遠(yuǎn)得不到執(zhí)行。
在通信框架中,超時(shí)控制必須要滿足高效、準(zhǔn)確的要求,因?yàn)橥ㄐ趴蚣苁欠植际较到y(tǒng)的基礎(chǔ)組件,一旦通信框架出現(xiàn)性能問(wèn)題,那么上層系統(tǒng)的性能顯然是無(wú)法提升的。超時(shí)控制的準(zhǔn)確性也非常重要,比如用戶預(yù)期一次調(diào)用最多只能執(zhí)行3秒,因?yàn)槌瑫r(shí)控制不準(zhǔn)確導(dǎo)致用戶調(diào)用時(shí)線程被阻塞了4秒,這顯然是不能接受的。
SOFABolt 的超時(shí)控制采用了 Netty 中的 HashedWheelTimer,其原理如上圖。假設(shè)一次 tick 表示100毫秒,那么上面的時(shí)間輪 tick 一輪表示800毫秒,如果需要在300毫秒后觸發(fā)超時(shí),那么這個(gè)超時(shí)任務(wù)會(huì)被放到'2'的 bucket 中,等到 tick 到'2'時(shí)則被觸發(fā)。如果一個(gè)超時(shí)任務(wù)需要在900毫秒后觸發(fā),那么它會(huì)被放到如'0'的 bucket 中,并標(biāo)記 task 的 remainingRounds=1,當(dāng)?shù)谝淮?tick 到'0'時(shí)發(fā)現(xiàn) remainingRounds 不等于0,會(huì)對(duì) remainingRounds 進(jìn)行減1操作,當(dāng)?shù)诙?tick 到'0',發(fā)現(xiàn)這個(gè)任務(wù)的 remainingRounds 是0,則觸發(fā)這個(gè)任務(wù)。
如果將時(shí)間輪的一次 tick 設(shè)置為1秒,ticksPerWheel 設(shè)置為60,那么就是現(xiàn)實(shí)時(shí)鐘的秒針,走完一圈代表一分鐘。如果一個(gè)任務(wù)需要再1分15秒后執(zhí)行,就是標(biāo)記為秒針走一輪之后指向第15格時(shí)觸發(fā)。關(guān)于時(shí)間輪的原理推薦閱讀下面這篇論文:
《Hashed and Hierarchical Timing Wheels: data structures to efficiently implement a timer facility》。
快速失敗機(jī)制
超時(shí)控制機(jī)制可以保證客戶端的調(diào)用在一個(gè)預(yù)期時(shí)間之后一定會(huì)拿到一個(gè)響應(yīng),無(wú)論這個(gè)響應(yīng)是由服務(wù)端返回的真實(shí)響應(yīng),還是觸發(fā)了超時(shí)。如果因?yàn)槟承┰驅(qū)е驴蛻舳说恼{(diào)用超時(shí)了,而服務(wù)端在超時(shí)之后實(shí)際將響應(yīng)結(jié)果返回給客戶端了會(huì)怎么樣?
這個(gè)響應(yīng)結(jié)果在客戶端會(huì)被丟棄,因?yàn)閷?duì)應(yīng)的請(qǐng)求已經(jīng)因?yàn)槌瑫r(shí)被釋放掉,服務(wù)端的這個(gè)響應(yīng)會(huì)因?yàn)檎也坏綄?duì)應(yīng)的請(qǐng)求而被丟棄。既然響應(yīng)在請(qǐng)求超時(shí)之后返回給客戶端會(huì)被丟棄,那么在確定請(qǐng)求已經(jīng)超時(shí)的情況下服務(wù)端是否可以不處理這個(gè)請(qǐng)求而直接返回超時(shí)的響應(yīng)給客戶端?——這就是 SOFABolt 的快速失敗機(jī)制。
快速失敗機(jī)制可以減輕服務(wù)端的負(fù)擔(dān),使服務(wù)端盡快恢復(fù)服務(wù)。比如因?yàn)槟承┩獠恳蕾嚨囊蛩貙?dǎo)致服務(wù)端處理一批請(qǐng)求產(chǎn)生了阻塞,而此時(shí)客戶端還在將更多的請(qǐng)求發(fā)送到服務(wù)端堆積在 Buffer 中等待處理。當(dāng)外部依賴恢復(fù)時(shí),服務(wù)端因?yàn)橐幚硪呀?jīng)在 Buffer 中的請(qǐng)求(實(shí)際這些請(qǐng)求已經(jīng)超時(shí),處理這些請(qǐng)求將沒(méi)有業(yè)務(wù)意義),而導(dǎo)致后續(xù)正常的請(qǐng)求排隊(duì)阻塞。加入快速失敗機(jī)制后,在這種情況下可以將 Buffer 中的請(qǐng)求進(jìn)行丟棄而開(kāi)始服務(wù)當(dāng)前新增的未超時(shí)的請(qǐng)求,使的服務(wù)能快速的恢復(fù)。
快速失敗機(jī)制的前提條件是能判斷出一個(gè)請(qǐng)求已經(jīng)超時(shí),而判斷超時(shí)需要依賴時(shí)間,依賴時(shí)間則需要統(tǒng)一的時(shí)間參照。在分布式系統(tǒng)中是無(wú)法依賴不同的機(jī)器上的時(shí)間的,因?yàn)榫W(wǎng)絡(luò)會(huì)有延遲、機(jī)器時(shí)間的時(shí)間會(huì)有偏差。為了避免參照時(shí)間的不一致(機(jī)器之間的時(shí)鐘不一致),SOFABolt 的快速失敗機(jī)制只依賴于服務(wù)端機(jī)器自身的時(shí)鐘(統(tǒng)一的時(shí)間參照),判斷請(qǐng)求已經(jīng)超時(shí)的條件為:
System.currentTimestamp - request.arriveTimestamp > request.timeout
request.arriveTimestamp 為請(qǐng)求達(dá)到服務(wù)端時(shí)的時(shí)間,request.timeout 為請(qǐng)求設(shè)置的超時(shí)時(shí)間,因?yàn)檎?qǐng)求從客戶端發(fā)出到服務(wù)端需要時(shí)間,所以當(dāng)以到達(dá)時(shí)間來(lái)計(jì)算時(shí),如果這個(gè)請(qǐng)求已經(jīng)超時(shí),那么這個(gè)請(qǐng)求在客戶端側(cè)必然已經(jīng)超時(shí),可以安全的將這個(gè)請(qǐng)求丟棄。
具體分布式系統(tǒng)中時(shí)間和順序等相關(guān)的文件推薦閱讀《Time, Clocks, and the Ordering of Events in a Distributed System》,Lamport 在此文中透徹的分析了分布式系統(tǒng)中的順序問(wèn)題。
協(xié)議框架
SOFABolt 中包含的協(xié)議命令如上圖所示。在 RPC 版本的協(xié)議命令中只包含兩類(lèi):RPC 請(qǐng)求/響應(yīng)、心跳的請(qǐng)求/響應(yīng)。RPC 的請(qǐng)求/響應(yīng)負(fù)責(zé)攜帶用戶的請(qǐng)求數(shù)據(jù)和響應(yīng)數(shù)據(jù),心跳請(qǐng)求用于連接的保活,只攜帶少量的信息(一般只包含請(qǐng)求 ID 之類(lèi)的必要信息即可)。
有了命令之后,還需要有命令的編解碼器和命令處理器,以實(shí)現(xiàn)命令的編解碼和處理。RemotingCommand 的處理模型如下:
整個(gè)請(qǐng)求和響應(yīng)的過(guò)程設(shè)計(jì)的核心組件如上圖所示,其中:
-
客戶端側(cè):
- Connection 連接對(duì)象的封裝,封裝對(duì)底層網(wǎng)絡(luò)的操作;
- CommandEncoder 負(fù)責(zé)編碼 RemotingCommand,將 RemotingCommand 按照私有協(xié)議編碼成 byte 數(shù)據(jù);
- RpcResponseProcessor 負(fù)責(zé)處理服務(wù)端的響應(yīng);
-
服務(wù)端側(cè):
- CommandDecoder 分別負(fù)責(zé)解碼 byte 數(shù)據(jù),按照私有協(xié)議將 byte 數(shù)據(jù)解析成 RemotingCommand 對(duì)象;
- RpcHandler 按照協(xié)議碼將 RemotingCommand 轉(zhuǎn)發(fā)到對(duì)應(yīng)的 CommandHandler 處理;
- CommandHandler 按照 CommandCode 將 RemotingCommand 轉(zhuǎn)發(fā)到對(duì)應(yīng)的 RpcRequestProcessor 處理;
- RpcRequestProcessor 按照 RemotingCommand 攜帶對(duì)象的 Class 將請(qǐng)求轉(zhuǎn)發(fā)到用戶的 UserProcessor 執(zhí)行業(yè)務(wù)邏輯,并將結(jié)果通過(guò) CommandDecoder 編碼后返回給客戶端;
私有協(xié)議實(shí)現(xiàn)
內(nèi)置私有協(xié)議實(shí)現(xiàn)
SOFABolt 除了提供基礎(chǔ)通信能力外,內(nèi)置了私有協(xié)議的實(shí)現(xiàn),可以做到開(kāi)箱即用。內(nèi)置的私有協(xié)議實(shí)現(xiàn)是經(jīng)過(guò)實(shí)踐打磨的,具備擴(kuò)展性的私有協(xié)議實(shí)現(xiàn)。
- proto:預(yù)留的協(xié)議碼字段,當(dāng)協(xié)議發(fā)生較大變更時(shí),可以通過(guò)協(xié)議碼進(jìn)行區(qū)分;
- ver1:確定協(xié)議之后,通過(guò)協(xié)議版本來(lái)兼容未來(lái)協(xié)議的小調(diào)整,比如追加字段;
- type:標(biāo)識(shí) Command 類(lèi)型:oneway、request、response;
- cmdcode:命令碼,比如之前介紹的 RpcRequestCommand、HeartbeatCommand 就需要用不同的命令碼進(jìn)行區(qū)分;
- ver2:Command 的版本,用于標(biāo)識(shí)同一個(gè)命令的不同版本;
- requestId:請(qǐng)求的 ID,用于唯一標(biāo)識(shí)一個(gè)請(qǐng)求,在異步操作中通過(guò)此 ID 來(lái)映射請(qǐng)求和響應(yīng);
- codec:序列化碼,用于標(biāo)識(shí)使用哪種方式來(lái)進(jìn)行業(yè)務(wù)數(shù)據(jù)的序列化;
- switch:協(xié)議開(kāi)關(guān),用于標(biāo)識(shí)是否開(kāi)啟某些協(xié)議層面的能力,比如開(kāi)啟 CRC 校驗(yàn);
- timeout:客戶端進(jìn)行請(qǐng)求時(shí)設(shè)置的超時(shí)時(shí)間,快速失敗機(jī)制所依賴的超時(shí)時(shí)間;
- classLen:業(yè)務(wù)請(qǐng)求類(lèi)的的類(lèi)名長(zhǎng)度;
- headerLen:業(yè)務(wù)請(qǐng)求頭的長(zhǎng)度;
- contentLen:業(yè)務(wù)請(qǐng)求體的長(zhǎng)度;
- className:業(yè)務(wù)請(qǐng)求類(lèi)的類(lèi)名;
- header:業(yè)務(wù)請(qǐng)求頭;
- content:業(yè)務(wù)請(qǐng)求體;
- CRC32:CRC校驗(yàn)碼;
實(shí)現(xiàn)自定義協(xié)議
在 SOFABolt 中實(shí)現(xiàn)私有協(xié)議的關(guān)鍵是實(shí)現(xiàn)編解碼器(CommandEncoder/CommandDecoder)及命令處理器(CommandHandler)。
上面是為了在 SOFABolt 中實(shí)現(xiàn)自定義私有協(xié)議鎖需要編寫(xiě)的類(lèi)。SOFABolt 將編解碼器及命令處理器都綁定到 Protocol 對(duì)象上,每個(gè) Protocol 實(shí)現(xiàn)都有一組自己的編解碼器和命令處理器。
在編解碼器中實(shí)現(xiàn)自定義的私有協(xié)議。在設(shè)計(jì)私有協(xié)議時(shí)一定要考慮好協(xié)議的可拓展性,以便在未來(lái)進(jìn)行功能增強(qiáng)時(shí)不會(huì)出現(xiàn)協(xié)議無(wú)法兼容的情況。
完成編解碼之后剩余工作就是實(shí)現(xiàn)處理器。處理器分為兩塊:命令處理入口 CommandHandler 及具體的業(yè)務(wù)邏輯執(zhí)行器 RemotingProcessor。
完成以上工作后,使用 SOFABolt 實(shí)現(xiàn)自定義私有協(xié)議通信的開(kāi)發(fā)工作基本完成了,但是在實(shí)際編寫(xiě)這部分代碼時(shí)會(huì)遇到種種困難及限制,主要體現(xiàn)在以下一些方面:
- 擴(kuò)展性不足:比如在 RpcClient 中默認(rèn)使用了內(nèi)置的編解碼器,且沒(méi)有預(yù)留接口進(jìn)行設(shè)置,當(dāng)使用自定義協(xié)議時(shí)只能繼承 RpcClient 進(jìn)行覆蓋;
- 框架和協(xié)議耦合:比如默認(rèn)提供了 CommandHandler->RemotingProcessor->UserProcessor 這樣的處理模型,但是這個(gè)模型和協(xié)議耦合嚴(yán)重(依賴于 CommandCode 和 RequestCode),導(dǎo)致使用自定義協(xié)議時(shí)只能自己實(shí)現(xiàn) CommandHandler,然后自己在實(shí)現(xiàn)請(qǐng)求的分發(fā)邏輯等,相當(dāng)于要重寫(xiě) CommandHandler->RemotingProcessor->UserProcessor 這個(gè)模型;
- 協(xié)議限制:雖然可以通過(guò)自定義 Encoder 和 Decoder 實(shí)現(xiàn)自定義協(xié)議,但是框架內(nèi)部組織時(shí)都依賴 ProtocolCode,導(dǎo)致需要將 ProtocolCode 加入到協(xié)議中,限制了用戶設(shè)計(jì)私有協(xié)議的自由;
總體而言,當(dāng)前 SOFABolt 提供了非常強(qiáng)大的通信能力和多年沉淀的協(xié)議設(shè)計(jì)。如果用戶需要去適配自己當(dāng)前已經(jīng)在運(yùn)行的私有協(xié)議還有可以完善的地方,根本原因還是在于設(shè)計(jì)之初是貼合這 RPC 框架來(lái)設(shè)計(jì)的(從很多代碼的命名上也能看出來(lái)),所以在協(xié)議和框架的分離上可以做的更好。
總結(jié)
本次分享從 SOFABolt 整體框架的實(shí)現(xiàn)開(kāi)始,介紹了 SOFABolt 的基礎(chǔ)通信模型、超時(shí)控制以及快速失敗機(jī)制,著重分析了私有協(xié)議實(shí)現(xiàn)的示例,總結(jié)而言 SOFABolt 提供了:
- 基于 Netty 的最佳實(shí)踐;
- 基礎(chǔ)的通信模型和高效的超時(shí)控制機(jī)制、快速失敗機(jī)制;
- 內(nèi)置的私有協(xié)議實(shí)現(xiàn),開(kāi)箱即用;
歡迎 Star SOFABolt:https://github.com/sofastack/sofa-bolt
以上就是本期分享的主要內(nèi)容。因?yàn)橹辈r(shí)間有限,關(guān)于 SOFABolt 更詳細(xì)的介紹,可以閱讀「剖析 SOFABolt 框架」系列文章,由 SOFABolt 團(tuán)隊(duì)以及開(kāi)源社區(qū)同學(xué)共同出品:
「剖析 SOFABolt 框架」解析:https://www.sofastack.tech/blog/ 點(diǎn)擊 tag 「剖析 | SOFABolt 框架」
one more thing
SOFABolt 目前也存在可以提升完善的地方,在嘗試實(shí)現(xiàn)完全自定義的私有協(xié)議時(shí)是相對(duì)困難的,需要對(duì)代碼做一些繼承改造。
針對(duì)這個(gè)現(xiàn)狀,我們?cè)凇鞍⒗锇桶途幊讨摹被顒?dòng)中提交了一個(gè) SOFABolt 的課題:“拆分 SOFABolt 的框架和協(xié)議”,希望先通過(guò)拆分框架和協(xié)議,之后再進(jìn)行模塊化的處理,使 SOFABolt 成為一個(gè)靈活的、可拓展的通信框架最佳實(shí)踐!
歡迎大家一起共建來(lái)解決這個(gè)問(wèn)題,讓 SOFABolt 變得更好:
https://github.com/sofastack/sofa-bolt/issues/224
SOFAStack 也歡迎更多開(kāi)源愛(ài)好者加入社區(qū)共建,成為社區(qū) Contributor、Committer(emoji 表情)
SOFACommunity:https://www.sofastack.tech/community/
本期視頻回顧以及 PPT 查看地址
https://tech.antfin.com/community/live/1265
原文鏈接:https://developer.aliyun.com/article/768430?
版權(quán)聲明:本文中所有內(nèi)容均屬于阿里云開(kāi)發(fā)者社區(qū)所有,任何媒體、網(wǎng)站或個(gè)人未經(jīng)阿里云開(kāi)發(fā)者社區(qū)協(xié)議授權(quán)不得轉(zhuǎn)載、鏈接、轉(zhuǎn)貼或以其他方式復(fù)制發(fā)布/發(fā)表。申請(qǐng)授權(quán)請(qǐng)郵件developerteam@list.alibaba-inc.com,已獲得阿里云開(kāi)發(fā)者社區(qū)協(xié)議授權(quán)的媒體、網(wǎng)站,在轉(zhuǎn)載使用時(shí)必須注明"稿件來(lái)源:阿里云開(kāi)發(fā)者社區(qū),原文作者姓名",違者本社區(qū)將依法追究責(zé)任。 如果您發(fā)現(xiàn)本社區(qū)中有涉嫌抄襲的內(nèi)容,歡迎發(fā)送郵件至:developer2020@service.aliyun.com 進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),本社區(qū)將立刻刪除涉嫌侵權(quán)內(nèi)容。總結(jié)
以上是生活随笔為你收集整理的蚂蚁集团网络通信框架 SOFABolt 功能介绍及协议框架解析 | 开源的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 星辰大海:阿里数据体验技术揭秘!
- 下一篇: 同样是查询语言,它和 SQL 竟然有这么