1、單服務(wù)器配置
萬里征途總是從第一步開始的,構(gòu)建一個復雜系統(tǒng)也是如此。我們從簡單的部分著手,先讓所有的功能都在一個服務(wù)器上運行。圖1-1展示了如何配置單臺服務(wù)器,讓一切都在其上運行,包括Web應用、數(shù)據(jù)庫、緩存等。
研究請求流和流量源頭有助于我們理解這個配置。我們先來看請求流(如圖1-2所示)。
圖片
圖片
1.用戶通過輸入域名(例如api.mysite.com)來訪問網(wǎng)站。通常,域名系統(tǒng)(DNS)是由第三方提供的付費服務(wù),它并不是由我們的服務(wù)器來托管的。
2.IP地址被返回給網(wǎng)頁瀏覽器或者移動應用。在圖1-2所示的例子中,被返回的IP地址是15.125.23.214。
3.一旦獲知IP地址,HTTP請求就被直接發(fā)送給Web服務(wù)器。
4.Web服務(wù)器返回HTML頁面或者JSON響應來渲染頁面。
接下來,我們研究一下流量源頭。Web服務(wù)器的流量有兩個源頭:Web應用和移動應用。
—Web應用:它運用服務(wù)器端語言(Java、Python等)來處理業(yè)務(wù)邏輯、數(shù)據(jù)存儲等;它還使用客戶端語言(HTML和JavaScript)來展示內(nèi)容。
—移動應用:HTTP是移動應用與Web服務(wù)器之間的通信協(xié)議。而JSON(JavaScript Object Notation)因其十分簡單而被廣泛用作數(shù)據(jù)傳輸時的API響應格式。以下是一個JSON格式的API響應例子。
GET/users/12–獲取id=12的用戶對象 { "id":12, "firstName'":"John", "lastName":"Smith", "address":{ "streetAddress":"212ndStreet", "city":"NewYork", "state'":"NY", "postalCode":10021 }, "phoneNumbers":[ "212555-1234", "646555-4567" ] }
2、數(shù)據(jù)庫
隨著用戶基數(shù)的增長,一臺服務(wù)器已經(jīng)無法滿足需求,我們需要多臺服務(wù)器:一臺用于處理Web應用/移動應用的流量,另一臺用作數(shù)據(jù)庫(如圖1-3所示)。把處理Web應用/移動應用流量(網(wǎng)絡(luò)層)的服務(wù)器與數(shù)據(jù)庫(數(shù)據(jù)層)服務(wù)器分開,我們就可以對它們分別進行擴展。
圖片
使用何種數(shù)據(jù)庫
你可以選擇傳統(tǒng)的關(guān)系型數(shù)據(jù)庫,也可以選擇非關(guān)系型數(shù)據(jù)庫。我們來看看它們的區(qū)別。
關(guān)系型數(shù)據(jù)庫通常也叫作關(guān)系型數(shù)據(jù)庫管理系統(tǒng)(RDBMS)或者SQL數(shù)據(jù)庫,其中最流行的有MySQL、Oracle、PostgreSQL等。關(guān)系型數(shù)據(jù)庫通過表和行來表示和存儲數(shù)據(jù)。你可以使用SQL對不同的數(shù)據(jù)庫表執(zhí)行連接(join)操作。
非關(guān)系型數(shù)據(jù)庫又叫作NoSQL數(shù)據(jù)庫。流行的非關(guān)系型數(shù)據(jù)庫有CouchDB、Neo4j、Cassandra、HBase、Amazon DynamoDB等。它們可以分為四類:鍵值存儲、圖存儲、列存儲和文檔存儲。非關(guān)系型數(shù)據(jù)庫一般不支持連接操作。
對于大多數(shù)開發(fā)者而言,關(guān)系型數(shù)據(jù)庫是最好的選擇,因為它們已經(jīng)有40多年的歷史,而且一直表現(xiàn)不錯。但如果它們無法滿足你的特殊使用場景要求,你就需要考慮關(guān)系型數(shù)據(jù)庫之外的選項。當需要滿足如下條件時,非關(guān)系型數(shù)據(jù)庫可能是一個正確的選擇:
—你的應用只能接受非常低的延時。
—應用中的數(shù)據(jù)是非結(jié)構(gòu)化的,或者根本沒有任何關(guān)系型數(shù)據(jù)。
—只需要序列化(JSON、XML、YAML等格式)和反序列化數(shù)據(jù)。
—需要存儲海量數(shù)據(jù)。
3、縱向擴展 vs. 橫向擴展
縱向擴展也叫作向上擴展,指的是提升服務(wù)器的能力(CPU、RAM等)。橫向擴展也叫作向外擴展,指的是為你的資源池添加更多服務(wù)器。
當流量小的時候,縱向擴展是一個很好的選擇,其主要優(yōu)勢是簡單。不過,它有一些重大局限。
—縱向擴展是有硬性限制的,你不可能給一臺服務(wù)器無限添加CPU和內(nèi)存。
—縱向擴展沒有故障轉(zhuǎn)移和冗余。一旦一臺服務(wù)器宕機,網(wǎng)站/應用也會隨著一起完全不可用。
由于縱向擴展存在這些限制,因此對于大型應用來說,采用橫向擴展更合適一些。
在我們前面的設(shè)計中,用戶是直接連接到Web服務(wù)器的。一旦服務(wù)器離線,用戶就無法訪問網(wǎng)站了。還有一種場景是,非常多的用戶同時訪問Web服務(wù)器,達到了其負載上限,這時用戶就會普遍感受到網(wǎng)站響應慢或者無法連上服務(wù)器。解決這些問題的最佳方法是使用負載均衡器。
4、負載均衡器
負載均衡器會把輸入流量均勻分配到負載均衡集里的各個Web服務(wù)器上。圖1-4展示了負載均衡器是怎么工作的。
如圖1-4所示,用戶可以直接連接該負載均衡器的公共IP地址。這樣設(shè)置后,Web服務(wù)器就再也不能被任何客戶端直接訪問了。為了提高安全性,服務(wù)器之間的通信使用私有IP地址。私有IP地址只可以被同一個網(wǎng)絡(luò)中的服務(wù)器訪問,在公網(wǎng)中是無法訪問的。負載均衡器和Web服務(wù)器之間使用私有IP地址來通信。
增加了負載均衡器和一臺Web服務(wù)器后,我們成功解決了網(wǎng)絡(luò)層的故障轉(zhuǎn)移問題,提升了網(wǎng)絡(luò)層的可用性。具體細節(jié)如下:
—如果服務(wù)器1離線,所有的流量都會被路由到服務(wù)器2,從而避免整個網(wǎng)站宕機。我們可以之后再將一臺新的“健康的”Web服務(wù)器添加到服務(wù)器池中,以平衡負載。
—如果網(wǎng)站流量增長非???,兩臺服務(wù)器不足以處理這些流量,那么負載均衡器可以輕松地解決這個問題。只需要在服務(wù)器池中添加更多服務(wù)器,負載均衡器就會自動將請求發(fā)給新加入的服務(wù)器。
圖片
現(xiàn)在網(wǎng)絡(luò)層看來已經(jīng)不錯了,那么數(shù)據(jù)層呢?目前的設(shè)計方案中只有一個數(shù)據(jù)庫,所以無法支持數(shù)據(jù)庫的故障轉(zhuǎn)移和冗余。數(shù)據(jù)庫復制是解決這些問題的常用技巧。
5、數(shù)據(jù)庫復制
根據(jù)維基百科上的定義,“在很多數(shù)據(jù)庫管理系統(tǒng)中,通常都可以利用原始數(shù)據(jù)庫(Master,主庫)和拷貝數(shù)據(jù)庫(Slave,從庫)之間的主從關(guān)系進行數(shù)據(jù)庫復制?!?。
主庫通常只支持寫操作,從庫保存主庫的數(shù)據(jù)副本且僅支持讀操作。所有修改數(shù)據(jù)的指令,如插入、刪除或更新等,都必須發(fā)送給主庫來執(zhí)行。在大部分應用中,對數(shù)據(jù)庫的讀操作遠多于寫操作,因此系統(tǒng)中從庫的數(shù)量通常多于主庫的數(shù)量。圖1-5展示了一個主庫搭配多個從庫的例子。
數(shù)據(jù)庫復制有如下優(yōu)點:
—性能更好。在主從模式下,所有的寫操作和更新操作都發(fā)生在主節(jié)點(主庫)上,而讀操作被分配到各個從節(jié)點(從庫),因此系統(tǒng)能并行處理更多的查詢,性能得到提升。
—可靠性高。如果有一臺數(shù)據(jù)庫服務(wù)器因自然災害而損毀,比如遭遇臺風或者地震,數(shù)據(jù)依然被完好保存,你不需要擔心數(shù)據(jù)會丟失,因為這些數(shù)據(jù)已經(jīng)被復制到處于不同地理位置的其他數(shù)據(jù)庫服務(wù)器中。
—可用性高。由于不同物理位置的從庫都復制了數(shù)據(jù),因此即使一臺數(shù)據(jù)庫服務(wù)器宕機,你的網(wǎng)站依然可以運行,因為另一臺數(shù)據(jù)庫服務(wù)器里存儲了數(shù)據(jù)。
前面討論了負載均衡器是如何幫助提升系統(tǒng)可用性的,這里我們問一個同樣的問題:如果有數(shù)據(jù)庫服務(wù)器宕機了怎么辦?圖1-5所示的架構(gòu)可以應對這種情況。
—如果只有一個從庫,而它宕機了,則系統(tǒng)暫時會將讀操作路由至主庫。一旦發(fā)現(xiàn)有從庫宕機,就會有一個新的從庫來替代它。要是有多個從庫可用,讀操作會被重定向到其他正常工作的從庫上;同樣,也會有一個新的數(shù)據(jù)庫服務(wù)器來替代宕機的那個。
—如果主庫宕機,會有一個從庫被推選為新的主庫。所有的數(shù)據(jù)庫操作會暫時在新的主庫上執(zhí)行。另一個從庫會替代原來的從庫并立即開始復制數(shù)據(jù)。在生產(chǎn)環(huán)境中,因為從庫的數(shù)據(jù)不一定是最新的,所以推選一個新的主庫會更麻煩。缺失的數(shù)據(jù)需要通過運行數(shù)據(jù)恢復腳本來補全。盡管還有別的數(shù)據(jù)復制方式可以解決數(shù)據(jù)缺失問題,比如多主復制或者循環(huán)復制,但是它們的設(shè)置更加復雜,本書不對這些內(nèi)容進行討論。感興趣的讀者可以進一步閱讀相關(guān)參考資料。
圖1-6展示了添加了負載均衡器和數(shù)據(jù)庫復制之后的系統(tǒng)設(shè)計方案。
圖片
我們再來看一下現(xiàn)在的設(shè)計:
—用戶從DNS獲取負載均衡器的IP地址。
—用戶通過這個IP地址連接負載均衡器。
—HTTP請求被轉(zhuǎn)發(fā)到服務(wù)器1或者服務(wù)器2上。
—Web服務(wù)器在從庫中讀取用戶數(shù)據(jù)。
—Web服務(wù)器把所有修改數(shù)據(jù)的操作請求都轉(zhuǎn)發(fā)到主庫上,包括寫、更新和刪除操作。
現(xiàn)在我們對于網(wǎng)絡(luò)層和數(shù)據(jù)層都有了一定的理解,接下來可以提升加載和響應速度了??梢酝ㄟ^添加緩存層、把靜態(tài)資源(JavaScript、CSS、圖片、視頻文件)轉(zhuǎn)移到內(nèi)容分發(fā)網(wǎng)絡(luò)(CDN)上來實現(xiàn)加速。
6、緩存
緩存是臨時的存儲空間,用于存儲一些很耗時的響應結(jié)果或者內(nèi)存中經(jīng)常被訪問的數(shù)據(jù),這樣后續(xù)再訪問這些數(shù)據(jù)時能更快。如圖1-6所示,每次加載一個新網(wǎng)頁,都要執(zhí)行一個或者多個數(shù)據(jù)庫請求來獲取數(shù)據(jù)。不斷向數(shù)據(jù)庫發(fā)送請求會使應用的性能受到很大影響,而緩存可以緩解這種情況。
緩存層
緩存層是一個臨時數(shù)據(jù)存儲層,比數(shù)據(jù)庫快很多。設(shè)置獨立緩存層的好處有:提高系統(tǒng)性能,減輕數(shù)據(jù)庫的工作負載以及能夠單獨擴展緩存層。圖1-7展示了一種設(shè)置緩存層的方式。
圖片
當收到一個請求時,Web服務(wù)器首先檢查緩存中是否有可用的數(shù)據(jù):如果有,Web服務(wù)器就直接將數(shù)據(jù)返回給客戶端;如果沒有,就去查詢數(shù)據(jù)庫并把返回的響應存儲在緩存中,再將其返回給Web服務(wù)器。這種緩存策略叫作通過緩存讀(Read-through Cache)。根據(jù)數(shù)據(jù)的類型、大小和訪問模式,可以采用不同的緩存策略。在網(wǎng)站Codeahoy上有一篇文章“Caching Strategies and How to Choose the Right One”,解釋了不同的緩存策略是如何工作的。
大部分緩存服務(wù)器都為常見的編程語言提供了API,與其進行交互很簡單。下面的代碼段展示了典型的Memcached API:
SECONDS=1 cache.set('myKey','hithere',3600*SECONDS) cache.get('myKey')
使用緩存時的注意事項
使用緩存時有以下幾點需要注意:
—決定什么時候應使用緩存。如果對數(shù)據(jù)的讀操作很頻繁,而修改卻不頻繁,則可考慮使用緩存。因為被緩存的數(shù)據(jù)是存儲在易變的內(nèi)存中的,所以緩存服務(wù)器不是持久化數(shù)據(jù)的理想位置。比如,如果緩存服務(wù)器重啟,其中的所有數(shù)據(jù)就會丟失。因此,重要的數(shù)據(jù)應該保存在持久性的數(shù)據(jù)存儲中。
—過期策略。執(zhí)行過期策略是好的做法。一旦緩存中的數(shù)據(jù)過期,就應該將其從緩存中清除。如果不設(shè)置過期策略,緩存中的數(shù)據(jù)會一直被保存在內(nèi)存中。通常建議不要把過期時間設(shè)得太短,因為這樣會導致系統(tǒng)不得不經(jīng)常從數(shù)據(jù)庫重新加載數(shù)據(jù);當然,也不要設(shè)得太長,這樣會導致數(shù)據(jù)過時。
—一致性:這關(guān)系到數(shù)據(jù)存儲和緩存的同步。當對數(shù)據(jù)的修改在數(shù)據(jù)存儲和緩存中不是通過同一個事務(wù)來操作的時候,就會發(fā)生不一致。當跨越多個地區(qū)進行擴展時,保持數(shù)據(jù)存儲和緩存之間的一致性是很有挑戰(zhàn)性的。如果你感興趣,可以閱讀Facebook的文章“Scaling Memcache at Facebook”。
—減輕出錯的影響:單緩存服務(wù)器是系統(tǒng)中的一個潛在單點故障(Single Point Of Failure,SPOF)(如圖1-8所示)。在維基百科中,單點故障的定義如下:“單點故障是指系統(tǒng)中的某一部分,如果它出現(xiàn)故障,整個系統(tǒng)就不能工作”。所以,推薦的做法是在不同的數(shù)據(jù)中心部署多個緩存服務(wù)器以避免單點故障。另一個推薦的做法是為緩存超量提供一定比例的內(nèi)存,這樣可以在內(nèi)存使用量上升時提供一定的緩沖。
驅(qū)逐策略:一旦緩存已滿,任何對緩存添加條目的請求都有可能導致已有條目被刪除,這叫作緩存驅(qū)逐。LRU(Least-Recently-Used,最近最少使用)是最流行的緩存驅(qū)逐策略。也可以采用其他緩存驅(qū)逐策略,比如LFU(Least Frequently Used,最不經(jīng)常使用)或者FIFO(First In First Out,先進先出),以滿足不同的使用場景。
圖片
7、單服務(wù)器配置
內(nèi)容分發(fā)網(wǎng)絡(luò)(Content Delivery Network,CDN)是由在地理上分散的服務(wù)器組成的網(wǎng)絡(luò),被用來傳輸靜態(tài)內(nèi)容。CDN中的服務(wù)器緩存了像圖片、視頻、CSS和JavaScript文件這一類的靜態(tài)內(nèi)容。
動態(tài)內(nèi)容緩存是一個相對新的概念,不在本書討論的范圍內(nèi)。它可以基于請求路徑、查詢字符串、cookie和請求頭來緩存HTML頁面。感興趣的讀者可以訪問ASW的網(wǎng)站以了解更多內(nèi)容。本書只講解如何使用CDN緩存靜態(tài)內(nèi)容。
現(xiàn)在我們大致介紹一下CDN是如何工作的:當用戶訪問一個網(wǎng)站時,離用戶最近的CDN服務(wù)器會返回靜態(tài)資源。給人的直觀感受是,離CDN服務(wù)器越遠,網(wǎng)站加載內(nèi)容就越慢。舉個例子,如果CDN服務(wù)器在舊金山,那么洛杉磯的用戶就比歐洲的用戶更快獲取網(wǎng)站內(nèi)容。圖1-9展示了CDN是如何縮短加載時間的。
圖片
圖1-10展示了CDN的工作流。
圖片
1.用戶A嘗試通過請求圖片的URL去獲取image.png。這個URL的域名由CDN服務(wù)商提供。亞馬遜和Akamai CDN上的圖片URL大概是下面這個樣子:
—https://mysite.cloudfront.net/logo.jpg
—https://mysite.akamai.com/image-manager/img/logo.jpg
2.如果CDN服務(wù)器的緩存中沒有image.png,CDN服務(wù)器就會向數(shù)據(jù)源服務(wù)器請求這個文件。數(shù)據(jù)源服務(wù)器可以是Web服務(wù)器,或者線上存儲,比如Amazon S3。
3.數(shù)據(jù)源服務(wù)器將image.png文件返回給CDN服務(wù)器,其中包括可選的HTTP頭Time-to-Live(TTL,生存時間)。TTL描述了該圖片文件應該被緩存多長時間。
4.CDN服務(wù)器緩存這個圖片并將其返回給用戶A。這個圖片一直緩存在CDN服務(wù)器中,直到TTL到期。
5.用戶B發(fā)送請求,要求獲取這張圖片。
6.只要TTL還沒到期,CDN服務(wù)器的緩存就會返回該圖片。
使用CDN時的注意事項
—花銷:CDN是由第三方供應商來運營的,對數(shù)據(jù)在CDN中的進出都會收費。緩存不經(jīng)常使用的內(nèi)容,并不能給性能帶來顯著的好處,應該考慮把這些內(nèi)容從CDN中移出。
—設(shè)置合理的緩存過期時間:對于時間敏感的內(nèi)容,設(shè)置緩存過期時間是很重要的。這個時間不應該過長或過短。如果過長,內(nèi)容會不夠新。如果過短,可能導致頻繁地將內(nèi)容從數(shù)據(jù)源服務(wù)器重新加載至CDN。
—CDN回退:要好好考慮你的網(wǎng)站或應用如何應對CDN故障。如果CDN出現(xiàn)故障暫時無法提供服務(wù),客戶端應該有能力發(fā)現(xiàn)這個問題,并直接向數(shù)據(jù)源服務(wù)器請求資源。
—作廢文件:以下操作均可以在文件過期之前將其從CDN中移除。
調(diào)用CDN服務(wù)商提供的API來作廢CDN對象。
通過對象版本化來提供一個不同版本的對象??梢栽赨RL中添加一個參數(shù),比如版本號,來給一個對象添加版本。比如,在查詢字符串中可以加入版本號2(image.png?v=2)。
圖1-11展示了加入了CDN和緩存之后的系統(tǒng)設(shè)計方案。
1.靜態(tài)資源(JavaScript代碼、CSS文件、圖片等)不再由Web服務(wù)器提供,而是從CDN中獲取,以提高響應速度。
2.數(shù)據(jù)被緩存后,數(shù)據(jù)庫的負載就減輕了。
8、無狀態(tài)網(wǎng)絡(luò)層
現(xiàn)在是時候考慮橫向擴展網(wǎng)絡(luò)層了。為此,我們需要將狀態(tài)(例如,用戶會話數(shù)據(jù))從網(wǎng)絡(luò)層中移出。一個好的做法是將會話數(shù)據(jù)存儲在持久性存儲(如關(guān)系型數(shù)據(jù)庫或NoSQL)中。集群中的每個Web服務(wù)器都可以經(jīng)由數(shù)據(jù)庫訪問狀態(tài)數(shù)據(jù)。這就是所謂的無狀態(tài)網(wǎng)絡(luò)層。
有狀態(tài)架構(gòu)
有狀態(tài)的和無狀態(tài)的服務(wù)器是有一些關(guān)鍵差異的。有狀態(tài)的服務(wù)器處理客戶端發(fā)來的一個個請求,并記下客戶端的數(shù)據(jù)(狀態(tài))。無狀態(tài)的服務(wù)器則不保存狀態(tài)信息。
圖1-12展示了一個有狀態(tài)架構(gòu)。
圖片
在圖1-12所示的架構(gòu)中,用戶A的會話數(shù)據(jù)和個人資料圖片會被存儲到服務(wù)器1上。為了對用戶A進行身份驗證,必須將HTTP請求發(fā)給服務(wù)器1。如果將請求發(fā)給其他服務(wù)器,比如服務(wù)器2,由于服務(wù)器2上沒有用戶A的會話數(shù)據(jù),因此身份驗證就會失敗。同理,用戶B的所有HTTP請求必須發(fā)給服務(wù)器2;用戶C的所有請求必須發(fā)給服務(wù)器3。
現(xiàn)在的問題是,如何將來自同一客戶端的所有請求都發(fā)給同一個服務(wù)器。大部分負載均衡器都提供的黏性會話可以解決這個問題,但是會增加成本。這種方法使得添加或者移除服務(wù)器變得更加困難,同時也使得應對服務(wù)器故障變得更具挑戰(zhàn)性。
無狀態(tài)架構(gòu)
圖1-13展示了一個無狀態(tài)架構(gòu)。
在這個無狀態(tài)架構(gòu)中,用戶的HTTP請求可以發(fā)給任意Web服務(wù)器,然后Web服務(wù)器從共享的數(shù)據(jù)存儲中拉取數(shù)據(jù)。狀態(tài)數(shù)據(jù)存儲在共享數(shù)據(jù)存儲而非Web服務(wù)器中。無狀態(tài)的系統(tǒng)更加簡單,更健壯,也更容易擴展。
圖1-14展示了加入了無狀態(tài)網(wǎng)絡(luò)層后的系統(tǒng)設(shè)計。
圖片
圖片
如圖1-14所示,我們把會話數(shù)據(jù)從網(wǎng)絡(luò)層中移出,放到持久化存儲中保存。共享數(shù)據(jù)存儲可以是關(guān)系型數(shù)據(jù)庫或者NoSQL(比如,Memcached、Redis)。選擇NoSQL的原因是它容易擴展。自動擴展的意思是,基于網(wǎng)絡(luò)流量自動地增加或者減少Web服務(wù)器。將狀態(tài)數(shù)據(jù)從Web服務(wù)器中移除后,就很容易實現(xiàn)網(wǎng)絡(luò)層的自動擴展了。
如果你的網(wǎng)站發(fā)展迅速,而且吸引了非常多的國際用戶,要提高可用性以及在更廣的地理區(qū)域提供更好的用戶體驗,讓網(wǎng)站支持多數(shù)據(jù)中心就非常關(guān)鍵。
9、數(shù)據(jù)中心
圖1-15展示了有兩個數(shù)據(jù)中心的例子。正常情況下,用戶會被基于地理位置的域名服務(wù)導流到最近的數(shù)據(jù)中心,也就是說流量被分散到不同的數(shù)據(jù)中心,在圖1-15中有美國東部和美國西部兩個數(shù)據(jù)中心。基于地理位置的域名服務(wù)(geoDNS)是一種基于用戶的地理位置將域名解析為不同IP地址的DNS服務(wù)。
圖片
如果有某個數(shù)據(jù)中心出現(xiàn)嚴重的故障,可以把所有的流量轉(zhuǎn)到另一個運轉(zhuǎn)正常的數(shù)據(jù)中心。在圖1-16所示的例子中,數(shù)據(jù)中心2(美國西部)發(fā)生了故障,全部流量被轉(zhuǎn)至數(shù)據(jù)中心1(美國東部)。
圖片
要設(shè)置多數(shù)據(jù)中心,必須先解決如下技術(shù)難題:
—流量重定向。要有能把流量引導到正確數(shù)據(jù)中心的有效工具。geoDNS可以基于用戶的地理位置把流量引導到最近的數(shù)據(jù)中心。
—數(shù)據(jù)同步。不同地區(qū)的用戶可以使用不同的本地數(shù)據(jù)庫或者緩存。在故障轉(zhuǎn)移的場景中,流量可能被轉(zhuǎn)到一個數(shù)據(jù)不可用的數(shù)據(jù)中心。常用的一個策略是在多個數(shù)據(jù)中心復制數(shù)據(jù)。Netflix工程博客上的文章“Active-Active for Multi-Regional Resiliency”說明了Netflix是如何實現(xiàn)多數(shù)據(jù)中心異步復制的。
—測試和部署:設(shè)置多數(shù)據(jù)中心后,在不同的地點測試你的網(wǎng)站/應用是很重要的。而自動部署工具則對于確保所有數(shù)據(jù)中心的服務(wù)一致性至關(guān)重要。
為了進一步擴展我們的系統(tǒng),我們需要解耦系統(tǒng)中不同的組件,這樣它們就可以單獨擴展了。在現(xiàn)實世界中,很多分布式系統(tǒng)用消息隊列來解決這個問題。
10、消息列隊
消息隊列是一個持久化的組件,存儲在內(nèi)存中,支持異步通信。它被用作緩沖區(qū),分配異步的請求。消息隊列的基本架構(gòu)很簡單:輸入服務(wù)(也稱為生產(chǎn)者或發(fā)布者)創(chuàng)建消息,并把它們發(fā)布到消息隊列中;其他服務(wù)或者服務(wù)器(也稱為消費者或訂閱者)與消息隊列連接,并執(zhí)行消息所定義的操作。這個模型如圖1-17所示。
圖片
解耦使消息隊列成為構(gòu)建可擴展和可靠應用的首選架構(gòu)。有了消息隊列,當消費者無法處理消息時,生產(chǎn)者依然可以將消息發(fā)布到隊列中;就算生產(chǎn)者不可用,消費者也可以從隊列中讀取消息。
考慮以下用例:你的應用支持修改圖像,包括裁剪、銳化、模糊化等,這些任務(wù)都需要時間來完成。在圖1-18中,Web服務(wù)器把圖像處理的任務(wù)發(fā)布到消息隊列。圖像處理進程或服務(wù)(Worker)從消息隊列中領(lǐng)取這個任務(wù),并異步執(zhí)行。生產(chǎn)者和消費者都可以獨立地擴展。隊列的規(guī)模變大以后,可以加入更多的Worker,以減少處理時間。如果隊列在大部分時間中都是空的,就可以減少Worker的數(shù)量。
11、錄日志、收集指標與自動化
對于一個只有幾臺服務(wù)器的小網(wǎng)站,記錄日志、收集指標和自動化只是錦上添花的實踐而非必需的工作。但是當網(wǎng)站發(fā)展成為大企業(yè)提供服務(wù)的平臺時,這些工作就是必需的了。
記錄日志:監(jiān)控錯誤日志非常重要,因為它可以幫助識別系統(tǒng)的錯誤和問題。你可以監(jiān)控每個服務(wù)器的錯誤日志,也可以用工具把各個服務(wù)器的日志匯總到一個中心化的服務(wù)中,方便搜索和查看。
收集指標:收集不同類型的指標數(shù)據(jù),有助于獲得商業(yè)洞察力和了解系統(tǒng)的健康狀態(tài)。
以下幾個指標很有用:
—主機級別指標:CPU、內(nèi)存、磁盤I/O等。
—聚合級別指標:比如整個數(shù)據(jù)庫層的性能,整個緩存層的性能等。
—關(guān)鍵業(yè)務(wù)指標:每日活躍用戶數(shù)、留存率、收益等。
自動化:當系統(tǒng)變得龐大且復雜時,就需要創(chuàng)建或者使用自動化工具來提高生產(chǎn)力。持續(xù)集成是一個很好的做法。在這種做法中,每次代碼檢入(check in)都需要通過自動化工具的審核,使團隊能及時發(fā)現(xiàn)問題。同時,將構(gòu)建、測試和部署等流程自動化,可以顯著提高開發(fā)人員的生產(chǎn)力。
添加消息隊列和各種工具
圖1-19展示了更新后的系統(tǒng)設(shè)計,因為圖書版面有限,只畫了一個數(shù)據(jù)中心。
1.這個系統(tǒng)中包含一個消息隊列,它使系統(tǒng)更加松散地耦合且更容易從故障中恢復。
2.它包含了記錄日志、監(jiān)控和收集指標的功能,以及自動化工具。
隨著數(shù)據(jù)與日俱增,你的數(shù)據(jù)庫過載變得越來越嚴重。是時候擴展數(shù)據(jù)層了。
12、數(shù)據(jù)庫擴展
數(shù)據(jù)庫的擴展有兩種方式:縱向擴展和橫向擴展。
縱向擴展
縱向擴展又叫作向上擴展,就是為已有機器增加算力(CPU、內(nèi)存、硬盤等)。業(yè)界有一些非常強勁的數(shù)據(jù)庫服務(wù)器。亞馬遜的RDS(關(guān)系型數(shù)據(jù)庫服務(wù))可以提供擁有24 TB內(nèi)存的數(shù)據(jù)庫服務(wù)器。這種性能強勁的數(shù)據(jù)庫服務(wù)器可以存儲和處理非常多的數(shù)據(jù)。舉個例子,Stack Overflow的網(wǎng)站在2013年每個月有超過1000萬的獨立用戶訪問,但是它只有一個主數(shù)據(jù)庫。然而,縱向擴展也有一些重大缺點:
—盡管可以給數(shù)據(jù)庫服務(wù)器添加更多的CPU、內(nèi)存等,但是硬件的能力總是有上限的。如果網(wǎng)站的用戶基數(shù)很大,單服務(wù)器是不夠的。
—更大的單點故障風險。
—總成本很高。強勁的服務(wù)器比一般的服務(wù)器貴很多。
橫向擴展
橫向擴展,也叫分片,就是添加更多服務(wù)器。圖1-20對比了縱向擴展和橫向擴展。
數(shù)據(jù)庫分片是指把大數(shù)據(jù)庫拆分成更小、更容易管理的部分(這些部分叫作Shard,分片)。每個Shard共享同樣的數(shù)據(jù)庫Schema,但是里面的數(shù)據(jù)都是這個Shard獨有的。
圖1-21展示了一個做了分片的數(shù)據(jù)庫。根據(jù)用戶ID,用戶數(shù)據(jù)被分配到其中一個數(shù)據(jù)庫服務(wù)器上。每次要訪問數(shù)據(jù)時,就會用一個哈希函數(shù)來找對應的Shard。在我們的例子中,以user_id(用戶ID)對4求余作為哈希函數(shù)。如果余數(shù)為0,那么Shard 0就被用來存儲和獲取數(shù)據(jù);如果余數(shù)為1,就用Shard 1,依此類推。
圖片
圖1-22展示了做過分片的數(shù)據(jù)庫中的用戶表示例。
實施分片策略時,要考慮的最重要的問題是選擇什么分片鍵(Sharding Key)。分片鍵(也叫作分區(qū)鍵,Partition Key)由一個或者多個數(shù)據(jù)列組成,用來決定將數(shù)據(jù)分到哪個Shard。在圖1-22所示的例子中,user_id被用作分片鍵。分片鍵可以把數(shù)據(jù)庫查詢路由到正確的數(shù)據(jù)庫,使你高效地檢索和修改數(shù)據(jù)。在選擇分片鍵時,最重要的標準之一是選擇一個可以讓數(shù)據(jù)均勻分布的鍵。
分片是一種不錯的擴展數(shù)據(jù)庫的技術(shù),但它還遠不是一個完美的解決方案。它為系統(tǒng)引入了復雜性和新的挑戰(zhàn)。
重分片數(shù)據(jù):出現(xiàn)如下情況時,需要對數(shù)據(jù)重新分片。第一種是因為數(shù)據(jù)快速增長,單個Shard無法存儲更多的數(shù)據(jù)。第二種是因為數(shù)據(jù)的分布不均勻,有些Shard的空間可能比其他的更快耗盡。當Shard被耗盡時,就需要更新用于分片的哈希函數(shù),然后把數(shù)據(jù)移到別的地方去。我們會在第5章介紹一致性哈希算法,它是解決這個問題的常用技術(shù)。
名人問題:也叫作熱點鍵問題。過多訪問一個特定的Shard可能造成服務(wù)器過載。想象一下,把Katy Perry、Justin Bieber和Lady Gaga的數(shù)據(jù)都放在同一個Shard里,對于社交應用而言,這個Shard會因讀操作太多而不堪重負。為了解決這個問題,我們可能需要為每個名人都分配一個Shard,而且每個Shard可能還需要進一步分區(qū)。
連接和去規(guī)范化(de-normalization):一旦數(shù)據(jù)庫通過分片被劃分到多個服務(wù)器上,就很難跨數(shù)據(jù)庫分片執(zhí)行連接(join)操作了。解決這個問題的常用方法就是對數(shù)據(jù)庫去規(guī)范化,把數(shù)據(jù)冗余存儲到多張表中,以便查詢可以在一張表中執(zhí)行。
在圖1-23中,我們對數(shù)據(jù)庫做了分片,以支持數(shù)據(jù)流量的快速增長;同時,將有些非關(guān)系型功能遷移到NoSQL數(shù)據(jù)庫中,以降低數(shù)據(jù)庫的負載。High Scalability網(wǎng)站上有一篇文章“What the Heck are You Actually Using NoSQL for?”介紹了很多NoSQL數(shù)據(jù)庫的使用案例。
圖片
審核編輯:湯梓紅
-
Web
+關(guān)注
關(guān)注
2文章
1287瀏覽量
71366 -
服務(wù)器
+關(guān)注
關(guān)注
13文章
9786瀏覽量
87903 -
數(shù)據(jù)庫
+關(guān)注
關(guān)注
7文章
3925瀏覽量
66176
原文標題:系統(tǒng)設(shè)計,被我拿捏了!
文章出處:【微信號:小林coding,微信公眾號:小林coding】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
SIM800C與后臺服務(wù)器通訊返回錯誤
Digi控制臺服務(wù)器通過NIST FIPS 140-2認證
如何配置基于Win 2003 的服務(wù)器
基于單服務(wù)器實現(xiàn)大容量會議服務(wù)的系統(tǒng)及方法

租用一臺服務(wù)器多少錢?
輕松使用SaltStack管理成千上萬臺服務(wù)器(入門教程)

評論