【升級變成邀請-15人】還能邀請-2人??知乎的這麼明顯的BUG,貼上截圖,大家猜一下是啥原因造成的?
如圖所示,百思不得其解。
今天是11.12號,一看更加誇張:
謝@孤盡邀,我上半年讀過《阿里巴巴Java開發手冊》,裡面的強制和推薦很貼心,以前的好些習慣我細細思量和手冊對比確實有很多不妥之處,對我寫代碼的習慣有了潛移默化的修正,手冊對我們這些正在大量coding的人來說有很大幫助,在這裡表示感謝。也推薦新手可以邊學習便參考該手冊,因為最開始是形成coding好習慣的最好時機嘛。
說到這個話題,我說說自己的看法。
假如有一段執行邀請他人回答的代碼invite();那麼它肯定有個執行條件:
if(alreadyPersonNum&<=15){
invite();
}
那麼開始有兩個線程從資料庫或者緩存拿到alreadyPersonNum(已邀請人數)目前都是14,沒有加鎖的的情況下上面這一段代碼必然被執行兩次,會出現如圖的情況;但是圖上好像是alreadyPersonNum大於15的情況下還會執行invite();方法,我感覺可能就是簡單的業務邏輯問題,說不定是後端覺得前台肯定會校驗這個參數不調用後台api的,那前端妹紙還覺得這後台小哥肯定做了吧,我稍微給用戶一個友好的提示就可以了,所以前台妹紙拿到alreadyPersonNum一看大於15就拋出一個萌萌噠的「24小時最多邀請15次」!後台小哥說「哼,24小時才15次,你是在看不起誰?」所以可能傲嬌的多來了幾次。
我可沒在開車,各位坐穩了!
知乎是一個大網站,出現這種低級的錯誤不應該啊。阿里巴巴JAVA開發手冊中有一條:
【強制】在高並發場景中,避免使用「等於」判斷作為做中斷或退出的條件。
說明:如果並發控制沒有處理好,容易產生等值判斷被「擊穿」的情況,使用大於或小於的區間判斷條件來代替。
比如:庫存數=0退出,由於並發,成為-1,導致永遠無法退出。
這像《白夜追兇》一樣,大家分析一下案情。案情的奇怪之處是截圖中的-2,是在我明顯幾秒後點擊產生的,並發的錯誤不太可能,有可能是架構上的緩存問題,或者是故意而為之?
順便做個招聘的小廣告,如果想和我們一起奮鬥,享受編程的快樂,請發一句話,或者簡歷至:
guanbao.yanggb@alibaba-inc.com
我多麼希望把支付寶一直用到 》》餘額:-9999999元。
之前的答案只是舉了個沒加鎖突破限制的例子,但可能跟知乎的這個情況有所區別。下面再介紹一下更可能的猜測。
知乎的程序大概率應該是
1) a = 從資料庫中讀取該問題的邀請數
2) 判斷a是否小於15,如果大於15則結束程序,否則繼續執行3)
3) 將資料庫中該問題的邀請數+1
跟原回答中的情況類似,當邀請數已經達到14的情況下,多個請求都查詢到了a = 14,於是2)中判斷都認為可以繼續執行3),於是邀請數就超過了15。
當然還有一種可能就是這根本就跟並發沒有關係,而完全是前端邏輯混亂。比如每個用戶每天限制邀請15個用戶,然後前端以為是每個問題最多邀請15個用戶,結果第一天邀請了兩個,然後第二天再邀請15個就突破了單問題15個的限制了。
最後再解釋一下大家經常會問的其他問題:
1. 知乎這種級別的網站也會出這種bug?
你多邀請幾個人對知乎其實並沒有什麼損失。。。
2. 為什麼我覺得是記錄邀請數而不是剩餘可邀請數?
如果我哪天要把可邀請數改成20那豈不是資料庫里所有的欄位都要再更新一遍?
===== 原回答 ======
沒加鎖唄~
舉個例子,比如我要統計你這個問題邀請了幾個人了,那一般更新計數器的代碼會是這樣。
1) a = 從資料庫中讀取該問題的邀請數
2) a = a + 13) 把資料庫中該問題的邀請數更新為a
如果我同時邀請多個人,默認情況下程序不會一個一個邀請,而是同時邀請已提高處理效率,這意味著計算機會同時執行上面的程序。
那就有可能出現多個程序都執行到了1),並且都讀取到了一樣的數值,因為在執行3)之前其他任務讀取出來的數值是不會更新的。例如兩個任務在代碼1)中讀出來的都是3(之前已經邀請了三個了),然後最終在代碼4)中更新到資料庫的數值都是4。但實際邀請數已經到5了。
知乎好像不是用java的吧 以前據說是python。應該有用分散式來提升並發,但是具體編程沒有考慮分散式的數據更新並發。
再送你一個同類bug
========================================
然後一不小心發現一個傻的bug
請看下面的系列圖。。
我邀請三人後顯示:已經邀請11人還可以邀請4人
當我邀請第四個人的時候,顯示已經邀請十人還可以邀請5人
我再邀請兩個人顯示已經邀請八人還可以邀請7人
知乎的計數方式很有趣啊~~~~~讓我思考思考
====================================
@孤盡 大佬看這裡。目前的結果是邀請數字到了8之後也無法繼續邀請了。。。。
那麼說明判斷與15這個數字關係不是太大哦。。
並且請求有發出返回403~~~~~~~~
我過了十二點後的再次請求會變成反向遞增。
目前掌握的條件是:
1,請求不會判斷已經邀請人數中斷訪問,因為滿了之後會繼續請求並返回403。滿人數之後不中斷請求不符合常規做法。2,根據1與實際觀察,已經邀請人數對判斷幾乎沒有影響。
3,根據bug2可以看出。已經邀請人數與可邀請人數並非單純的i++或者i--的累加模式,故並發情況下不存在同時出現兩個已邀請人為14的請求同時到達知乎伺服器。
4,知乎伺服器大概率會統計同一用戶請求數作為判斷依據,而並非某個request參數。
5,知乎的設計上看第二天可以繼續增加邀請人數,所以超過15是必然。
6,根據以上所述,判斷值與已經邀請人數無關。
大佬您的判斷個人感覺有些輕視了。這個bug還是有點意思的。。。。
謝邀,題目中出現了我頭像,我也是嚇一跳。
這個應該是後台邏輯判斷不嚴謹
1. 24小時內,只能邀請15個人,很明顯超過15個還能邀請,所以資料庫里寫進去數據了,但是前台算的時候還是用15減的。至於為什麼寫進去數據了,難道是因為沒有進行人數判斷?2.另外24個小時過去了,邀請人數應該重新計算,後台也沒有重置?
3.應該是測試沒到位?
4.也有可能只是前端錯了,一直用15減邀請人數,應該是n天后用 n*15-邀請人數一堆熱心人幫人家試BUG……
我覺得是前端問題。我也遇到過這個情況。因為知乎好像在用戶操作之後會在前端立刻顯示更新,前端判斷不嚴謹造成了數字成為負數。但是實際上刷新一下又變成正常的了,是因為後端數據同步過來了。
謝大佬。被大佬邀請。
大佬的Java手冊看了好幾遍。我也不是知乎程序員,我也不知道什麼原因。
可能是兩邊數據統計的不一致,少個判斷吧。
比如15人是個常量,你邀請過的人是前面那個值,-15,就直接是後面的還能邀請。這裡少個判斷。
兩邊數據,這條我只能想出來可能原因,但是解釋不出來。前端…… 編輯器也是極其垃圾 粘貼文字亂加換行,沒法粘貼圖片,只能一個一個上傳……
應該是判斷條件寫成「==」了。並發處理不好的話 就會出問題。
請求在被執行的時候沒有做好並發處理,最後三個請求同時被執行結束了。
另外我查看問題日誌,會自動跳轉到網頁端登錄頁面...ios10,難道只有我有這個bug,這個bug我就百思不得其解了,難道是查看問題日誌token丟失了?驚奇的發現Tencent大大騰訊新聞也有這個問題
之前沒仔細看題,我覺得我又一次高估了知乎的技術人員的水平!
………………以下是原答案………………
如果只憑感覺說的話,可能是資料庫讀寫分離,數據沒有及時同步造成的。
類似的,新增加到某個話題的問題,是不會馬上就能通過話題找到的。這些現象可以看出讀寫分離的痕迹。
————————————
說一下我的分析吧。
1:服務端做了檢查,但是因為讀寫不同步,造成了在某個時間段實際上超過15的時候沒有檢查到。所以產生了實際上超過15的邀請。
2:同步以後,因為超過了15,服務端的檢查不會通過。但是web客戶端判斷寫的是==15,所以依然可以提交請求。請求提交以後,返回200,客戶端接著根據服務端的信息執行業務邏輯,彈出了那條紅色信息。
這個如果以mysql為例的話,應該是使用mysql proxy造成的。改用mysql cluster,並且保證服務端的[檢查和發起邀請]是同一個事務,就能徹底解決了。
已邀請xx人,還能邀請xx-15人 的這句是前端自己計數的吧,然後沒有加判斷條件。
那個紅色的句子則是寫死的。中間應該是有2個請求沒發到後端,所以前端以為自己發了17次,就記了17,後端這時才夠15個,剛剛返回了達到上限的標記,前端就把那2句話都顯示出來了。3條邀請同時到了,然後他們幾乎同時進入了檢查剩餘邀請數的代碼段,獲取了資料庫剩餘邀請數,都發現剩餘1人,都通過了檢查。然後創建邀請。然後更新資料庫邀請人數減1?
並發沒有處理好
感覺還是不一致,提示語和頁面顯示的數據源不一致?
我覺得是判斷條件不夠嚴格造成的,不能小於零
就是沒加鎖,並發沒控好
只能說明這個邀請功能比較容易,是讓新人寫的,每家公司都會有幾個萌新,只能做一些偏門的功能,領導看到你做出來了,實現效果了,也就不管具體業務下會不會出現bug了。
@知乎小管家 希望能夠修正這個BUG?謝謝
推薦閱讀:
※賦能遊戲產業鏈!這或許是阿里遊戲第一次真正展示自己的野心
※財報解讀|阿里一季度超預期增長60%,股價為什麼沒大漲?
※管理變陣,戰略落地——阿里再造阿里
※阿里28.8億美元入股高鑫,新零售「未來已來,正在加速流行」