前些日子,我還在西溪園區上班的時候,如果不是忙得不可開交,我都會在午飯的時候儘可能選擇一個離所在辦公樓遠一些的食堂吃飯。因為午餐和晚餐是一天的工作中難得的兩個「放風」時間,如果碰到了有趣的話題還能在路上和同事交流一二。
有一次,同事問了我一個問題:「為什麼 Spring Boot 應用傾向於打 fat jar 直接啟動,而集團的應用傾向於打 war 包從應用容器啟動?」當時我從 IT 主流思潮的角度給了一個解釋,大意為 Spring Boot 是 DevOps 時代的產物,集團大多數應用是 Dev 和 Ops 分離時代的產物。
這種說法抽象程度略高,雖然也能做為一種解釋,但是沒能很好地把事情表達完整。於是我把當時的解釋整理完善後,寫下了現在這篇博文。
Java 應用部署於應用容器中,其實是受到 J2EE 的影響,也算是 Java Web 有別於其他 Web 快速開發語言的一大特色。通常我們在交付 Java Web 應用的時候,交付件是一個字尾為 war 的內部目錄結構符合一定規則的 zip 壓縮包,這個壓縮包裡(幾乎)完整打包了 Web 頁面(模板)、Web 站點描述、Java Web 的各個模組的 jar 以及依賴的第三方 jar。運維將這個 war 檔案部署到應用容器中,站點就能被訪問了。
在虛擬機器在資料中心裡開始流行以前,Java 應用是直接部署在物理機上的。但是單一的 Java Web 又很難將一個物理主機的全部資源有效利用,為了節省成本,我們通常會將多個 Java Web 同時部署在一臺物理機上,確切的說,是將多個 war 檔案部署在一個應用容器裡。
在一個應用容器中部署多個 war 檔案,就能實現在一個 Java 虛擬機器程式中為多個站點提供服務,這能有效地節省記憶體資源,特別是在那個記憶體比較金貴的年代,這種特性意義重大,甚至應用容器還能動態地部署和解除安裝 war 檔案而無需重啟 Java 虛擬機器。
剛才我們說 war 檔案是一個 zip 壓縮包,其實我們更常見的做法不是部署這個壓縮包,而是部署 war 檔案解壓之後的目錄。那是一個運維和開發分離的年代,開發交付 war,運維部署 war(解壓之後的目錄)。隨著公司業務飛速發展,Java Web 承載了巨大的流量,應用容器開始暴露一些尋常難以發現的問題,甚至有時候這些問題會導致線上故障。於是漸漸的,開始有團隊專門去維護開源的應用容器,修復漏洞,提升效能。
由於研發團隊交付的是 war 檔案,當應用容器需要更新的時候,運維團隊能夠在研發團隊不需要介入的情況下完成 Java Web 的重新部署。甚至當一些常用的底層框架出現了安全漏洞的時候,運維團隊也能掃描全部機器全部 war 解壓出來的目錄中的 jar,將有問題的依賴替換之後重啟應用完成修復。
隨著硬體效能逐步提升,也隨著虛擬機器技術被資料中心廣泛使用,之前一個物理機上混合部署的十幾個 Java Web,搖身一變成了一個物理機上虛擬出來的十幾個虛擬機器,每個虛擬機器裡部署一個應用容器和一個 Java Web。
虛擬機器技術的廣泛使用,給應用運維帶來了極大的便利,再也不用擔心機器環境被破壞,再也不用擔心應用之間依賴衝突,只需要幾行命令幾個指令碼,一個配置完善的開箱即用的 Linux Server 就唾手可得。再也不用糾結哪些應用可以混合部署哪些應用需要獨立部署,流量低峰期就超賣來壓縮成本,流量高峰到來之前再將虛擬機器飄到空閒主機上避免資源爭搶。
後來開發殺入運維領域,誕生了一種新的工種,DevOps。當開發和運維都是一個團隊甚至一個人的時候,將應用和應用容器分開來部署,就顯得十分繁瑣了。因為無論是升級容器還是升級應用,對於 DevOps 來說,都是一次沒什麼明顯差別的升級任務,最好能用一套統一的部署流程去完成。也許 embedded servlet containers 就是在這種需求背景下誕生的,應用容器不再是獨立於應用之外的容器,而是作為應用的一部分,伴隨應用一起部署和升級。
Spring Boot 就誕生在 DevOps 盛行的這幾年。藉助 embedded servlet containers,使用 Spring Boot 開發的應用將一個 Jetty 或者 Tomcat 嵌入在它的交付件中,整個 Java Web 應用連同應用容器打包成一個 fat jar,只需要一行 java -jar webapp.jar
就能完成應用的啟動,我們甚至都感知不到應用容器的存在,彷彿只是在執行一個普通的 Java Application。於是升級容器的工作,就和升級一個第三方類庫一樣,修改 pom 檔案,打包,釋出,輕而易舉。
再後來,伴隨著以 Docker 為首的一眾容器技術的興起,我們正在漸漸進入 Immutable Infrastructure 的時代。
不可變基礎設施,是 Chad Fowler 於 2013 年提出的一個很有前瞻性的構想:在這種模式中,任何基礎設施的例項(包括伺服器、容器等各種軟硬體)一旦建立之後便成為一種只讀狀態,不可對其進行任何更改。如果需要修改或升級某些例項,唯一的方式就是建立一批新的例項以替換。
在容器時代到來之前,雖然我們已經在 Spring Boot 之類的框架的引導下,將 Java 應用打成了一個 fat jar 來分發和部署,但實際上我們分發到生產環境中的內容,遠不止這個 fat jar。為了讓應用程式碼能夠在不同環境中部署,我們會將各個環境不一致的內容抽取出來,儲存在配置檔案中供 Java Web 應用啟動時讀取,比如資料庫連線串、密碼,比如 ZooKeeper 叢集的 IP 列表。為了能夠動態調節日誌等級和格式,我們還會單獨為 logback 等日誌器提供配置檔案,還要監聽這個日誌配置的變化。
這些 fat jar 之外的配置,給應用的部署、擴容帶來了外的負擔。容器想要為我們處理這一切。如果我們將配置檔案打包進容器映象中,我們就能得到一個隨時可以部署的映象,應用的部署和擴容變得簡單起來。但是包含配置的映象完全沒有對環境變化的適應能力,在叢集 A 上跑的好好的映象,也許就沒法部署在叢集 B 裡頭。於是我們開始使用環境變數去描述各個環境不一致的內容,在啟動 Java Web 之前先用環境變數渲染出一份適合當前環境的配置。於是,我們又得使用一個配置管理資料庫來管理這許多環境中的許多環境變數,用一箇中心化的 CMDB 去取代之前散落在各個叢集的應用配置。
Java Web 應用部署的方式,從最初的應用容器 + 物理機 + 多應用混合部署,到應用容器 + 虛擬機器 + 獨立部署,再到 fat jar + 虛擬機器,最後是如今的 fat jar + Linux 容器,伴隨著業界運維自動化智慧化的浪潮一路走來,也讓我們看到了工程師從「術業有專攻」向 DevOps 乃至全棧工程師轉變的趨勢。通過提供隨時隨地輕鬆獲取的 API 化的計算資源,雲端計算正在加速這一轉變,雲端計算也讓正處在轉變過程中的工程師的工作越來越輕鬆有趣。
創業去做雲端計算並沒有比之前任何一個時代輕鬆,真正變得容易的是基於雲端計算的創業
很幸運身處這樣一個時代,能夠參與到雲的建設之中,為了無法計算的價值。據可靠訊息,阿里雲 ApsaraDB 管控團隊近期正在招聘,加入團隊就有機會在雲端計算環境下管理和自動化運維海量伺服器,瞭解多機房容災的原理,深度瞭解 MySQL、SQL Server、PostgreSQL、Redis 和 MongoDB 等各種資料庫的原理和實戰應用。我們希望你和我們一樣,具備如下能力:
- 掌握紮實的 Java/Python 基礎,熟悉集合類,I/O 及多執行緒/協程程式設計,理解各種容器類的內部實現
- 三年以上 Java 進行 Web,API 或中介軟體的全流程開發經驗,熟悉 Spring,iBatis,快取,連線池等常見基礎框架的使用、原理和實現
- 熟悉常用設計模式,熟悉基本 JVM 原理、引數及問題排查,掌握 JVM 效能調優的常見方法及故障排查方法
- 熟練掌握 SQL 和 MySQL,對 SQL 優化有一定經驗,掌握事務的基本原理及實現
- 熟練掌握 Linux 下常用的 shell 命令,掌握 Linux 基礎效能指標及線上問題排查與解決方法
- 對分散式系統及分散式儲存理論,如 CAP,一致性雜湊,MVCC 等原理及演算法有一定了解
- 熟悉日常開發流程,熟悉常用開發、除錯工具、程式碼管理工具,如 Git、Maven、Eclipse 等
- 思路清晰,良好的溝通能力與技術學習能力
- 有線上大規模分散式系統開發、部署或運維經驗者優先
- 有 Python、Perl 等其它指令碼語言開發經驗者優先
如果你願意和我們一起打造最優秀的雲資料庫平臺,請不要吝嗇你的簡歷,傳送郵件至 xile@alibaba-inc.com 盡情勾搭吧!