jvm-sandbox生態(tài)簡介
jvm-sandbox 是 “一種JVM的非侵入式運行期AOP解決方案”,來自于阿里開源。
先講狹義的sandbox,它基于JVMTI來實現(xiàn)jvm字節(jié)碼替換,并基于此進行一層抽象,實現(xiàn)對任意方法,執(zhí)行前、執(zhí)行后、異常時添加使用方想要做的一些動作,因為sandbox對JVMTI做了良好的封裝,所以只要按照sandbox的規(guī)范來寫,添加的代碼都是大家最熟悉的純java代碼。(比如官方的這個例子
)
在廣義的講sandbox生態(tài),sandbox這個能力雖然大大降低了JVMTI的使用門檻也提供了更高級的抽象,但如果止步于此就只能算是一個工具而已。而其作者思路不僅僅局限于此,基于這個能力發(fā)揮了想想空間,其內部開源了一些sandbox的module,又在某些細分的領域里做了更加高級的抽象,其中最具代表性的就是jvm-sandbox-repeater,而且這個生態(tài)已開源,所以我們也可以照貓畫虎開發(fā)自己的module,實現(xiàn)更多的細分領域的模塊開發(fā)。
就像作者說的:做一個底層中臺,讓每一位技術人員都可以在它的基礎上快速的實現(xiàn)業(yè)務功能。
為什么要寫這篇文章
最近對sandbox生態(tài)里開源的一些代碼做了一些研讀,也嘗試做了一些落地,有一些心得、有一些想法,之前也寫了一篇文章做了記錄。
隨著對sanbox生態(tài)體系了解的深入,更加意識到他目前并不是一個可以開箱即用的可落地方案,所以想把自己腦子里的一個整體的藍圖進行一個闡述:在公司內部自己團隊中,如果要充分利用sandbox生態(tài)的能力,整體平臺搭建的藍圖是什么樣的,要做哪些工作,期望對大家一些幫助和靈感。
整體架構

我的設計,整體需要分四層,可以按照由下至上的進行落地,在數(shù)據層
和基礎層搭建完成之后即具備基本可用能力,再向上的模塊管理層和應用層更多的是實現(xiàn)拓展性以及流程化、規(guī)范化、自動化的能力。
數(shù)據層
數(shù)據層要基于大數(shù)據的各種技術,包括:存儲、批處理、流處理、采集等,再向上輸出數(shù)據采集、數(shù)據清洗、數(shù)據存儲、數(shù)據查詢能力。這塊如果是小體量公司,也可以基于mysql數(shù)據庫做小成本落地。當然這塊一般有一定體量的公司大數(shù)據這一塊都是必備的基礎設施,此處不是本文重點,不在詳細展開。
基礎層
基礎層這一塊主要實現(xiàn)如下四個功能:
- sandbox版本管理
- sandbox 運行管理
- sandbox module管理
- sandbox module 運行管理
為什么要去實現(xiàn)這四個能力呢?為了實現(xiàn)更上層的場景,我們需要向不同的集群、不同服務、不同副本植入不同的module,不同的module又有不同的版本,版本更新可能還需要進行灰度,如果不具備對sandbox module的中心化管理能力,后面會比較麻煩。
另外,sandbox本身后續(xù)也會做版本升級,你肯定不想因為升級sandbox版本更新一遍線上所有服務吧?
這塊實現(xiàn)起來有一些需要考慮的點和方案,會詳細進行展開。
基礎層整體架構

