溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的

發(fā)布時(shí)間:2022-01-07 20:14:35 來源:億速云 閱讀:122 作者:iii 欄目:編程語言

這篇文章主要介紹“大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的”,在日常操作中,相信很多人在大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的

接下來,我們將看看高階的權(quán)衡和取舍:

  • 性能與可擴(kuò)展性

  • 延遲與吞吐量

  • 可用性與一致性

記住每個(gè)方面都面臨取舍和權(quán)衡。

然后,我們將深入更具體的主題,如 DNS、CDN負(fù)載均衡器。

1. 性能與可擴(kuò)展性

如果服務(wù)性能的增長與資源的增加是成比例的,服務(wù)就是可擴(kuò)展的。通常,提高性能意味著服務(wù)于更多的工作單元,另一方面,當(dāng)數(shù)據(jù)集增長時(shí),同樣也可以處理更大的工作單位。 1

另一個(gè)角度來看待性能與可擴(kuò)展性:

  • 如果你的系統(tǒng)有性能問題,對于單個(gè)用戶來說是緩慢的。

  • 如果你的系統(tǒng)有可擴(kuò)展性問題,單個(gè)用戶較快但在高負(fù)載下會變慢。

2. 延遲與吞吐量

延遲是執(zhí)行操作或運(yùn)算結(jié)果所花費(fèi)的時(shí)間。

吞吐量是單位時(shí)間內(nèi)(執(zhí)行)此類操作或運(yùn)算的數(shù)量。

通常,你應(yīng)該以可接受級延遲下最大化吞吐量為目標(biāo)。

3. 可用性與一致性

CAP 理論

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的 

在一個(gè)分布式計(jì)算系統(tǒng)中,只能同時(shí)滿足下列的兩點(diǎn):

  • 一致性 ─ 每次訪問都能獲得最新數(shù)據(jù)但可能會收到錯(cuò)誤響應(yīng)

  • 可用性 ─ 每次訪問都能收到非錯(cuò)響應(yīng),但不保證獲取到最新數(shù)據(jù)

  • 分區(qū)容錯(cuò)性 ─ 在任意分區(qū)網(wǎng)絡(luò)故障的情況下系統(tǒng)仍能繼續(xù)運(yùn)行

網(wǎng)絡(luò)并不可靠,所以你應(yīng)要支持分區(qū)容錯(cuò)性,并需要在軟件可用性和一致性間做出取舍。

CP ─ 一致性和分區(qū)容錯(cuò)性

等待分區(qū)節(jié)點(diǎn)的響應(yīng)可能會導(dǎo)致延時(shí)錯(cuò)誤。如果你的業(yè)務(wù)需求需要原子讀寫,CP 是一個(gè)不錯(cuò)的選擇。

AP ─ 可用性與分區(qū)容錯(cuò)性

響應(yīng)節(jié)點(diǎn)上可用數(shù)據(jù)的最近版本可能并不是最新的。當(dāng)分區(qū)解析完后,寫入(操作)可能需要一些時(shí)間來傳播。

如果業(yè)務(wù)需求允許最終一致性,或當(dāng)有外部故障時(shí)要求系統(tǒng)繼續(xù)運(yùn)行,AP 是一個(gè)不錯(cuò)的選擇。

4. 一致性模式

有同一份數(shù)據(jù)的多份副本,我們面臨著怎樣同步它們的選擇,以便讓客戶端有一致的顯示數(shù)據(jù)?;叵?nbsp;CAP 理論中的一致性定義 ─ 每次訪問都能獲得最新數(shù)據(jù)但可能會收到錯(cuò)誤響應(yīng)

弱一致性

在寫入之后,訪問可能看到,也可能看不到(寫入數(shù)據(jù))。盡力優(yōu)化之讓其能訪問最新數(shù)據(jù)。

這種方式可以 memcached 等系統(tǒng)中看到。弱一致性在 VoIP,視頻聊天和實(shí)時(shí)多人游戲等真實(shí)用例中表現(xiàn)不錯(cuò)。打個(gè)比方,如果你在通話中丟失信號幾秒鐘時(shí)間,當(dāng)重新連接時(shí)你是聽不到這幾秒鐘所說的話的。

最終一致性

在寫入后,訪問最終能看到寫入數(shù)據(jù)(通常在數(shù)毫秒內(nèi))。數(shù)據(jù)被異步復(fù)制。

DNS 和 email 等系統(tǒng)使用的是此種方式。最終一致性在高可用性系統(tǒng)中效果不錯(cuò)。

強(qiáng)一致性

在寫入后,訪問立即可見。數(shù)據(jù)被同步復(fù)制。

文件系統(tǒng)和關(guān)系型數(shù)據(jù)庫(RDBMS)中使用的是此種方式。強(qiáng)一致性在需要記錄的系統(tǒng)中運(yùn)作良好。

5. 可用性模式

有兩種支持高可用性的模式: 故障切換(fail-over)和復(fù)制(replication)。

故障切換

工作到備用切換(Active-passive)

關(guān)于工作到備用的故障切換流程是,工作服務(wù)器發(fā)送周期信號給待機(jī)中的備用服務(wù)器。如果周期信號中斷,備用服務(wù)器切換成工作服務(wù)器的 IP 地址并恢復(fù)服務(wù)。

宕機(jī)時(shí)間取決于備用服務(wù)器處于“熱”待機(jī)狀態(tài)還是需要從“冷”待機(jī)狀態(tài)進(jìn)行啟動(dòng)。只有工作服務(wù)器處理流量。

工作到備用的故障切換也被稱為主從切換。

雙工作切換(Active-active)

在雙工作切換中,雙方都在管控流量,在它們之間分散負(fù)載。

如果是外網(wǎng)服務(wù)器,DNS 將需要對兩方都了解。如果是內(nèi)網(wǎng)服務(wù)器,應(yīng)用程序邏輯將需要對兩方都了解。

雙工作切換也可以稱為主主切換。

缺陷:故障切換

  • 故障切換需要添加額外硬件并增加復(fù)雜性。

  • 如果新寫入數(shù)據(jù)在能被復(fù)制到備用系統(tǒng)之前,工作系統(tǒng)出現(xiàn)了故障,則有可能會丟失數(shù)據(jù)。

復(fù)制

主 ─ 從復(fù)制和主 ─ 主復(fù)制

這個(gè)主題進(jìn)一步探討了數(shù)據(jù)庫部分:

  • 主 ─ 從復(fù)制

  • 主 ─ 主復(fù)制

6. 域名系統(tǒng)

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的 

域名系統(tǒng)是把 www.example.com 等域名轉(zhuǎn)換成 IP 地址。

域名系統(tǒng)是分層次的,一些 DNS 服務(wù)器位于頂層。當(dāng)查詢(域名) IP 時(shí),路由或 ISP 提供連接 DNS 服務(wù)器的信息。較底層的 DNS 服務(wù)器緩存映射,它可能會因?yàn)?DNS 傳播延時(shí)而失效。DNS 結(jié)果可以緩存在瀏覽器或操作系統(tǒng)中一段時(shí)間,時(shí)間長短取決于存活時(shí)間 TTL。

  • NS 記錄(域名服務(wù)) ─ 指定解析域名或子域名的 DNS 服務(wù)器。

  • MX 記錄(郵件交換) ─ 指定接收信息的郵件服務(wù)器。

  • A 記錄(地址) ─ 指定域名對應(yīng)的 IP 地址記錄。

  • CNAME(規(guī)范) ─ 一個(gè)域名映射到另一個(gè)域名或 CNAME 記錄( example.com 指向 www.example.com )或映射到一個(gè) A 記錄。

CloudFlare 和 Route 53 等平臺提供管理 DNS 的功能。某些 DNS 服務(wù)通過集中方式來路由流量:

  • 加權(quán)輪詢調(diào)度

    • 防止流量進(jìn)入維護(hù)中的服務(wù)器

    • 在不同大小集群間負(fù)載均衡

    • A/B 測試

  • 基于延遲路由

  • 基于地理位置路由

