中文字幕理论片,69视频免费在线观看,亚洲成人app,国产1级毛片,刘涛最大尺度戏视频,欧美亚洲美女视频,2021韩国美女仙女屋vip视频

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
可伸縮Web架構(gòu)與分布式系統(tǒng)(2)

開(kāi)源軟件近年來(lái)已變?yōu)闃?gòu)建一些大型網(wǎng)站的基礎(chǔ)組件。并且伴隨著網(wǎng)站的成長(zhǎng),圍繞著它們架構(gòu)的最佳實(shí)踐和指導(dǎo)準(zhǔn)則已經(jīng)顯露。這篇文章旨在涉及一些在設(shè)計(jì)大型網(wǎng)站時(shí)需要考慮的關(guān)鍵問(wèn)題和一些為達(dá)到這些目標(biāo)所使用的組件。上篇文章介紹了Web分布式系統(tǒng)設(shè)計(jì)準(zhǔn)則和基本原理,本文介紹構(gòu)建快速、可伸縮數(shù)據(jù)訪問(wèn)的組件。

(上文)談及了在設(shè)計(jì)分布式系統(tǒng)中需要考慮的一些核心問(wèn)題,現(xiàn)在讓我們來(lái)聊聊(比較)困難的部分:訪問(wèn)數(shù)據(jù)的可伸縮性。
大多數(shù)簡(jiǎn)單的web應(yīng)用,例如LAMP棧應(yīng)用,看上去如圖1.5

圖1.5:簡(jiǎn)單的web應(yīng)用

隨著它們的成長(zhǎng),會(huì)有兩個(gè)主要的挑戰(zhàn):訪問(wèn)應(yīng)用服務(wù)器和數(shù)據(jù)庫(kù)的可伸縮性。在一個(gè)高可伸縮的應(yīng)用設(shè)計(jì)中,應(yīng)用(或者web)服務(wù)器通常會(huì)最小化(minimized)并通常表現(xiàn)為一個(gè)非共享(無(wú)狀態(tài))架構(gòu)。這樣使得系統(tǒng)的應(yīng)用服務(wù)層能夠很好地進(jìn)行伸縮。這樣數(shù)據(jù)的結(jié)果是,壓力被向下推到了數(shù)據(jù)庫(kù)服務(wù)器和相關(guān)(底層)支持服務(wù);真正的伸縮和性能挑戰(zhàn)就在這一層起到作用。
本章余下部分致力于(介紹)一些更加通用的策略和方法,通過(guò)更快的數(shù)據(jù)訪問(wèn)使得這些類型的服務(wù)更加快速和可伸縮。

圖1.6:極簡(jiǎn)的web應(yīng)用

大多數(shù)系統(tǒng)可以極度簡(jiǎn)化為像圖1.6這樣的。這是一個(gè)很好的開(kāi)始。如果你有大量的數(shù)據(jù)且希望快速、簡(jiǎn)單地訪問(wèn),就像你把糖果藏在你桌子第一個(gè)抽屜里。雖然被極度簡(jiǎn)化,前面觀點(diǎn)仍暗示著兩個(gè)難題:存儲(chǔ)的可伸縮性和數(shù)據(jù)的快速訪問(wèn)。

為了本節(jié),我們假設(shè)你有數(shù)以TB計(jì)的數(shù)據(jù)并且希望能讓用戶隨機(jī)訪問(wèn)這些數(shù)據(jù)的一小部分。(見(jiàn)圖1.7)這就類似于在圖片應(yīng)用例子里定位文件服務(wù)器上一個(gè)圖片文件的位置。

圖1.7:訪問(wèn)特定的數(shù)據(jù)

由于很難將TB級(jí)的數(shù)據(jù)加載到內(nèi)存,所以這會(huì)使得事情變得非常有挑戰(zhàn)性;這(種訪問(wèn))將直接變?yōu)榇疟PIO操作。從磁盤讀取會(huì)比從內(nèi)存要慢得多——訪問(wèn)內(nèi)存就像Chuck Norris一樣快,然而訪問(wèn)磁盤比DMV線還要慢。這樣的速度差異對(duì)于大數(shù)據(jù)來(lái)說(shuō)比較客觀(This speed difference really adds up for large data sets);順序讀方面訪問(wèn)內(nèi)存的速度是訪問(wèn)磁盤的6倍,而在隨機(jī)讀方面,前者是后者的十萬(wàn)倍(參見(jiàn)”The Pathologies of Big Data”, http://queue.acm.org/detail.cfm?id=1563874)。而且,即使有唯一ID,從哪里能夠找到這樣一小塊數(shù)據(jù)仍然是一項(xiàng)艱巨的任務(wù)。這就好比從你藏糖果的地方不看一眼地想拿到最后一塊Jolly Rancher。

幸運(yùn)的是,你有很多能把事情變得更加容易的選擇;其中重要的有如下4個(gè):緩存、代理、索引、負(fù)載均衡。本節(jié)剩余部分將會(huì)討論每個(gè)用于加速數(shù)據(jù)訪問(wèn)的概念。

緩存

緩存利用了本地引用原則的好處:最近訪問(wèn)的數(shù)據(jù)可能被再次訪問(wèn)。緩存幾乎被用在計(jì)算機(jī)運(yùn)行的各層:硬件,操作系統(tǒng),web瀏覽器,web應(yīng)用等等。緩存就像短期的內(nèi)存:有著限定大小的空間,但通常比訪問(wèn)原始數(shù)據(jù)源更快,并且包含有最近最多被訪問(wèn)過(guò)的(數(shù)據(jù))項(xiàng)。緩存可以存在于架構(gòu)的各個(gè)層次,但會(huì)發(fā)現(xiàn)到經(jīng)常更靠近前端(非web前端界面,架構(gòu)上層),這樣就可盡快返回?cái)?shù)據(jù)而不用經(jīng)過(guò)繁重的下層(處理)了。

