天天看點

利用Docker輕松實作雲原生應用 - 高可用架構設計

利用Docker輕松實作雲原生應用 - 高可用架構設計

本文為利用docker和容器服務輕松實作雲原生應用系列的第一篇

高可用架構設計(本文)

<a href="https://yq.aliyun.com/articles/65272">spring boot + redis分布式會話</a>

最近對應用遷雲的讨論很多,很多使用者對雲環境中的應用架構和運維方式還不了解。直接利用雲伺服器替換自有實體機并不是使用雲的正确姿勢。

cloud native application(雲原生應用)是當下一個熱門名詞,簡單而言就是針對雲計算的特性,來設計應用架構,并優化應用的傳遞、運維流程。linux基金會旗下的雲原生計算基金會 cncf(cloud native computing foundation)開宗明義地描述了雲原生系統所具有的幾個關鍵特性

container packaged:容器化的傳遞方式,保證開發、傳遞和運維的一緻性

dynamically managed:自動化的管理,提升系統使用率、降低運維成本

micro-services oriented:松耦合應用架構,提升系統的靈活性和可維護性。

雲原生應用可以滿足我們的幾個關鍵訴求:

高可用:讓應用“傷得起”。 系統中沒有脆弱的故障單點,另外具有良好的自我恢複能力。

彈性伸縮:能夠讓應用從容應對峰值流量

快速疊代:天下武功唯快不破。在網際網路時代,快速疊代、最小化試錯成本是核心競争力。

下面我們将介紹,如何利用docker和阿裡雲容器服務在雲端實作應用的高可用。

雲原生應用中一個很重要的理念就是解耦

架構層面:通過微服務架構方法将應用邏輯分解為一組松耦合的服務,使得每個服務可以獨立開發、部署、演進和伸縮

實作層面:強調應用層和資料層的分離,隻有實作業務邏輯和持久化狀态的解耦,才能讓業務邏輯可以水準擴充,并且出現故障的時候可以快速恢複。

傳遞層面:通過容器來解耦應用和運作時環境,使得應用可以在不同的環境中可以重複、一緻地傳遞、部署、運維,進而更好地支援devops和彈性。

以前的兩篇博文中介紹了如何将一個ghost部落格應用,重構成一個符合雲原生應用架構的過程。

<a href="https://yq.aliyun.com/articles/2722">利用docker部署ghost部落格叢集</a>

<a href="https://yq.aliyun.com/articles/2985">當docker遇到資料庫:容器服務中使用rds</a>

最初ghost應用是利用嵌入式的sqlite來存儲資料,并将所有媒體檔案(圖像、視訊)儲存到本地檔案上。這個應用的性能受限于單機能力,無法水準擴充,也無法保證高可用。

而簡單的重構之後,我們将應用的資料層剝離出來:把關系型資料儲存在rds的mysql執行個體上,并将所有媒體檔案儲存到oss對象存儲之中。這樣配合slb的負載均衡,可以輕松地支援ghost部落格叢集的水準擴容。同時由于所有資料不再儲存到本地,這樣即使特點ecs執行個體失效,請求也可以交由其他節點應用接管。而資料的可用性是通過rds服務、oss存儲服務來保障的。

利用Docker輕松實作雲原生應用 - 高可用架構設計

相應的ghost的docker-compose模闆如下

阿裡雲擴充的注釋:

标簽 <code>aliyun.routing.port_xxxx</code> : 定義的虛拟域名通路方式

标簽 <code>aliyun.scale</code>: 定義了容器複本數量

<code>external</code>: 描述了容器對外部雲服務的引用,可以友善地将容器和雲服務組合在一起。

需要注意的是docker不是銀彈,僅依賴容器技術無法解決所有問題。使用者需要認真思考和判斷什麼樣的應用可以運作在容器中。容器非常适合部署無狀态的應用,因為這類應用可以友善地水準擴充和動态排程。然而對于有狀态應用,比如資料庫、消息隊列,我的建議是可以在開發測試環境和非關鍵應用的生産環境中使用容器;然而對于核心應用,建議采用雲服務提供的高可用中間件能力來實作。

解決了架構層面的水準伸縮能力和高可用,我們下面讨論一下應用部署中需要關注的可用性因素。

程序監控是最常用的可用性保證機制,傳統上是利用supervisor, monit等工具來監控應用程序,并自動拉起失效程序。

docker内置了程序監控能力,可以利用 <code>docker run --restart=always ...</code> 指令參數,或者在compose模闆中通過 <code>restart: always</code> 指明程序重新開機政策。

然而僅僅根據程序狀态判斷應用的健康狀态是不夠的:因為有時候由于應用邏輯問題導緻應用死鎖或挂起,雖然程序還處于運作狀态,但是已經無法接受新的請求。為此容器服務引入了服務的健康檢查機制,可以通過

目前支援的健康性設定包括:

标簽 <code>aliyun.probe.url</code>: 支援通過http/tcp協定的url請求對容器進行健康檢查

标簽 <code>aliyun.probe.cmd</code>: 通過 shell 腳本檢查對容器進行健康檢查

通過上面的方式,容器服務可以更加細粒度地判斷應用健康狀态,并會根據健康資訊實作應用可用性的優化控制,比如:

應用路由:如果服務容器狀态不健康,該容器會被從負載均衡上摘除,保障後續請求可以路由到健康的容器中。

容器依賴:docker compose一個缺陷是隻能描述容器之間的啟動順序,但是不能保證所依賴的容器已經正常運作,很多同學都為此吃過苦頭。而當容器服務部署應用模闆時,如果指明了<code>aliyun.depends</code>标簽或者使用compose v2中的<code>depends_on</code>指令,隻有當所依賴的容器進入健康狀态,容器才會被啟動。這樣可以非常優雅地保證應用中容器的啟動順序。

