您好,登錄后才能下訂單哦!
這篇文章主要介紹“大型互聯網系統架構是怎么設計的”,在日常操作中,相信很多人在大型互聯網系統架構是怎么設計的問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”大型互聯網系統架構是怎么設計的”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
接下來,我們將看看高階的權衡和取舍:
性能與可擴展性
延遲與吞吐量
可用性與一致性
記住每個方面都面臨取舍和權衡。
然后,我們將深入更具體的主題,如 DNS、CDN 和負載均衡器。
如果服務性能的增長與資源的增加是成比例的,服務就是可擴展的。通常,提高性能意味著服務于更多的工作單元,另一方面,當數據集增長時,同樣也可以處理更大的工作單位。 1
另一個角度來看待性能與可擴展性:
如果你的系統有性能問題,對于單個用戶來說是緩慢的。
如果你的系統有可擴展性問題,單個用戶較快但在高負載下會變慢。
延遲是執行操作或運算結果所花費的時間。
吞吐量是單位時間內(執行)此類操作或運算的數量。
通常,你應該以可接受級延遲下最大化吞吐量為目標。
在一個分布式計算系統中,只能同時滿足下列的兩點:
一致性 ─ 每次訪問都能獲得最新數據但可能會收到錯誤響應
可用性 ─ 每次訪問都能收到非錯響應,但不保證獲取到最新數據
分區容錯性 ─ 在任意分區網絡故障的情況下系統仍能繼續運行
網絡并不可靠,所以你應要支持分區容錯性,并需要在軟件可用性和一致性間做出取舍。
等待分區節點的響應可能會導致延時錯誤。如果你的業務需求需要原子讀寫,CP 是一個不錯的選擇。
響應節點上可用數據的最近版本可能并不是最新的。當分區解析完后,寫入(操作)可能需要一些時間來傳播。
如果業務需求允許最終一致性,或當有外部故障時要求系統繼續運行,AP 是一個不錯的選擇。
有同一份數據的多份副本,我們面臨著怎樣同步它們的選擇,以便讓客戶端有一致的顯示數據。回想 CAP 理論中的一致性定義 ─ 每次訪問都能獲得最新數據但可能會收到錯誤響應
在寫入之后,訪問可能看到,也可能看不到(寫入數據)。盡力優化之讓其能訪問最新數據。
這種方式可以 memcached 等系統中看到。弱一致性在 VoIP,視頻聊天和實時多人游戲等真實用例中表現不錯。打個比方,如果你在通話中丟失信號幾秒鐘時間,當重新連接時你是聽不到這幾秒鐘所說的話的。
在寫入后,訪問最終能看到寫入數據(通常在數毫秒內)。數據被異步復制。
DNS 和 email 等系統使用的是此種方式。最終一致性在高可用性系統中效果不錯。
在寫入后,訪問立即可見。數據被同步復制。
文件系統和關系型數據庫(RDBMS)中使用的是此種方式。強一致性在需要記錄的系統中運作良好。
有兩種支持高可用性的模式: 故障切換(fail-over)和復制(replication)。
關于工作到備用的故障切換流程是,工作服務器發送周期信號給待機中的備用服務器。如果周期信號中斷,備用服務器切換成工作服務器的 IP 地址并恢復服務。
宕機時間取決于備用服務器處于“熱”待機狀態還是需要從“冷”待機狀態進行啟動。只有工作服務器處理流量。
工作到備用的故障切換也被稱為主從切換。
在雙工作切換中,雙方都在管控流量,在它們之間分散負載。
如果是外網服務器,DNS 將需要對兩方都了解。如果是內網服務器,應用程序邏輯將需要對兩方都了解。
雙工作切換也可以稱為主主切換。
故障切換需要添加額外硬件并增加復雜性。
如果新寫入數據在能被復制到備用系統之前,工作系統出現了故障,則有可能會丟失數據。
這個主題進一步探討了數據庫部分:
主 ─ 從復制
主 ─ 主復制
域名系統是把 www.example.com 等域名轉換成 IP 地址。
域名系統是分層次的,一些 DNS 服務器位于頂層。當查詢(域名) IP 時,路由或 ISP 提供連接 DNS 服務器的信息。較底層的 DNS 服務器緩存映射,它可能會因為 DNS 傳播延時而失效。DNS 結果可以緩存在瀏覽器或操作系統中一段時間,時間長短取決于存活時間 TTL。
NS 記錄(域名服務) ─ 指定解析域名或子域名的 DNS 服務器。
MX 記錄(郵件交換) ─ 指定接收信息的郵件服務器。
A 記錄(地址) ─ 指定域名對應的 IP 地址記錄。
CNAME(規范) ─ 一個域名映射到另一個域名或 CNAME
記錄( example.com 指向 www.example.com )或映射到一個 A
記錄。
CloudFlare 和 Route 53 等平臺提供管理 DNS 的功能。某些 DNS 服務通過集中方式來路由流量:
加權輪詢調度
防止流量進入維護中的服務器
在不同大小集群間負載均衡
A/B 測試
基于延遲路由
基于地理位置路由
雖說緩存可以減輕 DNS 延遲,但連接 DNS 服務器還是帶來了輕微的延遲。
雖然它們通常由政府,網絡服務提供商和大公司管理,但 DNS 服務管理仍可能是復雜的。
DNS 服務最近遭受 DDoS 攻擊,阻止不知道 Twtter IP 地址的用戶訪問 Twiiter。
內容分發網絡(CDN)是一個全球性的代理服務器分布式網絡,它從靠近用戶的位置提供內容。通常,HTML/CSS/JS,圖片和視頻等靜態內容由 CDN 提供,雖然亞馬遜 CloudFront 等也支持動態內容。CDN 的 DNS 解析會告知客戶端連接哪臺服務器。
將內容存儲在 CDN 上可以從兩個方面來提供性能:
從靠近用戶的數據中心提供資源
通過 CDN 你的服務器不必真的處理請求
當你服務器上內容發生變動時,推送 CDN 接受新內容。直接推送給 CDN 并重寫 URL 地址以指向你的內容的 CDN 地址。你可以配置內容到期時間及何時更新。內容只有在更改或新增是才推送,流量最小化,但儲存最大化。
CDN 拉取是當第一個用戶請求該資源時,從服務器上拉取資源。你將內容留在自己的服務器上并重寫 URL 指向 CDN 地址。直到內容被緩存在 CDN 上為止,這樣請求只會更慢,
存活時間(TTL)決定緩存多久時間。CDN 拉取方式最小化 CDN 上的儲存空間,但如果過期文件并在實際更改之前被拉取,則會導致冗余的流量。
高流量站點使用 CDN 拉取效果不錯,因為只有最近請求的內容保存在 CDN 中,流量才能更平衡地分散。
CDN 成本可能因流量而異,可能在權衡之后你將不會使用 CDN。
如果在 TTL 過期之前更新內容,CDN 緩存內容可能會過時。
CDN 需要更改靜態內容的 URL 地址以指向 CDN。
負載均衡器將傳入的請求分發到應用服務器和數據庫等計算資源。無論哪種情況,負載均衡器將從計算資源來的響應返回給恰當的客戶端。負載均衡器的效用在于:
防止請求進入不好的服務器
防止資源過載
幫助消除單一的故障點
負載均衡器可以通過硬件(昂貴)或 HAProxy 等軟件來實現。 增加的好處包括:
SSL 終結 ─ 解密傳入的請求并加密服務器響應,這樣的話后端服務器就不必再執行這些潛在高消耗運算了。
不需要再每臺服務器上安裝 X.509 證書。
Session 留存 ─ 如果 Web 應用程序不追蹤會話,發出 cookie 并將特定客戶端的請求路由到同一實例。
通常會設置采用工作 ─ 備用 或 雙工作 模式的多個負載均衡器,以免發生故障。
負載均衡器能基于多種方式來路由流量:
隨機
最少負載
Session/cookie
輪詢調度或加權輪詢調度算法
四層負載均衡
七層負載均衡
四層負載均衡根據監看傳輸層的信息來決定如何分發請求。通常,這會涉及來源,目標 IP 地址和請求頭中的端口,但不包括數據包(報文)內容。四層負載均衡執行網絡地址轉換(NAT)來向上游服務器轉發網絡數據包。
七層負載均衡器根據監控應用層來決定怎樣分發請求。這會涉及請求頭的內容,消息和 cookie。七層負載均衡器終結網絡流量,讀取消息,做出負載均衡判定,然后傳送給特定服務器。比如,一個七層負載均衡器能直接將視頻流量連接到托管視頻的服務器,同時將更敏感的用戶賬單流量引導到安全性更強的服務器。
以損失靈活性為代價,四層負載均衡比七層負載均衡花費更少時間和計算資源,雖然這對現代商用硬件的性能影響甚微。
負載均衡器還能幫助水平擴展,提高性能和可用性。使用商業硬件的性價比更高,并且比在單臺硬件上垂直擴展更貴的硬件具有更高的可用性。相比招聘特定企業系統人才,招聘商業硬件方面的人才更加容易。
水平擴展引入了復雜度并涉及服務器復制
服務器應該是無狀態的:它們也不該包含像 session 或資料圖片等與用戶關聯的數據。
session 可以集中存儲在數據庫或持久化緩存(Redis、Memcached)的數據存儲區中。
緩存和數據庫等下游服務器需要隨著上游服務器進行擴展,以處理更多的并發連接。
如果沒有足夠的資源配置或配置錯誤,負載均衡器會變成一個性能瓶頸。
引入負載均衡器以幫助消除單點故障但導致了額外的復雜性。
單個負載均衡器會導致單點故障,但配置多個負載均衡器會進一步增加復雜性。
反向代理是一種可以集中地調用內部服務,并提供統一接口給公共客戶的 web 服務器。來自客戶端的請求先被反向代理服務器轉發到可響應請求的服務器,然后代理再把服務器的響應結果返回給客戶端。
帶來的好處包括:
增加安全性 - 隱藏后端服務器的信息,屏蔽黑名單中的 IP,限制每個客戶端的連接數。
提高可擴展性和靈活性 - 客戶端只能看到反向代理服務器的 IP,這使你可以增減服務器或者修改它們的配置。
本地終結 SSL 會話 - 解密傳入請求,加密服務器響應,這樣后端服務器就不必完成這些潛在的高成本的操作。
免除了在每個服務器上安裝 X.509 證書的需要
壓縮 - 壓縮服務器響應
緩存 - 直接返回命中的緩存結果
靜態內容 - 直接提供靜態內容
HTML/CSS/JS
圖片
視頻
等等
當你有多個服務器時,部署負載均衡器非常有用。通常,負載均衡器將流量路由給一組功能相同的服務器上。
即使只有一臺 web 服務器或者應用服務器時,反向代理也有用,可以參考上一節介紹的好處。
NGINX 和 HAProxy 等解決方案可以同時支持第七層反向代理和負載均衡。
引入反向代理會增加系統的復雜度。
單獨一個反向代理服務器仍可能發生單點故障,配置多臺反向代理服務器(如故障轉移)會進一步增加復雜度。
將 Web 服務層與應用層(也被稱作平臺層)分離,可以獨立縮放和配置這兩層。添加新的 API 只需要添加應用服務器,而不必添加額外的 web 服務器。
單一職責原則提倡小型的,自治的服務共同合作。小團隊通過提供小型的服務,可以更激進地計劃增長。
應用層中的工作進程也有可以實現異步化。
與此討論相關的話題是 微服務,可以被描述為一系列可以獨立部署的小型的,模塊化服務。每個服務運行在一個獨立的線程中,通過明確定義的輕量級機制通訊,共同實現業務目標。1
例如,Pinterest 可能有這些微服務: 用戶資料、關注者、Feed 流、搜索、照片上傳等。
像 Consul,Etcd 和 Zookeeper 這樣的系統可以通過追蹤注冊名、地址、端口等信息來幫助服務互相發現對方。Health checks 可以幫助確認服務的完整性和是否經常使用一個 HTTP 路徑。Consul 和 Etcd 都有一個內建的 key-value 存儲 用來存儲配置信息和其他的共享信息。
添加由多個松耦合服務組成的應用層,從架構、運營、流程等層面來講將非常不同(相對于單體系統)。
微服務會增加部署和運營的復雜度。
像 SQL 這樣的關系型數據庫是一系列以表的形式組織的數據項集合。
校對注:這里作者 SQL 可能指的是 MySQL
ACID 用來描述關系型數據庫事務的特性。
原子性 - 每個事務內部所有操作要么全部完成,要么全部不完成。
一致性 - 任何事務都使數據庫從一個有效的狀態轉換到另一個有效狀態。
隔離性 - 并發執行事務的結果與順序執行事務的結果相同。
持久性 - 事務提交后,對系統的影響是永久的。
關系型數據庫擴展包括許多技術:主從復制、主主復制、聯合、分片、非規范化和 SQL 調優。
主庫同時負責讀取和寫入操作,并復制寫入到一個或多個從庫中,從庫只負責讀操作。樹狀形式的從庫再將寫入復制到更多的從庫中去。如果主庫離線,系統可以以只讀模式運行,直到某個從庫被提升為主庫或有新的主庫出現。
不利之處:主從復制
將從庫提升為主庫需要額外的邏輯。
參考不利之處:復制中,主從復制和主主復制共同的問題。
兩個主庫都負責讀操作和寫操作,寫入操作時互相協調。如果其中一個主庫掛機,系統可以繼續讀取和寫入。
不利之處: 主主復制
你需要添加負載均衡器或者在應用邏輯中做改動,來確定寫入哪一個數據庫。
多數主-主系統要么不能保證一致性(違反 ACID),要么因為同步產生了寫入延遲。
隨著更多寫入節點的加入和延遲的提高,如何解決沖突顯得越發重要。
參考不利之處:復制中,主從復制和主主復制共同的問題。
不利之處:復制
如果主庫在將新寫入的數據復制到其他節點前掛掉,則有數據丟失的可能。
寫入會被重放到負責讀取操作的副本。副本可能因為過多寫操作阻塞住,導致讀取功能異常。
讀取從庫越多,需要復制的寫入數據就越多,導致更嚴重的復制延遲。
在某些數據庫系統中,寫入主庫的操作可以用多個線程并行寫入,但讀取副本只支持單線程順序地寫入。
復制意味著更多的硬件和額外的復雜度。
聯合(或按功能劃分)將數據庫按對應功能分割。例如,你可以有三個數據庫:論壇、用戶和產品,而不僅是一個單體數據庫,從而減少每個數據庫的讀取和寫入流量,減少復制延遲。較小的數據庫意味著更多適合放入內存的數據,進而意味著更高的緩存命中幾率。沒有只能串行寫入的中心化主庫,你可以并行寫入,提高負載能力。
不利之處:聯合
如果你的數據庫模式需要大量的功能和數據表,聯合的效率并不好。
你需要更新應用程序的邏輯來確定要讀取和寫入哪個數據庫。
用 server link 從兩個庫聯結數據更復雜。
聯合需要更多的硬件和額外的復雜度。
分片將數據分配在不同的數據庫上,使得每個數據庫僅管理整個數據集的一個子集。以用戶數據庫為例,隨著用戶數量的增加,越來越多的分片會被添加到集群中。
類似聯合的優點,分片可以減少讀取和寫入流量,減少復制并提高緩存命中率。也減少了索引,通常意味著查詢更快,性能更好。如果一個分片出問題,其他的仍能運行,你可以使用某種形式的冗余來防止數據丟失。類似聯合,沒有只能串行寫入的中心化主庫,你可以并行寫入,提高負載能力。
常見的做法是用戶姓氏的首字母或者用戶的地理位置來分隔用戶表。
不利之處:分片
你需要修改應用程序的邏輯來實現分片,這會帶來復雜的 SQL 查詢。
分片不合理可能導致數據負載不均衡。例如,被頻繁訪問的用戶數據會導致其所在分片的負載相對其他分片高。
再平衡會引入額外的復雜度。基于一致性哈希的分片算法可以減少這種情況。
聯結多個分片的數據操作更復雜。
分片需要更多的硬件和額外的復雜度。
非規范化試圖以寫入性能為代價來換取讀取性能。在多個表中冗余數據副本,以避免高成本的聯結操作。一些關系型數據庫,比如 PostgreSQL 和 Oracle 支持物化視圖,可以處理冗余信息存儲和保證冗余副本一致。
當數據使用諸如聯合和分片等技術被分割,進一步提高了處理跨數據中心的聯結操作復雜度。非規范化可以規避這種復雜的聯結操作。
在多數系統中,讀取操作的頻率遠高于寫入操作,比例可達到 100:1,甚至 1000:1。需要復雜的數據庫聯結的讀取操作成本非常高,在磁盤操作上消耗了大量時間。
不利之處:非規范化
數據會冗余。
約束可以幫助冗余的信息副本保持同步,但這樣會增加數據庫設計的復雜度。
非規范化的數據庫在高寫入負載下性能可能比規范化的數據庫差。
SQL 調優是一個范圍很廣的話題,有很多相關的書可以作為參考。
利用基準測試和性能分析來模擬和發現系統瓶頸很重要。
基準測試 - 用 ab 等工具模擬高負載情況。
性能分析 - 通過啟用如慢查詢日志等工具來輔助追蹤性能問題。
基準測試和性能分析可能會指引你到以下優化方案。
改進模式
為了實現快速訪問,MySQL 在磁盤上用連續的塊存儲數據。
使用 CHAR
類型存儲固定長度的字段,不要用 VARCHAR
。
CHAR
在快速、隨機訪問時效率很高。如果使用 VARCHAR
,如果你想讀取下一個字符串,不得不先讀取到當前字符串的末尾。
使用 TEXT
類型存儲大塊的文本,例如博客正文。TEXT
還允許布爾搜索。使用 TEXT
字段需要在磁盤上存儲一個用于定位文本塊的指針。
使用 INT
類型存儲高達 2^32 或 40 億的較大數字。
使用 DECIMAL
類型存儲貨幣可以避免浮點數表示錯誤。
避免使用 BLOBS
存儲對象,存儲存放對象的位置。
VARCHAR(255)
是以 8 位數字存儲的最大字符數,在某些關系型數據庫中,最大限度地利用字節。
在適用場景中設置 NOT NULL
約束來提高搜索性能。
使用正確的索引
你正查詢(SELECT
、GROUP BY
、ORDER BY
、JOIN
)的列如果用了索引會更快。
索引通常表示為自平衡的 B 樹,可以保持數據有序,并允許在對數時間內進行搜索,順序訪問,插入,刪除操作。
設置索引,會將數據存在內存中,占用了更多內存空間。
寫入操作會變慢,因為索引需要被更新。
加載大量數據時,禁用索引再加載數據,然后重建索引,這樣也許會更快。
避免高成本的聯結操作
有性能需要,可以進行非規范化。
分割數據表
將熱點數據拆分到單獨的數據表中,可以有助于緩存。
調優查詢緩存
在某些情況下,查詢緩存可能會導致性能問題。
NoSQL 是鍵-值數據庫、文檔型數據庫、列型數據庫或圖數據庫的統稱。數據庫是非規范化的,表聯結大多在應用程序代碼中完成。大多數 NoSQL 無法實現真正符合 ACID 的事務,支持最終一致。
BASE 通常被用于描述 NoSQL 數據庫的特性。相比 CAP 理論,BASE 強調可用性超過一致性。
基本可用 - 系統保證可用性。
軟狀態 - 即使沒有輸入,系統狀態也可能隨著時間變化。
最終一致性 - 經過一段時間之后,系統最終會變一致,因為系統在此期間沒有收到任何輸入。
除了在 SQL 還是 NoSQL 之間做選擇,了解哪種類型的 NoSQL 數據庫最適合你的用例也是非常有幫助的。我們將在下一節中快速了解下 鍵-值存儲、文檔型存儲、列型存儲和圖存儲數據庫。
抽象模型:哈希表
鍵-值存儲通常可以實現 O(1) 時間讀寫,用內存或 SSD 存儲數據。數據存儲可以按字典順序維護鍵,從而實現鍵的高效檢索。鍵-值存儲可以用于存儲元數據。
鍵-值存儲性能很高,通常用于存儲簡單數據模型或頻繁修改的數據,如存放在內存中的緩存。鍵-值存儲提供的操作有限,如果需要更多操作,復雜度將轉嫁到應用程序層面。
鍵-值存儲是如文檔存儲,在某些情況下,甚至是圖存儲等更復雜的存儲系統的基礎。
抽象模型:將文檔作為值的鍵-值存儲
文檔類型存儲以文檔(XML、JSON、二進制文件等)為中心,文檔存儲了指定對象的全部信息。文檔存儲根據文檔自身的內部結構提供 API 或查詢語句來實現查詢。請注意,許多鍵-值存儲數據庫有用值存儲元數據的特性,這也模糊了這兩種存儲類型的界限。
基于底層實現,文檔可以根據集合、標簽、元數據或者文件夾組織。盡管不同文檔可以被組織在一起或者分成一組,但相互之間可能具有完全不同的字段。
MongoDB 和 CouchDB 等一些文檔類型存儲還提供了類似 SQL 語言的查詢語句來實現復雜查詢。DynamoDB 同時支持鍵-值存儲和文檔類型存儲。
文檔類型存儲具備高度的靈活性,常用于處理偶爾變化的數據。
抽象模型:嵌套的
ColumnFamily<RowKey, Columns<ColKey, Value, Timestamp>>
映射
類型存儲的基本數據單元是列(名/值對)。列可以在列族(類似于 SQL 的數據表)中被分組。超級列族再分組普通列族。你可以使用行鍵獨立訪問每一列,具有相同行鍵值的列組成一行。每個值都包含版本的時間戳用于解決版本沖突。
Google 發布了第一個列型存儲數據庫 Bigtable,它影響了 Hadoop 生態系統中活躍的開源數據庫 HBase 和 Facebook 的 Cassandra。像 BigTable,HBase 和 Cassandra 這樣的存儲系統將鍵以字母順序存儲,可以高效地讀取鍵列。
列型存儲具備高可用性和高可擴展性。通常被用于大數據相關存儲。
抽象模型: 圖
在圖數據庫中,一個節點對應一條記錄,一個弧對應兩個節點之間的關系。圖數據庫被優化用于表示外鍵繁多的復雜關系或多對多關系。
圖數據庫為存儲復雜關系的數據模型,如社交網絡,提供了很高的性能。它們相對較新,尚未廣泛應用,查找開發工具或者資源相對較難。許多圖只能通過 REST API 訪問。
選取 SQL 的原因:
結構化數據
嚴格的模式
關系型數據
需要復雜的聯結操作
事務
清晰的擴展模式
既有資源更豐富:開發者、社區、代碼庫、工具等
通過索引進行查詢非常快
選取 NoSQL 的原因:
半結構化數據
動態或靈活的模式
非關系型數據
不需要復雜的聯結操作
存儲 TB (甚至 PB)級別的數據
高數據密集的工作負載
IOPS 高吞吐量
適合 NoSQL 的示例數據:
埋點數據和日志數據
排行榜或者得分數據
臨時數據,如購物車
頻繁訪問的(“熱”)表
元數據/查找表
緩存可以提高頁面加載速度,并可以減少服務器和數據庫的負載。在這個模型中,分發器先查看請求之前是否被響應過,如果有則將之前的結果直接返回,來省掉真正的處理。
數據庫分片均勻分布的讀取是最好的。但是熱門數據會讓讀取分布不均勻,這樣就會造成瓶頸,如果在數據庫前加個緩存,就會抹平不均勻的負載和突發流量對數據庫的影響。
緩存可以位于客戶端(操作系統或者瀏覽器),服務端或者不同的緩存層。
CDN 也被視為一種緩存。
反向代理和緩存(比如 Varnish)可以直接提供靜態和動態內容。Web 服務器同樣也可以緩存請求,返回相應結果而不必連接應用服務器。
數據庫的默認配置中通常包含緩存級別,針對一般用例進行了優化。調整配置,在不同情況下使用不同的模式可以進一步提高性能。
基于內存的緩存比如 Memcached 和 Redis 是應用程序和數據存儲之間的一種鍵值存儲。由于數據保存在 RAM 中,它比存儲在磁盤上的典型數據庫要快多了。RAM 比磁盤限制更多,所以例如 least recently used (LRU) 的緩存無效算法可以將「熱門數據」放在 RAM 中,而對一些比較「冷門」的數據不做處理。
Redis 有下列附加功能:
持久性選項
內置數據結構比如有序集合和列表
有多個緩存級別,分為兩大類:數據庫查詢和對象:
行級別
查詢級別
完整的可序列化對象
完全渲染的 HTML
一般來說,你應該盡量避免基于文件的緩存,因為這使得復制和自動縮放很困難。
當你查詢數據庫的時候,將查詢語句的哈希值與查詢結果存儲到緩存中。這種方法會遇到以下問題:
很難用復雜的查詢刪除已緩存結果。
如果一條數據比如表中某條數據的一項被改變,則需要刪除所有可能包含已更改項的緩存結果。
將您的數據視為對象,就像對待你的應用代碼一樣。讓應用程序將數據從數據庫中組合到類實例或數據結構中:
如果對象的基礎數據已經更改了,那么從緩存中刪掉這個對象。
允許異步處理:workers 通過使用最新的緩存對象來組裝對象。
建議緩存的內容:
用戶會話
完全渲染的 Web 頁面
活動流
用戶圖數據
由于你只能在緩存中存儲有限的數據,所以你需要選擇一個適用于你用例的緩存更新策略。
應用從存儲器讀寫。緩存不和存儲器直接交互,應用執行以下操作:
在緩存中查找記錄,如果所需數據不在緩存中
從數據庫中加載所需內容
將查找到的結果存儲到緩存中
返回所需內容
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 通常用這種方式使用。
添加到緩存中的數據讀取速度很快。緩存模式也稱為延遲加載。只緩存所請求的數據,這避免了沒有被請求的數據占滿了緩存空間。
緩存的缺點:
請求的數據如果不在緩存中就需要經過三個步驟來獲取數據,這會導致明顯的延遲。
如果數據庫中的數據更新了會導致緩存中的數據過時。這個問題需要通過設置 ? TTL 強制更新緩存或者直寫模式來緩解這種情況。
當一個節點出現故障的時候,它將會被一個新的節點替代,這增加了延遲的時間。
應用使用緩存作為主要的數據存儲,將數據讀寫到緩存中,而緩存負責從數據庫中讀寫數據。
應用向緩存中添加/更新數據
緩存同步地寫入數據存儲
返回所需內容
應用代碼:
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)
由于存寫操作所以直寫模式整體是一種很慢的操作,但是讀取剛寫入的數據很快。相比讀取數據,用戶通常比較能接受更新數據時速度較慢。緩存中的數據不會過時。
直寫模式的缺點:
由于故障或者縮放而創建的新的節點,新的節點不會緩存,直到數據庫更新為止。緩存應用直寫模式可以緩解這個問題。
寫入的大多數數據可能永遠都不會被讀取,用 TTL 可以最小化這種情況的出現。
在回寫模式中,應用執行以下操作:
在緩存中增加或者更新條目
異步寫入數據,提高寫入性能。
回寫模式的缺點:
緩存可能在其內容成功存儲之前丟失數據。
執行直寫模式比緩存或者回寫模式更復雜。
你可以將緩存配置成在到期之前自動刷新最近訪問過的內容。
如果緩存可以準確預測將來可能請求哪些數據,那么刷新可能會導致延遲與讀取時間的降低。
刷新的缺點:
不能準確預測到未來需要用到的數據可能會導致性能不如不使用刷新。
需要保持緩存和真實數據源之間的一致性,比如數據庫根據緩存無效。
需要改變應用程序比如增加 Redis 或者 memcached。
無效緩存是個難題,什么時候更新緩存是與之相關的復雜問題。
異步工作流有助于減少那些原本順序執行的請求時間。它們可以通過提前進行一些耗時的工作來幫助減少請求時間,比如定期匯總數據。
消息隊列接收,保留和傳遞消息。如果按順序執行操作太慢的話,你可以使用有以下工作流的消息隊列:
應用程序將作業發布到隊列,然后通知用戶作業狀態
一個 worker 從隊列中取出該作業,對其進行處理,然后顯示該作業完成
不去阻塞用戶操作,作業在后臺處理。在此期間,客戶端可能會進行一些處理使得看上去像是任務已經完成了。例如,如果要發送一條推文,推文可能會馬上出現在你的時間線上,但是可能需要一些時間才能將你的推文推送到你的所有關注者那里去。
Redis 是一個令人滿意的簡單的消息代理,但是消息有可能會丟失。
RabbitMQ 很受歡迎但是要求你適應「AMQP」協議并且管理你自己的節點。
Amazon SQS 是被托管的,但可能具有高延遲,并且消息可能會被傳送兩次。
任務隊列接收任務及其相關數據,運行它們,然后傳遞其結果。 它們可以支持調度,并可用于在后臺運行計算密集型作業。
Celery 支持調度,主要是用 Python 開發的。
如果隊列開始明顯增長,那么隊列大小可能會超過內存大小,導致高速緩存未命中,磁盤讀取,甚至性能更慢。背壓可以通過限制隊列大小來幫助我們,從而為隊列中的作業保持高吞吐率和良好的響應時間。一旦隊列填滿,客戶端將得到服務器忙或者 HTTP 503 狀態碼,以便稍后重試。客戶端可以在稍后時間重試該請求,也許是指數退避。
簡單的計算和實時工作流等用例可能更適用于同步操作,因為引入隊列可能會增加延遲和復雜性。
HTTP 是一種在客戶端和服務器之間編碼和傳輸數據的方法。它是一個請求/響應協議:客戶端和服務端針對相關內容和完成狀態信息的請求和響應。HTTP 是獨立的,允許請求和響應流經許多執行負載均衡,緩存,加密和壓縮的中間路由器和服務器。
一個基本的 HTTP 請求由一個動詞(方法)和一個資源(端點)組成。 以下是常見的 HTTP 動詞:
動詞 | 描述 | *冪等 | 安全性 | 可緩存 |
---|---|---|---|---|
GET | 讀取資源 | Yes | Yes | Yes |
POST | 創建資源或觸發處理數據的進程 | No | No | Yes,如果回應包含刷新信息 |
PUT | 創建或替換資源 | Yes | No | No |
PATCH | 部分更新資源 | No | No | Yes,如果回應包含刷新信息 |
DELETE | 刪除資源 | Yes | No | No |
多次執行不會產生不同的結果。
HTTP 是依賴于較低級協議(如 TCP 和 UDP)的應用層協議。
TCP 是通過 IP 網絡的面向連接的協議。 使用握手建立和斷開連接。 發送的所有數據包保證以原始順序到達目的地,用以下措施保證數據包不被損壞:
每個數據包的序列號和校驗碼。
確認包和自動重傳
如果發送者沒有收到正確的響應,它將重新發送數據包。如果多次超時,連接就會斷開。TCP 實行流量控制和擁塞控制。這些確保措施會導致延遲,而且通常導致傳輸效率比 UDP 低。
為了確保高吞吐量,Web 服務器可以保持大量的 TCP 連接,從而導致高內存使用。在 Web 服務器線程間擁有大量開放連接可能開銷巨大,消耗資源過多,也就是說,一個 memcached 服務器。連接池 可以幫助除了在適用的情況下切換到 UDP。
TCP 對于需要高可靠性但時間緊迫的應用程序很有用。比如包括 Web 服務器,數據庫信息,SMTP,FTP 和 SSH。
以下情況使用 TCP 代替 UDP:
你需要數據完好無損。
你想對網絡吞吐量自動進行最佳評估。
UDP 是無連接的。數據報(類似于數據包)只在數據報級別有保證。數據報可能會無序的到達目的地,也有可能會遺失。UDP 不支持擁塞控制。雖然不如 TCP 那樣有保證,但 UDP 通常效率更高。
UDP 可以通過廣播將數據報發送至子網內的所有設備。這對 DHCP 很有用,因為子網內的設備還沒有分配 IP 地址,而 IP 對于 TCP 是必須的。
UDP 可靠性更低但適合用在網絡電話、視頻聊天,流媒體和實時多人游戲上。
以下情況使用 UDP 代替 TCP:
你需要低延遲
相對于數據丟失更糟的是數據延遲
你想實現自己的錯誤校正方法
在 RPC 中,客戶端會去調用另一個地址空間(通常是一個遠程服務器)里的方法。調用代碼看起來就像是調用的是一個本地方法,客戶端和服務器交互的具體過程被抽象。遠程調用相對于本地調用一般較慢而且可靠性更差,因此區分兩者是有幫助的。熱門的 RPC 框架包括 Protobuf、Thrift 和 Avro。
RPC 是一個“請求-響應”協議:
客戶端程序 ── 調用客戶端存根程序。就像調用本地方法一樣,參數會被壓入棧中。
客戶端 stub 程序 ── 將請求過程的 id 和參數打包進請求信息中。
客戶端通信模塊 ── 將信息從客戶端發送至服務端。
服務端通信模塊 ── 將接受的包傳給服務端存根程序。
服務端 stub 程序 ── 將結果解包,依據過程 id 調用服務端方法并將參數傳遞過去。
RPC 調用示例:
GET /someoperation?data=anId POST /anotheroperation { "data":"anId"; "anotherdata": "another value"}
RPC 專注于暴露方法。RPC 通常用于處理內部通訊的性能問題,這樣你可以手動處理本地調用以更好的適應你的情況。
當以下情況時選擇本地庫(也就是 SDK):
你知道你的目標平臺。
你想控制如何訪問你的“邏輯”。
你想對發生在你的庫中的錯誤進行控制。
性能和終端用戶體驗是你最關心的事。
遵循 REST 的 HTTP API 往往更適用于公共 API。
RPC 客戶端與服務實現捆綁地很緊密。
一個新的 API 必須在每一個操作或者用例中定義。
RPC 很難調試。
你可能沒辦法很方便的去修改現有的技術。舉個例子,如果你希望在 Squid 這樣的緩存服務器上確保 RPC 被正確緩存的話可能需要一些額外的努力了。
REST 是一種強制的客戶端/服務端架構設計模型,客戶端基于服務端管理的一系列資源操作。服務端提供修改或獲取資源的接口。所有的通信必須是無狀態和可緩存的。
RESTful 接口有四條規則:
標志資源(HTTP 里的 URI) ── 無論什么操作都使用同一個 URI。
表示的改變(HTTP 的動作) ── 使用動作, headers 和 body。
可自我描述的錯誤信息(HTTP 中的 status code) ── 使用狀態碼,不要重新造輪子。
HATEOAS(HTTP 中的 HTML 接口) ── 你的 web 服務器應該能夠通過瀏覽器訪問。
REST 請求的例子:
GET /someresources/anId PUT /someresources/anId {"anotherdata": "another value"}
REST 關注于暴露數據。它減少了客戶端/服務端的耦合程度,經常用于公共 HTTP API 接口設計。REST 使用更通常與規范化的方法來通過 URI 暴露資源,通過 header 來表述并通過 GET、POST、PUT、DELETE 和 PATCH 這些動作來進行操作。因為無狀態的特性,REST 易于橫向擴展和隔離。
由于 REST 將重點放在暴露數據,所以當資源不是自然組織的或者結構復雜的時候它可能無法很好的適應。舉個例子,返回過去一小時中與特定事件集匹配的更新記錄這種操作就很難表示為路徑。使用 REST,可能會使用 URI 路徑,查詢參數和可能的請求體來實現。
REST 一般依賴幾個動作(GET、POST、PUT、DELETE 和 PATCH),但有時候僅僅這些沒法滿足你的需要。舉個例子,將過期的文檔移動到歸檔文件夾里去,這樣的操作可能沒法簡單的用上面這幾個 verbs 表達。
為了渲染單個頁面,獲取被嵌套在層級結構中的復雜資源需要客戶端,服務器之間多次往返通信。例如,獲取博客內容及其關聯評論。對于使用不確定網絡環境的移動應用來說,這些多次往返通信是非常麻煩的。
隨著時間的推移,更多的字段可能會被添加到 API 響應中,較舊的客戶端將會接收到所有新的數據字段,即使是那些它們不需要的字段,結果它會增加負載大小并引起更大的延遲。
操作 | 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 |
向用戶物品列表添加一項 | POST /addItemToUsersItemsList { "personid": "1234"; "itemid": "456" } | POST /persons/1234/items { "itemid": "456" } |
更新一個物品 | POST /modifyItem { "itemid": "456"; "key": "value" } | PUT /items/456 { "key": "value" } |
刪除一個物品 | POST /removeItem { "itemid": "456" } | DELETE /items/456 |
這一部分需要更多內容。一起來吧!
安全是一個寬泛的話題。除非你有相當的經驗、安全方面背景或者正在申請的職位要求安全知識,你不需要了解安全基礎知識以外的內容:
在運輸和等待過程中加密
對所有的用戶輸入和從用戶那里發來的參數進行處理以防止 XSS 和 SQL 注入。
使用參數化的查詢來防止 SQL 注入。
使用最小權限原則。
一些時候你會被要求做出保守估計。比如,你可能需要估計從磁盤中生成 100 張圖片的縮略圖需要的時間或者一個數據結構需要多少的內存。2 的次方表和每個開發者都需要知道的一些時間數據(譯注: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
基于上述數字的指標:
從磁盤以 30 MB/s 的速度順序讀取
以 100 MB/s 從 1 Gbps 的以太網順序讀取
從 SSD 以 1 GB/s 的速度讀取
以 4 GB/s 的速度從主存讀取
每秒能繞地球 6-7 圈
數據中心內每秒有 2,000 次往返
到此,關于“大型互聯網系統架構是怎么設計的”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。