1、引言
當你在瀏覽器輸入 qq.com 按下回車鍵,到頁面呈現在你面前,整個過程發生了什么?我以前思考過這個問題,從最前面的瀏覽器到最后的 db 都梳理的一遍,觸發了一次技術頓悟,將很多散落的知識點貫通起來了。
本文將拋棄千篇一律的計網知識理論,從現實的互聯網技術實踐角度,一步步為你分享一次網絡請求背后的技術秘密。
2、系列文章
本文是系列文章中的第 17篇,本系列文章的大綱如下:
3、 IP、DNS 和 CDN
如果面試時問你「局域網 IP 有哪些 IP 段」,你怎么答?
3.1為什么不是每個設備一個公網 IP?
先說個 QQ 的小故事。QQ 剛開發時也沒想到 QQ 會發展成中國互聯網基礎設施,就用4字節整形表示 QQ 號了。早期內部的一些項目有用 int 表示 QQ 號,能表示的最大值是2^31-1,即21億多。在 QQ 號發放近20億時,即通搞了個22億 QQ 號的專項,通知每個項目檢查修改,使用 unsigned int 表示 QQ 號,以支持21億以上的 QQ 號。
可以看出在底層和協議設計中,字段的擴大是非常麻煩的。IP 地址也有類似問題。
目前廣泛使用的是 IPv4,一個 IP 地址4個字節,理論上共有2^32個 IP 地址,接近43億。這個數量還不到人均一個,遠遠不夠,自然也不能每個設備一個公網 IP 了,所以 Internet 規定了 IPv4 地址空間的一部分供專用地址使用,這些地址永遠不會被當做公用地址來分配,局域網內部 IP 就是使用這些專用地址。
常見專用地址有:10.x.x.x,172.16-31.x.x,192.168.x.x,另外127.0.0.1表示本地回環地址,代表設備的本地虛擬接口。
了解這個后,如果你發現你在公司的 IP 是192.168.0.100,在家里的IP也是192.168.0.100時,就不會詫異了。局域網內部 IP 只用于局域網內部通訊,如果要連接廣域網,還要用到 NAT(網絡地址轉換)技術(詳見《通俗易懂:快速理解P2P技術中的NAT穿透原理》)。
NAT 常用于局域網內部 IP 和局域網分配的公網 IP 之間進行轉換,使用最多的是端口多路復用(PAT)方式,簡單的描述就是,你在局域網內訪問 qq 時,路由器會記錄你的內網 IP 和端口(假設是192.168.0.100:12345),用路由器的公網IP和一個未使用的端口向公網發網絡包(假設是202.96.134.133:23456),路由器還會把TCP~202.96.134.133:23456~192.168.0.100:12345配對保存起來。當 qq 的響應發到202.96.134.133:23456后,路由器通過查找配對表就知道是發給192.168.0.100:12345。
PS:相關資料可進一步查閱:
- 《腦殘式網絡編程入門(六):什么是公網IP和內網IP?NAT轉換又是什么鬼?》
- 《P2P技術詳解(一):NAT詳解——詳細原理、P2P簡介》
- 《IPv6技術詳解:基本概念、應用現狀、技術實踐(上篇)》
3.2DNS 有話說
搞網絡管理的同學對 DNS 比較熟悉,程序員也需要了解,不管是前端還是后端。
IP 地址不好記,于是就有了域名。瀏覽器訪問 qq.com 時,會先做一次域名解析,把 qq.com 這個域名解析成 IP 地址,然后才能發出 IP 包。
在 windows 和 linux 下解析域名前,會先從本地 hosts 文件里查找網址映射關系,如果有,就先調用這個 IP 地址映射,完成域名解析。早期做 Web 開發時會用這種方式來切換開發環境、測試環境、預發布環境和正式環境。
比如你在騰訊云注冊了一個個人用的域名,一般會直接用騰訊云的 DNS 服務器來管理該域名的解析。對于門戶網站,則會自己搭建 DNS 服務器來管理域名。自建 DNS 服務器既方便管理,又能提高安全等級,防范 DDOS 域名攻擊。
如果域名的訪問量比較大,可以讓域名對應多個 IP 地址,操作系統會隨機選擇其中一個,這是早期的 Web 負載均衡方式。但因為有些 DNS Server 不按 TTL 指示緩存,導致 DNS 變更生效時間最長可達到24~48小時。一旦某個 IP 的機器故障,而 DNS 又不能立即刷新,會讓部分用戶服務不可用。于是就有了用 LVS/nginx 來動態負載均衡的方式,LVS 的負載均衡基于 IP 層,nginx 則是用 HTTP 層的反向代理機制。
此外還要考慮到電信/聯通/移動三大運營商跨網的問題。運營商之間的通訊帶寬有限,如果你的服務器在電信機房,那么聯通用戶訪問就會比較慢。所以就有了多線機房的出現。多線機房實際是一個機房有電信、聯通、移動等多條線路接入。通過多線機房內部路由器設置,及 BGP 自動路由的分析,實現電信用戶訪問電信線路,聯通用戶訪問聯通線路,這樣實現電信聯通均可以快速訪問 。
市面上的各種云(比如騰訊云、阿里云)的 CLB 選用 BGP 多線,就可實現電信/聯通/移動多網統一接入和自動負載均衡。
PS:相關資料可進一步查閱:
- 《不為人知的網絡編程(九):理論聯系實際,全方位深入理解DNS》
- 《全面了解移動端DNS域名劫持等雜癥:原理、根源、HttpDNS解決方案等》
- 《美圖App的移動端DNS優化實踐:HTTPS請求耗時減小近半》
- 《百度APP移動端網絡深度優化實踐分享(一):DNS優化篇》
3.3CDN 登場
為了給用戶提供更快的訪問速度,人們發明了 CDN(Content Delivery Network,內容分發網絡)。簡單的說就是,一個域名對應有多個 IP,這些 IP 分布在全國各地,用戶訪問域名時,DNS 服務器根據用戶的來源 IP,返回一個就近的 IP 給用戶,從而實現更快的訪問速度。
從上面的描述可以知道,CDN 要求各節點的內容是一致的,這樣才能讓各地用戶訪問到一致的內容,所以 CDN 主要用于 Web 靜態資源的分發和加速。
Web 性能優化方案一般會有一條動靜分離,即把靜態資源使用的域名和動態腳本的域名分開,有了 CDN 后,一般會把靜態資源的域名托管給 CDN 以提高更快的訪問速度和更低的成本。
現在也有動態 CDN,針對接口這種請求也能做就近接入,但原理是轉入云廠商的內部鏈路做網絡加速,一般不把數據緩存在邊緣節點上。
4、TCP、消息分包和協議設計
一次網絡請求經過 DNS 解析知道了目的 IP,現在就要發出網絡包了。
4.1TCP 是一種流式協議
講網絡編程的教科書一般都會對 TCP 的可靠傳輸做詳細說明,但對于 TCP 是一種流式協議講解的不多,但這背后隱藏著很重要的一個知識點。先做個名詞定義方便交流,這里的 “消息”是指應用層的一個完整的協議包。
流式協議的特點是什么?就像流水連續不斷那樣,消息之間沒有邊界。例如 send 了3條消息,分別是100字節、50字節、80字節,recv 時可能收到的是230字節,就是說一次 recv 收到了3條消息,需要應用邏輯自己對 recv 到的數據進行分析,得出完整的消息。
能一次 recv 到多個消息,也可能一次 recv 到一個半消息或半個消息,都是有可能的,這就是流式協議的特點。有的文章講的粘包也是這個概念。
4.2消息分包
既然 TCP 是一種流式協議,需要應用層自己來分析出完整的消息,那有哪些方式來確定一個完整消息呢?這個就是應用層通訊協議設計的工作了。
先看看最常見的 HTTP 協議是如何來分包的。HTTP 協議是一種文本協議(非二進制協議),用 \r\n\r\n 來分割消息頭和消息體,HTTP 請求的消息頭中有 Content-Length 來告知消息體有多大,如果沒有該字段就表示無消息體,GET 請求大多是這樣。HTTP 響應的消息頭中,或者有 Content-Length,或者有 Transfer-Encoding: chunked 告知以 chunk 模式分析消息體。