在我們的API例子中,如何使用一個(gè)緩存來(lái)加速你的數(shù)據(jù)訪問(wèn)速度呢?在這個(gè)場(chǎng)景下,你可以在很多地方插入一個(gè)緩存。選擇之一是在你的請(qǐng)求層節(jié)點(diǎn)中插入一個(gè)緩存,如圖1.8.

圖1.8:在你的請(qǐng)求層節(jié)點(diǎn)中插入緩存

將緩存直接放置在請(qǐng)求層節(jié)點(diǎn)中讓本地存儲(chǔ)響應(yīng)數(shù)據(jù)變?yōu)榭赡?。每次?duì)于一個(gè)服務(wù)的請(qǐng)求,節(jié)點(diǎn)將立即返回存在的本地、緩存的數(shù)據(jù)。如果(對(duì)應(yīng)的)緩存不存在,請(qǐng)求節(jié)點(diǎn)將會(huì)從磁盤中查詢數(shù)據(jù)。請(qǐng)求層節(jié)點(diǎn)的緩存既可以放置在內(nèi)存(更快)也可以在節(jié)點(diǎn)本地磁盤(比通過(guò)網(wǎng)絡(luò)快)上。

圖1.9:多個(gè)緩存

當(dāng)你擴(kuò)展到多個(gè)節(jié)點(diǎn)時(shí),會(huì)發(fā)生什么呢?正如你看到的圖1.9,如果請(qǐng)求曾擴(kuò)展到多個(gè)節(jié)點(diǎn),那么每個(gè)節(jié)點(diǎn)都可以擁有它自身的緩存。但是,如果你的負(fù)載均衡器將請(qǐng)求隨機(jī)分發(fā)到這些節(jié)點(diǎn)上,同樣的請(qǐng)求會(huì)到達(dá)不同的節(jié)點(diǎn),就會(huì)提高緩存miss率。兩種克服這種困難的方法是:全局緩存和分布式緩存。

全局緩存

正如聽(tīng)起來(lái)的一樣,全局緩存是指:所有節(jié)點(diǎn)使用同一緩存空間。這包括增加一臺(tái)服務(wù)器或是某種類型的文件存儲(chǔ),比從你原始存儲(chǔ)地方(訪問(wèn))更快,并且所有請(qǐng)求層的節(jié)點(diǎn)均可以訪問(wèn)(全局緩存)。所有請(qǐng)求節(jié)點(diǎn)統(tǒng)一像訪問(wèn)其本地緩存般訪問(wèn)(全局)緩存。這種類型的緩存機(jī)制可能會(huì)變得比較復(fù)雜,因?yàn)殡S著客戶端和請(qǐng)求數(shù)量的增加,單個(gè)緩存(服務(wù)器)很容易被壓垮,但是在一些架構(gòu)中非常有效(特別是有專門定制的硬件使得訪問(wèn)全局緩存非??焖?,或者需要緩存的數(shù)據(jù)集是固定的)。

通常有兩種形式的全局緩存,如下圖。圖1.10中,如果緩存中找不到對(duì)應(yīng)的響應(yīng),那緩存自身會(huì)去從下層存儲(chǔ)中獲取丟失的數(shù)據(jù)。在圖1.11中,當(dāng)緩存中找不到相應(yīng)數(shù)據(jù)時(shí),需要請(qǐng)求節(jié)點(diǎn)自己去獲取數(shù)據(jù)。

圖1.10:全局緩存自身負(fù)責(zé)存取

圖1.11 全局緩存,請(qǐng)求節(jié)點(diǎn)負(fù)責(zé)存取

【譯者注】第一種方式相當(dāng)于是全局緩存將查詢緩存、底層獲取數(shù)據(jù)、填充緩存這些操作一并做掉,理想情況下對(duì)于上層應(yīng)用應(yīng)該只需要提供一個(gè)獲取數(shù)據(jù)的API,上層應(yīng)用無(wú)需關(guān)心所請(qǐng)求的數(shù)據(jù)是已存在于緩存中的還是從底層存儲(chǔ)中獲取的,能夠更專注于上層業(yè)務(wù)邏輯,但這就可能需要這種全局緩存設(shè)計(jì)成能夠根據(jù)傳入API接口的參數(shù)去獲取底層存儲(chǔ)的數(shù)據(jù),譯者認(rèn)為接口簽名可以簡(jiǎn)化為Object getData(String uniqueId, DataRetrieveCallback callback),第一個(gè)參數(shù)代表與緩存約定的唯一標(biāo)示一個(gè)數(shù)據(jù)的ID,第二個(gè)是一個(gè)獲取數(shù)據(jù)回調(diào)接口,具體實(shí)現(xiàn)由調(diào)用該接口的業(yè)務(wù)端來(lái)實(shí)現(xiàn),即當(dāng)全局緩存中未找到uniqueId對(duì)應(yīng)的緩存數(shù)據(jù)時(shí),那就會(huì)以該callback去獲取數(shù)據(jù),并以u(píng)niqueId為key、callback獲取數(shù)據(jù)為value放入全局緩存中。第二種方式相對(duì)來(lái)說(shuō)自由一些。請(qǐng)求節(jié)點(diǎn)自行根據(jù)業(yè)務(wù)場(chǎng)景需求來(lái)決定查詢數(shù)據(jù)的方式,以及查數(shù)據(jù)后的處理(比如緩存回收策略),全局緩存只作為一個(gè)基礎(chǔ)組件讓請(qǐng)求節(jié)點(diǎn)能夠在其中存取數(shù)據(jù)。

