您好,登錄后才能下訂單哦!
這篇文章主要介紹“大型互聯(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í)吧!
接下來,我們將看看高階的權(quán)衡和取舍:
性能與可擴(kuò)展性
延遲與吞吐量
可用性與一致性
記住每個(gè)方面都面臨取舍和權(quán)衡。
然后,我們將深入更具體的主題,如 DNS、CDN 和負(fù)載均衡器。
如果服務(wù)性能的增長與資源的增加是成比例的,服務(wù)就是可擴(kuò)展的。通常,提高性能意味著服務(wù)于更多的工作單元,另一方面,當(dāng)數(shù)據(jù)集增長時(shí),同樣也可以處理更大的工作單位。 1
另一個(gè)角度來看待性能與可擴(kuò)展性:
如果你的系統(tǒng)有性能問題,對于單個(gè)用戶來說是緩慢的。
如果你的系統(tǒng)有可擴(kuò)展性問題,單個(gè)用戶較快但在高負(fù)載下會變慢。
延遲是執(zhí)行操作或運(yùn)算結(jié)果所花費(fèi)的時(shí)間。
吞吐量是單位時(shí)間內(nèi)(執(zhí)行)此類操作或運(yùn)算的數(shù)量。
通常,你應(yīng)該以可接受級延遲下最大化吞吐量為目標(biāo)。
在一個(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ò)性,并需要在軟件可用性和一致性間做出取舍。
等待分區(qū)節(jié)點(diǎn)的響應(yīng)可能會導(dǎo)致延時(shí)錯(cuò)誤。如果你的業(yè)務(wù)需求需要原子讀寫,CP 是一個(gè)不錯(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ò)的選擇。
有同一份數(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ò)。
在寫入后,訪問立即可見。數(shù)據(jù)被同步復(fù)制。
文件系統(tǒng)和關(guān)系型數(shù)據(jù)庫(RDBMS)中使用的是此種方式。強(qiáng)一致性在需要記錄的系統(tǒng)中運(yùn)作良好。
有兩種支持高可用性的模式: 故障切換(fail-over)和復(fù)制(replication)。
關(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ù)器處理流量。
工作到備用的故障切換也被稱為主從切換。
在雙工作切換中,雙方都在管控流量,在它們之間分散負(fù)載。
如果是外網(wǎng)服務(wù)器,DNS 將需要對兩方都了解。如果是內(nèi)網(wǎng)服務(wù)器,應(yīng)用程序邏輯將需要對兩方都了解。
雙工作切換也可以稱為主主切換。
故障切換需要添加額外硬件并增加復(fù)雜性。
如果新寫入數(shù)據(jù)在能被復(fù)制到備用系統(tǒng)之前,工作系統(tǒng)出現(xiàn)了故障,則有可能會丟失數(shù)據(jù)。
這個(gè)主題進(jìn)一步探討了數(shù)據(jù)庫部分:
主 ─ 從復(fù)制
主 ─ 主復(fù)制
域名系統(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 服務(wù)器還是帶來了輕微的延遲。
雖然它們通常由政府,網(wǎng)絡(luò)服務(wù)提供商和大公司管理,但 DNS 服務(wù)管理仍可能是復(fù)雜的。
DNS 服務(wù)最近遭受 DDoS 攻擊,阻止不知道 Twtter IP 地址的用戶訪問 Twiiter。
內(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ù)器不必真的處理請求
當(dāng)你服務(wù)器上內(nèi)容發(fā)生變動(dòng)時(shí),推送 CDN 接受新內(nèi)容。直接推送給 CDN 并重寫 URL 地址以指向你的內(nèi)容的 CDN 地址。你可以配置內(nèi)容到期時(shí)間及何時(shí)更新。內(nèi)容只有在更改或新增是才推送,流量最小化,但儲存最大化。
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 成本可能因流量而異,可能在權(quán)衡之后你將不會使用 CDN。
如果在 TTL 過期之前更新內(nèi)容,CDN 緩存內(nèi)容可能會過時(shí)。
CDN 需要更改靜態(tài)內(nèi)容的 URL 地址以指向 CDN。
負(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ù)載均衡根據(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ù)載均衡器根據(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)代商用硬件的性能影響甚微。
負(fù)載均衡器還能幫助水平擴(kuò)展,提高性能和可用性。使用商業(yè)硬件的性價(jià)比更高,并且比在單臺硬件上垂直擴(kuò)展更貴的硬件具有更高的可用性。相比招聘特定企業(yè)系統(tǒng)人才,招聘商業(yè)硬件方面的人才更加容易。
水平擴(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ā)連接。
如果沒有足夠的資源配置或配置錯(cuò)誤,負(fù)載均衡器會變成一個(gè)性能瓶頸。
引入負(fù)載均衡器以幫助消除單點(diǎn)故障但導(dǎo)致了額外的復(fù)雜性。
單個(gè)負(fù)載均衡器會導(dǎo)致單點(diǎn)故障,但配置多個(gè)負(fù)載均衡器會進(jìn)一步增加復(fù)雜性。
反向代理是一種可以集中地調(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
圖片
視頻
等等
當(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ù)雜度。
將 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)異步化。
與此討論相關(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 流、搜索、照片上傳等。
像 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 存儲 用來存儲配置信息和其他的共享信息。
添加由多個(gè)松耦合服務(wù)組成的應(yīng)用層,從架構(gòu)、運(yùn)營、流程等層面來講將非常不同(相對于單體系統(tǒng))。
微服務(wù)會增加部署和運(yùn)營的復(fù)雜度。
像 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)。
主庫同時(shí)負(fù)責(zé)讀取和寫入操作,并復(fù)制寫入到一個(gè)或多個(gè)從庫中,從庫只負(fù)責(zé)讀操作。樹狀形式的從庫再將寫入復(fù)制到更多的從庫中去。如果主庫離線,系統(tǒng)可以以只讀模式運(yùn)行,直到某個(gè)從庫被提升為主庫或有新的主庫出現(xiàn)。
不利之處:主從復(fù)制
將從庫提升為主庫需要額外的邏輯。
參考不利之處:復(fù)制中,主從復(fù)制和主主復(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)合(或按功能劃分)將數(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ù)雜度。
分片將數(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ī)范化試圖以寫入性能為代價(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)是一個(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
約束來提高搜索性能。
使用正確的索引
你正查詢(SELECT
、GROUP BY
、ORDER BY
、JOIN
)的列如果用了索引會更快。
索引通常表示為自平衡的 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 是鍵-值數(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ù)。
抽象模型:嵌套的
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ù)庫中,一個(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 的原因:
結(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ù)/查找表
緩存可以提高頁面加載速度,并可以減少服務(wù)器和數(shù)據(jù)庫的負(fù)載。在這個(gè)模型中,分發(fā)器先查看請求之前是否被響應(yīng)過,如果有則將之前的結(jié)果直接返回,來省掉真正的處理。
數(shù)據(jù)庫分片均勻分布的讀取是最好的。但是熱門數(shù)據(jù)會讓讀取分布不均勻,這樣就會造成瓶頸,如果在數(shù)據(jù)庫前加個(gè)緩存,就會抹平不均勻的負(fù)載和突發(fā)流量對數(shù)據(jù)庫的影響。
緩存可以位于客戶端(操作系統(tǒng)或者瀏覽器),服務(wù)端或者不同的緩存層。
CDN 也被視為一種緩存。
反向代理和緩存(比如 Varnish)可以直接提供靜態(tài)和動(dòng)態(tài)內(nèi)容。Web 服務(wù)器同樣也可以緩存請求,返回相應(yīng)結(jié)果而不必連接應(yīng)用服務(wù)器。
數(shù)據(jù)庫的默認(rèn)配置中通常包含緩存級別,針對一般用例進(jìn)行了優(yōu)化。調(diào)整配置,在不同情況下使用不同的模式可以進(jìn)一步提高性能。
基于內(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)縮放很困難。
當(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ù)據(jù),所以你需要選擇一個(gè)適用于你用例的緩存更新策略。
應(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í)間。
應(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)。
在回寫模式中,應(yīng)用執(zhí)行以下操作:
在緩存中增加或者更新條目
異步寫入數(shù)據(jù),提高寫入性能。
回寫模式的缺點(diǎn):
緩存可能在其內(nèi)容成功存儲之前丟失數(shù)據(jù)。
執(zhí)行直寫模式比緩存或者回寫模式更復(fù)雜。
你可以將緩存配置成在到期之前自動(dòng)刷新最近訪問過的內(nèi)容。
如果緩存可以準(zhǔn)確預(yù)測將來可能請求哪些數(shù)據(jù),那么刷新可能會導(dǎo)致延遲與讀取時(shí)間的降低。
刷新的缺點(diǎn):
不能準(zhǔn)確預(yù)測到未來需要用到的數(shù)據(jù)可能會導(dǎo)致性能不如不使用刷新。
需要保持緩存和真實(shí)數(shù)據(jù)源之間的一致性,比如數(shù)據(jù)庫根據(jù)緩存無效。
需要改變應(yīng)用程序比如增加 Redis 或者 memcached。
無效緩存是個(gè)難題,什么時(shí)候更新緩存是與之相關(guān)的復(fù)雜問題。
異步工作流有助于減少那些原本順序執(zhí)行的請求時(shí)間。它們可以通過提前進(jìn)行一些耗時(shí)的工作來幫助減少請求時(shí)間,比如定期匯總數(shù)據(jù)。
消息隊(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ù)及其相關(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ù)退避。
簡單的計(jì)算和實(shí)時(shí)工作流等用例可能更適用于同步操作,因?yàn)橐腙?duì)列可能會增加延遲和復(fù)雜性。
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 | 讀取資源 | Yes | Yes | Yes |
POST | 創(chuàng)建資源或觸發(fā)處理數(shù)據(jù)的進(jìn)程 | No | No | Yes,如果回應(yīng)包含刷新信息 |
PUT | 創(chuàng)建或替換資源 | Yes | No | No |
PATCH | 部分更新資源 | No | No | Yes,如果回應(yīng)包含刷新信息 |
DELETE | 刪除資源 | Yes | No | No |
多次執(zhí)行不會產(chǎn)生不同的結(jié)果。
HTTP 是依賴于較低級協(xié)議(如 TCP 和 UDP)的應(yīng)用層協(xié)議。
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)行最佳評估。
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ò)誤校正方法
在 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。
RPC 客戶端與服務(wù)實(shí)現(xiàn)捆綁地很緊密。
一個(gè)新的 API 必須在每一個(gè)操作或者用例中定義。
RPC 很難調(diào)試。
你可能沒辦法很方便的去修改現(xiàn)有的技術(shù)。舉個(gè)例子,如果你希望在 Squid 這樣的緩存服務(wù)器上確保 RPC 被正確緩存的話可能需要一些額外的努力了。
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ò)展和隔離。
由于 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 |
---|---|---|
注冊 | POST /signup | POST /persons |
注銷 | POST /resign { "personid": "1234" } | DELETE /persons/1234 |
讀取用戶信息 | GET /readPerson?personid=1234 | GET /persons/1234 |
讀取用戶物品列表 | GET /readUsersItemsList?personid=1234 | GET /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 |
這一部分需要更多內(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)限原則。
一些時(shí)候你會被要求做出保守估計(jì)。比如,你可能需要估計(jì)從磁盤中生成 100 張圖片的縮略圖需要的時(shí)間或者一個(gè)數(shù)據(jù)結(jié)構(gòu)需要多少的內(nèi)存。2 的次方表和每個(gè)開發(fā)者都需要知道的一些時(shí)間數(shù)據(jù)(譯注:OSChina 上有這篇文章的譯文)都是一些很方便的參考資料。
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
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 次往返
到此,關(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í)用的文章!
免責(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)容。