WebSocket是目前比較成熟的技術了,WebSocket協議爲建立客戶端和服務器端須要實時雙向通信的webapp提供了一個選擇。其爲HTML5的一部分,WebSocket相較於原來開發這類app的方法來講,其能使開發更加地簡單。大部分如今的瀏覽器都支持WebSocket,好比Firefox,IE,Chrome,Safari,Opera,而且愈來愈多的服務器框架如今也一樣支持WebSocket。html
在實際的生產環境中,要求多個WebSocket服務器必須具備高性能和高可用,那麼WebSocket協議就須要一個負載均衡層,NGINX從1.3版本開始支持WebSocket,其能夠做爲一個反向代理和爲WebSocket程序作負載均衡。nginx
WebSocket協議與HTTP協議不一樣,但WebSocket握手與HTTP兼容,使用HTTP升級工具將鏈接從HTTP升級到WebSocket。這容許WebSocket應用程序更容易地適應現有的基礎架構。例如,WebSocket應用程序可使用標準HTTP端口80和443,從而容許使用現有的防火牆規則。web
WebSocket應用程序能夠在客戶端和服務器之間保持長時間運行的鏈接,從而有助於開發實時應用程序。用於將鏈接從HTTP升級到WebSocket的HTTP升級機制使用Upgrade和Connection頭。反向代理服務器在支持WebSocket時面臨一些挑戰。一個是WebSocket是一個逐跳協議,所以當代理服務器攔截客戶端的升級請求時,須要向後端服務器發送本身的升級請求,包括相應的頭文件。此外,因爲WebSocket鏈接長期存在,與HTTP使用的典型短時間鏈接相反,反向代理須要容許這些鏈接保持打開狀態,而不是關閉它們,由於它們彷佛處於空閒狀態。後端
容許在客戶機和後端服務器之間創建隧道,NGINX支持WebSocket。對於NGINX將升級請求從客戶端發送到後臺服務器,必須明確設置Upgrade和Connection標題。瀏覽器
Nginx開啓websocket代理功能的配置以下:bash
1)編輯nginx.conf,在http區域內必定要添加下面配置: map $http_upgrade $connection_upgrade { default upgrade; '' close; } map指令的做用: 該做用主要是根據客戶端請求中$http_upgrade 的值,來構造改變$connection_upgrade的值,即根據變量$http_upgrade的值建立新的變量$connection_upgrade, 建立的規則就是{}裏面的東西。其中的規則沒有作匹配,所以使用默認的,即 $connection_upgrade 的值會一直是 upgrade。而後若是 $http_upgrade爲空字符串的話, 那值會是 close。 2)編輯vhosts下虛擬主機的配置文件,在location匹配配置中添加以下內容: proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; 示例以下: upstream socket.kevin.com { hash $remote_addr consistent; server 10.0.12.108:9000; server 10.0.12.109:9000; } location / { proxy_pass http://socket.kevin.com/; proxy_set_header Host $host:$server_port; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }
WebSocket 機制
WebSocket是HTML5下一種新的協議。它實現了瀏覽器與服務器全雙工通訊,能更好的節省服務器資源和帶寬並達到實時通信的目的。它與HTTP同樣經過已創建的TCP鏈接來傳輸數據,可是它和HTTP最大不一樣是:
1) WebSocket是一種雙向通訊協議。在創建鏈接後,WebSocket服務器端和客戶端都能主動向對方發送或接收數據,就像Socket同樣;
2)WebSocket須要像TCP同樣,先創建鏈接,鏈接成功後才能相互通訊。服務器
傳統HTTP客戶端與服務器請求響應模式以下圖所示:websocket
WebSocket模式客戶端與服務器請求響應模式以下圖:網絡
上圖對比能夠看出,相對於傳統HTTP每次請求-應答都須要客戶端與服務端創建鏈接的模式,WebSocket是相似Socket的TCP長鏈接通信模式。一旦WebSocket鏈接創建後,後續數據都以幀序列的形式傳輸。在客戶端斷開WebSocket鏈接或Server端中斷鏈接前,不須要客戶端和服務端從新發起鏈接請求。在海量併發及客戶端與服務器交互負載流量大的狀況下,極大的節省了網絡帶寬資源的消耗,有明顯的性能優點,且客戶端發送和接受消息是在同一個持久鏈接上發起,實時性優點明顯。架構
相比HTTP長鏈接,WebSocket有如下特色:
1)是真正的全雙工方式,創建鏈接後客戶端與服務器端是徹底平等的,能夠互相主動請求。而HTTP長鏈接基於HTTP,是傳統的客戶端對服務器發起請求的模式。
2)HTTP長鏈接中,每次數據交換除了真正的數據部分外,服務器和客戶端還要大量交換HTTP header,信息交換效率很低。Websocket協議經過第一個request創建了TCP鏈接以後,以後交換的數據都不須要發送 HTTP header就能交換數據,這顯然和原有的HTTP協議有區別因此它須要對服務器和客戶端都進行升級才能實現(主流瀏覽器都已支持HTML5)。此外還有 multiplexing、不一樣的URL能夠複用同一個WebSocket鏈接等功能。這些都是HTTP長鏈接不能作到的。
總的來講:
WebSocket與Http相同點
- 都是同樣基於TCP的,都是可靠性傳輸協議。
- 都是應用層協議。
WebSocket與Http不一樣點
- WebSocket是雙向通訊協議,模擬Socket協議,能夠雙向發送或接受信息。HTTP是單向的。
- WebSocket是須要瀏覽器和服務器握手進行創建鏈接的。而http是瀏覽器發起向服務器的鏈接,服務器預先並不知道這個鏈接。
WebSocket與Http聯繫
WebSocket在創建握手時,數據是經過HTTP傳輸的。可是創建以後,在真正傳輸時候是不須要HTTP協議的。
在WebSocket中,只須要服務器和瀏覽器經過HTTP協議進行一個握手的動做,而後單獨創建一條TCP的通訊通道進行數據的傳送。
WebSocket鏈接的過程是:
1)客戶端發起http請求,通過3次握手後,創建起TCP鏈接;http請求裏存放WebSocket支持的版本號等信息,如:Upgrade、Connection、WebSocket-Version等;
2)服務器收到客戶端的握手請求後,一樣採用HTTP協議回饋數據;
3)客戶端收到鏈接成功的消息後,開始藉助於TCP傳輸信道進行全雙工通訊。
下面再經過客戶端和服務端交互的報文對比WebSocket通信與傳統HTTP的不一樣點:
1)在客戶端,new WebSocket實例化一個新的WebSocket客戶端對象,請求相似 ws://yourdomain:port/path 的服務端WebSocket URL,客戶端WebSocket對象會自動解析並識別爲WebSocket請求,並鏈接服務端端口,執行雙方握手過程,客戶端發送數據格式相似:
GET /webfin/websocket/ HTTP/1.1 Host: localhost Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg== Origin: http://localhost:8080 Sec-WebSocket-Version: 13
能夠看到,客戶端發起的WebSocket鏈接報文相似傳統HTTP報文,Upgrade:websocket參數值代表這是WebSocket類型請求,Sec-WebSocket-Key是WebSocket客戶端發送的一個 base64編碼的密文,要求服務端必須返回一個對應加密的Sec-WebSocket-Accept應答,不然客戶端會拋出Error during WebSocket handshake錯誤,並關閉鏈接。
2)服務端收到報文後返回的數據格式相似:
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: K7DJLdLooIwIG/MOpvWFB3y3FE8=
Sec-WebSocket-Accept
的值是服務端採用與客戶端一致的密鑰計算出來後返回客戶端的,HTTP/1.1 101 Switching Protocols
表示服務端接受WebSocket協議的客戶端鏈接,通過這樣的請求-響應處理後,兩端的WebSocket鏈接握手成功, 後續就能夠進行TCP通信了。
在開發方面,WebSocket API 也十分簡單:只須要實例化 WebSocket,建立鏈接,而後服務端和客戶端就能夠相互發送和響應消息。在WebSocket 實現及案例分析部分能夠看到詳細的 WebSocket API 及代碼實現。
騰訊雲公網有日租類型七層負載均衡轉發部分支持Websocket,目前包括英魂之刃、銀漢遊戲等多家企業已接入使用。當出現不兼容問題時,請修改websocket配置,websocket server不校驗下圖中圈出的字段:
好比一個使用WebSocket應用於視頻的業務思路以下:
1)使用心跳維護websocket鏈路,探測客戶端端的網紅/主播是否在線
2)設置負載均衡7層的proxy_read_timeout默認爲60s
3)設置心跳爲50s,便可長期保持Websocket不斷開
Nginx代理webSocket常常中斷的解決方法(也就是如何保持長鏈接)
現象描述:用nginx反代代理某個業務,發現平均1分鐘左右,就會出現webSocket鏈接中斷,而後查看了一下,是nginx出現的問題。
產生緣由:nginx等待第一次通信和第二次通信的時間差,超過了它設定的最大等待時間,簡單來講就是超時!
解決方法1
其實只要配置nginx.conf的對應localhost裏面的這幾個參數就好
proxy_connect_timeout;
proxy_read_timeout;
proxy_send_timeout;
解決方法2
發心跳包,原理就是在有效地再讀時間內進行通信,從新刷新再讀時間
配置示例:
http { server { location / { root html; index index.html index.htm; proxy_pass http://webscoket; proxy_http_version 1.1; proxy_connect_timeout 4s; #配置點1 proxy_read_timeout 60s; #配置點2,若是沒效,能夠考慮這個時間配置長一點 proxy_send_timeout 12s; #配置點3 proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; } } }
關於上面配置2的解釋
這個是服務器對你等待最大的時間,也就是說當你webSocket使用nginx轉發的時候,用上面的配置2來講,若是60秒內沒有通信,依然是會斷開的,因此,你能夠按照你的需求來設定。好比說,我設置了10分鐘,那麼若是我10分鐘內有通信,或者10分鐘內有作心跳的話,是能夠保持鏈接不中斷的,詳細看我的需求
WebSocket與Socket的關係
- Socket其實並非一個協議,而是爲了方便使用TCP或UDP而抽象出來的一層,是位於應用層和傳輸控制層之間的一組接口。當兩臺主機通訊時,必須經過Socket鏈接,Socket則利用TCP/IP協議創建TCP鏈接。TCP鏈接則更依靠於底層的IP協議,IP協議的鏈接則依賴於鏈路層等更低層次。
- WebSocket就像HTTP同樣,則是一個典型的應用層協議。
總的來講:Socket是傳輸控制層接口,WebSocket是應用層協議。