設計一個支持百萬用戶的系統

設計一個支持數百萬用戶的系統是非常有挑戰性的, 這是一個需要不斷調整和優化的過程, 接下來的內容中, 我將構建一個系統, 從單個用戶開始,到最后支持數百萬的用戶。


? ? 從單個服務開始? ?

千里之行,始于足下,讓我們從最簡單的單個服務開始。所有的內容都在一臺服務器上運行,包括 Web 程序, 數據庫,緩存 等等, 如下圖

0d3634ae8e9e8eebc5cb1a3b5c304e3a.png

我們看一下它的工作流程。

006c0a9ff444a65aa0d58ab64dbd120f.png

1.用戶通過域名訪問網站, 比如, api.mysite.com, 通常情況下, 域名解析服務 (DNS) 是由第三方提供的付費服務, 而不是我們的服務器所提供的。2.返回 IP 地址給瀏覽器或者移動設備, 比如, 15.125.23.214。3.通過 IP 地址, 發送 Http 請求到我們的 Web 服務器。4.Web 服務器返回 html 或者 json 內容, 瀏覽器進行渲染。


? ? 分離數據庫? ?

隨著用戶量的增長,此時一臺服務器已經獨木難支,我們需要兩臺服務器, 一個用于 Web 服務, 一個用于數據庫。

77852486122f642297331b0501a084f2.png


? ? 數據庫選型???

您可以選擇關系型數據庫和非關系型數據庫,那它們都有什么特點呢?

關系型數據庫也稱為關系型數據庫管理系統 (RDBMS) 或 SQL 數據庫,最常見的有 MySQL、Oracle 、PostgreSQL、Sql Server 等,可以通過 SQL 進行跨表查詢。

而非關系型數據庫也稱為 NoSQL 數據庫,最常見的有 Redis、 CouchDB,Neo4j、Cassandra、HBase、Amazon DynamoDB 等。它們分為四類:鍵值(Key-Value)存儲數據庫、列存儲數據庫、文檔型數據庫、圖(Graph)數據庫。

對于大多數開發人員來說,通常會選擇關系型數據庫。而非關系型數據庫更適合以下幾種情況:

?應用程序需要超低延遲。
?數據是非結構化的,或者沒有任何關系數據。
?只需要序列化和反序列化數據(JSON、XML、YAML 等)。
?需要存儲海量數據。


? ? 垂直縮放 、 水平縮放? ?

垂直縮放,又稱為 "縱向擴展" (scale up), 是指升級服務器資源, 比如 CPU, RAM 等。而水平縮放又稱為 "橫向擴展" (scale out), 是指添加服務器到資源池中。

30b342470a3dd7e56ac6a334861250cb.png

當流量比較少的時候, 選擇縱向擴展就足夠了,因為它足夠簡單,不過也有很大的局限性。

?縱向擴展有硬件限制, 無限制的升級 CPU 和內存是不現實的。?縱向擴展沒有高可用,如果一臺服務器出現故障,網站或者應用就會直接崩潰。

而流量較大的時候,橫向擴展是更好的選擇,多個服務器也保證了高可用。如何讓這些服務器更好的提供服務,我們還需要做負載均衡。


? ? Load balancer? ?

負載均衡器可以平均分配流量給每臺服務器,如下

2ac50cde96297cb0723ab376a836b632.png

我們水平擴展了 Web 服務,并引入了負載均衡器,來應對快速增長的網站流量, 并提供了高可用的服務。

現在,Web 層看上去不錯,但是不要忘了,當前的設計只有一個數據庫,并不支持故障轉移和冗余。而數據庫復制是一種常見的技術,可以解決這個問題。


? ? Database replication? ?

數據庫復制是把數據復制、傳輸到另外一個數據庫,最終形成一個分布式數據庫。用戶可以訪問到相同的信息,從而提高一致性、可靠性和性能。

通常它們之間是主/從(master/slave) 的關系,一主多從,主節點支持讀寫操作,而從節點僅支持讀取操作,如下

5b666d559f559ce3142b681ecdb9892c.png

引入了數據庫復制, 讓我們看看現在網站整體的設計。

d55d5a820d78178aa023b16fc83444b8.png

1.用戶從 DNS 獲取到 Load balancer 的 IP 地址,并連接到 Load balancer。
2.Http 請求被路由到服務器1 或者 服務器2。
3.使用數據庫復制,進行讀寫分離。
現在,web 服務和數據庫都已經做了優化,看上去不錯!
接下來,還需要提升 web 的加載和響應時間,我們可以使用 CDN 緩存靜態資源, 包括 js、css、image 等。

? ? Content delivery network (CDN)? ?

CDN 是一個用于交付靜態內容的網絡服務,分布在不同的地理位置。當用戶訪問網站時,距離最近的 CDN 服務器提供靜態資源,可以很好的改善網站的加載時間。

8a854f48d483f6199b682e80b05d9777.png

另外,對于數據庫來說,我們也可以把一些熱點數據添加到緩存中,這樣可以減輕數據庫的壓力。

現在,我們的系統加了兩層緩存。

0c44c24bcc28e5fad4a04ad9d6bfc6f9.png

1.對于靜態資源,由 CDN 提供而不是 Web 服務器。2.通過緩存數據來減少對數據庫的訪問。


? ? 無狀態 Web 層???

現在我們的 Web 應用是有狀態的服務,什么意思呢?假如用戶在 Server 1 進行了登陸, 那后續也只能在 Server1 請求資源,因為只有 Server1 才擁有用戶的會話信息,每個 Web 服務的狀態都是獨立的、隔離的。

ceb40cd2349a21eaaf234b58a41699c9.png

我們需要把這些狀態移出 Web層,通常單獨保存在關系型數據庫或者 NoSQL, 這樣 Web 層就變成了無狀態的。

b29c95dd24e0bf7ba88959edb43c7b9c.png

這樣做有什么好處呢?在無狀態的架構中,來自用戶的 Http 請求可以發送到任何 Web 服務器,而狀態信息統一保存在單獨的共享存儲中。無狀態系統更簡單、更容易擴展。

e14abe439e26114e24eedbcbf6cf422c.png


? ? 數據中心???

您的網站受到越來越多人的關注,用戶也迅速發展,并擴展到全球。

如何為各個地區的用戶都提供滿意的服務?您可以在不同的地區設置多個數據中心。

如下圖,我們分別在東、西兩個地區配置了單獨的數據中心, DC1、DC2。

6c55821d02bd1f80e276d8d726134319.png

看上去不錯!但是如何引導用戶去不同的數據中心呢?答案是:DNS, 是的,眾所周知,DNS 可以把我們網站的域名解析為 IP 地址,而使用 GeoDNS, 可以根據用戶請求所在的位置,解析為不同的地區的 IP 地址。把用戶引導到離他最近的數據中心,來達到加速的目的。

d2ce6dcb9144ea8d37872974891090c5.png

另外,如果某個數據中心發生重大事故,導致集群故障,我們可以把所有的流量都引導到健康的數據中心,這種架構就是我們常說的 "異地多活"。


? ? Message queue???

當需要進行解耦時,引入消息隊列通常是優先考慮的, 它支持異步通信,當您有耗時的任務需要處理時,可以通過生產者把消息發送到消息隊列,Web 服務可以盡快的響應用戶的請求,而消費者可以異步地去處理這些耗時任務。

4b18382ca5e8df7fb6b971ab51659279.png


? ? 日志、指標、自動化???

當網站的流量越來越大時,就必須要引入監控工具了。

日志:監控錯誤日志很重要,它可以幫助您發現系統問題。您可以把日志統一發送到日志中心,這樣便于分析和查看。

指標:收集各種各樣的指標,可以幫助我們更好的理解業務和系統。

?系統指標::CPU、內存、磁盤 I/O,數據庫等等。?業務指標:每日用戶、活躍度等等。

自動化,當系統變得龐大且復雜時,我們需要引入自動化工具,CI/CD 很重要,自動化構建、測試、部署可以極大的提高開發人員的生產力。

現在,我們的系統引入了消息隊列,以及一些監控和自動化工具。

93a8be723d055ea8276f436949e44a07.png


? ? Database Sharding???

數據庫的數據每天都在大步的增長,我們的數據庫已經不堪重負了,是時候擴展數據庫了,數據庫分片是個很好的方案。

在下面的示例中,我們使用了哈希函數來進行分片, 根據不同的 user_id, 把數據平均分配到 4個數據庫中。

58d85051754c82d050f443489a42aca9.png

現在,我們看一下數據庫的數據。

46ce9012cc60b007363938d113ed628d.png

使用數據庫分片的方案時,有一個要考慮的重要因素是分片鍵(sharding key), 或者叫分區鍵,比如上面的 user_id,因為可以通過 sharding key 找到相對應的數據庫,另外,我們要選擇一個可以均勻分布數據的鍵。

看起來不錯!不過這種方案也給系統帶來的復雜性和新的挑戰,當數據越來越多,增加了數據庫節點之后,我們需要重新進行數據分片。比如 useri_id % 5, 此時,為了保證哈希函數的正確路由,我們需要移動數據庫大量的數據。

我們可以使用一致性哈希技術,來解決上面的問題,重新分片后,只需要移動一小部分數據即可,當然一致性哈希本文就不做詳細的介紹了。

讓我們看看最終的系統設計。

dbfcd229f505d8e9ad2178fe5df3ba3a.png


? ?總結???

構建一個健壯的架構系統,其實是一個迭代的過程,為了支持數百萬的用戶的架構,我們需要做到以下幾點:

?保證 Web 層無狀態?盡可能的緩存數據?異地多活,配置多個數據中心?使用分片擴展數據庫?監控系統并使用自動化工具

希望對您有用!

譯:等天黑

作者:Alex Xu

來源:《System Design Interview》

cf9954393992d875287d407ab1e24936.png

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/287785.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/287785.shtml
英文地址,請注明出處:http://en.pswp.cn/news/287785.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SQL Server T-SQL編程:數據庫用戶與安全設置

目錄 一、數據庫的注冊、用戶建立 二 、用戶安全設置:角色

原百萬訪問量博客http://blog.chinaunix.net/uid/20656672.html不再維護(10年前數百篇oracle/teradata性能優化、故障處理案例)...

原博客地址http://blog.chinaunix.net/uid/20656672.html不再維護(數百篇oracle/teradata性能優化、故障處理原創文章)轉載于:https://www.cnblogs.com/zhjh256/p/5497797.html

《零基礎看得懂的C語言入門教程 》——(九)C語言二維數組與循環嵌套

一、學習目標 了解二維數組的使用方法了解循環嵌套的使用方法 目錄 C語言真的很難嗎?那是你沒看這張圖,化整為零輕松學習C語言。 第一篇:(一)脫離學習誤區 第二篇:(二)C語言沒那么…

LRU算法

1 LRU算法 LRU(Least recently used,最近最少使用)根據數據的歷史訪問記錄來進行淘汰數據,思想是“如果數據最近被訪問過,那么將來被訪問的幾率也更高”。 2 具體實現過程 新數據插入到鏈表頭部; 每當緩存命中(即緩存數據被訪問),則將數據移到鏈表頭部; 當鏈表滿…

Scala-2.13.0 安裝及配置

Scala 簡介 Scala 是一門多范式(multi-paradigm)的編程語言,設計初衷是要集成面向對象編程和函數式編程的各種特性。 Scala 運行在Java虛擬機上,并兼容現有的Java程序。 Scala 源代碼被編譯成Java字節碼,所以它可以運…

檢測python進程是否存活

crontab -e */3 * * * * /data/log_realtime/check.sh > /data/log_realtime/check.log 2>&1 1 0 1 * * /data/jx3log_import_realtime/shutdown.sh 說明:每3分鐘檢查一次進程是否存在,每個月1號0點1分殺掉進程,重啟 check.sh cd …

中科大鏡像源_JETPACK4.4安裝軟件和備份鏡像的方法介紹

一、使用SDK Manager的文件夾安裝Jetson軟件(以NX為例)當JETPACK安裝出現錯誤的時候,可以嘗試下面的安裝辦法,前提是JETPACK4.4完整安裝(即本文第三節的下載已經完成),并且選擇JETSON NX的相關的下載已經完成。安裝步驟:1、$cd /n…

站在前人的肩膀上重新透視C# SpanT數據結構

先談一下我對Span的看法, Span是指向任意連續內存空間的類型安全、內存安全的視圖,可操作的滑動窗口。Span和Memory都是包裝了可以在pipeline上使用的結構化數據的內存緩沖器,他們被設計用于在pipeline中高效傳遞數據。定語解讀這里面許多定語&#xff0…

集合學習

List集合:ArrayList集合基于動態數組結構,查詢優,LinkedList 基于鏈表結構 數據移動優。是一個有序的隊列集合 set集合:HashSet和TreeSet 。是一個無序不重復集合 Map集合:HashMap和TreeMap。是一個KEY-VALUE映射的集合…

《零基礎看得懂的C語言入門教程 》——(十)C語言的指針原來是這樣

一、學習目標 了解指針的概念了解指針的使用方法了解雙重指針 目錄 C語言真的很難嗎?那是你沒看這張圖,化整為零輕松學習C語言。 第一篇:(一)脫離學習誤區 第二篇:(二)C語言沒那…

T-SQL編程基礎之一:變量與基本語句

一個標準的計算機語言,大概要提供的必要主要功能是:變量說明、分支判斷、循環和輸入輸出結果。T-SQL也一樣,具有這些功能,只不過T-SQL的輸入和輸出不是界面,而是表。 完全精確描述一個計算機語言,大概要很厚的書才能做到,好在目前這些書籍的發行也很多,許多書描述的都…

Java之volatile如何保證可見性和指令重排序

1 我們先了解CPU緩存 CPU緩存為了解決CPU運算速度與內存讀寫速度不匹配的問題,因為CPU運算速度要比內存讀寫速度快得多 一次主內存的訪問通常在幾十到幾百個時鐘周期一次L1高速緩存的讀寫只需要1~2個時鐘周期一次L2高速緩存的讀寫也只需要數十個時鐘周期 CPU大多數…

bigpipe提升網站響應速度

2019獨角獸企業重金招聘Python工程師標準>>> 主要思想就是通過異步 發起一次請求,后端不關閉輸出流,多個線程處理各自任務,然后分別發送到客戶端。 https://github.com/4rnold/Demo-Project/tree/master/bigpipe-demohttps://gith…

mysql 添加用戶_mysql創建用戶與授權

一、創建用戶CREATE USER usernamehost IDENTIFIED BY password;說明username:你將創建的用戶名host:指定該用戶在哪個主機上可以登陸,如果是本地用戶可用localhost,如果想讓該用戶可以從任意遠程主機登陸,可以使用通配…

《零基礎看得懂的C語言入門教程 》——(十一)C語言自定義函數真的很簡單

一、學習目標 了解C語言的自定義函數的使用方法了解C語言自定義函數的傳參了解C語言自定義函數的返回值 目錄 C語言真的很難嗎?那是你沒看這張圖,化整為零輕松學習C語言。 第一篇:(一)脫離學習誤區 第二篇&#xf…

T-SQL編程基礎之二:條件選擇、循環編程

1. 條件判斷以及GOTO語句 條件判斷是計算機語言的重要功能,在T-SQL中,條件判斷的語句是: if 條件 … else … 或者是: if 條件 … 注意寫法和C類似,但條件描述不使用()也可以。如果是在一個條件里執行多條語句,則要構造復合語句,復合語句是在BEGIN…EDN中構造…

**【ci框架】精通CodeIgniter框架

http://blog.csdn.net/yanhui_wei/article/details/25803945 一、大綱 [php] view plaincopy1、codeigniter框架的授課內容安排 2、codeigniter框架的簡介 |-----關于框架的概念 |-----使用CI框架的好處 |-----為什么選擇CI框架 3、codeigniter框架…

AspNetCore開源中間件-VueRouterHistory

前言用過VueRouter路由組件的應該都知道,VueRouter有hash和history兩種模式。hash模式會在url中插入#,history模式下url則看上去更加簡潔美觀。如果想要支持history模式則必須要后端服務進行配合。常用后端服務器配置方式請參考 后端配置例子后端配置例子…

T-SQL編程基礎之三:游標(Cursor)編程

SQL是一種面向集合操作的語言,大多情況下,一個SQL語句將會操作數據庫表里的很多數據,基本上,一個數據庫的程序員腦子里應該想的是如何整體操作一個表或者是幾個表。 但也有一些情況下,試圖整表操作是不現實的,需要一行一行處理數據,這種情況下,SQL語言提供了所謂游標的…

《假如編程是魔法之零基礎看得懂的Python入門教程 》——(一)既然你選擇了這系列教程那么我就要讓你聽得懂

一、前言 幾個月前編寫了一份python語言入門的博文,近期重新審閱了一遍發現編寫的質量太過隨意,可能對于一部分人并不是非常友好,故此重新編寫Python語言的零基礎教程。 本篇教程將會盡量把一些專業術語給讀者講解清楚,并且讓讀…