本次分享 William 將從技術角度分析在雲計算環境中,當用戶業務面對流量激增、數據量翻番、訪問量指數級攀升的「煩惱」時,如何利用雲計算平臺的彈性,結合業務自身特色,設計和構建一個高可用、高伸縮性的後端系統架構。同時會以 QingCloud 平臺上的真實案例爲背景,講述從簡單後端系統到大規模分佈式系統的演進之路。node
青雲QingCloud 系統研發工程師,負責 QingStor 對象存儲服務的設計與研發,對 Linux 操做系統、計算機網絡、分佈式系統、雲計算等領域有較深刻的研究。原街旁團隊創始成員,基礎架構負責人。九零前,文青程序員,代碼詩人,北京土著。nginx
你們好,我是 QingCloud 系統工程師王煜,今天由來分享在雲計算平臺上構建穩定可靠的分佈式系統架構。程序員
不少企業和開發者在開發一款產品時,首要考慮的是產品功能的實現,其後端架構一般都是很是簡單直接的。產品在剛上線初期,因爲用戶訪問壓力很小,數據量積累也並不大,在短期內都會運行良好。redis
然而現在移動互聯網的普及和成熟,讓一款產品極可能在短期內彙集大量用戶,面對流量激增、數據量翻番、訪問量指數級攀升等諸多「煩惱」,這原本是一件好事,但是若是後端系統不能及時擴展,勢必會形成響應緩慢,頻繁出錯甚至拒絕服務的狀況。算法
即使沒有上述系統壓力忽然增大的「煩惱」,產品在不斷開發升級的過程當中,各類功能模塊會變的愈來愈複雜,若是不能很好的梳理和組織後端架構,系統出錯崩潰、不可以使用的風險也會愈來愈大。數據庫
在沒有云計算的時代,物理硬件從採購、上架、插線,到安裝、調試、部署,再到真正投入使用,是一個漫長而耗費人力的過程,每每跟不上系統緊急擴容的節奏。而云服務的出現不只僅讓咱們節約了使用成本,更重要的是能夠利用雲計算極度彈性的特色,讓企業和開發者根據需求,對系統進行在線快速的擴容。後端
但僅僅在雲服務上快速擴容是不夠的,企業也須要在業務層面,關注各個系統組件的可用性和伸縮性。接下來我來給你們介紹若是利用雲計算的優點,結合企業的業務特色構建穩定可靠的分佈式系統。緩存
首先咱們從一個最簡單的後端架構開始:安全
接入層:nginx
業務層:Java application
數據層:MySQL服務器
在雲計算環境中,網絡架構的組織很是重要,QingCloud 提供了基礎網絡和 VPC 兩種網絡,他們的區別在官網用戶指南和之前的文章中已經介紹,這裏不贅述。推薦企業使用 VPC 來構建本身的網絡,將全部主機和系統資源放置在 VPC 網絡中,指定內網網段(如 192.168.x.x / 172.16.x.x),主機能夠經過內網地址進行通訊,該地址不會變化。
隨着主機愈來愈多,IP 地址不易記憶,爲了方便主機間相互識別,能夠給每臺主機設置內網別名。爲方便在控制檯管理,給每一個資源打上標籤,按照標籤來組織分類。
接下來咱們回到上面那個簡單的後端架構。隨着訪問壓力愈來愈大,單臺 nginx + Java application 可能不足以應付,你會看到這臺主機的 CPU 愈來愈忙 ,內存使用愈來愈多。並且這臺主機一旦故障,整個服務都不可用了。
因此咱們首先調整這裏的結構,增長多臺 nignx + Java application 同時提供服務,在接入層引入負載均衡器(下文用 LB 這個詞代替),使外網請求首先發到 LB 上。LB 的選擇有不少,好比提供七層負載能力的 nginx 和 HAProxy,也有提供四層負載能力的 LVS,安裝和配置的方法各有不一樣。
LB 的引入能夠分攤請求壓力到後端的多臺業務服務器,而且可經過心跳檢查,自動隔離後端出現故障的服務器,實現業務層的高可用。但這時 LB 自己也會成爲一個單點,當出現故障也會致使全局不可用。因此可使用 Keeplived 服務爲 LB 提供一個副本,在一臺出問題的時候能夠立刻頂上,部署方法網上有不少資料。
有人會說能夠經過 DNS 輪詢到不一樣的 IP ,實現 LB 的高可用,但事實上這樣不行,由於一旦一臺 LB 掛掉,DNS 還會解析到這個 LB,此時即使立刻修改 DNS,在 DNS 緩存更新以前(一般要好久),服務也是不可用的。
雖然 LB 的原理並不複雜,可是部署配置有不少工做量,並且爲了實現 LB 的高可用還要額外作一些事情。QingCloud 從北京3區開始提供了高性能、高可用的 LB 集羣服務,能夠直接拿來使用。
改造後的架構以下圖所示:
接下來咱們來思考業務層的擴展問題。首先要解決如何快速擴充業務服務器。若是業務服務器的運行環境和程序不會頻繁更新,能夠基於已有的業務服務器製做主機映像,當須要擴容時,直接基於映像建立新的主機,掛接到 LB 後端就能夠立刻對外服務了。
此時你還可使用 AutoScaling 功能自動化這一過程,即當到達某種觸發條件,如 LB 併發數、響應延遲達到多少後,自動觸發主機的擴容。當觸發條件不知足時,能夠回收資源。
固然若是你的業務服務器的環境或程序須要頻繁更新,不適合作成固定模版。此時能夠本身搭建自動化部署(如 Puppet / Ansible)實現業務自動擴容,這一切操做可使用 QingCloud 的開放 API 接口,結合你的自動化部署程序完成。
此外你還須要保證業務服務器是無狀態的,由於每次 LB 請求的後端可能不一樣,不能假設上一次請求和這一次請求落在同一臺業務服務器上。若是服務器須要保存用戶訪問的 session 信息,可將其下放到緩存或數據庫中存儲。
隨着產品功能愈來愈豐富,你會發現原有單一的業務項目愈來愈龐大,各類功能邏輯交織在一塊兒,當一個功能出現故障,能夠引起全局不可用。此時你須要考慮將單一的業務項目分拆成多個獨立子服務。子服務之間能夠基於消息的通訊,亦或基於 RPC 的通訊方式。
子服務的調用可分爲需同步處理和可異步處理兩類。你應該儘可能異步化全部不須要立刻返回結果的請求。對於可異步處理的請求,咱們經過引入消息隊列,爲請求產生的數據作緩衝,請求的接收者(隊列消費者)可根據隊列中任務的數量作水平擴容。消息隊列的選擇有不少,例如 Redis, RabbitMQ, ActiveMQ, Kafka,QingCloud 平臺上目前已經提供分佈式、可分區、多副本的消息隊列服務,具備高吞吐量、低延遲等特色,用戶能夠方便的集成到本身的系統中。
現在數據分析對於企業愈來愈相當重要,業務服務器在處理請求的過程當中,能夠將原始數據經過隊列,源源不斷地導入大數據處理系統,QingCloud 提供完善的大數據分佈式處理平臺 Spark 和 Hadoop,用戶能夠根據需求方便的建立,使用和擴容。
經過拆分子服務,使得咱們有能力在某項子服務發生故障時,儘量下降對於全局的影響,提升系統總體的可用性。另外,對於處理壓力比較大的子服務,咱們還能夠進行獨立的水平擴容,方式和前面講到的業務服務器擴容類似,QingCloud 內網 LB 服務也能夠在這裏發揮做用。
改造後的架構以下圖所示:
隨着業務的增加,數據層面臨的壓力會愈來愈大,單機數據庫已經不足以支撐,接下來咱們談一下數據層的分佈式和擴展技術。
對於大多數的業務場景來講,數據的操做都是讀多寫少,並且讀都集中在少部分的熱點數據上,首先應該引入緩存層來緩解數據庫的讀壓力,若是緩存容量需求比較大,能夠構建緩存集羣,在上層按照 consistent hashing 算法將數據分散到多個節點,後續須要增長新緩存節點時,只有少部分的數據會失效。
接着引入新的數據庫種類,Redis 已經成爲諸多企業的首選標配,由於其支持豐富的數據類型和數據查詢接口,且內存型的數據庫自然具備更高的性能。
你能夠講業務中關係性要求不高的數據,從 MySQL 轉移到 Redis 中,尤爲是列表類的數據以及計數統計類的數據。給 MySQL 減負的同時提升數據的查詢性能。
單臺 Redis 節點也許不能知足你對容量的需求,QingCloud 平臺提供了支持多主多從 Redis 3.0 集羣服務,一方面可對數據自動分區提升存儲容量,另外一方面保證了服務的高可用性。
對於 MySQL 的擴展能夠分爲幾個步驟來作。首先,增長 MySQL slave 節點,在上層將部分讀請求分發到 slave 節點上去,因爲 slave 同步可能有延時,業務應該能容忍短暫的數據不一致現象,舉例,好比你的一個用戶修改了年齡屬性,其餘用戶要等一下子才能看到他的新年齡。
QingCloud MySQL 數據庫支持一主多從的架構,而且已經在多個從節點之上作好了負載均衡,你能夠輕易在界面上操做增長新的從節點來爲你分擔讀壓力。
即使有 slave 做爲數據副本,你也應該按期對你的數據庫進行冷備份,方便當業務出現誤操做時,可以回滾或恢復到曾經的某個時間點。在 QingCloud 平臺上,備份的過程能夠手動執行或者配置爲自動任務,在備份過程當中對數據庫正常使用沒有影響。
隨着數據的增加,單個數據庫不能承載完整的數據集合,而且寫操做對於單庫的壓力愈來愈明顯,你應該考慮分庫分表技術。將比較龐大的數據表拆分出來單獨存放,能夠給主數據庫騰出來一部分空間,分擔讀寫壓力。拆分的時候,還能夠按照功能邏輯,把相關聯的數據表存在一個庫裏。
當數據庫單表很是龐大,對讀寫都形成瓶頸時,你須要開始考慮水平分表 sharding,這種擴展方式能夠同時解決單表容量過大,讀壓力和寫壓力很大的問題,但帶來的研發和運維難度也會增大,推薦把上述的優化作完之後,最後在有必要的狀況下再作。
這裏簡略說一下水平分表的要點。首先要從數據表的字段中,選擇一個合理的分區鍵(shard key),這個鍵應該是全部該表查詢條件裏,最常常用到的字段,這樣纔會使大部分的查詢,可以提早判斷應該向哪些特定的分區(shard)發送請求,若是查詢條件中不帶shard key,須要遍歷全部的分區,並將結果進行merge。
有了 shard key 還要設計一種分區算法,好比常見的有按照區間,如 user_id in [0, 100] 在 shard 1,user_id in [101, 200] 在 shard2,還好比按照 hash 取模等等。設計分區算法的時候要充分考慮業務特色,多從讀寫操做的角度思考,這麼設計可否將壓力和數據均勻分攤到每一個 shard 上去。
還須要考慮數據層的擴展如何對上層透明,好比引入分佈式數據庫中間件,或者結合業務邏輯把數據庫操做作成一個獨立的子服務,供其它服務調用。若是不作成子服務,至少在業務代碼裏有獨立的一層來封裝對數據庫的操做。
至此,數據層的擴展現意圖以下所示:
除了上述的結構化數據的存取之外,企業還有存儲海量小文件數據(非結構化數據)的需求,單機硬盤、LVM 和 NAS 能夠做爲臨時方案使用,但都沒法同時知足無限容量、高性能、高安全性、高可用性的多重須要。而自行搭建分佈式存儲系統,如 Ceph、GlusterFS、HDFS 適用場景很是有限,且運維和二次開發的成本也很是高。
在 QingCloud 平臺上用戶可使用 QingStor 對象存儲服務來存儲海量的數據文件,服務自己提供了無限容量、高擴展性、高可用性和高安全性的特性。
講完數據層的擴展技術,最後來談一下多機房部署和異地容災的話題。QingCloud 從北京3區機房開始,經過自營的骨幹網光纖和多路環網技術,使得當機房出現網絡故障時對用戶無感知,在基礎設施上保障了高可用性。可是用戶的業務若是可以多機房部署,能夠在分攤訪問負載的同時加速區域訪問,好比加速中國南北方的用戶或者海外用戶的訪問。
如上圖所示,如果有三個機房,中間是 QingCloud 北京3區機房,負責主營業務。左邊是 QingCloud 亞太1區機房,主要服務亞太和海外的客戶。這兩個機房都使用了 QingCloud 私有網絡(VPC)部署,經過GRE或IPsec加密隧道在網絡上的互聯互通。右邊是你辦公室的物理機房,IT 人員能夠在這個環境下進行開發和辦公。
在業務上實現異地多活時,一般從易到難有三個階段:第一,在備用機房搭建反向代理,用戶請求到備用機房,請求直接被轉向主機房,若是兩機房有專線互聯或延時很小,這樣部署最爲簡單。第二,兩個機房同時部署業務服務器和緩存,因爲大部分數據請求能夠從緩存中讀取,不用進行跨機房訪問。但當緩存失效時,依然要從主機房的數據庫去查詢。第三,兩機房同時部署全套系統,包括接入層、業務層和數據層。數據層依靠數據庫雙主或主從技術進行跨機房同步。
最後總結一下今天的分享。沒有一個所謂經典或完美的架構,只有最適合企業業務的架構,今天分享的是在最通用的業務場景下,系統在接入層、業務層和數據層的經常使用擴展方法。企業後端架構的演進過程是一個漫長而艱鉅的過程,不可能從零開始一蹴而就,就能設計出一個萬般周全的系統,但若是設計之初能更多着眼於將來,就能夠爲進一步優化留出了餘地。
企業首先要清楚當前業務的規模有多大,好比業務的種類,服務QPS,數據的種類和數據量的大小,同時清楚業務和數據的SLA 和性能預期。只有在清楚這些的狀況下,才能在規劃的過程當中有權衡取捨。
雲計算環境下,基礎資源的建立和銷燬都很是迅速,要把更多關注放在業務層面的可擴展能力上,好比業務層要無狀態,數據層要作好索引,作好冷熱區分。不管規模大小,系統的組件不該該有單點故障和單點瓶頸。在規模較小的時候,系統能夠不擴展,可是要具有可擴展的能力。
更熱的數據應該被更快的訪問到,決定存取速度的因素主要是距離和介質。從距離來看 本地內存 > 本地硬盤 > 遠端內存 > 遠端硬盤,從介質來看 SSD > SAS > SATA。冷熱數據的比例通常是很是懸殊的,要將熱的數據存放到更近更好的介質上。
每一種存儲系統諸如 MySQL Redis 都有本身的數據持久化策略。
其實不管數據的存儲形式是怎樣的,數據的安全性主要取決因而否有冗餘,冗餘度是多少,冗餘的分佈是不是跨物理機,甚至是否跨機房。數據寫入是否真正落盤,以及數據的副本是同步寫入仍是異步寫入。
首先考慮緩存的粒度,太粗的粒度會致使失效太頻繁。還要考慮緩存容量,若是單臺節點沒法承載足夠的熱點數據,在使用多節點是要注意選擇合適分佈策略,比較常有的有一致性hash和hash取模。Redis3.0以上版本提供了集羣能力,能夠自動對數據分區,並提供高可用能力。
可在數據庫服務之上增長代理中間件,有開源方案也有本身實現,對使用者提供的接口要屏蔽分佈式的細節,用戶不用關心容量,性能,分佈策略等,彷彿看到的是一臺單機數據庫
交易數據最重要的是不能丟失,性能是次要,曾經不少傳統企業會選擇oracle這樣的商業數據庫,新型企業愈來愈多願意採用 MySQL PostgreSQL 等開源實現,可是配置的時候必定是配成最嚴格的同步寫多份成功才返回,而且有日誌留存
雲計算作爲 IT 基礎設施資源,在各行各業都有成功案例,已經不分適合哪類應用。惟一衡量標準就是可否知足需求,要看是否能取代傳統硬件可以提供的能力,而且可以提供傳統硬件之外的能力,例如彈性伸縮,按用量計費,快速啓動銷燬等。
keepalived 主要經過引入虛擬路由冗餘(VRRP)來實現高可用,本質上不會對性能形成影響,它是一個獨立的服務,和HAProxy沒有關係。
目前青雲的IaaS層在物理機掉電時會觸發災難恢復,另外一臺一樣的主機會啓動起來,數據不會丟失,而後再啓動hdfs的服務便可恢復集羣使用。Hadoop的自身的HA也會很快提供,這樣就能夠自動恢復hdfs服務了。
能夠在實例和db之間引入代理中間件,還能夠本身實現一個獨立的數據訪問服務,不讓實例直接操做db。