1. 程式人生 > >什麼時候應該將應用程式切分為多個容器?

什麼時候應該將應用程式切分為多個容器?

圍繞著應該將應用程式的哪些部分切分為多個容器以及為什麼要這樣做,存在著很多困惑。我最近對Docker使用者郵箱列表的迴應促成了今天的文章。在這篇文章中我打算評估一個映象化的Java應用程式,它歷史上曾經執行在一個單一的Tomcat伺服器裡,並解釋為什麼我會把它切分為獨立的容器。為了讓事情有趣——我也旨在證明這個動作(比如將應用程式分割為獨立的容器)和資料及(工程)邏輯,而不是簡單地說“有一個原則”,即必須在所有時間都遵守。
讓我們看一個Java應用程式示例,由以下兩部分組成: 基於Struts Web框架構建的一個前端應用 基於Java
EE構建的一個後端REST API
如前所述,這個應用程式歷史上曾經跑在一個Tomcat伺服器裡,兩個元件是通過一個基於REST的API進行通訊的,所以問題變成了:
我應該要將這個應用程式切分成多個容器嗎?
答案是肯定的,我相信這個應用程式應該切分為兩個不同的Docker容器,但這應該經過慎重考慮之後。
而不是“僅僅因為”將應用程式切分成多個容器或試圖堅持一些新奇的原則(比如“每個容器只執行一個程序”)——我建議我們應該通盤考慮專案需求然後做出明智和聰明的決定。是否所有的應用程式都應該切分為多個容器?容器化通過提供一個更簡單的部署策略至少會使你的軟體生涯更便捷。
讓我們在示例應用程式的分析上做些短暫的停留,做一些設計思考:
JVM是多執行緒的,所以沒有必要執行多個Unix/Linux程序。事實上,我認為這是Java工程師理所當然的困惑。從歷史上看,Java開發人員實際上喜歡在同一個JVM裡邊執行多個應用程式,在實踐中,這樣做可以節省相當多的記憶體。此外,Web應用伺服器比如Tomcat是打從一開始就支援在單個JVM上執行多個應用程式。這實際上是執行一個簡單的Java程式相對於Java
EE應用程式(這可能是由多個執行緒和多個不同的程式組成)的主要區別。 在現實中,許多應用在每個容器中使用多個程序,Apache
Web伺服器的Prefork和MPM和模組都在同一個容器中使用多個程序。現代的Web應用具有事件驅動程式設計或反應器模式的特性(例如Nginx),實際衍生了許多子程序。我認為,FastCGI、AIO以及反應器模式的整個理念是將工作分擔給其他程序(或執行緒),而讓核心專注處理I/O。Linux核心是相當擅長子程序排程的,Kubernetes、Swarm和單個的Docker容器不太擅長幹這活。程序(及執行緒)都是有關核心資源分配的,而容器涉及到了叢集資源分配。
執行單容器單程序的“最佳實踐”被廣泛認為是“原則“,但聽起來更多像哲學。作為一名工程師,我想要理解技術元件,並做出合乎邏輯的決定。我認為,這種”最佳實踐“甚至不是普遍的共識,其控制應用程式根源於廣泛缺乏瞭解的Unix是如何工作的。
Linux容器在歷史上有許多種形式,許多實際推薦執行的是在單個容器裡執行多個程序。什麼使得Docker容器與眾不同的呢?Linux容器本質上就是對於系統呼叫的克隆、SElinux和Cgroups,它們是否是LXC或者Docker(通過libcontainer)型別是無關緊要的,因為Linux核心自身就可以處理程序隔離。
在有效的時間之內通過Socket、檔案或者網路等處理通訊,每一個方法都有它各自的優點和缺點。給定應用程式的通訊方式肯定會影響你是否想將您的應用程式切分成多個容器。
程式碼、配置和資料的分離也會影響您的應用程式切分為多個容器的能力。如果你的應用程式具有良好的程式碼、配置和資料的分離能力,將會非常容易切分為多個容器,如果你的應用程式碼非常古老,並且不太好理解,將會對於檔案系統帶來不必要的改變,並且非常難以作切分,注意,下面的方法是非常棒的!你不必重寫你的應用來容器化,而可以通過將你的應用放入一個容器就可以享受Docker容器格式的好處。你可以輕鬆地移動(使用註冊中心服務)和部署(執行docker
run命令)。 好的,有一些Unix應用遇到101錯誤了,讓我們回到示例Java應用的分析:
如上所述的兩個Java元件看起來做的都是不同的事情,一個元件是Web前端,另外一個是API伺服器。既然這些元件做的是不同的事情(比如他們確實是不同的服務),幾乎沒有機會比在相同的JVM裡有效能優勢(當然了,沒有實際的測試效能,我不能100%確定)。
這兩個應用程式使用REST API來進行通訊(而不是使用Socket、共享記憶體或檔案等方式)。
一般來說,如果一個應用程式包含一個API層和一個前端層,對於獨立地擴充套件這些應用就非常有用。比如說如果一個API也被一個移動應用所消費,根據使用者負載進行動態伸縮就很有用,而基於Web的前端就不需要伸縮。相反,如果我擴充套件web前端,我可能還需要擴充套件API伺服器的部分,但每五個Web前端我可能只需要再多一個API伺服器。長話短說,伸縮邏輯複雜,藉助於類似Kubernetes這樣的工具進行獨立的伸縮是非常有用的。
基於這三個單獨的觀察,我推薦將這兩個元件切分為單獨的容器,我還推薦使用容器編排工具比如Kubernets或者OpenShift來將這些服務連線在一起。我不會將這一決定基於所謂的“原則”或“最佳實踐”,而是會基於它的應用架構和某種形式的資訊推理。
這兒的事情變得瘋狂,我提交(給你)一個新的“最佳實踐”,請擊鼓:
是的,如果您的應用程式/服務具有很好的程式碼、配置和資料的隔離,安裝非常清晰(因為安裝指令碼會使整個過程變得困難),提供了一個非常清晰的通訊模式,就非常有意義來切分/分配為單容器執行單個服務。
從根本上說,我建議我們所有人都應該開始更加理性地考慮如何把應用放入容器裡,意識到容器化不僅僅是一個哲學理論,更是可以解決技術痛點問題的。我喜歡容器,並且在所有的時間都願意使用它們,但是也是以一個睿智的方式。我確信人們對於容器化應用的意見和想法,我鼓勵您在下面的評論欄中分享你的想法。