大多數(shù)應(yīng)用傾向于通過(guò)第一種方式使用全局緩存,由緩存自身來(lái)管理回收、獲取數(shù)據(jù),來(lái)應(yīng)對(duì)從客戶端發(fā)起的對(duì)同一數(shù)據(jù)的眾多請(qǐng)求。但是,對(duì)于一些場(chǎng)景來(lái)說(shuō),第二種實(shí)現(xiàn)就比較有意義。比如,如果是用來(lái)緩存大型文件,那緩存低命中率將會(huì)導(dǎo)致緩存緩沖區(qū)被緩存miss給壓垮;在這種情況下,緩存中緩存大部分?jǐn)?shù)據(jù)集(或熱門數(shù)據(jù))將會(huì)有助解決這個(gè)問(wèn)題。另一個(gè)例子是,一個(gè)架構(gòu)中緩存的文件是靜態(tài)、不應(yīng)回收的。(這可能跟應(yīng)用對(duì)于數(shù)據(jù)延遲的需求有關(guān)——對(duì)于大數(shù)據(jù)集來(lái)說(shuō),某些數(shù)據(jù)段需要被快速訪問(wèn)——這時(shí)應(yīng)用的業(yè)務(wù)邏輯會(huì)比緩存更懂得回收策略或熱點(diǎn)處理。)

分布式緩存

在一個(gè)分布式緩存中(如圖1.12),沒(méi)個(gè)節(jié)點(diǎn)擁有部分緩存的數(shù)據(jù),如果將雜貨店里的冰箱比作一個(gè)緩存,那么一個(gè)分布式緩存好比是將你的食物放在幾個(gè)不同的地方——你的冰箱、食物柜、午餐飯盒里——非常便于取到快餐的地方而無(wú)需跑一趟商店。通常這類緩存使用一致性Hash算法進(jìn)行切分,這樣一個(gè)請(qǐng)求節(jié)點(diǎn)在查詢指定數(shù)據(jù)時(shí),可以很快知道去哪里查詢,并通過(guò)分布式緩存來(lái)判斷數(shù)據(jù)可用性。這種場(chǎng)景下,每個(gè)節(jié)點(diǎn)都會(huì)擁有一部分緩存,并且會(huì)將請(qǐng)求傳遞到其他節(jié)點(diǎn)來(lái)獲取數(shù)據(jù),最后才到原始地方查詢數(shù)據(jù)。因此,分布式緩存的一個(gè)優(yōu)勢(shì)就是通過(guò)往請(qǐng)求池里增加節(jié)點(diǎn)來(lái)擴(kuò)大緩存空間。

分布式緩存的一個(gè)缺點(diǎn)在于節(jié)點(diǎn)丟失糾正問(wèn)題。一些分布式緩存通過(guò)將復(fù)制數(shù)據(jù)多份存放在不同的節(jié)點(diǎn)來(lái)解決這個(gè)問(wèn)題;但是,你可以想象到這樣做會(huì)讓邏輯迅速變得復(fù)雜,特別是當(dāng)你向請(qǐng)求層增加或減少節(jié)點(diǎn)的時(shí)候。雖然一個(gè)節(jié)點(diǎn)丟失并且緩存失效,但請(qǐng)求仍然可以從源頭來(lái)獲?。〝?shù)據(jù))——所以這不一定是最悲劇的。

圖1.12 分布式緩存

緩存的偉大之處在于它們讓事情進(jìn)行的更快(當(dāng)然需要執(zhí)行正確)。你所選擇的方法只是讓你能夠更快處理更多的請(qǐng)求。但是,這些緩存是以需要維護(hù)更多存儲(chǔ)空間為代價(jià)的,特別是昂貴的內(nèi)存方式;天下沒(méi)有免費(fèi)的午餐。緩存讓事情變得更快,同時(shí)還保證了高負(fù)載條件下系統(tǒng)的功能,否則(系統(tǒng))服務(wù)可能早已降級(jí)。

一個(gè)非常受歡迎的開(kāi)源緩存叫做Memcached(http://memcached.org/)(既可以是本地又可以是分布式緩存);但是,還有很多其他選擇(包括許多語(yǔ)言/框架特定選擇)。Memcached被應(yīng)用于許多大型web網(wǎng)站,縱然它功能強(qiáng)大,但它簡(jiǎn)單來(lái)說(shuō)就是一個(gè)內(nèi)存key-value存儲(chǔ),對(duì)任意數(shù)據(jù)存儲(chǔ)和快速查找做了優(yōu)化(時(shí)間復(fù)雜度O(1))。

Facebook使用了若干種不同類型的緩存以達(dá)到他們網(wǎng)站的性能(要求,參加see “Facebook caching and performance“)。他們?cè)谡Z(yǔ)言層面使用$GLOBALS和APC緩存(在PHP中提供的函數(shù)調(diào)用)使得中間功能調(diào)用和(得到)結(jié)果更加快速。(大多數(shù)語(yǔ)言都有這種類型的類庫(kù)來(lái)提高web性能,應(yīng)該經(jīng)常去使用。)Facebook使用一種全局緩存,分布在多臺(tái)服務(wù)器上(參見(jiàn)”Scaling memcached at Facebook“),這樣一個(gè)訪問(wèn)緩存的函數(shù)調(diào)用就會(huì)產(chǎn)生很多并行請(qǐng)求來(lái)從Memcached服務(wù)器(集群)獲取數(shù)據(jù)。這使得他們能夠在用戶概況數(shù)據(jù)上獲得更高的性能和吞吐量,并且有一個(gè)集中的地方去更新數(shù)據(jù)(當(dāng)你運(yùn)行著數(shù)以千計(jì)的服務(wù)器時(shí),緩存失效、管理一致性都將變得很有挑戰(zhàn),所以這是很重要的)。

現(xiàn)在讓我們來(lái)聊聊當(dāng)數(shù)據(jù)不存在于緩存的時(shí)候應(yīng)該做什么。

代理

從基本層面來(lái)看,代理服務(wù)器是硬件/軟件的一個(gè)中間層,用于接收從客戶端發(fā)起的請(qǐng)求并傳遞到后端服務(wù)器。通常來(lái)說(shuō),代理是用來(lái)過(guò)濾請(qǐng)求、記錄請(qǐng)求日志或者有時(shí)對(duì)請(qǐng)求進(jìn)行轉(zhuǎn)換(增加/去除頭文件,加密/解密或者進(jìn)行壓縮)。

圖1.13:代理服務(wù)器

代理同樣能夠極大幫助協(xié)調(diào)多個(gè)服務(wù)器的請(qǐng)求,有機(jī)會(huì)從系統(tǒng)的角度來(lái)優(yōu)化請(qǐng)求流量。使用代理來(lái)加快數(shù)據(jù)訪問(wèn)速度的方式之一是將多個(gè)同種請(qǐng)求集中放到一個(gè)請(qǐng)求中,然后將單個(gè)結(jié)果返回到請(qǐng)求客戶端。這就叫做壓縮轉(zhuǎn)發(fā)(原文叫做collapsed forwarding)。

假設(shè)在幾個(gè)節(jié)點(diǎn)上存在對(duì)同樣數(shù)據(jù)的請(qǐng)求(我們叫它littleB),并且這份數(shù)據(jù)不在緩存里。如果請(qǐng)求通過(guò)代理路由,那么這些請(qǐng)求可以被壓縮為一個(gè),就意味著我們只需要從磁盤讀取一次littleB即可。(見(jiàn)圖1.14)這種設(shè)計(jì)是會(huì)帶來(lái)一定的開(kāi)銷,因?yàn)槊總€(gè)請(qǐng)求都會(huì)產(chǎn)生更高的延遲(跟不用代理相比),并且一些請(qǐng)求會(huì)因?yàn)橐c相同請(qǐng)求合并而產(chǎn)生一些延遲。但這種做法在高負(fù)載的情況下提高系統(tǒng)性能,特別是當(dāng)相同的數(shù)據(jù)重復(fù)被請(qǐng)求。這很像緩存,但不用像緩存那樣存儲(chǔ)數(shù)據(jù)/文件,而是優(yōu)化了對(duì)那些文件的請(qǐng)求或調(diào)用,并且充當(dāng)那些客戶端的代理。

例如,在局域網(wǎng)(LAN)代理中,客戶端不需有自己的IP來(lái)連接互聯(lián)網(wǎng),而局域網(wǎng)會(huì)將對(duì)同樣內(nèi)容的客戶端請(qǐng)求進(jìn)行壓縮。這里可能很容易產(chǎn)生困惑,因?yàn)樵S多代理同樣也是緩存(因?yàn)樵谶@里放一個(gè)緩存很合理),但不是所有緩存都能充當(dāng)代理。

圖1.14:使用一個(gè)代理服務(wù)器來(lái)壓縮請(qǐng)求

另一個(gè)使用代理的好方法是,不單把代理用來(lái)壓縮對(duì)同樣數(shù)據(jù)的請(qǐng)求,還可以用來(lái)壓縮對(duì)那些在原始存儲(chǔ)中空間上緊密聯(lián)系的數(shù)據(jù)(磁盤連續(xù)塊)的請(qǐng)求。使用這一策略最大化(利用)所請(qǐng)求數(shù)據(jù)的本地性,可以減少請(qǐng)求延遲。例如,我們假設(shè)一群節(jié)點(diǎn)請(qǐng)求B的部分(數(shù)據(jù)):B1, B2,等。我們可以對(duì)代理進(jìn)行設(shè)置使其能夠識(shí)別出不同請(qǐng)求的空間局部性,將它們壓縮為單個(gè)請(qǐng)求并且只返回bigB,最小化對(duì)原始數(shù)據(jù)的讀取操作。(見(jiàn)圖1.15)當(dāng)你隨機(jī)訪問(wèn)TB級(jí)的數(shù)據(jù)時(shí),這樣會(huì)大幅改變(降低)請(qǐng)求時(shí)間。在高負(fù)載情況下或者當(dāng)你只有有限的緩存,代理是非常有幫助的,因?yàn)榇砜梢詮母旧蠈⑷舾蓚€(gè)請(qǐng)求合并為一個(gè)。

圖1.15:使用代理壓縮空間上鄰近的數(shù)據(jù)請(qǐng)求

你完全可以一并使用代理和緩存,但通常最好將緩存放在代理之前使用,正如在馬拉松賽跑中最好讓跑得快的選手跑在前面。這是因?yàn)榫彺嫱ㄟ^(guò)內(nèi)存來(lái)提供數(shù)據(jù)非常快速,并且它也不關(guān)心多個(gè)對(duì)同樣結(jié)果的請(qǐng)求。但如果緩存被放在代理服務(wù)器的另一邊(后面),那在每個(gè)請(qǐng)求訪問(wèn)緩存前就會(huì)有額外的延遲,這會(huì)阻礙系統(tǒng)性能。

如果你在尋找一款代理想要加入到你的系統(tǒng)中,那有很多選擇可供考慮;Squid和Varnish都是經(jīng)過(guò)路演并廣泛應(yīng)用于很多網(wǎng)站的生產(chǎn)環(huán)境中。這些代理方案做了很多優(yōu)化來(lái)充分使用客戶端與服務(wù)端的通信。安裝其中之一并在web服務(wù)器層將其作為一個(gè)反向代理(將在下面的負(fù)載均衡小節(jié)解釋)可以提高web服務(wù)器相當(dāng)大的性能,降低處理來(lái)自客戶端的請(qǐng)求所消耗的工作量。

索引

使用索引來(lái)加快訪問(wèn)數(shù)據(jù)已經(jīng)是優(yōu)化數(shù)據(jù)訪問(wèn)性能眾所周知的策略;可能更多來(lái)自數(shù)據(jù)庫(kù)。索引是以增加存儲(chǔ)開(kāi)銷和減慢寫(xiě)入速度(因?yàn)槟惚仨毻瑫r(shí)寫(xiě)入數(shù)據(jù)并更新索引)的代價(jià)來(lái)得到更快讀取的好處。

就像對(duì)于傳統(tǒng)的關(guān)系數(shù)據(jù)庫(kù),你同樣可以將這種概念應(yīng)用到大數(shù)據(jù)集上。索引的訣竅在于你必須仔細(xì)考慮你的用戶會(huì)如何使用你的數(shù)據(jù)。對(duì)于TB級(jí)但單項(xiàng)數(shù)據(jù)比較?。ū热?KB,原文這里寫(xiě)的是small payload)的數(shù)據(jù)集,索引是優(yōu)化數(shù)據(jù)訪問(wèn)非常必要的方式。在一個(gè)大數(shù)據(jù)集中尋找一個(gè)小單元是非常困難的,因?yàn)槟悴豢赡茉谝粋€(gè)可接受的時(shí)間里遍歷這么大的數(shù)據(jù)。并且,像這么一個(gè)大數(shù)據(jù)集很有可能是分布在幾個(gè)(或更多)物理設(shè)備上——這就意味著你需要有方法能夠找到所要數(shù)據(jù)正確的物理位置。索引是達(dá)到這個(gè)的最好方法。

圖1.16:索引

索引可以像一張可以引導(dǎo)你至所要數(shù)據(jù)位置的表格來(lái)使用。例如,我們假設(shè)你在尋找B的part2數(shù)據(jù)——你將如何知道到哪去找到它?如果你有一個(gè)按照數(shù)據(jù)類型(如A,B,C)排序好的索引,它會(huì)告訴你數(shù)據(jù)B在哪里。然后你查找到位置,然后讀取你所要的部分。(見(jiàn)圖1.16)
這些索引通常存放在內(nèi)存中,或者在更靠近客戶端請(qǐng)求的地方。伯克利數(shù)據(jù)庫(kù)(BDBs)和樹(shù)形數(shù)據(jù)結(jié)構(gòu)經(jīng)常用來(lái)有序地存儲(chǔ)數(shù)據(jù),非常適合通過(guò)索引來(lái)訪問(wèn)。

索引經(jīng)常會(huì)有很多層,類似一個(gè)map,將你從一個(gè)地方引導(dǎo)至另一個(gè),以此類推,直到你獲取到你所要的那份數(shù)據(jù)。(見(jiàn)圖1.17)

圖1.17:多層索引

索引也可以用來(lái)對(duì)同樣的數(shù)據(jù)創(chuàng)建出一些不同的視圖。對(duì)于大數(shù)據(jù)集來(lái)說(shuō),通過(guò)定義不同的過(guò)濾器和排序是一個(gè)很好的方式,而不需要?jiǎng)?chuàng)建很多額外數(shù)據(jù)拷貝。

例如,假設(shè)之前的圖片托管系統(tǒng)就是在管理書(shū)頁(yè)上的圖片,并且服務(wù)能夠允許客戶端查詢圖片中的文字,按照標(biāo)題搜索整本書(shū)的內(nèi)容,就像搜索引擎允許你搜索HTML內(nèi)容一樣。這種場(chǎng)景下,所有書(shū)中的圖片需要很多很多的服務(wù)器去存儲(chǔ)文件,查找到其中一頁(yè)渲染給用戶將會(huì)是比較復(fù)雜的。首先,對(duì)需要易于查詢的任意單詞、詞組進(jìn)行倒排索引;然后挑戰(zhàn)在于導(dǎo)航至那本書(shū)具體的頁(yè)面、位置并獲取到正確的圖片。所以,在這一場(chǎng)景,倒排索引將會(huì)映射到一個(gè)位置(比如B書(shū)),然后B可能會(huì)包含每個(gè)部分的所有單詞、位置、出現(xiàn)次數(shù)的索引。
倒排索引可能如同下圖——每個(gè)單詞或詞組會(huì)提供一個(gè)哪些書(shū)包含它的索引。

這種中間索引看上去都類似,僅會(huì)包含單詞、位置和B的一些信息。這種嵌套索引的架構(gòu)允許每個(gè)索引占用更少的空間而非將所有的信息存放在一個(gè)巨大的倒排索引中。

在大型可伸縮的系統(tǒng)中,即使索引已被壓縮但仍會(huì)變得很大,不易存儲(chǔ)。在這個(gè)系統(tǒng)里,我們假設(shè)世界上有很多書(shū)——100,000,000本——并且每本書(shū)僅有10頁(yè)(為了便于計(jì)算),每頁(yè)有250個(gè)單詞,這就意味著一共有2500億個(gè)單詞。如果我們假設(shè)平均每個(gè)單詞有5個(gè)字符,每個(gè)字符占用8個(gè)比特,每個(gè)單詞5個(gè)字節(jié),那么對(duì)于僅包含每個(gè)單詞的索引的大小就達(dá)到TB級(jí)。所以你會(huì)發(fā)現(xiàn)創(chuàng)建像一些如詞組、數(shù)據(jù)位置、出現(xiàn)次數(shù)之類的其他信息的索引將會(huì)增長(zhǎng)得更快。

創(chuàng)建這些中間索引并且以更小的方式表達(dá)數(shù)據(jù),將大數(shù)據(jù)的問(wèn)題變得易于處理。數(shù)據(jù)可以分布在多臺(tái)服務(wù)器但仍可以快速訪問(wèn)。索引是信息獲取的基石,也是當(dāng)今現(xiàn)代搜索引擎的基礎(chǔ)。當(dāng)然,這一小節(jié)僅僅是揭開(kāi)表面,為了把索引變得更小、更快、包含更多信息(比如關(guān)聯(lián))、無(wú)縫更新,還有大量的研究工作要做。(還有一些可管理性方面的挑戰(zhàn),比如競(jìng)爭(zhēng)條件、增加或修改數(shù)據(jù)所帶來(lái)的更新操作,特別是再加上關(guān)聯(lián)、scoring)

能夠快速、簡(jiǎn)單地找到你的數(shù)據(jù)非常重要;索引是達(dá)到這一目標(biāo)非常有效、簡(jiǎn)單的工具。

負(fù)載均衡

另一個(gè)任何分布式系統(tǒng)的關(guān)鍵組件是負(fù)載均衡器。負(fù)載均衡器是任何架構(gòu)的關(guān)鍵部分,用于將負(fù)載分?jǐn)傇谝恍┝胸?fù)責(zé)服務(wù)請(qǐng)求的節(jié)點(diǎn)上。這使得一個(gè)系統(tǒng)的多個(gè)節(jié)點(diǎn)能夠?yàn)橄嗤δ芴峁┓?wù)。(見(jiàn)圖1.18)它們主要目的是處理許多同時(shí)進(jìn)行的連接并將這些連接路由到其中的一個(gè)請(qǐng)求節(jié)點(diǎn)上,使得系統(tǒng)能夠可伸縮地通過(guò)增加節(jié)點(diǎn)來(lái)服務(wù)更多請(qǐng)求。

圖1.18 負(fù)載均衡器

有很多不同的用于服務(wù)請(qǐng)求的算法,包括隨機(jī)挑選一個(gè)節(jié)點(diǎn)、循環(huán)(round robin)或給予某些標(biāo)準(zhǔn)如內(nèi)存/CPU使用率選取節(jié)點(diǎn)。一個(gè)廣泛使用的開(kāi)源軟件級(jí)負(fù)載均衡器是HAProxy。

在一個(gè)分布式系統(tǒng)中,負(fù)責(zé)均衡器通常是放置在系統(tǒng)很前端的地方,這樣就能路由所有進(jìn)入(系統(tǒng))的請(qǐng)求。在一個(gè)復(fù)雜的分布式系統(tǒng)中,一個(gè)請(qǐng)求被多個(gè)負(fù)載均衡器路由也不是不可能。(見(jiàn)圖1.19)

圖1.19:多重負(fù)責(zé)均衡器

如同代理一般,一些負(fù)載均衡器也能根據(jù)不同類型的請(qǐng)求進(jìn)行路由。(從技術(shù)上來(lái)說(shuō),就是所謂的反向代理。)

負(fù)載均衡器的挑戰(zhàn)之一在于(如何)管理用戶session數(shù)據(jù)。在一個(gè)電子商務(wù)網(wǎng)站,當(dāng)你只有一個(gè)客戶端時(shí)很容易讓用戶把東西放到他們的購(gòu)物車并且在不同的訪問(wèn)間保存(這是很重要的,因?yàn)楫?dāng)用戶回來(lái)時(shí)很有可能買放在購(gòu)物車?yán)锏漠a(chǎn)品)。但是,如果一個(gè)用戶先被路由到一個(gè)session節(jié)點(diǎn),然后在他們下次訪問(wèn)時(shí)路由到另一個(gè)不同的節(jié)點(diǎn),那將會(huì)因?yàn)樾鹿?jié)點(diǎn)可能丟失用戶購(gòu)物車?yán)锏臇|西而產(chǎn)生不一致。(如果你精心挑選了6包Mountain Dew放到購(gòu)物車,但當(dāng)你回來(lái)的時(shí)候發(fā)現(xiàn)購(gòu)物車清空了,你會(huì)不會(huì)很沮喪?)解決辦法之一通過(guò)粘性session機(jī)制總是將用戶路由到同一節(jié)點(diǎn),但這樣既很難享受到一些像自動(dòng)failover的可靠機(jī)制了。在這一場(chǎng)景下,用戶的購(gòu)物車總是會(huì)有東西的,如果他們所對(duì)應(yīng)的粘性節(jié)點(diǎn)不可用了,那么就會(huì)是一個(gè)特殊情況對(duì)于(保存)在那里的東西的假設(shè)就無(wú)效了(當(dāng)然我們希望這種假設(shè)不會(huì)出現(xiàn)在應(yīng)用里)。當(dāng)然,這個(gè)問(wèn)題可以通過(guò)本章中的一些其他策略或者工具來(lái)解決,比如服務(wù),還有一些沒(méi)有提到的(如瀏覽器緩存、cookie、URL地址重寫(xiě))。

【譯者注】上段中提到的用戶session問(wèn)題,實(shí)際上在很多大型網(wǎng)站如淘寶、支付寶,都是通過(guò)一個(gè)分布式session的中間件來(lái)解決的。原理其實(shí)很簡(jiǎn)單,比如用戶登錄了支付寶,那么系統(tǒng)會(huì)給當(dāng)前用戶分配一個(gè)全局唯一的sessionId并寫(xiě)入到瀏覽器的cookie中,在后臺(tái)服務(wù)端也會(huì)有專門的一個(gè)分布式存儲(chǔ)以sessionId為key開(kāi)辟一個(gè)空間存放該用戶session數(shù)據(jù)。雖然應(yīng)用都是集群部署方式,但每個(gè)無(wú)狀態(tài)應(yīng)用節(jié)點(diǎn)都會(huì)統(tǒng)一連接到該分布式存儲(chǔ)。由于用戶session數(shù)據(jù)是統(tǒng)一保存在分布式存儲(chǔ)上,即對(duì)session數(shù)據(jù)的存取都是發(fā)生在同一個(gè)地方,而非各個(gè)節(jié)點(diǎn)內(nèi)部,所以不會(huì)因?yàn)椴煌恼?qǐng)求路由到不同的應(yīng)用節(jié)點(diǎn)上導(dǎo)致session數(shù)據(jù)不一致的情況。同時(shí),這一方法不會(huì)像sticky session機(jī)制那樣限制了系統(tǒng)的可伸縮性。如果出現(xiàn)session存取的性能問(wèn)題,那只需通過(guò)擴(kuò)展后端分布式存儲(chǔ)即可解決。
如果系統(tǒng)只是由少數(shù)節(jié)點(diǎn)構(gòu)成的,那么像Round Robin DNS那樣的系統(tǒng)就更加明智,因?yàn)樨?fù)責(zé)均衡器很貴而且增加了一層不必要的復(fù)雜度。當(dāng)然在大型系統(tǒng)里有各種各樣的調(diào)度和負(fù)載均衡算法,包括簡(jiǎn)單的像隨機(jī)選擇或循環(huán)方式,還有更加復(fù)雜的機(jī)制如考慮(系統(tǒng))使用率和容量的。所有這些算法都分布化了流量和請(qǐng)求,并且提供像自動(dòng)failover或者自動(dòng)去除壞節(jié)點(diǎn)(當(dāng)該節(jié)點(diǎn)失去響應(yīng)后)這類對(duì)可靠性非常有幫助的工具。但是,這些先進(jìn)特性也會(huì)使得問(wèn)題診斷變得復(fù)雜化。比如,在一個(gè)高負(fù)載情況下,負(fù)載均衡器會(huì)去除掉那些變慢或者超時(shí)(由于請(qǐng)求過(guò)多)的節(jié)點(diǎn),但這樣反而加重了其他節(jié)點(diǎn)的(惡劣)處境。在這些情況下,全面監(jiān)控變得很重要,因?yàn)閺娜謥?lái)看系統(tǒng)的流量和吞吐量正在下降(由于各節(jié)點(diǎn)服務(wù)請(qǐng)求越來(lái)越少),但從節(jié)點(diǎn)個(gè)體來(lái)看正在達(dá)到極限。

負(fù)載均衡器是一個(gè)非常簡(jiǎn)單能讓你提高系統(tǒng)容量的方法,并且像本文其他的技術(shù)一樣,在分布式系統(tǒng)架構(gòu)中扮演者重要角色。負(fù)載均衡器還能用來(lái)判斷一個(gè)節(jié)點(diǎn)的健康度,這樣當(dāng)一個(gè)節(jié)點(diǎn)失去響應(yīng)或者過(guò)載時(shí),得益于系統(tǒng)不同節(jié)點(diǎn)的冗余性,可以將其從請(qǐng)求處理池中去除。
隊(duì)列

至此,我們已經(jīng)覆蓋了很多用于加快數(shù)據(jù)讀取的方法,另一個(gè)擴(kuò)展數(shù)據(jù)層的重要部分是有效管理寫(xiě)入操作。當(dāng)系統(tǒng)比較簡(jiǎn)單,系統(tǒng)處理負(fù)載很低,數(shù)據(jù)庫(kù)也很小,可以預(yù)見(jiàn)寫(xiě)入操作是很快的;但是,在更加復(fù)雜的系統(tǒng)中,寫(xiě)入操作的時(shí)間可能無(wú)法確定。例如,數(shù)據(jù)需要被寫(xiě)入到不同服務(wù)器或索引的多個(gè)地方,或者系統(tǒng)負(fù)載很高。這些情況下,由于上面的原因,寫(xiě)操作或者任何任務(wù)都會(huì)花費(fèi)很長(zhǎng)的時(shí)間,這時(shí)需要異步化系統(tǒng)才能提高系統(tǒng)的性能和可靠性;通常的方法之一是使用隊(duì)列。

圖1.20:同步化請(qǐng)求

假設(shè)在一個(gè)系統(tǒng)中,每個(gè)客戶端在請(qǐng)求遠(yuǎn)程服務(wù)來(lái)處理任務(wù)。每個(gè)客戶端將其請(qǐng)求送至服務(wù)器,服務(wù)器盡可能快地完成這些任務(wù)并返回結(jié)果給相應(yīng)的客戶端。在小型系統(tǒng)中,當(dāng)一臺(tái)服務(wù)器(或者邏輯上的一個(gè)服務(wù))可以盡快地服務(wù)到來(lái)的客戶端(請(qǐng)求),這種情況下(系統(tǒng))工作會(huì)比較好。但是,當(dāng)服務(wù)器接收到超過(guò)其處理能力的請(qǐng)求時(shí),那每個(gè)客戶端都只能被迫等待其他客戶端請(qǐng)求完成才能得到響應(yīng)。圖1.20描繪的就是一個(gè)同步請(qǐng)求的例子。

這種同步的方式將會(huì)嚴(yán)重降低客戶端性能;客戶端被強(qiáng)制等待,在請(qǐng)求被響應(yīng)前什么都做不了。增加額外的服務(wù)器并不能解決這個(gè)問(wèn)題;即使通過(guò)有效的負(fù)載均衡,依然難以保證最大化客戶端性能所需做的公平分配的工作。更進(jìn)一步來(lái)說(shuō),當(dāng)處理請(qǐng)求的服務(wù)器不可用或掛掉了,那么上游的客戶端同樣也會(huì)失敗。有效解決這個(gè)問(wèn)題需要抽象化客戶端的請(qǐng)求和真正服務(wù)它所做的工作。

圖1.21:使用隊(duì)列來(lái)管理請(qǐng)求

現(xiàn)在進(jìn)入隊(duì)列環(huán)節(jié)。一個(gè)隊(duì)列,正如聽(tīng)上去的,簡(jiǎn)單來(lái)說(shuō)就是當(dāng)一個(gè)任務(wù)過(guò)來(lái)時(shí),會(huì)被加入到隊(duì)列中,然后會(huì)有當(dāng)前有能力處理(任務(wù))的worker去取下一個(gè)任務(wù)來(lái)做。(見(jiàn)圖1.21。)這些任務(wù)可以是對(duì)數(shù)據(jù)庫(kù)的寫(xiě)入操作,或是復(fù)雜一些的如生成文件的小型預(yù)覽圖。當(dāng)一個(gè)客戶端將任務(wù)的請(qǐng)求提交到隊(duì)列后,它們不再需要被迫等待結(jié)果;取而代之的是,它們只需要確認(rèn)請(qǐng)求被得到正確接收。當(dāng)客戶端需要的時(shí)候,這個(gè)確認(rèn)此后可以當(dāng)做是任務(wù)結(jié)果的引用。

隊(duì)列使得客戶端能夠以異步的方式進(jìn)行工作,至關(guān)重要地抽象了一個(gè)客戶端請(qǐng)求及其響應(yīng)。另一方面,一個(gè)同步化系統(tǒng)不會(huì)區(qū)分請(qǐng)求和響應(yīng),因此就無(wú)法分開(kāi)管理。在一個(gè)異步化系統(tǒng)里,客戶端提交任務(wù)請(qǐng)求,后端服務(wù)反饋一個(gè)收到任務(wù)的確認(rèn)信息,并且客戶端可以定期地查看任務(wù)的狀態(tài),一旦完成即可取得任務(wù)結(jié)果。在客戶端等待一個(gè)異步請(qǐng)求完成時(shí),它可以自由地處理其他的工作,即使是發(fā)起對(duì)其他服務(wù)的異步請(qǐng)求。上面第二個(gè)就是分布式系統(tǒng)中采用隊(duì)列和消息的例子。

隊(duì)列還能提供對(duì)服務(wù)斷供/失敗的保護(hù)措施。比如,很容易創(chuàng)建一個(gè)健壯的隊(duì)列來(lái)重試那些由于服務(wù)器短暫失敗的服務(wù)請(qǐng)求。更好的是通過(guò)使用隊(duì)列來(lái)確保服務(wù)品質(zhì),而非將客戶端直接面對(duì)斷斷續(xù)續(xù)的服務(wù),因?yàn)槟菢訒?huì)需要客戶端復(fù)雜且經(jīng)常不一致的錯(cuò)誤處理。

隊(duì)列是管理大型可伸縮分布式應(yīng)用不同部分間通信的基礎(chǔ),可以通過(guò)很多方式來(lái)實(shí)現(xiàn)。有一些開(kāi)源的隊(duì)列如RabbitMQ, ActiveMQBeanstalkD,也有一些使用像Zookeeper的服務(wù),還有像Redis那樣的數(shù)據(jù)存儲(chǔ)。

【譯者注】隊(duì)列是分布式系統(tǒng)異步化的一個(gè)關(guān)鍵基礎(chǔ)組件。在淘寶、支付寶這類大型分布式網(wǎng)站中應(yīng)用廣泛。正如大家所知的雙十一、雙十二,這兩天用戶的請(qǐng)求可謂超級(jí)海量。拿支付寶來(lái)說(shuō),核心系統(tǒng)如支付、賬務(wù),即使使用了很多技術(shù)方案來(lái)確保高性能、高可用,但面對(duì)數(shù)倍、數(shù)十倍于平時(shí)的請(qǐng)求量,依然捉急。在開(kāi)發(fā)了一套分布式隊(duì)列基礎(chǔ)中間件后,網(wǎng)站的吞吐量、可用性得到了很大的提高。同時(shí),對(duì)于隊(duì)列來(lái)說(shuō),除了將客戶端請(qǐng)求與服務(wù)端處理分離外,通過(guò)對(duì)隊(duì)列加上額外的一些特性,能夠起到非常大的作用。比如,在隊(duì)列上加入限流特性,當(dāng)請(qǐng)求量大大超過(guò)后端服務(wù)處理能力時(shí),可以采取丟棄請(qǐng)求的方式來(lái)保證系統(tǒng)、隊(duì)列不至于被海量請(qǐng)求壓垮;當(dāng)請(qǐng)求量回到一定水平,再將限流放開(kāi)。這種做法,正好滿足了系統(tǒng)對(duì)可用性、性能、可伸縮性、可管理性的要求。

總結(jié)

設(shè)計(jì)出能夠快速訪問(wèn)大量數(shù)據(jù)的高效系統(tǒng)(的方法)是存在的,并且又很多非常棒的工具來(lái)幫助各種各樣的新應(yīng)用來(lái)達(dá)到這一點(diǎn)。本章只覆蓋了少量例子,僅僅是掀開(kāi)了面紗,但其實(shí)還有更多,并將繼續(xù)保持創(chuàng)新。


本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
構(gòu)建高可擴(kuò)Web架構(gòu)和分布式系統(tǒng)實(shí)戰(zhàn)(下)
分布式系統(tǒng)中碰到的問(wèn)題
.net面試題-15k+左右
《大型技術(shù)架構(gòu)》讀書(shū)筆記
最全面的緩存架構(gòu)設(shè)計(jì)(全是干貨)
Nginx Redis Ehcache:大型高并發(fā)與高可用的三層緩存架構(gòu)總結(jié)
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服