nginx代理了兩台socket.io伺服器。 socket.io的工作模式是polling升級到websocket
現象
透過nginx請求服務時,出現了大量的400錯誤,有時能升級到websocket,有時候會一直報錯。但直接透過 ip 連接埠
存取時,100%能成功。
分析
sid
sid是我們這個問題的關鍵。在初始建立連線時(polling模式就是在模擬一個長連線),客戶端會啟動這樣的要求:
https://***/?eio=3&transport=polling&t=1540820717277-0
服務端收到後會建立一個對象,綁定在這個連接上,同時傳回一個sid(session id),來標記這個會話。會話指什麼呢,會話是一連串的交互,這些交互之間是有聯繫的,在我們這個場景下就是,下一次的http請求到來,我需要找到之前綁定在理論上的長連接(這裡還沒有websocket,所以是理論上的)上的那個物件。我們知道http請求是無狀態的,每個請求之間獨立,所以socket.io引入了sid來做這件事。服務端收到請求後會產生一個sid,看下response:
複製程式碼 程式碼如下:
{"sid":"eogal3frqlptoalp5est","upgrades":["websocket"] ,"pinginterval":8000,"pingtimeout":10000}
之後每次要求都需要帶上這個sid,建立websocket請求的連線也不例外。所以說,sid是polling,以及polling升級到websocket的關鍵。這之後的請求類似:
https://***/?eio=3&transport=polling&t=1540820717314-1&sid=eogal3frqlptoalp5est or wss://***/?eio=3&transport=websocket&t=1540820717314-1&sid=eogal3frqlptoalp5est
那麼問題來了,如果請求是帶上的sid不是服務端產生的會怎麼樣呢?服務端會不認識,給你回傳一個400,並告訴你
invalid sid
我們遇到的便是這個問題,nginx預設的負載平衡策略是輪詢,所以請求有可能會打到不是生成這sid的機器上去,這時候我們就會收到一個400,如果運氣好,可能也會打到原來的機器上,運氣更好一點,甚至能堅持到websocket連接建立。
解決
這裡提出兩種方案
#nginx的負載平衡採用ip_hash,這樣可以保證一個客戶端的請求都走到一台伺服器上
不使用polling模式,只使用websocket
以上是nginx代理socket.io服務的坑怎麼解決的詳細內容。更多資訊請關注PHP中文網其他相關文章!