sandbox-ota-server
此處套用了物聯(lián)網里的OTA的概念,ota-server是中心化的版本分發(fā)和管理平臺,需要設計好與sandbox-ota-agent之間的協(xié)議,保留好拓展性。我的想法是只需要一個http接口,定時接受ota-agent的心跳請求,服務端這邊可以從心跳請求中取得客戶端基本信息以及sandbox、sandbox-module的checkSum信息;然后基于ota的策略,返回版本更新指令;然后ota-agent這邊會根據返回的指令下載升級包,并進行升級動作。
心跳接口參考:
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"
}
}
當然此處協(xié)議上有許多細節(jié)需要在詳細設計階段進行考慮,比如ota-agent這邊對安裝包的后續(xù)處理要做到通用、可拓展,不能后續(xù)比如有某些復雜的module開發(fā)出來,但不支持升級。此處設計思路上做簡單提醒:
- sanbox可以按照固化模式進行升級
- sandbox-module建議支持zip包和jar包兩種升級模式,zip包模式下可以實現(xiàn)升級配置文件,類似FOTA的場景
- 文件包的放置目錄需要可靈活配置,比如zip包里是否可以放置一個properties文件,約定要文件放置規(guī)則
- ota心跳協(xié)議里query里有一個字段
type=build/running這塊先不要糾結,后面會做解釋
sandbox-ota-agent
ota-agent這一邊,我是基于目前最常見的k8s部署模式進行設計的。
在基于k8s進行部署時,jvm這邊一定會有一個基礎鏡像,這個基礎鏡像原本就是提供了一些基礎的jvm優(yōu)化和配置,而此時我們要做的是開發(fā)一個ota-agent程序,并把程序植入到基礎鏡像中,在程序啟動和構建時可以拉取對應的sandbox和sandbox-module版本。
程序邏輯上主要就是基于上面的協(xié)議,基于返回值對升級包進行升級處理,同事ota-agent也可以提供一些標準的http接口,比如sandbox本身的啟動、停止等功能。
cluster-proxy
這個主要是用來解決跨集群網絡不通所涉及的網絡解決方案,可以是一個7層的網絡代理服務器,在k8s集群里可以通過ingress來做,不過建議和業(yè)務的ingress做好隔離,并對sandbox接口做好鑒權。此處都是純工具使用層面的事情,不展開。
既要考慮運行時的方便又要考慮不留后遺癥
平臺搭建起來后,我們會將各種各樣的module安裝到我們的業(yè)務副本上,如果只基于ATTACH模式進行安裝,那么當服務重啟、版本更新等情況發(fā)生時,我們ATTACH的動作都需要重新再做一遍;這樣一方面會消耗服務器性能,另一方面會對module的生效時間造成一定的窗口期,對于某些敏感module,可能是不能容忍的。比如,我們開發(fā)了一個fastjson安全漏洞修復插件,每次都需要服務啟動完成后20s后才能生效,那么就有可能會給攻擊者以可乘之機。所以設計上需要對這個問題進行考慮。
我的建議是基礎層支持ATTACH模式和AGENT模式并用,既可以在構建時植入module也可以在運行時植入module。具體的模塊編排和協(xié)調由上一層的模塊管理層實現(xiàn),基礎層只是在設計上保留兩種能力。
構建時植入的實現(xiàn)

在源碼變?yōu)殓R像的過程中,會到ota-server拉取一次安裝包(上文里http協(xié)議層query里的參數(shù)type的作用就和這個有關系)。服務啟動后,就不再拉取已安裝過的module了。這樣可以通過agent模式實現(xiàn)jvm進程啟動就具備必要的module,避免運行時通過attach模式安裝造成的滯后、性能開銷等問題。
固化module和臨時module的概念
ota-server里對模塊要有臨時和固化的概念,只有固化的module才會在image build階段裝載到鏡像里。至于一個module什么時候變?yōu)楣袒膍odule,要接受上一層模塊管理層和應用層的控制。在不通的細分領域是不一樣的。比如在安全漏洞修復領域,經過驗證的漏洞修復module就需要變?yōu)楣袒痬odule了;在線上診斷領域臨時加的一些日志,就不需要固化。
另外,我們的固化module可以按照集群、app、甚至副本進行控制,比如有些module可以做到對某一個app進行固化。
模塊管理層
基礎層是一切的基礎,有了這層之后,我們基本就可以具備簡單的使用能力,只是使用方法上不那么平臺化。
模塊管理層,主要是在module層面進行個性化管理,封裝抽象通用的模塊級api供業(yè)務層使用。
同時這一層也是對下層的基礎層管理控制臺頁面的實現(xiàn)層,可以通過頁面對集群內各個服務sandbox版本和運行狀態(tài)、sandbox module版本和運行狀態(tài)、進行頁面化管理。
同時也可以對一些基礎層和數(shù)據層之間的管理配置放到這一層的頁面上進行管理,比如數(shù)據采集規(guī)模查看、數(shù)據采集點管理、數(shù)據清洗進度等。
總之這一層可以做一些業(yè)務層之外的模塊級通用的web頁面,提供模塊管理的窗口。
這一層技術層面設計空間不大,更多的是功能設計的考量,可以隨著使用深度的加強,逐步迭代。
應用層
到了這一層,就是直接面向終端用戶的一層了。這一層的某一個細分領域,可以對標到官方的 repeater-console](https://github.com/alibaba/jvm-sandbox-repeater/tree/master/repeater-console), 但是官方的repeater console太糙了,這一層我覺得每一個公司的使用場景不同,需要結合自己的場景進行考慮。
此處結合repeater場景,談一下我的想法。
官方的repeater功能理解如下:

這個項目,只能說是給大家一個demo,拋磚引玉。
不談技術層面,從功能設計上講,這個demo其實是有一些概念缺失的。
下面我就說一下我的設計想法,此處更多的是功能&流程設計。
概念模型

核心概念至少要包含上圖中的概念,每個服務可以提前配置很多功能點,每一個功能點可以有一份專屬的配置,配置好入口的uri、入口執(zhí)行函數(shù)、需要的子調用插件。
- 功能點可以有最懂功能的產品經理維護
- 功能點配置可以由最熟悉代碼的開發(fā)人員維護
- 錄制批次由測試人員維護
針對功能做好合理的規(guī)劃和拆分,不同的功能由不同的團隊使用,雖然這個是功能設計,但和我們技術設計里的康菲定律真心是異曲同工。
試想,如果上面的功能一股腦全部給測試去做,這個功能平臺只能說是技術上完美落地了,但使用層面落地情況肯定是差強人意的,總體落地效果會大打折扣。
概念模型搞清楚后,就可以梳理功能點清單,然后設計具體的功能點了,這里不再詳細展開。
關于應用層,不同的細分領域,都有很多需要注意的地方;每一個領域,都可以單獨拿出一篇文章來進行展開了。
結束語
sandbox開源生態(tài),給我們提供了很大的想象空間,但如果真的想在公司內部落地,還有很多工作要做。
這部分工作的難點不僅僅只在技術層面、還有功能設計層面的挑戰(zhàn),需要一個技術和產品都過硬的團隊去執(zhí)行,否則還是很難落地的。
當然這個落地的過程,相信還是要付出很大的人力成本的,對一般的小公司來講這種事情只能作為自驅的事項緩慢推進。
這是一篇從宏觀設計調度的文章,目的是給大家一個思路,拋磚引玉。
文章內容和本人精力有限,很難一篇文章說出全部,在此也歡迎斧正和共同探討。
下面是我寫的其他文章,歡迎查閱:
異步編程一:異步編程的魅力
異步編程二:promise模式
異步編程三:reactor模式
異步編程四:協(xié)程
java程序員的kotlin課(一):環(huán)境搭建
java程序員的kotlin課程(二): 高階函數(shù)與泛型的幾個套路
java程序員的kotlin課(N):coroutines基礎
java程序員的kotlin課(N+1):coroutines 取消和超時
java程序員的kotlin課(N+2):suspending函數(shù)執(zhí)行編排
jvm-sandbox-repeater http回放的“陷阱”與源碼研讀
歡迎大家關注我的,不常更新的公眾號,與我保持聯(lián)絡:
