wafer信道的不可靠性

wafer信道的不可靠性

wafer - 企業級微信小程序全棧方案

近期幫他人處理了一個與wafer信道有關的技術問題,通過了解wafer信道相關內容,自己也對websocket也多了些認識,本文捋一捋自己這次經歷以及收穫。

問題場景

一個雙人問答對戰的小程序,多輪對戰的過程中某一方可能出現卡住的情況,由於是第一次接觸這個項目,花了些時間摸清技術大概:

小程序使用一個叫wafer的騰訊雲SDK做的,服務器也是用騰訊雲提供的小程序解決方案,業務上對戰雙方通過websocket連接服務器,由服務器派發問題,對戰雙方作答

核心信息大概就是這些,在看了下項目代碼後,感覺騰訊雲真是想盡辦法爲程序員降低了開發複雜度,有點像是DreamWave與前端開發,我也就像一個前端工程師初次接觸DreamWave一樣,有點茫然。

花了好一會才知道wafer大概是個什麼東西,以及wafer信道的工作原理,具體可以參考這篇文章

問題分析

最初聽完問題的描述後,猜測可能是沒有收到服務器發過來的問題消息,然後出現卡住情況。在檢查一遍代碼後發現這個邏輯確實成立,隨後先從代碼着手找原因。

wafer信道方案

先簡單介紹一下wafer的信道方案如何使用websocket通信,一共三個參與方,client、server與third-server(騰訊雲PaaS服務),交互是client與third-server建立websocket連接,third-server使用http與server通信。

client發送消息給server:

client通過websocket發送消息給third-server,thrid-server收到後會以http的方式調用server

server發送消息給client:

server通過http調用third-server,然後third-server再通過websocket發送給client

這個方案本身應該OK,但文檔中缺少細節,導致難以定位client沒有收到消息的問題所在,從文檔發現唯一有聯繫的大概是broadcast方法回調中返回了invalidTunnelIds(無效的信道ID),但代碼中有對invalidTunnelIds做消息重發。

invalidTunnelIds疑點

看到invalidTunnelIds這個回調內容後非常好奇,因爲我知道websocket消息發出去後並不能確定對方是否成功收到,那麼wafer這裏如何判斷某個信道無效呢?

難道說invalidTunnelIds只是識別關閉了的目標信道,又或者wafer實現了一套類似TCP-ACK的機制,關於這個invalidTunnelIds,文檔裏面並沒有額外說明,猜不出啥,因爲難以確認這個細節,對定位問題產生莫大阻礙。

通過查看調試log,發現客戶端websocket連接通信正常的情況下,invalidTunnelIds也有可能非空,猜測third-server有ACK機制+timeout,然後在timeout內沒有收到客戶端的ACK,隨後當成無效信道返回給server,但這些猜測同樣沒找到相關文檔證實。

意外收穫

由於糾結invalidTunnelIds的具體含義,調試過程中有一個意外收穫,發現同一個消息client出現收到兩次的情況,這讓我有些意外。

假設wafer信道功能有ACK機制,但在指定的timeout內third-server沒有收到消息的ACK,當成無效信道返回給了server。client雖有收到消息,但由於ACK超時,third-server返回的invalidTunnelIds導致這條消息被重發,所以client又收到了一次。

測試過程中,發現這種情況也導致了客戶端出現BUG,解決方案相對簡單:“爲每一條消息標記一個ID,客戶端按收到過的消息去重”。

調試

理論分析過程中沒有實質性收穫,但判斷問題原因還是wafer信道服務的不穩定,有猜測是因爲websocket出現重連導致丟失消息,而且代碼中關於ws連接異常的處理邏輯也不完善,遂在代碼中加了一堆調試log,比如打印各種ws事件、收到消息等。

經過測試出現卡住情況後查看日誌,發現確實是問題未收到,但是ws連接並無異常,同時從服務器的日誌上看,消息有發出。這很意外,同時很無奈,ws連接沒有異常,服務端的確向信道發送了消息,但客戶端就是沒收到,只能猜測是因爲third-server不可靠。

問題處理

猜測是因爲third-server不可靠導致client沒有收到消息之後,做了一個嘗試性修改:“針對每一個發送問題的消息,採用間隔300ms發送10次的策略”,因爲客戶端做了消息去重,所以不會造成業務邏輯BUG。經過這樣的嘗試性修改後再測試,測了近一個小時也沒有出現一次收不到的情況。

而在沒修改之前,測3-5分鐘大概會出現一次消息收不到,修改後一小時不出現,間接證明third-server不可靠的可能性,而如果真的是third-server不可靠,從開發的角度來說,針對收不到消息的問題基本沒轍。

這個項目我只是指導修改,把情況跟對方技術詳細說明後,讓他們先用這種低成本的修改方案試試,實際上這個修改方案針對的只是third-server可能不可靠,但並沒有從根本上解決問題,也不優雅。

思考

拋開對wafer信道的可靠性懷疑,如果是client用websocket與server直連,通信是不是可靠的呢?答案是:“同樣不可靠”,原因是因爲連接可能出現異常,比如網絡不穩定、網絡環境切換。

假設server通過websocket協議向client發送一條消息A,但此時client確突然斷網,過了兩秒後client重新連接到服務器,但如果沒有其它措施的話,client就錯過了消息A。針對這種情況,需要一個類似TCP-ACK機制用於client向server反饋消息接收情況,同時server需要維護消息的狀態,當消息沒有被確認收到,client重新連接後需要補發這些消息。

有了ACK機制同樣不能避免重複收到消息,上面的場景,假設client收到消息A回ACK的時候,網絡異常導致ACK沒有送達,隨後自己異常觸發重連,由於服務器沒有收到消息A的ACK,故在client連接後還會收到一次消息A,所以client去重的邏輯同樣需要。

假設ws連接是穩定的,即不考慮重連或異常斷開等情況,server發出的消息是否可以保證client一定收到呢?我想是能夠保證的,因爲ws協議建立在TCP之上,TCP是可靠傳輸,只要協議處理上不出現問題,那麼就能夠保證server發出的消息,client能夠收到。當然,TCP連接異常會導消息傳輸不可靠,但我指的前提就是不考慮連接異常情況。

針對wafer的信道模式,server與client中間多了個一個third-server,事情變的更復雜,比如server -> third-server的HTTP超時與異常處理,再比如third-server本身的可靠性等。這其中缺少的技術細節導致這個問題難以繼續定位根本原因,雖然看起來是因爲wafer信道的不穩定導致消息沒有收到,但也有可能不是,自己最終沒有更多精力和成本去尋找,只能作罷。

後記

對於小程序生態圈其實不算了解,只是聽聞小程序對開發者越來越友好,門檻也越來越低,感覺這樣的技術低門檻難以滿足具有競爭力產品所需要的技術能力,卻可以讓更多的人或者說是程序員發揮其創造力,營造一個多元化,多樣化的小程序生態。

雖然我喜歡這種生態,但好像現實情況恰恰相反…

博客原文

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章