相信你們都據說過Amazon的AWS。做爲業內最爲成熟的雲服務提供商,其運行規模,穩定性,安全性都已經通過了市場的考驗。時至今日,愈來愈多的應用被部署在了AWS之上。這其中不乏Zynga及Netflix這樣著名的服務。html
然而這一切並無停滯不前:AWS根據市場的變化提供了愈來愈多的內建服務,在下降了用戶成本的同時更是提升了用戶開發的效率。並且隨着各個企業對雲的興趣的不斷增長,網絡上也出現了愈來愈多的有關如何正確高效地使用AWS的討論。數據庫
在這裏,本文將會介紹一系列在雲上建立服務所經常使用的一些方法及設計思路。固然,它們並不侷限於AWS。您一樣也能夠將這裏介紹的各類思路和準則借鑑到您部署在Azure上,阿里雲上,或者其它雲上的應用中。安全
另外,本文不限於公有云,Openstack等私有云上的應用一樣也能夠借鑑本文中所提到的思路和部分功能。服務器
認識雲所帶來的不一樣網絡
在介紹這些準則和最佳實踐以前,咱們首先要坐下來好好想想,咱們部署在雲上的應用須要是什麼樣子的。在雲的早期階段,用戶只能從它那裏獲得一系列虛擬機,以及一些很是有限的附加服務。在那個年代,在雲上承載一個服務和經過物理機承載一個服務的確沒有什麼太大的不一樣。時至今日,雲已經不限於爲用戶提供虛擬機這樣單一的服務了。各個雲所提供的衆多附加功能使得用戶能夠很是靈活地對這些虛擬機進行操做及管理。運維
這致使了最根本的兩點不一樣:對虛擬機的處理方式以及對自動化功能的支持。tcp
在以往的基於物理機的服務中,每臺物理機都是彌足珍貴的。所以服務中的每一個服務實例都須要運維人員的細緻照顧。一旦其中一個服務實例出現了問題,那麼運維人員就須要經過各類方式嘗試對該服務實例進行修復,並將從新恢復到健康狀態的服務實例從新添加到整個服務中。ide
基於雲的解決方案則不須要這麼麻煩。用戶徹底能夠經過雲在幾分鐘內從新部署一臺具備完整功能的虛擬機,所以相應的解決方案也就變成了經過從新建立一臺具備完整功能的虛擬機來替換出現問題的虛擬機。函數
一樣的,若是咱們要增長服務實例,那麼基於物理機的服務經常須要幾個月的準備才能完成。而在雲上,這個過程經常只須要幾分鐘。工具
因此在這裏,咱們再強調一遍您在爲雲設計服務時須要緊緊記住的第一條準則,那就是:在雲上建立虛擬機很是快速,咱們要儘可能利用這種特性。
如今咱們再來看第二點不一樣:對自動化功能的支持。咱們知道,管理一個基於物理機的服務集羣經常是一件很是麻煩的事情,尤以一系列常見的運維操做爲甚。這些運維操做包括服務實例失效處理,添加/移除服務實例,更改服務實例設置等。反過來,市面上常見的雲平臺經常容許用戶標示在特定事件發生時須要被觸發的自動化腳本。若是用戶可以經過這些腳原本控制在特定狀況下須要執行哪些運維操做,那麼對雲上應用的管理就會簡單得多,並且對各類情況的響應也會快速得多。
好,讓咱們來強調第二點:儘可能經過雲平臺所提供的自動化支持來完成咱們所須要的功能。
固然,這只是開發雲上服務的兩個最基本的準則。因爲它們是如此常見,所以不少雲服務提供商都已經將它們以附加功能的形式直接暴露給了用戶。例如各公有云中常見的一個附加功能就是Auto Scaling。亞馬遜的AWS和微軟的Azure都提供了該功能,而私有云解決方案Openstack也有了一個提案。該功能會根據當前Auto Scaling所管理的各虛擬機實例的負載來自動調整其所包含的虛擬機數量,從而保證系統不會產生過載或系統不會有過多的冗餘容量:
而這一切對容量的控制都是自動完成的,基本沒必要由咱們寫任何的監控和控制邏輯。
固然,這種功能還有不少,讓咱們在後面的章節中逐漸爲您展現。
該好好使用的特點功能
在當前業界內,不管是公有云平臺仍是私有云平臺,都會提供一系列特點功能。對這些特點功能的使用經常須要咱們在設計及實現服務時採起和以往不一樣的視角。所以在在本節中,咱們將會介紹這些常見的特點功能以及有關它們的一系列使用經驗。
AMI
第一個要討論的就是AMI。能夠說,這是用戶所最爲熟知可是也最不容易被使用好的一個功能。AMI的全稱是Amazon Machine Image,也便是在AWS上建立新的虛擬機時所須要使用的模板。其不只僅能夠包含虛擬機運行時所須要的操做系統,更能夠包含一系列已經配置完畢的各個組件。一旦用戶經過某個AMI建立了一臺虛擬機,那麼該虛擬機在建立完畢以後將直接擁有這些AMI上所預先配置好的各個組成。
Openstack的Glance也提供了相似的功能。
那麼這些預先配置好的組成都有哪些呢?答案就是,它能夠是您正常運行的虛擬機上所擁有的部分甚至全部組成。試想一下,要讓一個虛擬機實例可以在集羣中正常工做,其經常須要包含操做系統,Servlet Container,服務運行所須要的類庫,服務的源碼以及服務的配置等衆多組成。一個AMI所包含的組成越全面,那麼經由它所建立的虛擬機實例所須要配置,安裝等工做的工做量就越少:
從上圖中能夠看到,若是一個AMI中所包含的組成越全面,那麼經過它來建立一個虛擬機實例所須要的時間就越短。熟悉高可用性等非功能性需求的讀者可能會知道,這就意味着越短的恢復時間以及更高的安全係數。
反過來,一個AMI所包含的組成越全面,那麼它的更改就越爲頻繁。設想一下,若是一個AMI包括了服務運行所須要的源碼,那麼每次對源碼的修改都須要咱們從新制做AMI。這對於一個擁有幾十我的甚至上百我的的開發團隊來講就是一個災難。由於製做AMI也是須要時間和精力的。
那麼一個AMI到底應該包含哪些組成呢?相信讀者們本身也能估計得出:在服務的開發過程當中,AMI所包含的內容將頻繁地發生變化,所以此時AMI所包含的組成應該儘可能的少。而在開發完成以後,AMI的變化將再也不那麼頻繁了,所以爲它建立一個包含較多固定組成的AMI則能夠減小整個系統對各類狀況的響應時間。
Instance Monitoring & Lifecycle Hooks
在知道了這些AMI應該包含哪些組成以後,接下來咱們要考慮的就是如何使用這些AMI了。在系統發生異常或者須要經過建立新的虛擬機實例來提升系統容量時,咱們首先須要經過AMI來建立一個虛擬機實例,而後再在虛擬機實例建立完畢之後執行必要的安裝及配置。僅僅擁有AMI的支持是不夠的,咱們還須要可以監控到這些事件並在虛擬機實例的各個生存期事件發生時對其進行處理,不是麼?
在以往的服務開發過程當中,監控系統的設計不多被軟件開發人員所重視。畢竟這絕大部分是運維人員所須要負責的事情。而在雲上的應用中,全部這些事件都須要自動化起來。也就是說,與軟件開發人員的距離更近了。
AWS提供的監控系統是CloudWatch(Openstack彷佛也有了一個提案)。其主要的工做原理就是:在AWS上的每種資源都會將其指標定時地保存在相應的Repository中。用戶能夠經過一系列API來讀取這些指標,也能夠經過這些API來保存一系列自定義指標。接下來用戶就能夠經過建立一個Alarm來對這些指標進行偵聽。一旦發現這些指標達到了Alarm所標示的條件,那麼CloudWatch就會將該Alarm發送到Amazon SNS或Auto Scaling Group之上:
講到這裏估計您已經看出來了,監控是雲應用的核心。若是沒有將監控系統放在雲應用的核心位置來考慮,那麼咱們就沒有辦法遵照本文剛開始時候所提到的「儘可能經過雲平臺所提供的自動化支持來完成咱們所須要的功能」這樣一條準則。而某些AWS的附加功能已經爲某些經常使用的組成抽象出了一系列生存期事件。
例如在AWS的Auto Scaling功能中,咱們能夠經過其所包含的Lifecycle Hook來指定建立或移除一臺虛擬機實例時所須要執行的用戶自定義邏輯。讓咱們首先考慮一下Auto Scaling是如何與Cloud Watch協做處理以下圖所示的負載峯值應對方案的:
對於上圖所示的容量變化過程,Auto Scaling與CloudWatch之間的互動將以下所示:
整個運行流程大體以下所示:
並且在其它一些附加功能中,咱們也經常會看到這種對自動化腳本的支持。有些附加功能直接提供了對自動化腳本的支持,如用戶能夠直接在OpsWorks中標示針對特定事件的執行邏輯。而在另外一些組成中,就好比咱們剛剛提到的Auto Scaling對自動化腳本的支持,則是須要多個組成協同配合來完成的。
若是實在沒有找到一個合適的解決您所須要的Hook,那麼最終極的辦法就是在製做您本身的AMI時在裏面放一個Agent,以經過它來執行您的自定義邏輯,不是麼?
虛擬機實例管理
如今咱們已經知道如何經過AMI快速地建立一臺虛擬機,以及如何經過腳原本協調這些虛擬機之間的協同工做。可是這裏還有一個問題,那就是,難道須要咱們手動地一臺臺部署虛擬機,並逐個配置它們麼?
其實並沒必要要。針對這個需求,AWS爲咱們提供了三種不一樣的工具:CloudFormation,Beanstalk以及OpsWorks。
先來看看最爲簡單可是靈活度也最高的CloudFormation。簡單地說,軟件開發人員只須要經過一個JSON格式的模板來描述所須要的全部種類的AWS資源,並將其推送到CloudFormation上便可。在接收到該模板以後,CloudFormation就會根據其所包含的內容來分配並配置資源。例以下面就是一段CloudFormation模板(來自於Amazon官方文檔):
1 { 2 "Resources": { 3 "Ec2Instance": { 4 "Type": "AWS::EC2::Instance", 5 "Properties": { 6 "SecurityGroups": [{ 7 "Ref" : "InstanceSecurityGroup" 8 }], 9 "KeyName": "mykey", 10 "ImageId": "" 11 } 12 }, 13 14 "InstanceSecurityGroup" : { 15 "Type": "AWS::EC2::SecurityGroup", 16 "Properties": { 17 "GroupDescription": "Enable SSH access via port 22", 18 "SecurityGroupIngress": [{ 19 "IpProtocol": "tcp", 20 "FromPort": "22", 21 "ToPort": "22", 22 "CidrIp": "0.0.0.0/0" 23 }] 24 } 25 } 26 } 27 }
略爲熟悉AWS的讀者可能已經可以讀懂上面的代碼所描述的資源組合:建立一個名稱爲「Ec2Instance」的虛擬機實例,以及一個名稱爲「InstanceSecurityGroup」的Security Group。Ec2Instance實例將被置於InstanceSecurityGroup這個Security Group中。
然而咱們能作的不僅是經過JSON文件來描述一些靜態資源,更能夠經過Conditions來指定條件,Fn:FindInMap等函數來執行特定邏輯,更能夠經過cfn-init等helper script來完成軟件安裝,虛擬機配置等一系列動做。只不過CloudFormation更多地關注資源管理這一層面,所以用它對大型服務中的實例進行管理則會略顯吃力。
另外一個工具,Beanstalk,則最適合於在項目的初期使用。在使用Beanstalk建立服務時,咱們只須要上傳該應用的Source Bundle,如WAR包,並提供一系列部署的信息便可。Beanstalk會幫助咱們完成資源分配,服務部署,負載平衡,伸縮性以及服務實例的監控等一系列操做。若是須要對服務進行更新,咱們只須要上傳新版本的Source Bundle並指定新的配置便可。在部署完成之後,咱們還能夠經過一系列管理工具,如AWS Management Console,對這些應用進行管理。
隨着服務的規模逐漸增大,咱們就須要使用更復雜一些的工具了,那就是OpsWorks。在OpsWorks中包含一個被稱爲Layer的概念。每一個Layer包含一系列用於某一特定用途的EC2實例,如一系列數據庫實例。而每一個Layer則依賴於一系列Chef recipe來在特定生存期事件發生時執行相應的邏輯,如安裝軟件包,執行腳本等(沒錯,配置管理軟件Chef)。這些事件有Setup,Configure,Deploy,Undeploy以及Shutdown等。
在Openstack中,您可能須要考慮Heat。它在Openstack中是負責Cloud Orchestration的。
其它工具
好,剩下的就是一些經常使用且容易用對,或者並不很是經常使用或適用於特定領域的功能了。例如咱們能夠經過Route 53所提供的功能實現基於DNS的負載平衡及災難恢復解決方案,經過CloudFront爲咱們的應用添加一個CDN,經過EBS,S3,Glacier等不一樣種類的存儲記錄不一樣種類的數據等。
鑑於本文的定位是一篇綜述性質的文章,所以咱們就再也不花較大精力對它們進行介紹了。畢竟本文的目標就是讓你們意識到雲上服務和基於物理機上的服務之間的不一樣,並可以根據這些不一樣來以正確的方式思考如何搭建一個雲上的服務。
在個人計劃中,後面還會有幾篇和Amazon相關的文章。這些文章抑或是如何以更適合的方式知足服務的非功能性需求,要麼就是對Amazon中的一些較爲類似的功能的概括總結,所以咱們還有機會談到它們。
建立雲服務的最佳實踐
這部分是從我筆記中抽出來的。這些筆記不少都是你們在網絡上討論的總結,並且我也沒有在筆記中逐個記明出處是在哪裏,所以可能沒法按照標準作法給出這些觀點的原始出處。
好,那咱們開始。
考慮全部可能的失效
咱們知道,雲下面有一層是虛擬化層。因此相較於直接運行於物理機上的服務而言,運行在雲上的服務不只僅須要面對物理機的失效,更須要面對虛擬化層的失效,甚至有時雲平臺上某些功能的失效也可能影響咱們服務的運行。所以就雲上的單個虛擬機而言,其發生失效的機率將遠大於物理機。所以在雲上應用所須要遵照的第一條守則就是:要假設全部的組成都有可能失效。
這些失效可能存在於雲上服務的任何地方,甚至咱們都須要考慮雲平臺的數據中心失效的狀況。就以AWS爲例,其所提供的最基本的資源就是虛擬機。虛擬機之間彼此相互隔離。所以在一臺虛擬機出現了問題的時候,其它虛擬機的運行也不會受到任何影響。而在虛擬機之上則是Availability Zone。Availability Zone在Region以內彼此隔離,所以若是其中的一個Availability Zone出現了問題,那麼其它的Availability Zone中的虛擬機仍可以正常工做。而Region則是世界範圍內的相互隔離。若是一個Region出現了問題,那麼其它Region不會受到任何影響。在一般狀況下,整個Region發生宕機的機率其實是微乎其微的。
可是AWS自身在今年內也出現過整個Region失效的狀況。若是軟件開發人員在實現部署在AWS上的服務時心存僥倖,認爲Region宕機的機率很小,那麼在相應的Region宕機時,該服務將沒法爲用戶提供服務。有時候,這種服務中斷是致命的。
因此在實現一個須要承載於AWS上的服務時,咱們必需要考慮:若是虛擬機出現了問題,咱們的應用應該如何處理;若是Availability Zone出現了問題,咱們又應該如何處理;若是整個Region都不能正常工做,那麼咱們又該如何處理?這些問題發生時,咱們應該提供什麼樣的服務?又須要在多少時間內恢復?
做爲一個可選的解決方案,咱們能夠將一個服務部署在多個Availability Zone中,並且在不一樣的Region中擁有一個拷貝。這樣在整個Region失效的狀況下,用戶仍然能夠經過其它Region訪問服務,只不過因爲用戶所訪問的是離他較遠的Region,所以整個服務的響應速度會顯得有些慢。
而在Region中的某個Availability Zone失效的狀況下,其它Availability Zone中的拷貝將仍可以提供服務。所以對於用戶而言,其基本不會受到很大的影響:
除此以外,有些存儲也可能達不到您的要求。例如,若是我沒有記錯的話,EBS存儲的可靠率是99.99%,而S3的可靠率則是11個9。所以一種誤用就是用EBS當作持久化存儲,那麼結果可想而知:數據丟失。
其實不只僅是針對於AWS。在其它雲上運行的應用,不管是公有云,私有云,仍是混合雲,咱們都須要在實現時就考慮如何避免這些層次上的失效。除非雲平臺自身已經爲某些組成提供了高可用性保證。例如AWS的Route 53就是一個具備高可用性的DNS服務。
除了這些可能的失效,咱們還須要考慮如何處理這些失效。這經常和咱們所提供服務的自身特性有關。若是在某些組成失效的時候,咱們仍須要可以提供服務,那麼咱們就須要建立一個具備容錯性的系統;若是某些關鍵組成失效,那麼咱們須要多少時間可以恢復到正常服務狀態,又可能出現多少數據丟失等,都是由SLA來規定的。咱們要作的,就是根據SLA的要求設計基於雲上的具備容錯性,高可用性的服務,以及數據的備份及恢復等方案。
關於雲上如何設計一個具備容錯性的系統,以及如何執行數據的備份和恢復,我都會在其它文章中加以講解。畢竟不一樣的需求會致使不一樣的解決方案。這也不是一句兩句就能說清楚的。
而咱們只須要記住一點:假設雲上服務的全部組成都有可能失效,除非雲服務提供商聲明瞭該組成的高可用性。
經過較小的服務換取較高的伸縮性
對於一個在雲上運行的服務而言,良好的伸縮性是它可以成功運行的一個基本條件。因爲在雲上建立一個服務實例經常只須要幾分鐘的時間,所以其所包含的服務實例個數經常會根據當前負載變化,甚至一天會變化不少次:
市面上常見的雲基本上都是根據服務所佔用的資源數量來計費的。若是雲上的服務被設計爲一個不可分割的總體,那麼咱們就須要在某部分組成負載太重時對服務進行總體擴容。這使得其它的並不須要擴容的組成也同時進行了擴容,進而增長了對資源的沒必要要的佔用:
並且若是一個服務包含了太多的組成,那麼它的啓動時間也會受到必定的影響。反過來,若是雲上應用的各個組成彼此相互獨立,並可以獨立地進行擴展,那麼這個問題就將迎刃而解:
除此以外,這些小服務之間的較好的隔離性也會將錯誤隔離在較小的範圍內,進而提升了整個系統的穩定性。
若是您須要更多地瞭解如何建立一個具備高擴展性的應用,請查看《服務的擴展性》一文。若是您更但願能瞭解如何在雲上對服務進行切割,並有效地組織這些子服務的開發,請查看文章《Microservice簡介》及《Microservice Anti-patterns》。
注意服務的切割粒度和方式
咱們剛剛提到,若是但願咱們的服務可以在雲上具備良好的伸縮性,那麼咱們就須要將它劃分爲較小的子服務。可是這也容易讓一些讀者走到另外一個極端,那就是子服務的分割粒度過小,或者是在不適合的地方對服務進行了分割。
服務的分割粒度過小經常會致使服務對單一請求的響應速度變慢。這在某些系統中將會變成很是嚴重的問題。試想一下,若是一個請求須要由多個服務實例處理,那麼對該請求進行處理的過程就須要屢次的信息傳遞:
而若是將兩個頻繁交互的組成切割到了不一樣的子服務中,那麼對請求進行響應的過程也經常須要更多的信息傳遞:
從上面兩個示例中能夠看到,過細粒度的分割以及不合適的分割都會致使單次消息處理的流程變得更爲複雜,也便是消息的處理時間變長。這對於那些對單一請求處理時間較爲敏感的服務來講是很是很差的設計。
而另外一個與之類似的狀況就是兩個頻繁溝通的子服務。若是在通過正常分割以後,兩個子服務須要進行頻繁地通訊,那麼咱們就須要想辦法讓它們之間可以更高效地通訊,如經過在AWS上購買Dedicated Host實例讓兩個子服務在同一臺物理機上運行。
也就是說,爲了能讓雲上的服務能更爲高效地響應用戶的請求,咱們同時須要考慮數據流的拓撲結構,並根據該拓撲結構優化雲上服務的部署。
固然了,對於一個基於消息的服務,每一個子服務的劃分主要是經過考察是否可以增長整個系統的吞吐量來決定的。若是您對基於消息的服務感興趣,請查看《Enterprise Integration Pattern – 組成簡介》一文。
可配置的自動化解決方案
勿需質疑,一個雲上的服務基本上都擁有自定義的負載週期。例如一個主要面向國內客戶的服務,其負載高峯經常是在白天,而自凌晨以後其負載將一直處於一個較低的水平。並且該服務的負載可能會在某一個時間結點上迅速地增長,所以直到負載到達閾值纔開始建立新的虛擬機實例是來不及的:
除此以外,這些服務可能還須要在特定時期內做爲某些服務的平臺。在活動時間內,其負載將可能較其它時期的負載重得多。
針對第一個問題,咱們須要爲這種負載定義一個週期性的伸縮計劃。也就是說,對於一個AWS上的具備週期性負載變化的服務,咱們經常須要使用Auto Scaling Group中的Scheduled Scaling計劃。
而在面對舉辦活動這種打破週期性的負載時,咱們就須要一些額外的邏輯以保證咱們的服務擁有寬裕的容量。也就是說,此時咱們的Auto Scaling Group所使用的Scaling Plan處於一個特殊的狀態之中。
而這僅僅是處理有規律的負載所須要考慮的一些狀況。而對於那些具備非規律負載的服務,對服務容量的管理會變得更爲複雜。
全部這一切都有一個前提,那就是咱們須要可以將服務實例的伸縮自動化起來。在AWS中,這並非太大的問題。Auto Scaling已經提供了足夠的靈活度,以容許咱們經過Scaling Plan等組成提供自定義的伸縮邏輯。可是對於某些平臺,您可能就須要自行實現這些功能了。在此之上,您還須要讓它可以經過用戶所指定的配置以及負載規律進行伸縮。所以設計一個良好的解決方案並非一個簡單的事情。而這也是我在這裏提起這些的緣由。
爲何咱們要作這些呢?節省資金。其實將服務放到雲上的最終極目標無非就是爲了節省資金。在雲上,咱們能夠快速地獲取想要數量的服務實例,而不須要預先指定硬件的購置計劃;在雲上,咱們的容量能夠隨時根據負載進行伸縮,而不須要購買遠遠超過平常需求的足以應付負載峯值的服務器。
甚至在有些雲平臺中,同一種服務實例有多種不一樣的購買方式。這些購買方式的價格有時會相差不少。若是咱們可以在自動化伸縮功能的支持下充分利用這些購買方式所提供的優惠,那麼咱們的雲應用的運營成本將大大下降。
例如在AWS中,咱們有以下種類的虛擬機實例購買方式:
那麼對於上面所展現的週期性的負載,咱們就能夠經過如下方式的購買組合來下降整個服務的運行成本:
這種購買方法經常能夠幫您節省1/3甚至以上的服務運行成本。
除了可以完成服務容量的伸縮,更重要的是,這些自動化功能還能夠在其它一系列解決方案中使用,如災難恢復,服務的升級等。而咱們的目標就是,您的服務基本上再也不須要經過人爲干預就能完成自動伸縮,災難恢復等Day 2 Operation。這能夠顯著地下降服務的運營成本。
可是這裏有一點須要注意,那就是對日誌的保護,尤爲是發生故障的服務實例中的日誌。由於這些日誌經常記錄了服務產生故障的緣由,所以它們對於服務的開發人員很是有價值。所以在某些雲上(我忘記了是哪一個雲仍是哪一個解決方案提供商)提供了對雲上服務的日誌進行分析並將異常日誌進行保留的功能。若是您但願您的服務可以持續地改進,那麼對日誌的保護必不可少。
總結起來,那就是,讓您的服務的平常操做變成一個自動化流程,並基於這些自動化流程搭建您的平常運維解決方案,並經過它們來幫助您節省服務運行的開銷。並且在自動化過程當中,咱們要注意日誌的保護。
好了,本文要講的就只有這些了。對於文中所提到的一系列技術,我會在後續的文章中對它們進行較爲詳細地介紹。您只須要理解咱們爲何要這樣搭建雲服務,爲何要遵照這些守則便可。這是後面一系列雲服務解決方案文章的理論基礎。
轉載請註明原文地址並標明轉載:http://www.cnblogs.com/loveis715/p/5327584.html
商業轉載請事先與我聯繫:silverfox715@sina.com
公衆號必定幫忙別標成原創,由於協調起來太麻煩了。。。