HTTP 用 \r\n\r\n 來分割消息頭和消息體,這種用特定字符“/”字符串來分割或分包的方式,還有不少協議用到。例如 FTP/SMTP/POP3 都是用 \n 來作為一個命令結束的標志。
這種消息分包的方式,需要應用層去掃描已 recv 到的數據,性能上還不夠高效,代碼不嚴謹的還容易被攻擊。在需要自定義協議的項目中,不少選擇用二進制協議,解析高效,安全性更好些。
最簡單的二進制協議分包方式是消息的頭4個字節表示消息的總長度。這種方式還需要對最大消息長度做個限制,例如 64K 或 1024K 大小,避免超大數據包對接收方緩沖區的破壞。更進一步的,可以加入簡單校驗方法。例如消息頭1個字節固定式0x2,消息的最后1個字節固定式0x3,消息總長度放在第2~5字節。這樣收到完整消息后,如果頭尾不是0x2和0x3,就直接異常處理。
4.3協議設計
消息分包是協議設計的一個工作,協議設計的話題還不少,這里以 HTTP 協議為例,簡要的說說里面設計的點,自己設計的協議也可以對照著有選擇的使用,原理是共通的。
具體是:
- 1)由消息頭+消息體組成:空行分割 HTTP head 和 body,HTTP 頭的每一行以 \r\n 結尾,空行就是 \r\n\r\n ;
- 2)消息分包:如上所述,HTTP 用 Content-Length 和 Transfer-Encodeing 來分包;
- 3)消息壓縮:請求中有 Accept-Encoding 字段,響應中用 Content-Encoding 字段表明壓縮方式,一般采用 gzip 壓縮;
- 4)消息加密:https (SSL: Secure Socket Layer);
- 5)消息 ID:URL 就是消息 ID ;
- 6)響應的狀態碼:第一個數字定義了響應的類別: 1xx:指示信息--表示請求已接收,繼續處理 2xx:成功--表示請求已被成功接收、理解、接受 3xx:重定向--要完成請求必須進行更進一步的操作 4xx:客戶端錯誤--請求有語法錯誤或請求無法實現 5xx:服務器端錯誤--服務器未能實現合法的請求
- 7)協議版本號:HTTP/1.1中的1.1就是 HTTP 1.1 版本;
- 8)長連接:請求中 Connection: keep-alive 表示希望服務器保持連接,減少 TCP 連接的開銷;
- 9)字符集:Content-Type 字段表明了字符集,例如: Content-Type: text/html; charset=gb2312;
- 10)字符轉義:URL 中的參數需要做 URL 轉義處理,例如 http://xx.com/do?name=t%2F%3F%23%3Daa 表示 name 為 t/?#=aa。
在我們自己設計協議時,可以有選擇的使用:
- 1)如果消息比較大,可以采用支持壓縮;
- 2)如果要兼容多個版本的協議,那版本號必不可少;
- 3)如果采用二進制協議,字符集和字符轉義的用處不大。
4.4HTTP 協議和二進制協議的對比
HTTP 協議是一種文本協議,也是一種 Name-Based 協議,就從這兩方面來說。
文本協議 vs 二進制協議。
文本協議的特點:
- 1)便于人;
- 2)易于閱讀、理解、調試、構造;
- 3)解析復雜、冗余多;
- 4)需要考慮字符轉義。
二進制協議的特點:
Name-Based vs Position-Based。
Name-Based 協議的特點:
- 1)協議字段都用 Name 標識;
- 2)協議字段與位置無關;
- 3)協議字段可缺省;
- 4)新增協議字段比較方便;
- 5)解析復雜;
- 6)需要考慮字符轉義。
Position-Based 協議的特點:
5、CGI 和 FastCGI
消息經過網絡傳輸,到達了服務器端,最常見的服務器是 Web 服務器,做 PHP 的同學都知道 FastCGI 模式的 PHP 比普通 PHP 更高效,其中的原理是什么呢?
5.1古老但常見的 CGI
Web 服務器能解析 HTTP 請求,返回靜態資源(HTML 頁、圖片等),但要輸出動態內容,必須得 PHP/C#/Ruby/Java/Python/C/C++ 這些外部程序來實現。
早期有個技術叫 CGI(Common Gateway Interface,通用網關接口),是用于 Web 服務器和外部程序之間傳輸數據的一種標準。
一個簡單的 CGI 程序(C++ 語言)如下:
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("Content-type: text/html\r\n\r\n");
printf("your name is:%s\n", getenv("QUERY_STRING"));
return 0;
}
瀏覽器訪問這個 CGI 程序,就會顯示:your name is:name=xxx 。
CGI 規定了 Web 服務器如何和 CGI 程序之間傳輸數據。
具體過程大體是這樣:
- 1)Web 服務器收到的請求信息后,啟動 CGI 程序(apache 是 fork 進程 exec CGI 程序);
- 2)Web 服務器通過環境變量和標準輸入把請求信息傳遞給 CGI 程序;
- 3)CGI 程序執行業務邏輯后,通過標準輸出和標準錯誤把響應數據返回給 Web 服務器,CGI 程序 exit;
- 4)Web 服務器再組織成 HTTP 響應包發給瀏覽器。
在上面的例子中,第一行 printf 是輸出 HTTP 頭(還記得 HTTP Header 和 Body 是用 \r\n\r\n 分割的么?),getenv("QUERY_STRING")是從環境變量獲取 URL,printf 是通過標準輸出返回內容。
Web 服務器會把哪些信息通過環境變量傳遞給 CGI 程序?
常用的有這些:
- 1)CONTENT_LENGTH :向標準輸入發送的數據的字節數(POST);
- 2)QUERY_STRING:實際存放發送給 CGI 程序的數據(GET);
- 3)REQUEST_METHOD:傳送數據所用的 CGI 方法(GET或POST);
- 4)HTTP_COOKIE:cookie 值;
- 5)REMOTE_ADDR:用戶 IP;
- 6)SCRIPT_NAME:請求的 CGI。
可以看到 CGI 只是一種標準,可以用任何一種語言編寫 CGI 程序,只要這種語言具有標準輸入、標準輸出和環境變量,比如:C/C++,perl,PHP、ruby。按照 CGI 標準要求,就能和 Web 服務器交互起來。
5.2FastCGI 應運而生
CGI 是通過環境變量/標準輸入、標準輸出/標準錯誤來傳輸數據,運行性能比較低。
主要有兩點:
- 1)每個請求都需要 Web 服務器去 fork 出 CGI 程序,頻繁 fork 進程比較耗時;
- 2)CGI 程序每次都是從頭運行,讀配置、連接其他服務都得重新來,也比較耗時。
FastCGI 是對 CGI 的改進。
FastCGI 模式下,Web 服務器和 FastCGI 程序傳輸數據的過程大體是:
- 1)Web 服務器收到的請求信息后,按 FastCGI 協議把請求信息通過 socket 發給 FastCGI 程序;
- 2)FastCGI 程序執行業務邏輯后,通過 socket 把響應數據返回給 Web 服務器,FastCGI 程序不 exit;
- 3)Web 服務器再組織成 HTTP 響應包發給瀏覽器。

