多租戶綜述
多租戶(Multi Tenancy/Tenant)是一種軟件架構,其定義是:
在一台服務器上運行單個應 用實例,它為多個租戶提供服務。
在這種架構上,應用程序被設計成能將自己的數據、配置進行虛擬的分區,以便 每個租戶都感覺到自己是在一個私有的、可定制化的應用實例上工作。
這背後代表的是資源的伸縮能力。即在同樣 硬件配置,不同租戶在數據分離的情況下,共享同樣的應用程序,還隨著租戶數量的提升,應用程序的水平擴展,並維持著 類似的性能指標(一致響應時間等)。這同時意味著資源使用效率的提升,以及節省 IT 資產的投入。
在共享與安 全之間取得平衡,是多租戶架構最主要的關注點。更多的資源共享有益於靈活性的上升和總體成本的下降,但單個租戶的安 全性需求要有額外的技術手段來保證。
多租戶的設計牽涉到兩層:
數據
應用 / 平台
數據層的多租戶能力是一個很大的主題,主要是指不同的租戶如何共享或分離數據,並滿足安全性。本文則主要關注的 是應用 / 平台層的多租戶規范與方案。
Java PaaS 的多租戶概況
Java 平台已經在 J2EE 中提供了部分多租 戶能力。作為 Oracle 要給 Java 平台提供 PaaS 的目標中的一部分,多租戶特性在 Java EE 7 最初的規范中有多處體現 ,見表 1。
表 1. Java EE 7 中涉及多租戶的 JSR
Java EE 7 對 PaaS 模型支持的規范要求:對 PaaS 環境中的同一個 PaaS 應用能夠被多個租戶使用,每個租戶使用不同的應用程序實例,同時又能共享資源。
PaaS 規范中要求每個租戶都有一個 tenantId,這個 ID 對於某個 PaaS 供應商的全部租戶來說,是唯一的。 sevlet 容器可以將外部請求正確映射到對應的租戶實例,並在隨後的所有業務流程中以 tenantId 為處理的依據,保證不 同租戶所使用資源的隔離。同時租戶的界面等是可以定制化的。
例如帶給 JPA 的影響就包括:
支持共享數 據庫、分離 schema:通過元數據可以對 schema/ 表映射進行重配置。
支持共享數據庫、共享 schema:廠商可以使用 tenantId 實現數據行級別的隔離。
編程模型的影響:將對本地查詢和直接 JDBC 訪問進行限制。
但在 2012 年 8 月 30 號,Oracle 的 Java EE 7 規范主管 Linda Demichiel 在博客中宣布因為雲領域相關的應用方式不夠成熟,以及 Java EE 7 版本的發布壓力,將把 PaaS 和多租戶支持的部分推遲到 Java EE 8(以下翻譯引用自 InfoQ):
盡管 我們的願望很美好,但是在我們日程表中,雲相關的進展仍然很慢。一部分原因在於構建分配(provisioning)、多租戶( multi-tenancy)、彈性(elasticity)等領域以及應用部署部分仍然不成熟;一部分原因是我們保守的做事方式,我們盡 力把事情做‘正確’,但是在開展這項工作時,我們在雲領域仍然缺乏足夠的行業經驗。因此,我們認為,若要提供對標准 化的基於 PaaS 的編程方式和多租戶的完善的支持,就可能會將 Java EE 7 的發布推遲到 2014 年春天。該時間是兩年之 後,比規劃晚了一年。在我們看來,拖得時間太長了。
因此我們向 Java EE 7 專家組提議調整我們的計劃,堅持我 們當前的目標發布日期,而將我們日程表中 PaaS 和多租戶支持的部分推遲到 Java EE 8。”
那麼在 Java 8 中, 與雲相關的最重要的兩個特性就是多租戶與模塊化。具體說就是:
多租戶:指的是在一個 Java 虛擬機(JVM)中安 全運行多個應用的能力。
模塊化:指的是把 JDK 重新組織為一套盡管互相依賴但卻是定義清晰的模塊。Java 開發人員 的一個替代選擇是使用 OSGi。
來自 Red Hat 的 Mark Little 認為下一個 Java 版本支持這兩個特性將使得進行大 規模雲部署變得可行。
同時,Oracle 的規范領導 Linda Demichiel 提到,即使因為雲端應用還沒完全做好標准化 的准備而導致 Java EE 7 被迫放棄 PaaS 部分,但諸如 Oracle、Red Hat、IBM 和 CloudBees 等供應商已經開始提供在雲 上運行 Java EE 程序的能力。
因而本文的剩余部分將試圖對幾種比較流行的 Java 平台解決方案中涉及多租戶的部 分做出闡述。
Cloud JVM
前面提到,預期 Java 8 中對多租戶的支持需要在 JVM 這一層次中做到。那麼它的 細節如何,又原因何在?
對於一個傳統的 J2EE 容器(任意一個應用服務器)來說,它啟動一個 JVM,然後不同的 WEB 應用部署其上,供並發用戶訪問。這已經在概念上接近了多租戶。見圖 1。
圖 1. J2EE 部署圖
但這種結構在實 際中很少被使用到,因為各 Web App 之間沒有隔離機制。對於多數 J2EE 應用來說,上圖的模式通常被簡化為僅有一個應 用,運行在一個 JVM 上,後台一個數據庫 /schema 為之服務,即“one app per app-server per JVM”。但無論哪種模式 ,都依然離多租戶的數據 / 配置隔離以及共享需求,和應用程序的水平擴展能力需求相差甚遠。主要原因在於:
Web 應用彼此的運行時內存空間不是獨立的;
數據庫是分離的,但缺乏共享;
對加載的類無法完全彼此分開;
當需要水平擴展時,可以做集群(cluster)和負載平衡,但這種架構下存在很多技術難點,例如 session 復制就相當 脆弱。
另外傳統的 J2EE 應用也與雲時代的多租戶在業務模式上也有不同。傳統 J2EE 模式強調的是多用戶,本身的應用實例 是一個;而多租戶則在同一個應用實例上做了復制,是多個應用實例(彼此內容相同),一個實例服務於一個租戶。
隨之而來的是傳統的 J2EE 為了應對多租戶場景,會為每一個應用啟動一個 JVM,每個 JVM 彼此獨立,消耗各自的 資源。這無法完美實現多租戶的一個典型特征:在最大共享資源的基礎上做好各實例間的隔離。
因此,現在有一些 IT 廠商做出了自己的嘗試。Waratek 是澳大利亞的一家公司,他們將在新南威爾士大學期間進行的一個關於元循環(meta -circular,是指使用語言自身來實現其運行環境)抽象機解釋器和動態編譯框架的項目進行了商業化,開發出 Waratek Cloud VM。這個基於 Java 語言自身開發的虛擬機給運行在虛擬架構上的 Java 程序提供了一種高密集度宿主模型,即多個 應用程序可以同時運行在單個的 JVM 上,每個應用有自己的 Java 虛擬容器(Java Virtual Container,JVC)。如圖 2。
圖 2. Waratek Cloud VM
Waratek 在 JVM 內部構建了一個多租戶的虛 擬容器架構,每個 JVC 包含一個完全隔離又可控的共享 JVM 鏡像——它是一個元循環的虛擬機,和其它 JVC 一起分享主 機 VM 的環境(堆、類、JIT)。就如 hypervisor 對物理機一樣,JVC 對 Java 平台也做了虛擬化。它具有以下特點:
輕量級
一個 JVM 可以 host 幾十甚至上千個 VC,每個 VC 的大小可以從 1MB 到數 GB
VC 執行的每一方面都是隔離的,例如 CPU 優先級,內存上限和帶寬限額等
VC 使用的每一方面都是可計量的,例如 CPU 使用了多少 Hz,內存 /IO 使用了多少 byte
VC 提供了像電力千瓦 - 時的計算指標:CPU 消耗了多少 GHz- 時,內存消耗了多少 GB- 時
每個 .war/.ear 都有自己的 VC
每個 VC,有自己的堆空間。Waratek 提供了自動垃圾收集服務,在一台主機上,只有一個垃圾回收器,它負責給多個 VC 上的堆空間進行內存無用對象清理。相比較於多 App/ 多 JVM 模式引起的多個垃圾回收器進程同時工作,Waratek 在 CPU 資源的競用上好很多。
VC 在運行時的內存片彼此隔離則保證了應用間的安全性。傳統的 J2EE 多應用由於堆內 存空間是共用的,很難避免一個正常運行的應用的內存區域被惡意侵占。或者由於一個應用調用了 System.exit(0),導致 同一個 JVM 上所有的應用被迫一起退出。
對於核心的 JDK 庫,每個 VC 不需要重復加載,而是彼此共享,這極大 的簡化了應用的啟動。
單個 VC 的資源可配置和可計量對於雲應用至關重要,這等同於對物理機器和操作系統的虛 擬化後,每個虛機的可配置和可計量。它支持通過對主機的 JVM 進行 JVMTI(Java Virtual Machine Tool Interface)調 用獲取每個 VC 上應用程序的資源耗費情況。
同時,這類 JVC 對於 Scala、Jython 和 JRuby 等運行於 JVM 之上 的語言也是同樣直接支持的,而且由於是二進制代碼級別的兼容,因而無需為遷移到 Cloud VM 而改動程序。
在解決了共享與隔離的問題後,Waratek 甚至可以讓 64 個 JBoss 的應用服務器運行在一個 JVM 之上,這樣的性能很驚人 。
Waratek 公司的這個產品可以在 RHEL 和 CentOS 上安裝。由於它是在 JVM 之上實現的虛擬化,因而不需要再在 操作系統層面安裝任何虛擬化支持。出於測試目的,可以在一台干淨的物理服務器上安裝 Linux,然後僅僅運行一個 JVM, 並配置多個 JVC,每個 JVC 上運行一個不同的應用服務器實例。
Waratek 公司為它的產品申請了約 150 項專利, 其中 50 個已經被授權。目前尚不清楚這些專利會否對 Hotspot、JRockit、J9、Zing 等 JVM 的雲化開發構成影響。
Java PaaS
當前市面上支持 Java 語言的 PaaS 很多,包括 Amazon Elastic Beanstalk、CloudBees、Cloud Foundry、Google App Engine、Red Hat OpenShift、Jelastic、Heroku 等。它們各有特點,例如 GAE 線性擴展能力很強 ,在大規模訪問量時依然有良好性能表現,但它對 Java 程序做了諸多限制,像文件與網絡 IO 包等就不可使用,以及不支 持很多常用的框架(如 Spring、Struts)。Beanstalk 是基於 EC2 的,它提供 Tomcat 實例,並與 Amazon 的 Rest API 集成可訪問後台關系數據庫。在表 2 中給出一些關於它們的具體數據。
以 CloudBees、Jelastic 和 OpenShift 為例, 對於 Java 應用開發人員來說,它們對純 Java 的支持極好:即代碼無需修改,支持流行的 Java 應用服務器。它們也不會 導致平台綁定,而是易於在不同 PaaS 間遷移。
這些 PaaS 的使用模式都比較相似。首先注冊賬號,然後申請應用 程序,獲得免費的配額、域名、代碼庫 URL,再上傳自己的代碼,進行持續集成。
先來看一下通用的多租戶,從 SaaS 角度講,多租戶牽涉到多個層面:底層硬件、操作系統、應用服務器、數據層、應用代碼等。每個層面的虛擬化策略 ,甚至是沒有任何虛擬化僅僅是邏輯上的分離策略,都是這個架構的一部分。
PaaS 的多租戶主要體現在應用服務器 這個層面,又有兩類部署模型:
專用容器部署:一個租戶應用有一個或多個專用的 Java 應用服務器,應用對容器 是一對多的關系。
共享容器部署:多個租戶應用共享一組 Java 應用服務器,每個 Java 容器為不止一個租戶提供服務 。應用對容器是多對多的關系。
第一種模式是比較傳統的租戶模式,它在安全性隔離上做的很好,定義了一個租戶 所能訪問的資源,應用本身修改小或不用修改,但不夠靈活。而對於第二種共享容器多租戶模型來說,通常使用基於 OSGI 的分區、租戶資源上下文、和租戶組件的按需加載來共享 JVM 資源,能有更低的成本和更高的靈活性,但需要程序上相應 的變化。總體來說,決定采用哪種租戶架構,還要有更多的考慮。
Jelastic 使用的是基於容器的虛擬化方案,這與 傳統基於虛機的方式不同。(若不考慮 PHP)它是一個 Java 的宿主系統,對於雲用戶來說,他們得到的是 J2EE 容器 (Tomcat、Glassfish、Jetty)。顯而易見,多租戶的實現依賴於容器的實例數量,即每個應用程序都是彼此獨立的,租戶 A 的應用所在的 JVM 不同於租戶 B,包括後台的數據庫也各不相同。這個隔離的粒度是 App Server 級別的(當然一個租 戶擁有多個容器實例也很常見)。
順帶一提的是 Jelastic 資源管理方式的不同,即它獨特的自動垂直擴展 (automatic vertical scaling)能力:基於應用的負載狀況,動態分配 RAM 和 CPU,當負載增多時,系統會主動給應用 增加資源,而負載減少時,將資源自動返回給操作系統。其背後的機制是在 Java 7 中首先導入並在 Java 6 update 中也 加入的 G1(Garbage First)垃圾收集器。
Red Hat 的 OpenShift 使用了一種“multi-tenant in the OS”(而不 是“multi-tenant hypervisor”)的方法,它采用了兩層多租戶機制:
第一層:多個虛機運行在一台物理機上
第二層:多個應用運行在一個虛機上
具體說,就是利用 RHEL 操作系統自身的控制組和 SELinux 來實現隔離的安全 機制;用 RHEL 的資源管理實現多租戶環境設置;用 RHEV(Red Hat Enterprise Virtualization)實現虛擬化;用 JBoss 中間件實現 J2EE 全支持。OpenShift 的基礎就是 RHEL。
那麼從 Java 應用的角度來看,它的多租戶體現在多個 RHEL 實例 + 運行在 JBoss 上的多個應用組合上。這種 RHEL 操作系統級別的虛擬化方案比基於 hypervisor 的虛擬化方 案強在無需硬件層面的虛擬能力支持,沒有額外開銷,但弱點是不夠靈活,難以支持其它 OS,例如 windows。
現狀 與展望
多租戶對成本的節省是很顯著的,尤其是對於一些分布在不同時區的大企業尤其如此。其內部數據中心的硬 件資源利用率能達到很高(例如 70%~80%)的程度。
傳統的租戶實現通常是專用的現有的 PaaS 在多租戶實現上主 要是依賴於操作系統或者 Java 容器,同時在底層也常常依賴於 IaaS,多租戶的能力和虛擬化的目標(包括了硬件、OS、 應用服務器、數據庫等)相關。但類似於 Waratek 在 JVM 的虛擬化嘗試則是最近的趨勢,它對 PaaS 層面的多租戶支持提 升了資源的利用效率。Oracle 注意傾聽了 PaaS 廠商對雲平台的建議,我們期待在 Java EE 8 中能看到這部分功能。