開發(fā)運(yùn)維視角下,影響軟件高可擴(kuò)展性的6個(gè)因素

Geshan Manandhar
軟件可擴(kuò)展性是工具或系統(tǒng)的一種屬性,可以根據(jù)用戶需求增加其容量和功能??蓴U(kuò)展的軟件可以在適應(yīng)變化、升級(jí)、檢修和資源伸縮的同時(shí)保持穩(wěn)定。

軟件可擴(kuò)展性是一個(gè)有趣的話題。實(shí)現(xiàn)軟件可擴(kuò)展性涉及很多因素,我們?cè)诒疚膶⒂懻撘恍┡c開發(fā)和運(yùn)維方面相關(guān)的因素。

我們將深入討論如何編寫軟件(軟件開發(fā))以及如何運(yùn)行軟件(運(yùn)維)來實(shí)現(xiàn)軟件可擴(kuò)展性。對(duì)于初學(xué)者來說,成本和可擴(kuò)展性通常是成比例的。

2345截圖20200908083720.png

1、什么是軟件可擴(kuò)展性

Full-scale blog將軟件可擴(kuò)展性定義為:

軟件可擴(kuò)展性是工具或系統(tǒng)的一種屬性,可以根據(jù)用戶需求增加其容量和功能。可擴(kuò)展的軟件可以在適應(yīng)變化、升級(jí)、檢修和資源伸縮的同時(shí)保持穩(wěn)定。

因此,如果軟件可以彈性的處理負(fù)載,當(dāng)請(qǐng)求量增加時(shí)分配更多資源(通常是動(dòng)態(tài)分配),那我們可以說這個(gè)軟件是可擴(kuò)展的。現(xiàn)實(shí)中要實(shí)現(xiàn)這一點(diǎn),我們還需要重視代碼部分。

2、開發(fā)視角的軟件可擴(kuò)展性

軟件工程師應(yīng)該知道如何編寫可擴(kuò)展的軟件。你應(yīng)該專注于優(yōu)先編寫能使軟件易于擴(kuò)展的代碼。編寫勉強(qiáng)可用的軟件很容易,但編寫易于測(cè)試、可維護(hù)、易擴(kuò)展的代碼卻很難。以下是一些能讓軟件更易擴(kuò)展的編程方法。

可擴(kuò)展軟件的高性能代碼

軟件應(yīng)用程序編寫時(shí)可以只要求能用就行,也可以考慮到軟件的可擴(kuò)展性、維護(hù)性和彈性。

選擇合適算法

基于時(shí)間和空間復(fù)雜度,選擇適合場(chǎng)景的合適算法可以產(chǎn)生很好的效果。

了解大O符號(hào)和流處理來對(duì)抗空間復(fù)雜度,對(duì)編寫可擴(kuò)展的軟件非常有幫助。

例如,您可以采用二分搜索代替線性搜索來加快算法執(zhí)行。在空間復(fù)雜度要求高的場(chǎng)景下,您可以基于少量?jī)?nèi)存的流式處理來實(shí)現(xiàn)小內(nèi)存復(fù)制大文件??纯催@個(gè)用來可視化展示排序算法的6分鐘視頻。

更好的內(nèi)存管理

作為一位軟件工程師,您應(yīng)該關(guān)心像內(nèi)存管理、垃圾收集這樣的事情,不要讓它們成為可擴(kuò)展性的障礙。對(duì)于可擴(kuò)展軟件來說,預(yù)測(cè)資源爭(zhēng)用的情況并為其編寫代碼也是至關(guān)重要的。

選擇高性能函數(shù)庫(kù)

還有其他有助于軟件可擴(kuò)展性的方法,包括對(duì)比和使用更多的高性能解決方案。例如,您可以使用javascript代替lodash來獲得更快更高性能。

另外,不要僅僅因?yàn)槟硞€(gè)庫(kù)或軟件包很流行就使用它,還要檢查性能和軟件可擴(kuò)展性的影響。

例如,您可以使用Day.js代替Moment.js來執(zhí)行簡(jiǎn)單的日期操作。需要的話,還可以使用原生方法來使軟件更具可擴(kuò)展性。

異步處理