缺陷:DNS

  • 雖說緩存可以減輕 DNS 延遲,但連接 DNS 服務(wù)器還是帶來了輕微的延遲。

  • 雖然它們通常由政府,網(wǎng)絡(luò)服務(wù)提供商和大公司管理,但 DNS 服務(wù)管理仍可能是復(fù)雜的。

  • DNS 服務(wù)最近遭受 DDoS 攻擊,阻止不知道 Twtter IP 地址的用戶訪問 Twiiter。

7. 內(nèi)容分發(fā)網(wǎng)絡(luò)(CDN)

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的

內(nèi)容分發(fā)網(wǎng)絡(luò)(CDN)是一個(gè)全球性的代理服務(wù)器分布式網(wǎng)絡(luò),它從靠近用戶的位置提供內(nèi)容。通常,HTML/CSS/JS,圖片和視頻等靜態(tài)內(nèi)容由 CDN 提供,雖然亞馬遜 CloudFront 等也支持動(dòng)態(tài)內(nèi)容。CDN 的 DNS 解析會告知客戶端連接哪臺服務(wù)器。

將內(nèi)容存儲在 CDN 上可以從兩個(gè)方面來提供性能:

  • 從靠近用戶的數(shù)據(jù)中心提供資源

  • 通過 CDN 你的服務(wù)器不必真的處理請求

CDN 推送(push)

當(dāng)你服務(wù)器上內(nèi)容發(fā)生變動(dòng)時(shí),推送 CDN 接受新內(nèi)容。直接推送給 CDN 并重寫 URL 地址以指向你的內(nèi)容的 CDN 地址。你可以配置內(nèi)容到期時(shí)間及何時(shí)更新。內(nèi)容只有在更改或新增是才推送,流量最小化,但儲存最大化。

CDN 拉?。╬ull)

CDN 拉取是當(dāng)?shù)谝粋€(gè)用戶請求該資源時(shí),從服務(wù)器上拉取資源。你將內(nèi)容留在自己的服務(wù)器上并重寫 URL 指向 CDN 地址。直到內(nèi)容被緩存在 CDN 上為止,這樣請求只會更慢,

存活時(shí)間(TTL)決定緩存多久時(shí)間。CDN 拉取方式最小化 CDN 上的儲存空間,但如果過期文件并在實(shí)際更改之前被拉取,則會導(dǎo)致冗余的流量。

高流量站點(diǎn)使用 CDN 拉取效果不錯(cuò),因?yàn)橹挥凶罱埱蟮膬?nèi)容保存在 CDN 中,流量才能更平衡地分散。

缺陷:CDN

  • CDN 成本可能因流量而異,可能在權(quán)衡之后你將不會使用 CDN。

  • 如果在 TTL 過期之前更新內(nèi)容,CDN 緩存內(nèi)容可能會過時(shí)。

  • CDN 需要更改靜態(tài)內(nèi)容的 URL 地址以指向 CDN。

8. 負(fù)載均衡器

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的

負(fù)載均衡器將傳入的請求分發(fā)到應(yīng)用服務(wù)器和數(shù)據(jù)庫等計(jì)算資源。無論哪種情況,負(fù)載均衡器將從計(jì)算資源來的響應(yīng)返回給恰當(dāng)?shù)目蛻舳?。?fù)載均衡器的效用在于:

  • 防止請求進(jìn)入不好的服務(wù)器

  • 防止資源過載

  • 幫助消除單一的故障點(diǎn)

負(fù)載均衡器可以通過硬件(昂貴)或 HAProxy 等軟件來實(shí)現(xiàn)。 增加的好處包括:

  • SSL 終結(jié) ─ 解密傳入的請求并加密服務(wù)器響應(yīng),這樣的話后端服務(wù)器就不必再執(zhí)行這些潛在高消耗運(yùn)算了。

    • 不需要再每臺服務(wù)器上安裝 X.509 證書。

  • Session 留存 ─ 如果 Web 應(yīng)用程序不追蹤會話,發(fā)出 cookie 并將特定客戶端的請求路由到同一實(shí)例。

通常會設(shè)置采用工作 ─ 備用 或 雙工作 模式的多個(gè)負(fù)載均衡器,以免發(fā)生故障。

負(fù)載均衡器能基于多種方式來路由流量:

  • 隨機(jī)

  • 最少負(fù)載

  • Session/cookie

  • 輪詢調(diào)度或加權(quán)輪詢調(diào)度算法

  • 四層負(fù)載均衡

  • 七層負(fù)載均衡

四層負(fù)載均衡

四層負(fù)載均衡根據(jù)監(jiān)看傳輸層的信息來決定如何分發(fā)請求。通常,這會涉及來源,目標(biāo) IP 地址和請求頭中的端口,但不包括數(shù)據(jù)包(報(bào)文)內(nèi)容。四層負(fù)載均衡執(zhí)行網(wǎng)絡(luò)地址轉(zhuǎn)換(NAT)來向上游服務(wù)器轉(zhuǎn)發(fā)網(wǎng)絡(luò)數(shù)據(jù)包。

七層負(fù)載均衡器

七層負(fù)載均衡器根據(jù)監(jiān)控應(yīng)用層來決定怎樣分發(fā)請求。這會涉及請求頭的內(nèi)容,消息和 cookie。七層負(fù)載均衡器終結(jié)網(wǎng)絡(luò)流量,讀取消息,做出負(fù)載均衡判定,然后傳送給特定服務(wù)器。比如,一個(gè)七層負(fù)載均衡器能直接將視頻流量連接到托管視頻的服務(wù)器,同時(shí)將更敏感的用戶賬單流量引導(dǎo)到安全性更強(qiáng)的服務(wù)器。

以損失靈活性為代價(jià),四層負(fù)載均衡比七層負(fù)載均衡花費(fèi)更少時(shí)間和計(jì)算資源,雖然這對現(xiàn)代商用硬件的性能影響甚微。

水平擴(kuò)展

負(fù)載均衡器還能幫助水平擴(kuò)展,提高性能和可用性。使用商業(yè)硬件的性價(jià)比更高,并且比在單臺硬件上垂直擴(kuò)展更貴的硬件具有更高的可用性。相比招聘特定企業(yè)系統(tǒng)人才,招聘商業(yè)硬件方面的人才更加容易。

缺陷:水平擴(kuò)展
  • 水平擴(kuò)展引入了復(fù)雜度并涉及服務(wù)器復(fù)制

    • 服務(wù)器應(yīng)該是無狀態(tài)的:它們也不該包含像 session 或資料圖片等與用戶關(guān)聯(lián)的數(shù)據(jù)。

    • session 可以集中存儲在數(shù)據(jù)庫或持久化緩存(Redis、Memcached)的數(shù)據(jù)存儲區(qū)中。

  • 緩存和數(shù)據(jù)庫等下游服務(wù)器需要隨著上游服務(wù)器進(jìn)行擴(kuò)展,以處理更多的并發(fā)連接。

缺陷:負(fù)載均衡器

  • 如果沒有足夠的資源配置或配置錯(cuò)誤,負(fù)載均衡器會變成一個(gè)性能瓶頸。

  • 引入負(fù)載均衡器以幫助消除單點(diǎn)故障但導(dǎo)致了額外的復(fù)雜性。

  • 單個(gè)負(fù)載均衡器會導(dǎo)致單點(diǎn)故障,但配置多個(gè)負(fù)載均衡器會進(jìn)一步增加復(fù)雜性。

9. 反向代理(web 服務(wù)器)

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的 

