網絡傳輸
- 傳播延遲: 消息從發送端到接收端需要的時間,是信號傳播距離和速度的函數
- 傳輸延遲: 把消息中的所有比特轉移到鏈路中需要的時間,是消息長度和鏈路速率的函數
- 處理延遲: 處理分組首部、檢查位錯誤及確定分組目標所需的時間
- 排隊延遲: 到來的分組排隊等待處理的時間
CDN把距離縮短,以加快訪問速度
延遲的最后一公里
延遲相當大一部分往往花在最后的幾公里,因為客戶單端連接公網的方式和接入鏈路都比較差
TCP
時延
每個http連接都需要經過三次握手,從紐約向倫敦請求,啟動一次TCP連接,光三次握手至少要花56ms,向倫敦發送分組需要28ms,響應要28ms。可以看出三次握手帶來的延遲是非常大的
擁塞控制
擁塞崩潰
可能是往返時間超過了所有主機的最大中斷間隔,於是相應的主機會產生越來越多的副本,使整個網絡陷入癱瘓,最終個交換節點的緩沖區被填滿,多出來的分組必須刪除
流量控制
通過縮放接收窗口(rwnd)的大小來控制流量的發送(可配)
慢啟動
通過一個動態可變的擁塞窗口(cwnd)大小來控制流量的發送,網絡可發送的最大數據取rwnd和cwnd的最小值
如圖可見,一個請求需要經過220ms才可以達到最大速率。因為慢啟動限制了可用的吞吐量,對於小文件的傳輸是很不利的
慢啟動重啟:在連接空閑一段時間后,重置擁塞窗口到一個安全的默認值。毫無疑問,SSR對於長周期空閑而突發請求的TCP連接有很大的影響,建議服務器金庸SSR
擁塞預防
慢啟動每次往返都會成倍提高傳輸的數據量,知道超過接收端的流量控制窗口或者有分組丟失為止。此時擁塞預防算法接入
帶寬延遲積
BDP表示數據鏈路的容量與其端到端延遲的乘積,結果就是任意時刻在途未確認的最大數據量
發送端和接收端發送超過了未被確認的最大數據量,都會停下來等待對方的ACK,這就造成了數據缺口。為了解決這個問題應該設置窗口足夠大,過小的窗口會限制連接的吞吐量。窗口的大小最小應該設置為BDP
隊首阻塞
TCP按序交付與可靠交付,如果有時丟包,那么后續的包必須等到這個丟包的數據重發並接收,才能交付給應用程序,這就導致讀數據時會感覺延遲交付
在應用程序不關系按序交付和可靠交付的情況下TCP並不是最好的選擇。例如音頻,丟了一個包可以在音頻中插入一個小小的間隙,就可以繼續處理后面的包,只要間隙足夠小,用戶就注意不到,而等待丟包可能導致音頻輸出產生無法預料的。相對而言,后者的用戶體驗更差.
調優
原因
- TCP 三次握手增加了整整一次往返時間;
- TCP 慢啟動將被應用到每個新連接;
- TCP 流量及擁塞控制會影響所有連接的吞吐量;
- TCP 的吞吐量由當前擁塞窗口大小控制。
方案
- 把服務器內核升級到最新版本(Linux:3.2+);
- 確保 cwnd 大小為 10;
- 禁用空閑后的慢啟動;
- 確保啟動窗口縮放;
- 減少傳輸冗余數據;
- 壓縮要傳輸的數據;
- 把服務器放到離用戶近的地方以減少往返時間;
- 盡最大可能重用已經建立的 TCP 連接。
UDP
網絡地址轉換
這三段地址只允許私網擁有,不允許公網擁有這些ip
連接狀體超時
中轉UDP的路由,由於UDP沒有連接和終止的概念,這導致中轉路由不知道什么時候該刪除連接狀態。為了解決這個問題,路由器會定期清理,路由狀態一旦清除,UDP則需要重新建立。解決方法是定期雙向發keep-alive分組。按理TCP有明確的連接狀態,路由器應當可以完整把握TCP的生命周期,但是路由器沒有這么做,也同樣給TCP設置了超時清理的動作,這導致一個長時間不活躍的TCP,會無端端的連接斷開。
P2P
STUN: Session Traversal Utilities for NAT 是一個協議,可以讓內網應用程序獲得一個外網ip和端口,STUN服務器架設在公網
各自內網的應用程序使用STUN后,就能獲得一個外網ip,STUN服務器通過keepalive方式保持路由不超時,各應用程序就能直接UDP通訊了
TURN: Traversal Using Relays around NAT. 當內網不能使用NAT時,可以使用TURN服務器,應用程序通過TCP連接TURN服務器,服務器做消息中轉
libjingle是谷歌的一個實現了STUN/TURN/ICE的開源庫。
92% 的時間可以直接連接(STUN);
8% 的時間要使用中繼器(TURN)。
ICE: Interactive Connectivity Establishment協議,能直連就直連,不能直連則使用STUN,再不行則使用TURN
設計原則
- 應用程序必須容忍各種因特網路徑條件;
- 應用程序應該控制傳輸速度;
- 應用程序應該對所有流量進行擁塞控制;
- 應用程序應該使用與 TCP 相近的帶寬;
- 應用程序應該准備基於丟包的重發計數器;
- 應用程序應該不發送大於路徑 MTU 的數據報;
- 應用程序應該處理數據報丟失、重復和重排;
- 應用程序應該足夠穩定以支持 2 分鍾以上的交付延遲;
- 應用程序應該支持 IPv4 UDP 校驗和,必須支持 IPv6 校驗和;
- 應用程序可以在需要時使用 keep-alive(最小間隔 15 秒)。
建議使用WebRTC
帶寬/延遲與頁面加載時間的關系
時延的原因
TCP握手/流量擁塞控制/丟包/隊首擁塞
網站各資源的用戶體驗度量
通過Navigation Timing/User Timing/resource timing來度量
瀏覽器的優化
- 資源預取和排定優先次序
- DNS預解析
- TCP預連接
- 頁面預渲染
服務器如何利用這些優化
- CSS 和 JavaScript 等重要資源應該盡早在文檔中出現;
- 應該盡早交付 CSS,從而解除渲染阻塞並讓 JavaScript 執行;
- 非關鍵性 JavaScript 應該推遲,以避免阻塞 DOM 和 CSSOM 構建;
- HTML 文檔由解析器遞增解析,從而保證文檔可以間隙性發送,以求得最佳性能
http優化
- 減少DNS查詢
- 減少HTTP請求
- 使用CDN
- 添加Expires首部並配置ETag標簽
- Gzip資源
- 避免HTTP重定向
- 使用持久化連接
keep alive和連接池的局限
對於每個服務器的ip,客戶端維持一個長連接的連接池,如果有多個請求發往服務器,並超過連接池的數量,則會迫使客戶端必須等待連接池的空閑,而且啟用多個socket嚴重占用系統資源。
http協議的局限
每次發送http請求,都必須加上頭部,而頭部是沒有經過壓縮的,這直接導致頭部的長度有可能超過body的長度。