想象一下,當(dāng)客戶已經(jīng)成功下單需要發(fā)送一封訂單確認(rèn)郵件,您會(huì)怎么做?我總是會(huì)建議大家異步地執(zhí)行它,因?yàn)樗橇鞒讨蟹顷P(guān)鍵的部分。

使用隊(duì)列和消費(fèi)者

您可以輕松地設(shè)置隊(duì)列和消費(fèi)者,來完成下單后電子郵件的發(fā)送任務(wù)。即便郵件發(fā)送晚了1分鐘也沒問題。

如果您的訂單量很大,可以通過擴(kuò)展消費(fèi)者數(shù)量來降低延遲。任何非關(guān)鍵或非阻塞的任務(wù)都可以推到后臺(tái)異步完成,這有助于實(shí)現(xiàn)無故障的最優(yōu)化可用資源。

適當(dāng)使用異步代碼

異步處理的另一個(gè)例子是使用異步代碼。根據(jù)編程語(yǔ)言的具體情況,您應(yīng)該都能夠?qū)⒛承┤蝿?wù)推送到后臺(tái)執(zhí)行。當(dāng)任務(wù)被執(zhí)行時(shí),可以發(fā)送一個(gè)響應(yīng)表明它已經(jīng)被調(diào)度過。您可以查看一個(gè)Node.js的異步響應(yīng)示例。當(dāng)然,這取決于您所選擇的語(yǔ)言,有些語(yǔ)言(比如PHP)可能不提供開箱即用的異步代碼。

為可擴(kuò)展軟件編寫無狀態(tài)的程序

無狀態(tài)是高可擴(kuò)展性軟件的先決條件。正如Redhat在比較無狀態(tài)與有狀態(tài)時(shí)提到的“將無狀態(tài)事務(wù)想象成一臺(tái)自動(dòng)售貨機(jī):一個(gè)請(qǐng)求對(duì)應(yīng)一個(gè)響應(yīng)”,而將有狀態(tài)程序描述為“您可以將有狀態(tài)事務(wù)視為與同一個(gè)人進(jìn)行中的多輪對(duì)話”。

無狀態(tài)軟件在請(qǐng)求之間不會(huì)共享任何東西,也不依賴于本地文件系統(tǒng)之類的東西。

不要使用本地文件系統(tǒng)

如果需要保存文件,應(yīng)該使用可靠的遠(yuǎn)程系統(tǒng)如可進(jìn)行訪問控制的存儲(chǔ),例如Amazon S3 bucket。

這使得它很容易保存文件并通過CDN來提供可擴(kuò)展的服務(wù),它通過動(dòng)靜分離來提高軟件擴(kuò)展性。如圖像和其他類似PDF文件的靜態(tài)內(nèi)容,通過使用CDN來提供服務(wù)會(huì)比網(wǎng)站服務(wù)更高效。利用Apache或Nginx構(gòu)建網(wǎng)站服務(wù)來提供動(dòng)態(tài)內(nèi)容,會(huì)比提供靜態(tài)內(nèi)容更好。

使用客戶端會(huì)話替換服務(wù)器端會(huì)話

另一個(gè)經(jīng)典例子是不在web應(yīng)用使用服務(wù)端會(huì)話,而是使用客戶端cookie。

您可以輕松地用使用類似Json Web Token(JWT)的方案替換服務(wù)器端會(huì)話來進(jìn)行身份驗(yàn)證和授權(quán)。

JWTs可以在每個(gè)請(qǐng)求中作為header或者cookie的一部分被輕松的從客戶端傳給服務(wù)端。因?yàn)榉?wù)器可以像牲口而非寵物一樣工作,擴(kuò)展軟件變得非常容易。如果您必須使用會(huì)話,那么使用類似Redis的數(shù)據(jù)庫(kù)而不要保存在本地文件系統(tǒng),以保證服務(wù)器可以輕松的被替換。

這里的關(guān)鍵點(diǎn)是,不要留戀您的服務(wù)器,它們應(yīng)該是一次性并根據(jù)負(fù)載彈性配置的。這樣我們就可以通過編寫無狀態(tài)軟件來實(shí)現(xiàn)易擴(kuò)展和高可用成為可能。

3、運(yùn)維視角的軟件可擴(kuò)展性