平滑更新:在更新過程中,為了保證應用通路不被中斷,系統需要當一個容器更新完畢并健康運作之後再更新下一個容器。這個行為可以通過<code>aliyun.rolling_updates</code>标簽來非常簡單的配置。

在docker 1.12之後,docker engine将内置容器的健康檢查,可以通過指令方式支援容器的健康狀态檢測,并自動重新開機失效容器。容器服務已經實作對docker 1.12的支援和相容。

一個常見誤區是:使用者認為應用的高可用性可以完全由雲服務商的基礎設施保證,自己無需關注。而真實情況是:雖然雲服務提供了高可靠的基礎設施,還要合理配置組合才能保障應用的可用性。

在雲端和在自有實體機上部署應用有很多不同。在自有資料中心中,有經驗的運維人員會根據應用負載特性選擇合适的實體機。比如,根據應用的可用性要求,把應用部署到不同的實體伺服器或不同機架的實體伺服器上。然而在公共雲和專有雲中,由于虛拟化層支援虛拟機的遷移甚至熱遷移,我們不應也不能再試圖将應用和其部署位置簡單綁定。

正确的姿勢是:在了解雲供應商提供的隔離性、可用性保證機制上,根據應用負載特征設計部署架構,并讓系統來實作動态管理。

随着微服務架構的引入,應用的部署更加富有挑戰性。首先微服務和傳統應用相比,部署元件的數量可能有10倍以上的差別;而且由于每個服務都支援快速的演進和動态地伸縮,除了需要更好地服務治理能力,也需要系統提供自動化的部署和管理能力保障應用sla。

阿裡雲容器服務為docker應用提供了内置的高可用支援,可以更好地支援微服務應用部署。

對于容器服務中的叢集,使用者可以選擇建立ecs執行個體或者手動添加已有ecs執行個體,并支援手動和彈性擴容。如果使用者應用關注網絡性能,則可以選擇自于同一個可用區的ecs執行個體,這樣例之間的網絡延遲會最小化。如果使用者應用關注于高可用性。我們可以為叢集添加來自多個可用區的ecs執行個體,配合slb,rds等多可用區支援能力,我們就會有一個高可用的容器基礎架構。

下面是一個典型的高可用的容器叢集的配置。其中ecs執行個體和rds資料庫執行個體部署在不同可用區之上。哪怕一個機房掉電也不會影響到叢集中應用的可用性。

利用Docker輕松實作雲原生應用 - 高可用架構設計

然而這還不夠,因為在一個叢集上的ecs執行個體上,通常會運作成百上千個應用。在排程容器高效地利用ecs節點資源的同時,如何避免由ecs節點/可用區失效導緻的應用通路失敗?

比如,下面的指令可以讓兩個redis容器部署在不同的節點上

阿裡雲容器服務在此基礎之上提供了更加豐富而簡便的的服務級别的親和性限制。在compose模闆中,服務定義了一組容器的集合,它們擁有一緻的鏡像和配置。

如果指明了 <code>aliyun.scale</code>标簽,相同服務的不同容器複本會盡量分布到不同節點之上,防止因為ecs執行個體失效導緻該服務所有容器全部無法通路。

服務之間可以通過 <code>affinity:service</code>标簽來描述服務直接容器的親和性。比如下面的模闆,描述了一個mysql主從結構中,mysql master和slave容器不會排程到一個ecs執行個體上

為了保證服務有更高的可用性,我們可以将服務中的容器排程在不同的可用區(availability zone)裡。

比如,通過 <code>availability:az</code>标簽,我們可以非常簡單地把如下web服務的nginx容器部署到2個可用區之中。

一個容器叢集可以保證容器應用在節點或可用區級别的可用性。如果使用者需要達到更進階别的可用性,可以在不同地域建立容器叢集,并分别部署應用。阿裡雲容器服務也提供混合雲能力,支援使用者在自有資料中心和雲端分别建立容器叢集,并用統一的方式進行應用部署和管理。其簡單部署架構如下:

利用Docker輕松實作雲原生應用 - 高可用架構設計

在分布式架構中,節點失效是不可避免的。高可用部署讓應用可以容忍一定的失效;另一方面我們需要能夠讓應用從故障狀态中自動恢複回來。就像x戰警中的金剛狼,雖然戰鬥力可能不是最強,但是超強恢複力讓他成為決定戰鬥命運的角色。

阿裡雲容器服務支援容器自動重新排程政策。也就是當容器所屬主控端節點失效時,系統可以将該容器自動遷移到其他健康節點上繼續運作,進而保證應用的sla。

什麼樣的容器支援重排程?我們需要分析容器中應用對持久化狀态的依賴。無狀态應用可以簡單地被排程到任何節點上正确執行的;而如果容器應用依賴于主控端的本地存儲,則是無法被重排程的。對于後者,需要進一步分離應用層和資料層邏輯才能支援遷移。比如在阿裡雲容器服務中,容器可以利用檔案卷插件(volume plugin)提供的網絡存儲能力(nas/nfs和ossfs)來共享和儲存資料。一旦節點失效,容器被排程到其他節點,容器服務會保證其相應檔案卷的正确挂載。這樣應用可以從網絡中獲得已儲存的資料并繼續運作。

雲原生應用在架構、開發、運維等方面和傳統軟體應用有很多不同。利用docker和阿裡雲容器服務可以輕松解決高可用部署和故障恢複的複雜性。

阿裡雲容器服務在相容docker原生編排技術的同時,提供了針對阿裡雲能力的優化和內建。開發者可以利用聲明式的方式來描述容器應用的部署限制,以及內建阿裡雲服務,進而滿足對可用性sla的要求。