jvm-sandbox生態(tài)簡(jiǎn)介
jvm-sandbox 是 “一種JVM的非侵入式運(yùn)行期AOP解決方案”,來(lái)自于阿里開(kāi)源。
先講狹義的sandbox,它基于JVMTI
來(lái)實(shí)現(xiàn)jvm字節(jié)碼替換,并基于此進(jìn)行一層抽象,實(shí)現(xiàn)對(duì)任意方法,執(zhí)行前、執(zhí)行后、異常時(shí)添加使用方想要做的一些動(dòng)作,因?yàn)閟andbox對(duì)JVMTI做了良好的封裝,所以只要按照sandbox的規(guī)范來(lái)寫(xiě),添加的代碼都是大家最熟悉的純java代碼。(比如官方的這個(gè)例子
)
在廣義的講sandbox生態(tài),sandbox這個(gè)能力雖然大大降低了JVMTI
的使用門(mén)檻也提供了更高級(jí)的抽象,但如果止步于此就只能算是一個(gè)工具而已。而其作者思路不僅僅局限于此,基于這個(gè)能力發(fā)揮了想想空間,其內(nèi)部開(kāi)源了一些sandbox的module,又在某些細(xì)分的領(lǐng)域里做了更加高級(jí)的抽象,其中最具代表性的就是jvm-sandbox-repeater,而且這個(gè)生態(tài)已開(kāi)源,所以我們也可以照貓畫(huà)虎開(kāi)發(fā)自己的module,實(shí)現(xiàn)更多的細(xì)分領(lǐng)域的模塊開(kāi)發(fā)。
就像作者說(shuō)的:做一個(gè)底層中臺(tái),讓每一位技術(shù)人員都可以在它的基礎(chǔ)上快速的實(shí)現(xiàn)業(yè)務(wù)功能。
為什么要寫(xiě)這篇文章
最近對(duì)sandbox生態(tài)里開(kāi)源的一些代碼做了一些研讀,也嘗試做了一些落地,有一些心得、有一些想法,之前也寫(xiě)了一篇文章做了記錄。
隨著對(duì)sanbox生態(tài)體系了解的深入,更加意識(shí)到他目前并不是一個(gè)可以開(kāi)箱即用的可落地方案,所以想把自己腦子里的一個(gè)整體的藍(lán)圖進(jìn)行一個(gè)闡述:在公司內(nèi)部自己團(tuán)隊(duì)中,如果要充分利用sandbox生態(tài)的能力,整體平臺(tái)搭建的藍(lán)圖是什么樣的,要做哪些工作,期望對(duì)大家一些幫助和靈感。
整體架構(gòu)
我的設(shè)計(jì),整體需要分四層,可以按照由下至上的進(jìn)行落地,在數(shù)據(jù)層
和基礎(chǔ)層搭建完成之后即具備基本可用能力,再向上的模塊管理層和應(yīng)用層更多的是實(shí)現(xiàn)拓展性以及流程化、規(guī)范化、自動(dòng)化的能力。
數(shù)據(jù)層
數(shù)據(jù)層要基于大數(shù)據(jù)的各種技術(shù),包括:存儲(chǔ)、批處理、流處理、采集等,再向上輸出數(shù)據(jù)采集、數(shù)據(jù)清洗、數(shù)據(jù)存儲(chǔ)、數(shù)據(jù)查詢(xún)能力。這塊如果是小體量公司,也可以基于mysql數(shù)據(jù)庫(kù)做小成本落地。當(dāng)然這塊一般有一定體量的公司大數(shù)據(jù)這一塊都是必備的基礎(chǔ)設(shè)施,此處不是本文重點(diǎn),不在詳細(xì)展開(kāi)。
基礎(chǔ)層
基礎(chǔ)層這一塊主要實(shí)現(xiàn)如下四個(gè)功能:
- sandbox版本管理
- sandbox 運(yùn)行管理
- sandbox module管理
- sandbox module 運(yùn)行管理
為什么要去實(shí)現(xiàn)這四個(gè)能力呢?為了實(shí)現(xiàn)更上層的場(chǎng)景,我們需要向不同的集群、不同服務(wù)、不同副本植入不同的module,不同的module又有不同的版本,版本更新可能還需要進(jìn)行灰度,如果不具備對(duì)sandbox module的中心化管理能力,后面會(huì)比較麻煩。
另外,sandbox本身后續(xù)也會(huì)做版本升級(jí),你肯定不想因?yàn)樯?jí)sandbox版本更新一遍線上所有服務(wù)吧?
這塊實(shí)現(xiàn)起來(lái)有一些需要考慮的點(diǎn)和方案,會(huì)詳細(xì)進(jìn)行展開(kāi)。
基礎(chǔ)層整體架構(gòu)
sandbox-ota-server
此處套用了物聯(lián)網(wǎng)里的OTA的概念,ota-server是中心化的版本分發(fā)和管理平臺(tái),需要設(shè)計(jì)好與sandbox-ota-agent之間的協(xié)議,保留好拓展性。我的想法是只需要一個(gè)http接口,定時(shí)接受ota-agent的心跳請(qǐng)求,服務(wù)端這邊可以從心跳請(qǐng)求中取得客戶(hù)端基本信息以及sandbox、sandbox-module的checkSum信息;然后基于ota的策略,返回版本更新指令;然后ota-agent這邊會(huì)根據(jù)返回的指令下載升級(jí)包,并進(jìn)行升級(jí)動(dòng)作。
心跳接口參考:
POST /ota/version?cluster=&app=&instanceId=&type=build/running
REQUEST BODY
{
"sandbox":"checkSum",
"module-x":"checkSum"
}
RESPONSE
{
"code": "",
"data": {
"sandbox":"http://xxxx",
"module-x":"http://xxxxx"
}
}
當(dāng)然此處協(xié)議上有許多細(xì)節(jié)需要在詳細(xì)設(shè)計(jì)階段進(jìn)行考慮,比如ota-agent這邊對(duì)安裝包的后續(xù)處理要做到通用、可拓展,不能后續(xù)比如有某些復(fù)雜的module開(kāi)發(fā)出來(lái),但不支持升級(jí)。此處設(shè)計(jì)思路上做簡(jiǎn)單提醒:
- sanbox可以按照固化模式進(jìn)行升級(jí)
- sandbox-module建議支持zip包和jar包兩種升級(jí)模式,zip包模式下可以實(shí)現(xiàn)升級(jí)配置文件,類(lèi)似FOTA的場(chǎng)景
- 文件包的放置目錄需要可靈活配置,比如zip包里是否可以放置一個(gè)properties文件,約定要文件放置規(guī)則
- ota心跳協(xié)議里query里有一個(gè)字段
type=build/running
這塊先不要糾結(jié),后面會(huì)做解釋
sandbox-ota-agent
ota-agent這一邊,我是基于目前最常見(jiàn)的k8s部署模式進(jìn)行設(shè)計(jì)的。
在基于k8s進(jìn)行部署時(shí),jvm這邊一定會(huì)有一個(gè)基礎(chǔ)鏡像,這個(gè)基礎(chǔ)鏡像原本就是提供了一些基礎(chǔ)的jvm優(yōu)化和配置,而此時(shí)我們要做的是開(kāi)發(fā)一個(gè)ota-agent程序,并把程序植入到基礎(chǔ)鏡像中,在程序啟動(dòng)和構(gòu)建時(shí)可以拉取對(duì)應(yīng)的sandbox和sandbox-module版本。
程序邏輯上主要就是基于上面的協(xié)議,基于返回值對(duì)升級(jí)包進(jìn)行升級(jí)處理,同事ota-agent也可以提供一些標(biāo)準(zhǔn)的http接口,比如sandbox本身的啟動(dòng)、停止等功能。
cluster-proxy
這個(gè)主要是用來(lái)解決跨集群網(wǎng)絡(luò)不通所涉及的網(wǎng)絡(luò)解決方案,可以是一個(gè)7層的網(wǎng)絡(luò)代理服務(wù)器,在k8s集群里可以通過(guò)ingress來(lái)做,不過(guò)建議和業(yè)務(wù)的ingress做好隔離,并對(duì)sandbox接口做好鑒權(quán)。此處都是純工具使用層面的事情,不展開(kāi)。
既要考慮運(yùn)行時(shí)的方便又要考慮不留后遺癥
平臺(tái)搭建起來(lái)后,我們會(huì)將各種各樣的module安裝到我們的業(yè)務(wù)副本上,如果只基于ATTACH模式進(jìn)行安裝,那么當(dāng)服務(wù)重啟、版本更新等情況發(fā)生時(shí),我們ATTACH的動(dòng)作都需要重新再做一遍;這樣一方面會(huì)消耗服務(wù)器性能,另一方面會(huì)對(duì)module的生效時(shí)間造成一定的窗口期,對(duì)于某些敏感module,可能是不能容忍的。比如,我們開(kāi)發(fā)了一個(gè)fastjson安全漏洞修復(fù)插件,每次都需要服務(wù)啟動(dòng)完成后20s后才能生效,那么就有可能會(huì)給攻擊者以可乘之機(jī)。所以設(shè)計(jì)上需要對(duì)這個(gè)問(wèn)題進(jìn)行考慮。
我的建議是基礎(chǔ)層支持ATTACH模式和AGENT模式并用,既可以在構(gòu)建時(shí)植入module也可以在運(yùn)行時(shí)植入module。具體的模塊編排和協(xié)調(diào)由上一層的模塊管理層實(shí)現(xiàn),基礎(chǔ)層只是在設(shè)計(jì)上保留兩種能力。
構(gòu)建時(shí)植入的實(shí)現(xiàn)
在源碼變?yōu)殓R像的過(guò)程中,會(huì)到ota-server拉取一次安裝包(上文里http協(xié)議層query里的參數(shù)type的作用就和這個(gè)有關(guān)系)。服務(wù)啟動(dòng)后,就不再拉取已安裝過(guò)的module了。這樣可以通過(guò)agent模式實(shí)現(xiàn)jvm進(jìn)程啟動(dòng)就具備必要的module,避免運(yùn)行時(shí)通過(guò)attach模式安裝造成的滯后、性能開(kāi)銷(xiāo)等問(wèn)題。
固化module和臨時(shí)module的概念
ota-server里對(duì)模塊要有臨時(shí)和固化的概念,只有固化的module才會(huì)在image build階段裝載到鏡像里。至于一個(gè)module什么時(shí)候變?yōu)楣袒膍odule,要接受上一層模塊管理層
和應(yīng)用層
的控制。在不通的細(xì)分領(lǐng)域是不一樣的。比如在安全漏洞修復(fù)領(lǐng)域,經(jīng)過(guò)驗(yàn)證的漏洞修復(fù)module就需要變?yōu)楣袒痬odule了;在線上診斷領(lǐng)域臨時(shí)加的一些日志,就不需要固化。
另外,我們的固化module可以按照集群、app、甚至副本進(jìn)行控制,比如有些module可以做到對(duì)某一個(gè)app進(jìn)行固化。
模塊管理層
基礎(chǔ)層是一切的基礎(chǔ),有了這層之后,我們基本就可以具備簡(jiǎn)單的使用能力,只是使用方法上不那么平臺(tái)化。
模塊管理層,主要是在module層面進(jìn)行個(gè)性化管理,封裝抽象通用的模塊級(jí)api供業(yè)務(wù)層使用。
同時(shí)這一層也是對(duì)下層的基礎(chǔ)層管理控制臺(tái)頁(yè)面的實(shí)現(xiàn)層,可以通過(guò)頁(yè)面對(duì)集群內(nèi)各個(gè)服務(wù)sandbox版本和運(yùn)行狀態(tài)、sandbox module版本和運(yùn)行狀態(tài)、進(jìn)行頁(yè)面化管理。
同時(shí)也可以對(duì)一些基礎(chǔ)層和數(shù)據(jù)層之間的管理配置放到這一層的頁(yè)面上進(jìn)行管理,比如數(shù)據(jù)采集規(guī)模查看、數(shù)據(jù)采集點(diǎn)管理、數(shù)據(jù)清洗進(jìn)度等。
總之這一層可以做一些業(yè)務(wù)層之外的模塊級(jí)通用的web頁(yè)面,提供模塊管理的窗口。
這一層技術(shù)層面設(shè)計(jì)空間不大,更多的是功能設(shè)計(jì)的考量,可以隨著使用深度的加強(qiáng),逐步迭代。
應(yīng)用層
到了這一層,就是直接面向終端用戶(hù)的一層了。這一層的某一個(gè)細(xì)分領(lǐng)域,可以對(duì)標(biāo)到官方的 repeater-console](https://github.com/alibaba/jvm-sandbox-repeater/tree/master/repeater-console), 但是官方的repeater console太糙了,這一層我覺(jué)得每一個(gè)公司的使用場(chǎng)景不同,需要結(jié)合自己的場(chǎng)景進(jìn)行考慮。
此處結(jié)合repeater場(chǎng)景,談一下我的想法。
官方的repeater功能理解如下:
這個(gè)項(xiàng)目,只能說(shuō)是給大家一個(gè)demo,拋磚引玉。
不談技術(shù)層面,從功能設(shè)計(jì)上講,這個(gè)demo其實(shí)是有一些概念缺失的。
下面我就說(shuō)一下我的設(shè)計(jì)想法,此處更多的是功能&流程設(shè)計(jì)。
概念模型
核心概念至少要包含上圖中的概念,每個(gè)服務(wù)可以提前配置很多功能點(diǎn),每一個(gè)功能點(diǎn)可以有一份專(zhuān)屬的配置,配置好入口的uri、入口執(zhí)行函數(shù)、需要的子調(diào)用插件。
- 功能點(diǎn)可以有最懂功能的產(chǎn)品經(jīng)理維護(hù)
- 功能點(diǎn)配置可以由最熟悉代碼的開(kāi)發(fā)人員維護(hù)
- 錄制批次由測(cè)試人員維護(hù)
針對(duì)功能做好合理的規(guī)劃和拆分,不同的功能由不同的團(tuán)隊(duì)使用,雖然這個(gè)是功能設(shè)計(jì),但和我們技術(shù)設(shè)計(jì)里的康菲定律
真心是異曲同工。
試想,如果上面的功能一股腦全部給測(cè)試去做,這個(gè)功能平臺(tái)只能說(shuō)是技術(shù)上完美落地了,但使用層面落地情況肯定是差強(qiáng)人意的,總體落地效果會(huì)大打折扣。
概念模型搞清楚后,就可以梳理功能點(diǎn)清單,然后設(shè)計(jì)具體的功能點(diǎn)了,這里不再詳細(xì)展開(kāi)。
關(guān)于應(yīng)用層,不同的細(xì)分領(lǐng)域,都有很多需要注意的地方;每一個(gè)領(lǐng)域,都可以單獨(dú)拿出一篇文章來(lái)進(jìn)行展開(kāi)了。
結(jié)束語(yǔ)
sandbox開(kāi)源生態(tài),給我們提供了很大的想象空間,但如果真的想在公司內(nèi)部落地,還有很多工作要做。
這部分工作的難點(diǎn)不僅僅只在技術(shù)層面、還有功能設(shè)計(jì)層面的挑戰(zhàn),需要一個(gè)技術(shù)和產(chǎn)品都過(guò)硬的團(tuán)隊(duì)去執(zhí)行,否則還是很難落地的。
當(dāng)然這個(gè)落地的過(guò)程,相信還是要付出很大的人力成本的,對(duì)一般的小公司來(lái)講這種事情只能作為自驅(qū)的事項(xiàng)緩慢推進(jìn)。
這是一篇從宏觀設(shè)計(jì)調(diào)度的文章,目的是給大家一個(gè)思路,拋磚引玉。
文章內(nèi)容和本人精力有限,很難一篇文章說(shuō)出全部,在此也歡迎斧正和共同探討。
下面是我寫(xiě)的其他文章,歡迎查閱:
異步編程一:異步編程的魅力
異步編程二:promise模式
異步編程三:reactor模式
異步編程四:協(xié)程
java程序員的kotlin課(一):環(huán)境搭建
java程序員的kotlin課程(二): 高階函數(shù)與泛型的幾個(gè)套路
java程序員的kotlin課(N):coroutines基礎(chǔ)
java程序員的kotlin課(N+1):coroutines 取消和超時(shí)
java程序員的kotlin課(N+2):suspending函數(shù)執(zhí)行編排
jvm-sandbox-repeater http回放的“陷阱”與源碼研讀
歡迎大家關(guān)注我的,不常更新的公眾號(hào),與我保持聯(lián)絡(luò):