關(guān)于運(yùn)維和平臺(tái)這兩個(gè)表述,我指的是在哪里以什么方式部署和運(yùn)行軟件,另外還涵蓋這些系統(tǒng)的架構(gòu)以及它們?nèi)绾谓换ァ?/p>

軟件部署的位置是至關(guān)重要的。

如果您的用戶在悉尼,而軟件部署在歐洲,它將有很大的網(wǎng)絡(luò)延遲。

類似的,如果組件布局不好或選擇不當(dāng)都將產(chǎn)生負(fù)面影響。讓我們看一下在運(yùn)維層面對(duì)軟件可擴(kuò)展性有至關(guān)重要影響的因素。

垂直擴(kuò)展與水平擴(kuò)展

這是一個(gè)關(guān)于把服務(wù)器類比成牲口還是寵物的延伸討論。想象一下,您正在管理一個(gè)相當(dāng)受歡迎的電子商務(wù)網(wǎng)站,該網(wǎng)站每天約有500個(gè)訂單和5萬個(gè)獨(dú)立訪問用戶。您有一個(gè)規(guī)格接近Amazon EC2 m 5.4 xlarge的大型web服務(wù)器,它有16核CPU以及64 GB的大內(nèi)存。我們假設(shè)在上面運(yùn)行Woo Commerce商店,包括網(wǎng)站服務(wù)和MySQL數(shù)據(jù)庫(kù)都運(yùn)行在這同一臺(tái)服務(wù)器上。

現(xiàn)在,距離黑色星期五只有3個(gè)月了,公司打算做一個(gè)大規(guī)模的電視廣告推廣,預(yù)計(jì)流量在節(jié)日期間有5-7倍的增加。管理層將在廣告方面投入大量資金,在這4-5天內(nèi)網(wǎng)站不能癱瘓。

預(yù)計(jì)該網(wǎng)站在這3-4天內(nèi),每天將有30萬以上的獨(dú)立用戶訪問和3千以上的訂單。

您現(xiàn)在有兩個(gè)選項(xiàng)來擴(kuò)展應(yīng)用程序,要么垂直擴(kuò)展(scale-up),要么水平擴(kuò)展(scale-out)。

垂直擴(kuò)展(Scale-Up)

如果選擇垂直擴(kuò)展,那么需要增加更多的硬件資源來解決這個(gè)問題。

您可以改用一臺(tái)EC2 m5.24 xlarge的機(jī)器,它擁有96核CPU和384 GB內(nèi)存。

CPU和內(nèi)存是老機(jī)器的6倍,所以理論上它應(yīng)該足以支撐。

但有3個(gè)重要問題,首先您將需要一點(diǎn)時(shí)間停機(jī)來升級(jí)硬件,其次也是最重要的原因是這臺(tái)機(jī)器會(huì)造成單點(diǎn)故障??紤]到網(wǎng)站負(fù)載,數(shù)據(jù)庫(kù)很可能由于某個(gè)問題而崩潰。稍后如果流量沒有預(yù)期的那么大,您還將為避免過度浪費(fèi)資源進(jìn)行收縮操作。

水平擴(kuò)展(Scale-Out)

另一種選擇是水平擴(kuò)展,您將嘗試獲得許多較小的EC2實(shí)例,比如8-50個(gè)t3.mediums實(shí)例。

每個(gè)實(shí)例將擁有2核CPU和4 GB的內(nèi)存。因此,一組包括50個(gè)t3.mediums實(shí)例的集群可以為您提供總共100核CPU和200 GB內(nèi)存。要在這些新的EC2實(shí)例集群之間均勻分配負(fù)載,可以使用Amazon應(yīng)用程序負(fù)載均衡器。

為了使應(yīng)用程序更具可擴(kuò)展性,您可以使用具有32個(gè)核CPU和128 GB內(nèi)存的Amazon RDS db.m5.8 xlarge實(shí)例。根據(jù)需要,您還可以配置備份。這時(shí)您有50臺(tái)服務(wù)器可以使用,假如有3臺(tái)壞了可以馬上換上3臺(tái)新的。

如果負(fù)載偏低只有3個(gè)實(shí)例在運(yùn)行,當(dāng)流量激增時(shí)分分鐘就可以增加20個(gè)。

在打折季結(jié)束后,您可以將DB縮放到db.m5.large,這足以滿足每天500個(gè)訂單的情況。

考慮到這點(diǎn)很重要,讓我們?cè)谙旅婵梢暬亟忉屢幌隆?/p>

2345截圖20200908083720.png

這是Docker和Kubernetes的一部分亮點(diǎn),您可以將工作任務(wù)打包進(jìn)輕量級(jí)的容器,而Kubernetes可以管理水平擴(kuò)展和滾動(dòng)部署這些容器。這些年Docker已經(jīng)改變了我們工程師的工作方式。

這里要提到的一點(diǎn)是擴(kuò)展關(guān)系數(shù)據(jù)庫(kù)是非常困難的。即使有了分片之類的技術(shù)后,如果你不清楚自己在做什么,垂直擴(kuò)展關(guān)系數(shù)據(jù)庫(kù)會(huì)比水平擴(kuò)展更容易些。這里的Amazon就是一個(gè)例子,同樣的概念可以應(yīng)用于其他任何主要的云供應(yīng)商,比如谷歌云或Azure。這就引出了我要講的下個(gè)要點(diǎn),NoSQL數(shù)據(jù)庫(kù)的使用。

使用NoSQL提高軟件可擴(kuò)展性

在上面的例子中,如果您的在線商店網(wǎng)站上有20個(gè)人,可以使用關(guān)系數(shù)據(jù)庫(kù)提供服務(wù)。對(duì)于每個(gè)用戶的每個(gè)請(qǐng)求,應(yīng)用程序都會(huì)到達(dá)關(guān)系數(shù)據(jù)庫(kù),雖然慢,但不會(huì)造成嚴(yán)重后果。現(xiàn)在想象120個(gè)用戶同時(shí)在線,性能很可能已經(jīng)很明顯的嚴(yán)重下降,我們可以看到基于預(yù)分配的數(shù)據(jù)庫(kù)開始出現(xiàn)一些數(shù)據(jù)庫(kù)連接的問題。

https://sysadminxpert.com/aws-rds-max-connections-limit/

用于可擴(kuò)展軟件的NoSQL數(shù)據(jù)庫(kù)

NoSQL數(shù)據(jù)庫(kù)非常靈活的地方在于我們可以像Redis一樣使用NoSQL的內(nèi)存鍵值存儲(chǔ)。

使用像Redis這樣的內(nèi)存數(shù)據(jù)庫(kù)來提供所有產(chǎn)品詳情將大大降低響應(yīng)時(shí)間。

另一個(gè)用途可以是使用Solr或Elastic Search來實(shí)現(xiàn)類似查詢“中號(hào)阿迪達(dá)斯牌紅色T恤”這樣的快速多條件搜索,而不是運(yùn)行復(fù)雜的SQL查詢。Solr是一個(gè)支持事務(wù)的NoSQL數(shù)據(jù)庫(kù),它有助于提高軟件的可擴(kuò)展性和彈性。

Redis和Solr/Elastic Search都需要提前準(zhǔn)備一些數(shù)據(jù)才能正常工作,但這肯定比每次客戶端請(qǐng)求都要查詢關(guān)系數(shù)據(jù)庫(kù)要好得多。

對(duì)于每個(gè)寫請(qǐng)求,都需要寫入關(guān)系數(shù)據(jù)庫(kù)。

例如客戶的每次購(gòu)買都必須存儲(chǔ)在關(guān)系數(shù)據(jù)庫(kù)中,而在所有瀏覽場(chǎng)景至少有80-90%流量我們可以使用NoSQL數(shù)據(jù)庫(kù),這可以讓軟件更具可擴(kuò)展性。

最終一致性和CAP理論

NoSQL數(shù)據(jù)庫(kù)之所以速度快,是因?yàn)樗鼈儾扇×俗罱K一致性的折衷方案。為更好理解數(shù)據(jù)存儲(chǔ),我非常建議您更新一下CAP理論的相關(guān)知識(shí)——一致性、可用性和分區(qū)容錯(cuò)性。

https://twitter.com/mykola/status/1101337299525267457

在這篇關(guān)于高可擴(kuò)展性的文章中,您可以了解到更多關(guān)于從100萬到1100萬用戶如何擴(kuò)展的信息。因?yàn)镹oSQL數(shù)據(jù)庫(kù)還可以作為高效緩存工作,這就引出我的的下一個(gè)關(guān)于使用高效緩存來實(shí)現(xiàn)軟件可擴(kuò)展性的要點(diǎn)。

http://highscalability.com/blog/2016/1/11/a-beginners-guide-to-scaling-to-11-million-users-on-amazons.html

緩存實(shí)現(xiàn)軟件的可擴(kuò)展性

正如Phil Carlton所說

在計(jì)算機(jī)科學(xué)領(lǐng)域只有兩個(gè)難題:緩存失效和命名。

緩存失效也是面臨的一個(gè)有趣問題。您將需要一個(gè)大規(guī)模的緩存,因?yàn)闆]有緩存的普通方式不再可擴(kuò)展。對(duì)于優(yōu)秀的軟件可擴(kuò)展性來說,不同層級(jí)的緩存起著至關(guān)重要的作用。以下是您可以利用緩存來實(shí)現(xiàn)更可擴(kuò)展的軟件的一些方法。

Memoization

第一級(jí)的緩存可以在代碼層面進(jìn)行,其中一個(gè)基本方法是Memoization。

Memoization是其他緩存函數(shù)的高階函數(shù)。它可以優(yōu)化一些慢函數(shù)。它將函數(shù)第一次調(diào)用后的結(jié)果進(jìn)行緩存,在后續(xù)調(diào)用時(shí)只要參數(shù)相同就可以直接在緩存中找到結(jié)果。

您可以看一個(gè)Node.js Memoization的例子,服務(wù)器可以緩存響應(yīng)1分鐘。因此在1分鐘以內(nèi),即使數(shù)據(jù)發(fā)生了變化,客戶端也會(huì)得到相同的舊數(shù)據(jù)。

HTTP緩存

另一個(gè)級(jí)別的緩存可以在HTTP層上完成。通過良好的使用HTTP headers可以按需要將響應(yīng)緩存一段時(shí)間。HTTP緩存也可以使用像Cloudflare這樣的應(yīng)用程序來實(shí)現(xiàn),通過規(guī)則設(shè)置使響應(yīng)緩存數(shù)分鐘甚至數(shù)小時(shí)以減少服務(wù)器負(fù)載。這種類型的緩存機(jī)制有助于我們獲得高水平的軟件可擴(kuò)展性。

如果您有足夠容量可以管理全量HTTP緩存和HTTP加速器,Varnish是一個(gè)很好的選擇。Varnish聲稱:

根據(jù)您的架構(gòu),它通常以300-1000倍的速度提高交付。

目前Varnish Docker映像的下載多達(dá)100多萬次,我認(rèn)為人們?yōu)榱双@得其無與倫比的軟件可擴(kuò)展性和巨大的HTTP緩存,很可能已經(jīng)在Kubernetes上大量使用了。

我不確定讀副本是不是一種純粹的數(shù)據(jù)庫(kù)緩存機(jī)制。但是我非常確信,從讀副本上進(jìn)行查詢能大幅降低對(duì)主數(shù)據(jù)庫(kù)的壓力并有助于提高軟件可擴(kuò)展性。當(dāng)然還有很多在多層應(yīng)用程序上實(shí)現(xiàn)緩存的其他方法。在了解軟件可擴(kuò)展性后,您很可能根據(jù)自己的情況希望添加緩存來提高系統(tǒng)速度。

4、總結(jié)

軟件擴(kuò)展性是一個(gè)困難的問題,而運(yùn)行環(huán)境使其變得更加復(fù)雜。

一家中型公司眼中的大規(guī)模概念在FAANG公司的眼中可能根本排不上號(hào)。究竟什么水平才算得上是大規(guī)模,取決于您的軟件系統(tǒng)日常處理的RPM/RPS。

我沒有實(shí)際處理過每秒十萬或上百萬次請(qǐng)求的系統(tǒng),我只聽說過那樣的規(guī)模。我實(shí)際遇見并處理過的系統(tǒng)有每秒有100到1000次請(qǐng)求,即使是這樣規(guī)模滿足軟件可擴(kuò)展性也是非常有趣和富有挑戰(zhàn)性的問題。

原文鏈接:https://geshan.com.np/blog/2020/12/software-scalability/

THEEND

最新評(píng)論(評(píng)論僅代表用戶觀點(diǎn))

更多
暫無評(píng)論