摘要:最終獲得一個鏈接,里面有這樣的描述如何在阿里云負載均衡上啟用支持無需配置,當選用監聽時,默認支持無加密版本協議協議當選擇監聽時,默認支持加密版本的協議協議。詳細參見如何使用負載均衡性能保障型實例。
Websocket是HTML5之后的一個新事物,可以方便的實現客戶端到服務端的長會話,特別適合用于客戶端需要接收服務端推送的場景。例如在線客服聊天,提醒推送等等。改變了以往客戶端只能通過輪詢或者long poll來獲取服務端狀態的限制。
和HTTP協議有什么關系首先我們來看一下Websocket協議和HTTP有什么關系呢?
本質上說,Websocket和HTTP就不是一個協議,層級不一樣。但是為了兼容現有瀏覽器的握手規范,必須借助HTTP協議建立連接。
這是一個Websocket的握手請求
GET wss://server.example.com/ HTTP/1.1 Host: server.example.com Pragma: no-cache Cache-Control: no-cache Connection: Upgrade Upgrade: websocket Origin: https://server.example.com Accept-Encoding: gzip, deflate, br Sec-WebSocket-Version: 13 Sec-WebSocket-Key: fFFIlFcwULSAmQacRAbS2A== Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
這里面有幾個和一般HTTP Request不一樣的地方,
Connection: Upgrade Upgrade: websocket Sec-WebSocket-Version: 13 Sec-WebSocket-Key: fFFIlFcwULSAmQacRAbS2A== Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
這是告訴服務端這不是一個普通的請求,而是Websocket協議。Sec-WebSocket-Key 是一個Base64 encode的值,是瀏覽器隨機生成的,用于讓服務端知道這是一個全新的socket客戶端。
服務端如果開啟了Socket監聽,那么就會返回這樣的Response
HTTP/1.1 101 Switching Protocols Date: Fri, 09 Mar 2018 16:24:45 GMT Connection: upgrade upgrade: websocket sec-websocket-accept: i/tCy92JmOXIoZwGi8ROh6CgUwk=
表示接收了請求,并且即將切換到Websocket協議,所以code是101。Sec-WebSocket-Accept 這個則是經過服務器確認,并且加密過后的 Sec-WebSocket-Key。到這里HTTP協議的任務就已經完成,之后的通信都是基于Websocket協議了。
怎么通過nginx轉發Websocket的握手請求本質上說握手請求就是一個特殊的HTTP Request,只是需要加一些上文提到的特殊內容,從Nignx官方介紹可以看到
location /wsapp/ { proxy_pass http://wsbackend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; }
只是在Request header加了兩個屬性,并且強制升級到HTTP 1.1,原因是HTTP 1.0不支持keep alive。如果使用HTTP 1.0發握手請求,服務端返回101以后就會直接結束這次HTTP會話了。這一點也為之后的坑埋下了伏筆。
坑從何來自從上線了Websocket服務之后,就會經常發現socket無法建立,獲得504的超時響應。
HTTP/1.1 504 Gateway Time-out Date: Fri, 09 Mar 2018 03:34:54 GMT Content-Type: text/html Content-Length: 272 Connection: keep-alive
而且這一響應只有在經過SLB(負載均衡)時才有,如果直接請求到我們自己的nginx是沒有問題的。但是基于對阿里的信任,還是覺得問題應該還是我們自己這兒。從code review到nginx配置,折騰了五六個小時。
最后只有自己搭建的nginx access log上尋找蛛絲馬跡,一開始抓到一些響應都是499的返回,并且request_time時間都在60s上下。
[09/Mar/2018:15:04:51 +0800] 100.97.89.10 - - - 10.0.21.11 to: 10.0.20.11:8011: GET /ws/?id=168451&url=http://server.example.com/ HTTP/1.0 upstream_response_time - msec 1520579091.139 request_time 60.000 status 499 client - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36
就考慮是不是socket服務端建立連接后響應不及時,讓SLB發現60s沒有報文交互直接就切斷請求了。
但是因為我們在前端是做了心跳的,即使服務端不響應,只要socket建立通過心跳肯定也會在60s內進行交互。不應該出現上面的場景。
之后我們把access log中socket建立成功的請求和不成功的請求分開放到一起對比,發現不成功的都是HTTP 1.0的協議。
[09/Mar/2018:15:03:51 +0800] 100.97.88.238 - - - 10.0.20.11 to: 127.0.0.1:8011: GET /ws/?id=168451&url=http://server.example.com HTTP/1.1 upstream_response_time 11.069 msec 1520579031.198 request_time 11.|
069 status 101 client - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36 |
[09/Mar/2018:15:04:32 +0800] 100.97.88.254 - - - 10.0.20.11 to: 127.0.0.1:8011: GET /ws/?id=168451&url=http://server.example.com HTTP/1.0 upstream_response_time - msec 1520579072.716 request_time 36.755 s|
tatus 499 client - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36
就好像這兩個請求,同一個頁面發出的,但是一個成功一個失敗。失敗的正好就是HTTP/1.0,為什么會有兩個版本的協議呢,
為了證據更加“確鑿”,我們對請求進行了抓包分析,并將Sec-WebSocket-Key打印到Nginx的access log中方便trace同一個請求。
GET http://server.example.com/ws/ HTTP/1.1 Host: app.linkflowtech.com Connection: Upgrade Pragma: no-cache Cache-Control: no-cache Upgrade: websocket Origin: http://server.example.com Sec-WebSocket-Key: 8+qDYeKJGFTWKB2ov4p5TA== Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
[09/Mar/2018:17:07:07 +0800] 100.97.88.252 - - - 10.0.21.11 to: 10.0.20.11:8011: GET /ws/ HTTP/1.0 upstream_response_time - msec 1520586427.537 request_time 59.999 status 499 client - Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36 8+qDYeKJGFTWKB2ov4p5TA==
2018-03-09 17:12:04
可以看到都是 8+qDYeKJGFTWKB2ov4p5TA== 的請求,但是在經過SLB進入nginx時候協議降級到了1.0.這叫一個酸爽,趕緊給阿里云開了工單,經過大概3~4個小時的交流。最終獲得一個鏈接,里面有這樣的描述
如何在阿里云負載均衡上啟用WS/WSS支持?
無需配置,當選用HTTP監聽時,默認支持無加密版本WebSocket協議(WS協議);當選擇HTTPS監聽時,默認支持加密版本的WebSocket協議(WSS協議)。
注意:需要將實例升級為性能保障型實例。詳細參見如何使用負載均衡性能保障型實例。
這個大坑就在"注意"那一段,我們的SLB是性能共享型而不是性能保障型。看來也不是阿里云的問題,是我們的SLB檔次不夠高啊。知道原因后,立刻付費升級了保障型。實測一下所有問題都解決了。
雖然問題解決了,但是其實很難理解廠商的邏輯,為什么性能共享型中某些SLB節點就會降級HTTP協議版本呢,要知道1.0版本已經是一個相當落后的版本了。
在此記錄一下心路歷程,為了讓其他使用阿里云的同學不要重蹈覆轍。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/39840.html
摘要:本文將詳盡演示如何通過服務對接阿里云。概要阿里云負載均衡是將訪問流量根據轉發策略分發到后端多臺云服務器,簡稱的流量分發控制服務。 阿里云負載均衡(Server Load Balancer)是將訪問流量根據轉發策略分發到后端多臺云服務器(ECS)的流量分發控制服務。 本文將詳盡演示Rancher如何通過Aliyun-slb服務對接阿里云SLB。 概要 阿里云負載均衡(Server Loa...
摘要:對于負載均衡的公網和私網區別官方文檔什么是負載均衡實例中已經做了詳細解讀。私網負載均衡實例私網類型的負載均衡提供的是私網,私網類型的負載均衡實例只能在阿里云內部使用,可以轉發的請求只能來自具有負載均衡的私網訪問權限的客戶端。SLB負載均衡可以為多臺云服務器提供流量分發服務,阿里云的SLB負載均衡實例分為公網類型和私網類型兩種,那么二者之間有什么區別?云吞鋪子來說說: 公網SLB和私網SLB區...
閱讀 3674·2021-11-24 09:39
閱讀 1281·2021-09-30 09:48
閱讀 3267·2021-09-09 11:51
閱讀 2892·2021-09-08 10:41
閱讀 1335·2019-08-30 14:06
閱讀 2803·2019-08-30 14:01
閱讀 878·2019-08-29 17:11
閱讀 3177·2019-08-29 15:37