對比 CGI 的通過,可以發現主要是少了每次 fork 的過程,并且用 socket 來傳輸數據,這是 FastCGI 接口更高效的原因。
FastCGI 有這些特點:
- 1)FastCGI 程序常駐內存,啟動后可以反復處理請求;
- 2)FastCGI 就是進程池/線程池模型的通用同步服務器框架。
FastCGI 程序處理請求后不會退出,可以反復處理請求,那么在啟動后就把配置解析、與其他后臺的連接建立好,不用每次請求時搞一邊,自然更快了。
至于這個 FastCGI 內部如何實現進城池/線程池,就是 FastCGI 進程管理器(FastCGI 引擎)的事情了。C/C++ FastCGI 常用 apache 的 mod_fastcgi 模塊,PHP 常用 spawn-fcgi 和 PHP-FPM。
5.3nginx 的反向代理
現在更多是用 nginx 的反向代理功能,把 HTTP 請求轉發到后端的 trpc 服務直接處理。這里的 trpc 服務就有點 FastCGI 的感覺,但不用與 nginx 部署在一起了。
6、服務器后端架構模型
上節講到 Web 服務器和 CGI/FastCGI 能動態輸出內容,從而提供更強大的業務處理能力。Web 服務器這種架構,我稱之為 Web 模式,與之相對的是 Svr 模式。Web 模式和 Svr 模式是互聯網項目的后臺最常見的兩種模式。先介紹幾個概念。
6.1同步通訊 vs 異步通訊
同步通訊是指在一個連接中,一個請求的應答沒回來前,不能發送下一個請求,整個通訊過程是:請求1-應答1-請求2-應答2…… 這種。異步通訊與同步通訊相反,在一個連接中,可以隨意發送請求,而且收到應答的順序可能與發送請求的順序不一致。
從描述上就能理解,同步通訊的通訊性能比異步低,但好處是簡單,不用考慮亂序應答的復雜情況。
6.2同步邏輯 vs 異步邏輯
同步邏輯是指在代碼中遇到需要等待的調用時(例如向數據庫查詢數據),阻塞著,一直等待調用完成。異步邏輯則是不阻塞,繼續執行后續代碼。
我們常見的文件 IO 接口 read/write,網絡 IO 接口 send/recv 默認都是同步的,需要執行特別的設置 API 才能變成非阻塞的。同步邏輯符合人腦的思維模式,寫異步邏輯需要處理各種非阻塞和異常情況,極其挑戰智力,就算采用有限狀態機,也是件很具挑戰的工作。
6.3無狀態 vs 有狀態
CGI/FastCGI 每次執行時,會從數據層(db 或數據 cache)獲得數據,修改后再寫回到數據層,也就是說 CGI/FastCGI 并不會緩存數據。這就是無狀態。
無狀態的架構中,請求是這臺 Web 服務器處理,還是那臺處理,都沒有區別,因為數據都是從數據層獲得的。這種架構的擴容非常方便,但需注意,要防范一個請求同時多并發時,可能出現的數據不一致的漏洞,即要做防并發處理。
有狀態是與無狀態相對的概念,是指服務器中緩存了數據。這種架構中,因為不需要反復的從數據層取數據,性能會高很多,但因為服務器緩存了數據,為了保持數據一致性,只能把該數據的請求都分發到這臺服務器來處理。對于游戲來說,每個區的用戶數據是獨立的,對交互的實時性要求高,采用有狀態的架構正好合適。
6.4Web 模式 vs Svr 模式
早期的瀏覽器如果要實現在線聊天,需要瀏覽器定時請求服務器獲取聊天信息,Web 服務器無法主動給客戶端推送消息。到 WebSocket 出來后才具備實時推送的能力。
Web 模式業務一般有這些特點:
- 1)是請求-應答式:即先客戶端請求,才會有服務器應答(少數場景可借助 WebSocket 主動推送);
- 2)是同步通訊:一個連接里,只有收到應答后才能發下一個請求(HTTP2 可多路復用);
- 3)是同步邏輯:Web 模式較少采用異步邏輯;
- 4)是無狀態架構:CGI/FastCGI 每次從數據層獲取數據,修改后再寫回到數據層。
Svr 模式就是與之相對的,客戶端和服務器之間采用長連接,客戶端的請求不一定會有應答,服務器還可以主動推送消息到客戶端,通訊也不限定是同步的,客戶端可以不斷的發送請求,服務器的應答甚至可能與請求的順序不一致。
Svr 模式相對 Web 模式來說,通訊性能更強,因為采用了長連接和異步通訊,還能主動推送消息,這是優勢。但也因為采用了長連接和異步通訊,對客戶端開發的要求就更高些,需要處理好斷線重連和支持響應亂序。
Web 模式因為模式簡單,Web 服務器自己實現了 HTTP 協議處理和 FastCGI 進程管理等通用操作,FastCGI 這些外部程序只需要處理業務邏輯就行,降低了很多門檻。而且因為是無狀態的,擴容非常方便,直接加機器就能搞定,這個平滑擴容的優勢在 Web 時代的作用非常大——搞性能優化、架構優化的時間成本比較大,而且不可控,加硬件就能快速抗住,是個好的方案。
7、數據層的演進
我們用一個做手游的故事來聊聊數據層不斷優化提升的演進過程。
7.1簡單設計
有一天,老板突然說做個山寨版的糖果傳奇手游,你接到任務后,分析出游戲的交互頻率不大,都是點查詢,用 MySQL 能簡單搞定。建個表,設好主鍵和索引,你輕松搞定數據庫設計,愜意的泡了杯茶邊喝邊敲代碼。
這里說的“點查詢”,是指基于指定主鍵的查詢,例如查詢指定用戶的信息,因為是基于指定主鍵,查詢結果有限且較少,點查詢的效率非常高。另一種叫“面查詢”,是基于主鍵或索引的范圍查詢,例如查詢昨天所有的訂單,這種查詢雖然有主鍵或索引,但結果數量不確定,有時處理不好時會出現嚴重性能問題。
游戲刪檔內測上線了,用戶數不多,請求的響應也很及時,老板拍了拍你的肩膀。
7.2數據庫調優
游戲上線反響不錯,精美的畫面給了玩家不少驚喜,更多玩家蜂擁而入,你從監控上發現 MySQL 的壓力有點大,當初只是對數據庫表結構做了設計,現在你開始 review 數據庫優化了:修改 MySQL 參數加大 InnoDB 的 cache,不使用事務提交。
做了這些優化后,db 性能提升明顯,整個系統跑得很歡,你又愜意的去泡茶了。
7.3分庫分表
你們游戲山寨得比較牛叉,用戶持續增加,作為有風險意識的你,肯定不會等到系統告警了才去優化,于是你在想更大訪問量時怎么辦?
單臺 db 的性能有極限,必須有擴展到多臺 db 的能力,于是你重新修改了數據庫表結構和后臺代碼,把主鍵按規則做了分庫分表,目前用戶增長迅猛,假定單臺 db 存放500萬用戶,最終可能有上億用戶,那么可能有20臺 DB,于是你分了32個庫,每個庫里有32張表,共1024張表。
初始時這1024張表都在一臺 db 上,當用戶數增加時,分裂成2臺、4臺、8臺、16臺。涉及好分庫分表策略后,db 壓力能通過擴容來解決,你放心了。
PS:雖然使用 TDSQL 可以隱含的幫你分表,但有追求的你還是需要了解原始的分庫分表做法。
7.4關于讀寫分離
有不少介紹 MySQL 讀寫分離已提升 MySQL 并發性能的文章,在游戲項目中用得比較少,主要是讀寫比例的原因。像網站那種讀多寫少的應用場景可以采用讀寫分離,而游戲的讀和寫差不多多,讀寫分離的用處不大;而且用戶可能是海量的,分多臺 db 是常事,如果分庫后再搞讀寫分離,整個 db 就過于復雜了。
MySQL 讀寫分離是基于 MySQL 主從復制功能的,現在的項目實用的 db 基本都是一主多備。如果項目有 OLAP 需求要直接查詢 MySQL ,往往也是在 slave 上查詢,不直接操作 master,避免低效查詢降低 master 性能影響業務。這種做法也是 OLDP(On-Line Transaction Processing,聯機事務處理)和 OLAP(On-Line Analytical Processing,聯機分析處理)分離的常見做法。
7.5緩存
有了分庫分表來平滑擴容,項目安穩了較長一段時間,直到某一天,運維說db機器增長比較快,4個月就增加到了64臺(master+slave),希望后臺能提升單臺db的性能,以應對后續的業務增長。
OK,你祭出你留的后手——Redis,麻利的操起機械鍵盤,咔噠咔噠的改起后臺的代碼,加入緩存邏輯:讀的時候從 Redis 讀,如果沒有就從 MySQL 查詢并寫入 Redis。寫的時候同時寫入 MySQL 和 Redis。
好吧,你終于使用了 NoSQL。搞定這個問題后,成本下降了,項目收入可觀,happy!
7.6為什么 Redis 性能比 MySQL 高?
首要因素是 Redis 的數據是在內存中,而用 MySQL 一般是希望數據持久化到磁盤的。從 IO 速度來說,內存 IO 比磁盤 IO 會快幾個數量級,Redis 也就比 MySQL 性能更高。
架構和性能優化做到后面,會發現最終限制性能的是硬件瓶頸。例如 nginx 做靜態 Webserver 時,出口流量往往能達到網卡的最大值或出口帶寬的最大值。MySQL 是個性能不錯的 db,但它的數據持久化在磁盤上,自然就受限于磁盤 IO 速度。
次要因素是 MySQL 支持完全的增刪查改 SQL 操作,還得支持 where 條件組合,這種復雜性讓 MySQL 的緩存機制有較大挑戰,不像 Redis 這種 key-value 類型的操作是點查詢,所以 MySQL 的緩存機制不如 Redis 那么簡單有效。
總結一點就是,性能、通用性、成本三者難以同時滿足。在成本一定的情況下,專用的高效,通用的低效。如何同時滿足性能和通用性呢?那自然就是提高成本,最簡單的方案是以前將 db 的機械硬盤升級到固態硬盤,性能提升很明顯。
至此,從瀏覽器發起請求,到從 db 中獲取數據并返回的整個鏈路,都簡要分析了一遍,希望能幫你搭建一個知識框架,貫通你過往的知識點
8、參考資料
[1] TCP/IP詳解 - 第17章·TCP:傳輸控制協議
[2] 假如你來設計TCP協議,會怎么做?
[3] 深入淺出,全面理解HTTP協議
[4] 什么是公網IP和內網IP?NAT轉換又是什么鬼?
[5] 一文讀懂高性能網絡編程中的I/O模型
[6] 到底什么是高并發?一文即懂!
[7] 深入操作系統,徹底理解I/O多路復用
[8] 深入操作系統,徹底理解同步與異步
[9] 騰訊資深架構師干貨總結:一文讀懂大型分布式系統設計的方方面面
[10] 新手入門:零基礎理解大型分布式架構的演進歷史、技術原理、最佳實踐
[11] 一篇讀懂分布式架構下的負載均衡技術:分類、原理、算法、常見方案等
[12] 從新手到架構師,一篇就夠:從100到1000萬高并發的架構演進之路
[13] IM通訊協議專題學習(一):Protobuf從入門到精通,一篇就夠!
(本文已同步發布于:http://www.52im.net/thread-4723-1-1.html?_dsign=ab3ce5a3)