反向代理是一種可以集中地調(diào)用內(nèi)部服務(wù),并提供統(tǒng)一接口給公共客戶的 web 服務(wù)器。來自客戶端的請求先被反向代理服務(wù)器轉(zhuǎn)發(fā)到可響應(yīng)請求的服務(wù)器,然后代理再把服務(wù)器的響應(yīng)結(jié)果返回給客戶端。

帶來的好處包括:

  • 增加安全性 - 隱藏后端服務(wù)器的信息,屏蔽黑名單中的 IP,限制每個(gè)客戶端的連接數(shù)。

  • 提高可擴(kuò)展性和靈活性 - 客戶端只能看到反向代理服務(wù)器的 IP,這使你可以增減服務(wù)器或者修改它們的配置。

  • 本地終結(jié) SSL 會話 - 解密傳入請求,加密服務(wù)器響應(yīng),這樣后端服務(wù)器就不必完成這些潛在的高成本的操作。

    • 免除了在每個(gè)服務(wù)器上安裝 X.509 證書的需要

  • 壓縮 - 壓縮服務(wù)器響應(yīng)

  • 緩存 - 直接返回命中的緩存結(jié)果

  • 靜態(tài)內(nèi)容 - 直接提供靜態(tài)內(nèi)容

    • HTML/CSS/JS

    • 圖片

    • 視頻

    • 等等

負(fù)載均衡器與反向代理

  • 當(dāng)你有多個(gè)服務(wù)器時(shí),部署負(fù)載均衡器非常有用。通常,負(fù)載均衡器將流量路由給一組功能相同的服務(wù)器上。

  • 即使只有一臺 web 服務(wù)器或者應(yīng)用服務(wù)器時(shí),反向代理也有用,可以參考上一節(jié)介紹的好處。

  • NGINX 和 HAProxy 等解決方案可以同時(shí)支持第七層反向代理和負(fù)載均衡。

不利之處:反向代理

  • 引入反向代理會增加系統(tǒng)的復(fù)雜度。

  • 單獨(dú)一個(gè)反向代理服務(wù)器仍可能發(fā)生單點(diǎn)故障,配置多臺反向代理服務(wù)器(如故障轉(zhuǎn)移)會進(jìn)一步增加復(fù)雜度。

10. 應(yīng)用層

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的

將 Web 服務(wù)層與應(yīng)用層(也被稱作平臺層)分離,可以獨(dú)立縮放和配置這兩層。添加新的 API 只需要添加應(yīng)用服務(wù)器,而不必添加額外的 web 服務(wù)器。

單一職責(zé)原則提倡小型的,自治的服務(wù)共同合作。小團(tuán)隊(duì)通過提供小型的服務(wù),可以更激進(jìn)地計(jì)劃增長。

應(yīng)用層中的工作進(jìn)程也有可以實(shí)現(xiàn)異步化。

微服務(wù)

與此討論相關(guān)的話題是 微服務(wù),可以被描述為一系列可以獨(dú)立部署的小型的,模塊化服務(wù)。每個(gè)服務(wù)運(yùn)行在一個(gè)獨(dú)立的線程中,通過明確定義的輕量級機(jī)制通訊,共同實(shí)現(xiàn)業(yè)務(wù)目標(biāo)。1

例如,Pinterest 可能有這些微服務(wù): 用戶資料、關(guān)注者、Feed 流、搜索、照片上傳等。

服務(wù)發(fā)現(xiàn)

像 Consul,Etcd 和 Zookeeper 這樣的系統(tǒng)可以通過追蹤注冊名、地址、端口等信息來幫助服務(wù)互相發(fā)現(xiàn)對方。Health checks 可以幫助確認(rèn)服務(wù)的完整性和是否經(jīng)常使用一個(gè) HTTP 路徑。Consul 和 Etcd 都有一個(gè)內(nèi)建的 key-value 存儲 用來存儲配置信息和其他的共享信息。

不利之處:應(yīng)用層

  • 添加由多個(gè)松耦合服務(wù)組成的應(yīng)用層,從架構(gòu)、運(yùn)營、流程等層面來講將非常不同(相對于單體系統(tǒng))。

  • 微服務(wù)會增加部署和運(yùn)營的復(fù)雜度。

11. 數(shù)據(jù)庫

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的

關(guān)系型數(shù)據(jù)庫管理系統(tǒng)(RDBMS)

像 SQL 這樣的關(guān)系型數(shù)據(jù)庫是一系列以表的形式組織的數(shù)據(jù)項(xiàng)集合。

校對注:這里作者 SQL 可能指的是 MySQL

ACID 用來描述關(guān)系型數(shù)據(jù)庫事務(wù)的特性。

  • 原子性 - 每個(gè)事務(wù)內(nèi)部所有操作要么全部完成,要么全部不完成。

  • 一致性 - 任何事務(wù)都使數(shù)據(jù)庫從一個(gè)有效的狀態(tài)轉(zhuǎn)換到另一個(gè)有效狀態(tài)。

  • 隔離性 - 并發(fā)執(zhí)行事務(wù)的結(jié)果與順序執(zhí)行事務(wù)的結(jié)果相同。

  • 持久性 - 事務(wù)提交后,對系統(tǒng)的影響是永久的。

關(guān)系型數(shù)據(jù)庫擴(kuò)展包括許多技術(shù):主從復(fù)制、主主復(fù)制、聯(lián)合、分片、非規(guī)范化和 SQL 調(diào)優(yōu)。

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的

主從復(fù)制

主庫同時(shí)負(fù)責(zé)讀取和寫入操作,并復(fù)制寫入到一個(gè)或多個(gè)從庫中,從庫只負(fù)責(zé)讀操作。樹狀形式的從庫再將寫入復(fù)制到更多的從庫中去。如果主庫離線,系統(tǒng)可以以只讀模式運(yùn)行,直到某個(gè)從庫被提升為主庫或有新的主庫出現(xiàn)。

不利之處:主從復(fù)制

  • 將從庫提升為主庫需要額外的邏輯。

  • 參考不利之處:復(fù)制中,主從復(fù)制和主主復(fù)制共同的問題。

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的

主主復(fù)制

兩個(gè)主庫都負(fù)責(zé)讀操作和寫操作,寫入操作時(shí)互相協(xié)調(diào)。如果其中一個(gè)主庫掛機(jī),系統(tǒng)可以繼續(xù)讀取和寫入。

不利之處: 主主復(fù)制

  • 你需要添加負(fù)載均衡器或者在應(yīng)用邏輯中做改動(dòng),來確定寫入哪一個(gè)數(shù)據(jù)庫。

  • 多數(shù)主-主系統(tǒng)要么不能保證一致性(違反 ACID),要么因?yàn)橥疆a(chǎn)生了寫入延遲。

  • 隨著更多寫入節(jié)點(diǎn)的加入和延遲的提高,如何解決沖突顯得越發(fā)重要。

  • 參考不利之處:復(fù)制中,主從復(fù)制和主主復(fù)制共同的問題。

不利之處:復(fù)制

  • 如果主庫在將新寫入的數(shù)據(jù)復(fù)制到其他節(jié)點(diǎn)前掛掉,則有數(shù)據(jù)丟失的可能。

  • 寫入會被重放到負(fù)責(zé)讀取操作的副本。副本可能因?yàn)檫^多寫操作阻塞住,導(dǎo)致讀取功能異常。

  • 讀取從庫越多,需要復(fù)制的寫入數(shù)據(jù)就越多,導(dǎo)致更嚴(yán)重的復(fù)制延遲。

  • 在某些數(shù)據(jù)庫系統(tǒng)中,寫入主庫的操作可以用多個(gè)線程并行寫入,但讀取副本只支持單線程順序地寫入。

  • 復(fù)制意味著更多的硬件和額外的復(fù)雜度。

聯(lián)合

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的 

聯(lián)合(或按功能劃分)將數(shù)據(jù)庫按對應(yīng)功能分割。例如,你可以有三個(gè)數(shù)據(jù)庫:論壇、用戶和產(chǎn)品,而不僅是一個(gè)單體數(shù)據(jù)庫,從而減少每個(gè)數(shù)據(jù)庫的讀取和寫入流量,減少復(fù)制延遲。較小的數(shù)據(jù)庫意味著更多適合放入內(nèi)存的數(shù)據(jù),進(jìn)而意味著更高的緩存命中幾率。沒有只能串行寫入的中心化主庫,你可以并行寫入,提高負(fù)載能力。

不利之處:聯(lián)合

  • 如果你的數(shù)據(jù)庫模式需要大量的功能和數(shù)據(jù)表,聯(lián)合的效率并不好。

  • 你需要更新應(yīng)用程序的邏輯來確定要讀取和寫入哪個(gè)數(shù)據(jù)庫。

  • 用 server link 從兩個(gè)庫聯(lián)結(jié)數(shù)據(jù)更復(fù)雜。

  • 聯(lián)合需要更多的硬件和額外的復(fù)雜度。

分片

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的 

分片將數(shù)據(jù)分配在不同的數(shù)據(jù)庫上,使得每個(gè)數(shù)據(jù)庫僅管理整個(gè)數(shù)據(jù)集的一個(gè)子集。以用戶數(shù)據(jù)庫為例,隨著用戶數(shù)量的增加,越來越多的分片會被添加到集群中。

類似聯(lián)合的優(yōu)點(diǎn),分片可以減少讀取和寫入流量,減少復(fù)制并提高緩存命中率。也減少了索引,通常意味著查詢更快,性能更好。如果一個(gè)分片出問題,其他的仍能運(yùn)行,你可以使用某種形式的冗余來防止數(shù)據(jù)丟失。類似聯(lián)合,沒有只能串行寫入的中心化主庫,你可以并行寫入,提高負(fù)載能力。

常見的做法是用戶姓氏的首字母或者用戶的地理位置來分隔用戶表。

不利之處:分片

  • 你需要修改應(yīng)用程序的邏輯來實(shí)現(xiàn)分片,這會帶來復(fù)雜的 SQL 查詢。

  • 分片不合理可能導(dǎo)致數(shù)據(jù)負(fù)載不均衡。例如,被頻繁訪問的用戶數(shù)據(jù)會導(dǎo)致其所在分片的負(fù)載相對其他分片高。

    • 再平衡會引入額外的復(fù)雜度?;谝恢滦怨5姆制惴梢詼p少這種情況。

  • 聯(lián)結(jié)多個(gè)分片的數(shù)據(jù)操作更復(fù)雜。

  • 分片需要更多的硬件和額外的復(fù)雜度。

非規(guī)范化

非規(guī)范化試圖以寫入性能為代價(jià)來換取讀取性能。在多個(gè)表中冗余數(shù)據(jù)副本,以避免高成本的聯(lián)結(jié)操作。一些關(guān)系型數(shù)據(jù)庫,比如 PostgreSQL 和 Oracle 支持物化視圖,可以處理冗余信息存儲和保證冗余副本一致。

當(dāng)數(shù)據(jù)使用諸如聯(lián)合和分片等技術(shù)被分割,進(jìn)一步提高了處理跨數(shù)據(jù)中心的聯(lián)結(jié)操作復(fù)雜度。非規(guī)范化可以規(guī)避這種復(fù)雜的聯(lián)結(jié)操作。

在多數(shù)系統(tǒng)中,讀取操作的頻率遠(yuǎn)高于寫入操作,比例可達(dá)到 100:1,甚至 1000:1。需要復(fù)雜的數(shù)據(jù)庫聯(lián)結(jié)的讀取操作成本非常高,在磁盤操作上消耗了大量時(shí)間。

不利之處:非規(guī)范化

  • 數(shù)據(jù)會冗余。

  • 約束可以幫助冗余的信息副本保持同步,但這樣會增加數(shù)據(jù)庫設(shè)計(jì)的復(fù)雜度。

  • 非規(guī)范化的數(shù)據(jù)庫在高寫入負(fù)載下性能可能比規(guī)范化的數(shù)據(jù)庫差。

SQL 調(diào)優(yōu)

SQL 調(diào)優(yōu)是一個(gè)范圍很廣的話題,有很多相關(guān)的書可以作為參考。

利用基準(zhǔn)測試和性能分析來模擬和發(fā)現(xiàn)系統(tǒng)瓶頸很重要。

  • 基準(zhǔn)測試 - 用 ab 等工具模擬高負(fù)載情況。

  • 性能分析 - 通過啟用如慢查詢?nèi)罩镜裙ぞ邅磔o助追蹤性能問題。

基準(zhǔn)測試和性能分析可能會指引你到以下優(yōu)化方案。

改進(jìn)模式

  • 為了實(shí)現(xiàn)快速訪問,MySQL 在磁盤上用連續(xù)的塊存儲數(shù)據(jù)。

  • 使用 CHAR 類型存儲固定長度的字段,不要用 VARCHAR

    • CHAR 在快速、隨機(jī)訪問時(shí)效率很高。如果使用 VARCHAR,如果你想讀取下一個(gè)字符串,不得不先讀取到當(dāng)前字符串的末尾。

  • 使用 TEXT 類型存儲大塊的文本,例如博客正文。TEXT 還允許布爾搜索。使用 TEXT 字段需要在磁盤上存儲一個(gè)用于定位文本塊的指針。

  • 使用 INT 類型存儲高達(dá) 2^32 或 40 億的較大數(shù)字。

  • 使用 DECIMAL 類型存儲貨幣可以避免浮點(diǎn)數(shù)表示錯(cuò)誤。

  • 避免使用 BLOBS 存儲對象,存儲存放對象的位置。

  • VARCHAR(255) 是以 8 位數(shù)字存儲的最大字符數(shù),在某些關(guān)系型數(shù)據(jù)庫中,最大限度地利用字節(jié)。

  • 在適用場景中設(shè)置 NOT NULL 約束來提高搜索性能。

使用正確的索引

  • 你正查詢(SELECTGROUP BY、ORDER BYJOIN)的列如果用了索引會更快。

  • 索引通常表示為自平衡的 B 樹,可以保持?jǐn)?shù)據(jù)有序,并允許在對數(shù)時(shí)間內(nèi)進(jìn)行搜索,順序訪問,插入,刪除操作。

  • 設(shè)置索引,會將數(shù)據(jù)存在內(nèi)存中,占用了更多內(nèi)存空間。

  • 寫入操作會變慢,因?yàn)樗饕枰桓隆?/p>

  • 加載大量數(shù)據(jù)時(shí),禁用索引再加載數(shù)據(jù),然后重建索引,這樣也許會更快。

避免高成本的聯(lián)結(jié)操作

  • 有性能需要,可以進(jìn)行非規(guī)范化。

分割數(shù)據(jù)表

  • 將熱點(diǎn)數(shù)據(jù)拆分到單獨(dú)的數(shù)據(jù)表中,可以有助于緩存。

調(diào)優(yōu)查詢緩存

  • 在某些情況下,查詢緩存可能會導(dǎo)致性能問題。

NoSQL

NoSQL 是鍵-值數(shù)據(jù)庫、文檔型數(shù)據(jù)庫、列型數(shù)據(jù)庫或圖數(shù)據(jù)庫的統(tǒng)稱。數(shù)據(jù)庫是非規(guī)范化的,表聯(lián)結(jié)大多在應(yīng)用程序代碼中完成。大多數(shù) NoSQL 無法實(shí)現(xiàn)真正符合 ACID 的事務(wù),支持最終一致。

BASE 通常被用于描述 NoSQL 數(shù)據(jù)庫的特性。相比 CAP 理論,BASE 強(qiáng)調(diào)可用性超過一致性。

  • 基本可用 - 系統(tǒng)保證可用性。

  • 軟狀態(tài) - 即使沒有輸入,系統(tǒng)狀態(tài)也可能隨著時(shí)間變化。

  • 最終一致性 - 經(jīng)過一段時(shí)間之后,系統(tǒng)最終會變一致,因?yàn)橄到y(tǒng)在此期間沒有收到任何輸入。

除了在 SQL 還是 NoSQL 之間做選擇,了解哪種類型的 NoSQL 數(shù)據(jù)庫最適合你的用例也是非常有幫助的。我們將在下一節(jié)中快速了解下 鍵-值存儲、文檔型存儲、列型存儲和圖存儲數(shù)據(jù)庫。

鍵-值存儲

抽象模型:哈希表

鍵-值存儲通常可以實(shí)現(xiàn) O(1) 時(shí)間讀寫,用內(nèi)存或 SSD 存儲數(shù)據(jù)。數(shù)據(jù)存儲可以按字典順序維護(hù)鍵,從而實(shí)現(xiàn)鍵的高效檢索。鍵-值存儲可以用于存儲元數(shù)據(jù)。

鍵-值存儲性能很高,通常用于存儲簡單數(shù)據(jù)模型或頻繁修改的數(shù)據(jù),如存放在內(nèi)存中的緩存。鍵-值存儲提供的操作有限,如果需要更多操作,復(fù)雜度將轉(zhuǎn)嫁到應(yīng)用程序?qū)用妗?/p>

鍵-值存儲是如文檔存儲,在某些情況下,甚至是圖存儲等更復(fù)雜的存儲系統(tǒng)的基礎(chǔ)。

文檔類型存儲

抽象模型:將文檔作為值的鍵-值存儲

文檔類型存儲以文檔(XML、JSON、二進(jìn)制文件等)為中心,文檔存儲了指定對象的全部信息。文檔存儲根據(jù)文檔自身的內(nèi)部結(jié)構(gòu)提供 API 或查詢語句來實(shí)現(xiàn)查詢。請注意,許多鍵-值存儲數(shù)據(jù)庫有用值存儲元數(shù)據(jù)的特性,這也模糊了這兩種存儲類型的界限。

基于底層實(shí)現(xiàn),文檔可以根據(jù)集合、標(biāo)簽、元數(shù)據(jù)或者文件夾組織。盡管不同文檔可以被組織在一起或者分成一組,但相互之間可能具有完全不同的字段。

MongoDB 和 CouchDB 等一些文檔類型存儲還提供了類似 SQL 語言的查詢語句來實(shí)現(xiàn)復(fù)雜查詢。DynamoDB 同時(shí)支持鍵-值存儲和文檔類型存儲。

文檔類型存儲具備高度的靈活性,常用于處理偶爾變化的數(shù)據(jù)。

列型存儲

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的 

抽象模型:嵌套的 ColumnFamily<RowKey, Columns<ColKey, Value, Timestamp>> 映射

類型存儲的基本數(shù)據(jù)單元是列(名/值對)。列可以在列族(類似于 SQL 的數(shù)據(jù)表)中被分組。超級列族再分組普通列族。你可以使用行鍵獨(dú)立訪問每一列,具有相同行鍵值的列組成一行。每個(gè)值都包含版本的時(shí)間戳用于解決版本沖突。

Google 發(fā)布了第一個(gè)列型存儲數(shù)據(jù)庫 Bigtable,它影響了 Hadoop 生態(tài)系統(tǒng)中活躍的開源數(shù)據(jù)庫 HBase 和 Facebook 的 Cassandra。像 BigTable,HBase 和 Cassandra 這樣的存儲系統(tǒng)將鍵以字母順序存儲,可以高效地讀取鍵列。

列型存儲具備高可用性和高可擴(kuò)展性。通常被用于大數(shù)據(jù)相關(guān)存儲。

圖數(shù)據(jù)庫

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的 

抽象模型: 圖

在圖數(shù)據(jù)庫中,一個(gè)節(jié)點(diǎn)對應(yīng)一條記錄,一個(gè)弧對應(yīng)兩個(gè)節(jié)點(diǎn)之間的關(guān)系。圖數(shù)據(jù)庫被優(yōu)化用于表示外鍵繁多的復(fù)雜關(guān)系或多對多關(guān)系。

圖數(shù)據(jù)庫為存儲復(fù)雜關(guān)系的數(shù)據(jù)模型,如社交網(wǎng)絡(luò),提供了很高的性能。它們相對較新,尚未廣泛應(yīng)用,查找開發(fā)工具或者資源相對較難。許多圖只能通過 REST API 訪問。

SQL 還是 NoSQL

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的 

選取 SQL 的原因:

  • 結(jié)構(gòu)化數(shù)據(jù)

  • 嚴(yán)格的模式

  • 關(guān)系型數(shù)據(jù)

  • 需要復(fù)雜的聯(lián)結(jié)操作

  • 事務(wù)

  • 清晰的擴(kuò)展模式

  • 既有資源更豐富:開發(fā)者、社區(qū)、代碼庫、工具等

  • 通過索引進(jìn)行查詢非常快

選取 NoSQL 的原因:

  • 半結(jié)構(gòu)化數(shù)據(jù)

  • 動(dòng)態(tài)或靈活的模式

  • 非關(guān)系型數(shù)據(jù)

  • 不需要復(fù)雜的聯(lián)結(jié)操作

  • 存儲 TB (甚至 PB)級別的數(shù)據(jù)

  • 高數(shù)據(jù)密集的工作負(fù)載

  • IOPS 高吞吐量

適合 NoSQL 的示例數(shù)據(jù):

  • 埋點(diǎn)數(shù)據(jù)和日志數(shù)據(jù)

  • 排行榜或者得分?jǐn)?shù)據(jù)

  • 臨時(shí)數(shù)據(jù),如購物車

  • 頻繁訪問的(“熱”)表

  • 元數(shù)據(jù)/查找表

12. 緩存

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的

緩存可以提高頁面加載速度,并可以減少服務(wù)器和數(shù)據(jù)庫的負(fù)載。在這個(gè)模型中,分發(fā)器先查看請求之前是否被響應(yīng)過,如果有則將之前的結(jié)果直接返回,來省掉真正的處理。

數(shù)據(jù)庫分片均勻分布的讀取是最好的。但是熱門數(shù)據(jù)會讓讀取分布不均勻,這樣就會造成瓶頸,如果在數(shù)據(jù)庫前加個(gè)緩存,就會抹平不均勻的負(fù)載和突發(fā)流量對數(shù)據(jù)庫的影響。

客戶端緩存

緩存可以位于客戶端(操作系統(tǒng)或者瀏覽器),服務(wù)端或者不同的緩存層。

CDN 緩存

CDN 也被視為一種緩存。

Web 服務(wù)器緩存

反向代理和緩存(比如 Varnish)可以直接提供靜態(tài)和動(dòng)態(tài)內(nèi)容。Web 服務(wù)器同樣也可以緩存請求,返回相應(yīng)結(jié)果而不必連接應(yīng)用服務(wù)器。

數(shù)據(jù)庫緩存

數(shù)據(jù)庫的默認(rèn)配置中通常包含緩存級別,針對一般用例進(jìn)行了優(yōu)化。調(diào)整配置,在不同情況下使用不同的模式可以進(jìn)一步提高性能。

應(yīng)用緩存

基于內(nèi)存的緩存比如 Memcached 和 Redis 是應(yīng)用程序和數(shù)據(jù)存儲之間的一種鍵值存儲。由于數(shù)據(jù)保存在 RAM 中,它比存儲在磁盤上的典型數(shù)據(jù)庫要快多了。RAM 比磁盤限制更多,所以例如 least recently used (LRU) 的緩存無效算法可以將「熱門數(shù)據(jù)」放在 RAM 中,而對一些比較「冷門」的數(shù)據(jù)不做處理。

Redis 有下列附加功能:

  • 持久性選項(xiàng)

  • 內(nèi)置數(shù)據(jù)結(jié)構(gòu)比如有序集合和列表

有多個(gè)緩存級別,分為兩大類:數(shù)據(jù)庫查詢和對象:

  • 行級別

  • 查詢級別

  • 完整的可序列化對象

  • 完全渲染的 HTML

一般來說,你應(yīng)該盡量避免基于文件的緩存,因?yàn)檫@使得復(fù)制和自動(dòng)縮放很困難。

數(shù)據(jù)庫查詢級別的緩存

當(dāng)你查詢數(shù)據(jù)庫的時(shí)候,將查詢語句的哈希值與查詢結(jié)果存儲到緩存中。這種方法會遇到以下問題:

  • 很難用復(fù)雜的查詢刪除已緩存結(jié)果。

  • 如果一條數(shù)據(jù)比如表中某條數(shù)據(jù)的一項(xiàng)被改變,則需要?jiǎng)h除所有可能包含已更改項(xiàng)的緩存結(jié)果。

對象級別的緩存

將您的數(shù)據(jù)視為對象,就像對待你的應(yīng)用代碼一樣。讓應(yīng)用程序?qū)?shù)據(jù)從數(shù)據(jù)庫中組合到類實(shí)例或數(shù)據(jù)結(jié)構(gòu)中:

  • 如果對象的基礎(chǔ)數(shù)據(jù)已經(jīng)更改了,那么從緩存中刪掉這個(gè)對象。

  • 允許異步處理:workers 通過使用最新的緩存對象來組裝對象。

建議緩存的內(nèi)容:

  • 用戶會話

  • 完全渲染的 Web 頁面

  • 活動(dòng)流

  • 用戶圖數(shù)據(jù)

何時(shí)更新緩存

由于你只能在緩存中存儲有限的數(shù)據(jù),所以你需要選擇一個(gè)適用于你用例的緩存更新策略。

緩存模式

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的

應(yīng)用從存儲器讀寫。緩存不和存儲器直接交互,應(yīng)用執(zhí)行以下操作:

  • 在緩存中查找記錄,如果所需數(shù)據(jù)不在緩存中

  • 從數(shù)據(jù)庫中加載所需內(nèi)容

  • 將查找到的結(jié)果存儲到緩存中

  • 返回所需內(nèi)容

def get_user(self, user_id):
    user = cache.get("user.{0}", user_id)    if user is None:        user = db.query("SELECT * FROM users WHERE user_id = {0}", user_id)        if user is not None:            key = "user.{0}".format(user_id)
            cache.set(key, json.dumps(user))    return user

Memcached 通常用這種方式使用。

添加到緩存中的數(shù)據(jù)讀取速度很快。緩存模式也稱為延遲加載。只緩存所請求的數(shù)據(jù),這避免了沒有被請求的數(shù)據(jù)占滿了緩存空間。

緩存的缺點(diǎn):

  • 請求的數(shù)據(jù)如果不在緩存中就需要經(jīng)過三個(gè)步驟來獲取數(shù)據(jù),這會導(dǎo)致明顯的延遲。

  • 如果數(shù)據(jù)庫中的數(shù)據(jù)更新了會導(dǎo)致緩存中的數(shù)據(jù)過時(shí)。這個(gè)問題需要通過設(shè)置 ? TTL 強(qiáng)制更新緩存或者直寫模式來緩解這種情況。

  • 當(dāng)一個(gè)節(jié)點(diǎn)出現(xiàn)故障的時(shí)候,它將會被一個(gè)新的節(jié)點(diǎn)替代,這增加了延遲的時(shí)間。

直寫模式

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的 

應(yīng)用使用緩存作為主要的數(shù)據(jù)存儲,將數(shù)據(jù)讀寫到緩存中,而緩存負(fù)責(zé)從數(shù)據(jù)庫中讀寫數(shù)據(jù)。

  • 應(yīng)用向緩存中添加/更新數(shù)據(jù)

  • 緩存同步地寫入數(shù)據(jù)存儲

  • 返回所需內(nèi)容

應(yīng)用代碼:

set_user(12345, {"foo":"bar"})

緩存代碼:

def set_user(user_id, values):
    user = db.query("UPDATE Users WHERE id = {0}", user_id, values)
    cache.set(user_id, user)

由于存寫操作所以直寫模式整體是一種很慢的操作,但是讀取剛寫入的數(shù)據(jù)很快。相比讀取數(shù)據(jù),用戶通常比較能接受更新數(shù)據(jù)時(shí)速度較慢。緩存中的數(shù)據(jù)不會過時(shí)。

直寫模式的缺點(diǎn):

  • 由于故障或者縮放而創(chuàng)建的新的節(jié)點(diǎn),新的節(jié)點(diǎn)不會緩存,直到數(shù)據(jù)庫更新為止。緩存應(yīng)用直寫模式可以緩解這個(gè)問題。

  • 寫入的大多數(shù)數(shù)據(jù)可能永遠(yuǎn)都不會被讀取,用 TTL 可以最小化這種情況的出現(xiàn)。

回寫模式

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的 

在回寫模式中,應(yīng)用執(zhí)行以下操作:

  • 在緩存中增加或者更新條目

  • 異步寫入數(shù)據(jù),提高寫入性能。

回寫模式的缺點(diǎn):

  • 緩存可能在其內(nèi)容成功存儲之前丟失數(shù)據(jù)。

  • 執(zhí)行直寫模式比緩存或者回寫模式更復(fù)雜。

刷新

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的

你可以將緩存配置成在到期之前自動(dòng)刷新最近訪問過的內(nèi)容。

如果緩存可以準(zhǔn)確預(yù)測將來可能請求哪些數(shù)據(jù),那么刷新可能會導(dǎo)致延遲與讀取時(shí)間的降低。

刷新的缺點(diǎn):

  • 不能準(zhǔn)確預(yù)測到未來需要用到的數(shù)據(jù)可能會導(dǎo)致性能不如不使用刷新。

緩存的缺點(diǎn):

  • 需要保持緩存和真實(shí)數(shù)據(jù)源之間的一致性,比如數(shù)據(jù)庫根據(jù)緩存無效。

  • 需要改變應(yīng)用程序比如增加 Redis 或者 memcached。

  • 無效緩存是個(gè)難題,什么時(shí)候更新緩存是與之相關(guān)的復(fù)雜問題。

13. 異步

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的

異步工作流有助于減少那些原本順序執(zhí)行的請求時(shí)間。它們可以通過提前進(jìn)行一些耗時(shí)的工作來幫助減少請求時(shí)間,比如定期匯總數(shù)據(jù)。

消息隊(duì)列

消息隊(duì)列接收,保留和傳遞消息。如果按順序執(zhí)行操作太慢的話,你可以使用有以下工作流的消息隊(duì)列:

  • 應(yīng)用程序?qū)⒆鳂I(yè)發(fā)布到隊(duì)列,然后通知用戶作業(yè)狀態(tài)

  • 一個(gè) worker 從隊(duì)列中取出該作業(yè),對其進(jìn)行處理,然后顯示該作業(yè)完成

不去阻塞用戶操作,作業(yè)在后臺處理。在此期間,客戶端可能會進(jìn)行一些處理使得看上去像是任務(wù)已經(jīng)完成了。例如,如果要發(fā)送一條推文,推文可能會馬上出現(xiàn)在你的時(shí)間線上,但是可能需要一些時(shí)間才能將你的推文推送到你的所有關(guān)注者那里去。

Redis 是一個(gè)令人滿意的簡單的消息代理,但是消息有可能會丟失。

RabbitMQ 很受歡迎但是要求你適應(yīng)「AMQP」協(xié)議并且管理你自己的節(jié)點(diǎn)。

Amazon SQS 是被托管的,但可能具有高延遲,并且消息可能會被傳送兩次。

任務(wù)隊(duì)列

任務(wù)隊(duì)列接收任務(wù)及其相關(guān)數(shù)據(jù),運(yùn)行它們,然后傳遞其結(jié)果。 它們可以支持調(diào)度,并可用于在后臺運(yùn)行計(jì)算密集型作業(yè)。

Celery 支持調(diào)度,主要是用 Python 開發(fā)的。

背壓

如果隊(duì)列開始明顯增長,那么隊(duì)列大小可能會超過內(nèi)存大小,導(dǎo)致高速緩存未命中,磁盤讀取,甚至性能更慢。背壓可以通過限制隊(duì)列大小來幫助我們,從而為隊(duì)列中的作業(yè)保持高吞吐率和良好的響應(yīng)時(shí)間。一旦隊(duì)列填滿,客戶端將得到服務(wù)器忙或者 HTTP 503 狀態(tài)碼,以便稍后重試??蛻舳丝梢栽谏院髸r(shí)間重試該請求,也許是指數(shù)退避。

異步的缺點(diǎn):

  • 簡單的計(jì)算和實(shí)時(shí)工作流等用例可能更適用于同步操作,因?yàn)橐腙?duì)列可能會增加延遲和復(fù)雜性。

14. 通訊

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的 

超文本傳輸協(xié)議(HTTP)

HTTP 是一種在客戶端和服務(wù)器之間編碼和傳輸數(shù)據(jù)的方法。它是一個(gè)請求/響應(yīng)協(xié)議:客戶端和服務(wù)端針對相關(guān)內(nèi)容和完成狀態(tài)信息的請求和響應(yīng)。HTTP 是獨(dú)立的,允許請求和響應(yīng)流經(jīng)許多執(zhí)行負(fù)載均衡,緩存,加密和壓縮的中間路由器和服務(wù)器。

一個(gè)基本的 HTTP 請求由一個(gè)動(dòng)詞(方法)和一個(gè)資源(端點(diǎn))組成。 以下是常見的 HTTP 動(dòng)詞:

動(dòng)詞描述*冪等安全性可緩存
GET讀取資源YesYesYes
POST創(chuàng)建資源或觸發(fā)處理數(shù)據(jù)的進(jìn)程NoNoYes,如果回應(yīng)包含刷新信息
PUT創(chuàng)建或替換資源YesNoNo
PATCH部分更新資源NoNoYes,如果回應(yīng)包含刷新信息
DELETE刪除資源YesNoNo

多次執(zhí)行不會產(chǎn)生不同的結(jié)果。

HTTP 是依賴于較低級協(xié)議(如 TCP 和 UDP)的應(yīng)用層協(xié)議。

傳輸控制協(xié)議(TCP)

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的 
 

TCP 是通過 IP 網(wǎng)絡(luò)的面向連接的協(xié)議。 使用握手建立和斷開連接。 發(fā)送的所有數(shù)據(jù)包保證以原始順序到達(dá)目的地,用以下措施保證數(shù)據(jù)包不被損壞:

  • 每個(gè)數(shù)據(jù)包的序列號和校驗(yàn)碼。

  • 確認(rèn)包和自動(dòng)重傳

如果發(fā)送者沒有收到正確的響應(yīng),它將重新發(fā)送數(shù)據(jù)包。如果多次超時(shí),連接就會斷開。TCP 實(shí)行流量控制和擁塞控制。這些確保措施會導(dǎo)致延遲,而且通常導(dǎo)致傳輸效率比 UDP 低。

為了確保高吞吐量,Web 服務(wù)器可以保持大量的 TCP 連接,從而導(dǎo)致高內(nèi)存使用。在 Web 服務(wù)器線程間擁有大量開放連接可能開銷巨大,消耗資源過多,也就是說,一個(gè) memcached 服務(wù)器。連接池 可以幫助除了在適用的情況下切換到 UDP。

TCP 對于需要高可靠性但時(shí)間緊迫的應(yīng)用程序很有用。比如包括 Web 服務(wù)器,數(shù)據(jù)庫信息,SMTP,F(xiàn)TP 和 SSH。

以下情況使用 TCP 代替 UDP:

  • 你需要數(shù)據(jù)完好無損。

  • 你想對網(wǎng)絡(luò)吞吐量自動(dòng)進(jìn)行最佳評估。

用戶數(shù)據(jù)報(bào)協(xié)議(UDP)

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的 

UDP 是無連接的。數(shù)據(jù)報(bào)(類似于數(shù)據(jù)包)只在數(shù)據(jù)報(bào)級別有保證。數(shù)據(jù)報(bào)可能會無序的到達(dá)目的地,也有可能會遺失。UDP 不支持擁塞控制。雖然不如 TCP 那樣有保證,但 UDP 通常效率更高。

UDP 可以通過廣播將數(shù)據(jù)報(bào)發(fā)送至子網(wǎng)內(nèi)的所有設(shè)備。這對 DHCP 很有用,因?yàn)樽泳W(wǎng)內(nèi)的設(shè)備還沒有分配 IP 地址,而 IP 對于 TCP 是必須的。

UDP 可靠性更低但適合用在網(wǎng)絡(luò)電話、視頻聊天,流媒體和實(shí)時(shí)多人游戲上。

以下情況使用 UDP 代替 TCP:

  • 你需要低延遲

  • 相對于數(shù)據(jù)丟失更糟的是數(shù)據(jù)延遲

  • 你想實(shí)現(xiàn)自己的錯(cuò)誤校正方法

遠(yuǎn)程過程調(diào)用協(xié)議(RPC)

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的 

在 RPC 中,客戶端會去調(diào)用另一個(gè)地址空間(通常是一個(gè)遠(yuǎn)程服務(wù)器)里的方法。調(diào)用代碼看起來就像是調(diào)用的是一個(gè)本地方法,客戶端和服務(wù)器交互的具體過程被抽象。遠(yuǎn)程調(diào)用相對于本地調(diào)用一般較慢而且可靠性更差,因此區(qū)分兩者是有幫助的。熱門的 RPC 框架包括 Protobuf、Thrift 和 Avro。

RPC 是一個(gè)“請求-響應(yīng)”協(xié)議:

  • 客戶端程序 ── 調(diào)用客戶端存根程序。就像調(diào)用本地方法一樣,參數(shù)會被壓入棧中。

  • 客戶端 stub 程序 ── 將請求過程的 id 和參數(shù)打包進(jìn)請求信息中。

  • 客戶端通信模塊 ── 將信息從客戶端發(fā)送至服務(wù)端。

  • 服務(wù)端通信模塊 ── 將接受的包傳給服務(wù)端存根程序。

  • 服務(wù)端 stub 程序 ── 將結(jié)果解包,依據(jù)過程 id 調(diào)用服務(wù)端方法并將參數(shù)傳遞過去。

RPC 調(diào)用示例:

GET /someoperation?data=anId
POST /anotheroperation
{  "data":"anId";  "anotherdata": "another value"}

RPC 專注于暴露方法。RPC 通常用于處理內(nèi)部通訊的性能問題,這樣你可以手動(dòng)處理本地調(diào)用以更好的適應(yīng)你的情況。

當(dāng)以下情況時(shí)選擇本地庫(也就是 SDK):

  • 你知道你的目標(biāo)平臺。

  • 你想控制如何訪問你的“邏輯”。

  • 你想對發(fā)生在你的庫中的錯(cuò)誤進(jìn)行控制。

  • 性能和終端用戶體驗(yàn)是你最關(guān)心的事。

遵循 REST 的 HTTP API 往往更適用于公共 API。

缺點(diǎn):RPC
  • RPC 客戶端與服務(wù)實(shí)現(xiàn)捆綁地很緊密。

  • 一個(gè)新的 API 必須在每一個(gè)操作或者用例中定義。

  • RPC 很難調(diào)試。

  • 你可能沒辦法很方便的去修改現(xiàn)有的技術(shù)。舉個(gè)例子,如果你希望在 Squid 這樣的緩存服務(wù)器上確保 RPC 被正確緩存的話可能需要一些額外的努力了。

表述性狀態(tài)轉(zhuǎn)移(REST)

REST 是一種強(qiáng)制的客戶端/服務(wù)端架構(gòu)設(shè)計(jì)模型,客戶端基于服務(wù)端管理的一系列資源操作。服務(wù)端提供修改或獲取資源的接口。所有的通信必須是無狀態(tài)和可緩存的。

RESTful 接口有四條規(guī)則:

  • 標(biāo)志資源(HTTP 里的 URI) ── 無論什么操作都使用同一個(gè) URI。

  • 表示的改變(HTTP 的動(dòng)作) ── 使用動(dòng)作, headers 和 body。

  • 可自我描述的錯(cuò)誤信息(HTTP 中的 status code) ── 使用狀態(tài)碼,不要重新造輪子。

  • HATEOAS(HTTP 中的 HTML 接口) ── 你的 web 服務(wù)器應(yīng)該能夠通過瀏覽器訪問。

REST 請求的例子:

GET /someresources/anId
PUT /someresources/anId
{"anotherdata": "another value"}

REST 關(guān)注于暴露數(shù)據(jù)。它減少了客戶端/服務(wù)端的耦合程度,經(jīng)常用于公共 HTTP API 接口設(shè)計(jì)。REST 使用更通常與規(guī)范化的方法來通過 URI 暴露資源,通過 header 來表述并通過 GET、POST、PUT、DELETE 和 PATCH 這些動(dòng)作來進(jìn)行操作。因?yàn)闊o狀態(tài)的特性,REST 易于橫向擴(kuò)展和隔離。

缺點(diǎn):REST
  • 由于 REST 將重點(diǎn)放在暴露數(shù)據(jù),所以當(dāng)資源不是自然組織的或者結(jié)構(gòu)復(fù)雜的時(shí)候它可能無法很好的適應(yīng)。舉個(gè)例子,返回過去一小時(shí)中與特定事件集匹配的更新記錄這種操作就很難表示為路徑。使用 REST,可能會使用 URI 路徑,查詢參數(shù)和可能的請求體來實(shí)現(xiàn)。

  • REST 一般依賴幾個(gè)動(dòng)作(GET、POST、PUT、DELETE 和 PATCH),但有時(shí)候僅僅這些沒法滿足你的需要。舉個(gè)例子,將過期的文檔移動(dòng)到歸檔文件夾里去,這樣的操作可能沒法簡單的用上面這幾個(gè) verbs 表達(dá)。

  • 為了渲染單個(gè)頁面,獲取被嵌套在層級結(jié)構(gòu)中的復(fù)雜資源需要客戶端,服務(wù)器之間多次往返通信。例如,獲取博客內(nèi)容及其關(guān)聯(lián)評論。對于使用不確定網(wǎng)絡(luò)環(huán)境的移動(dòng)應(yīng)用來說,這些多次往返通信是非常麻煩的。

  • 隨著時(shí)間的推移,更多的字段可能會被添加到 API 響應(yīng)中,較舊的客戶端將會接收到所有新的數(shù)據(jù)字段,即使是那些它們不需要的字段,結(jié)果它會增加負(fù)載大小并引起更大的延遲。

RPC 與 REST 比較

操作RPCREST
注冊POST /signupPOST /persons
注銷POST /resign
{
"personid": "1234"
}
DELETE /persons/1234
讀取用戶信息GET /readPerson?personid=1234GET /persons/1234
讀取用戶物品列表GET /readUsersItemsList?personid=1234GET /persons/1234/items
向用戶物品列表添加一項(xiàng)POST /addItemToUsersItemsList
{
"personid": "1234";
"itemid": "456"
}
POST /persons/1234/items
{
"itemid": "456"
}
更新一個(gè)物品POST /modifyItem
{
"itemid": "456";
"key": "value"
}
PUT /items/456
{
"key": "value"
}
刪除一個(gè)物品POST /removeItem
{
"itemid": "456"
}
DELETE /items/456

15. 安全

這一部分需要更多內(nèi)容。一起來吧!

安全是一個(gè)寬泛的話題。除非你有相當(dāng)?shù)慕?jīng)驗(yàn)、安全方面背景或者正在申請的職位要求安全知識,你不需要了解安全基礎(chǔ)知識以外的內(nèi)容:

  • 在運(yùn)輸和等待過程中加密

  • 對所有的用戶輸入和從用戶那里發(fā)來的參數(shù)進(jìn)行處理以防止 XSS 和 SQL 注入。

  • 使用參數(shù)化的查詢來防止 SQL 注入。

  • 使用最小權(quán)限原則。

16. 附錄

一些時(shí)候你會被要求做出保守估計(jì)。比如,你可能需要估計(jì)從磁盤中生成 100 張圖片的縮略圖需要的時(shí)間或者一個(gè)數(shù)據(jù)結(jié)構(gòu)需要多少的內(nèi)存。2 的次方表和每個(gè)開發(fā)者都需要知道的一些時(shí)間數(shù)據(jù)(譯注:OSChina 上有這篇文章的譯文)都是一些很方便的參考資料。

2 的次方表

Power           Exact Value         Approx Value        Bytes---------------------------------------------------------------7                             128
8                             256
10                           1024   1 thousand           1 KB
16                         65,536                       64 KB
20                      1,048,576   1 million            1 MB
30                  1,073,741,824   1 billion            1 GB
32                  4,294,967,296                        4 GB
40              1,099,511,627,776   1 trillion           1 TB

每個(gè)程序員都應(yīng)該知道的延遲數(shù)

Latency Comparison Numbers--------------------------L1 cache reference                           0.5 ns
Branch mispredict                            5   ns
L2 cache reference                           7   ns                      14x L1 cacheMutex lock/unlock                          100   nsMain memory reference                      100   ns                      20x L2 cache, 200x L1 cacheCompress 1K bytes with Zippy            10,000   ns       10 us
Send 1 KB bytes over 1 Gbps network     10,000   ns       10 usRead 4 KB randomly from SSD*           150,000   ns      150 us          ~1GB/sec SSDRead 1 MB sequentially from memory     250,000   ns      250 usRound trip within same datacenter      500,000   ns      500 usRead 1 MB sequentially from SSD*     1,000,000   ns    1,000 us    1 ms  ~1GB/sec SSD, 4X memoryDisk seek                           10,000,000   ns   10,000 us   10 ms  20x datacenter roundtripRead 1 MB sequentially from 1 Gbps  10,000,000   ns   10,000 us   10 ms  40x memory, 10X SSDRead 1 MB sequentially from disk    30,000,000   ns   30,000 us   30 ms 120x memory, 30X SSD
Send packet CA->Netherlands->CA    150,000,000   ns  150,000 us  150 ms
Notes-----1 ns = 10^-9 seconds1 us = 10^-6 seconds = 1,000 ns1 ms = 10^-3 seconds = 1,000 us = 1,000,000 ns

基于上述數(shù)字的指標(biāo):

  • 從磁盤以 30 MB/s 的速度順序讀取

  • 以 100 MB/s 從 1 Gbps 的以太網(wǎng)順序讀取

  • 從 SSD 以 1 GB/s 的速度讀取

  • 以 4 GB/s 的速度從主存讀取

  • 每秒能繞地球 6-7 圈

  • 數(shù)據(jù)中心內(nèi)每秒有 2,000 次往返

延遲數(shù)可視化

大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的

到此,關(guān)于“大型互聯(lián)網(wǎng)系統(tǒng)架構(gòu)是怎么設(shè)計(jì)的”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI