可笑,架構師也能寫出這樣的Bug

雲棲號資訊:【點擊查看更多行業資訊
在這裏您可以找到不同行業的第一手的上雲資訊,還在等什麼,快來!

小夥話不多,但一旦說話斬釘截鐵,帶着無法撼動的自信。原因就是,有他着數億高併發經驗,每一秒鐘的請求,都是其他企業運行一年也無法企及的。這就讓人非常羨慕,畢竟他靠這個比我賺的錢要多。

俗話說,要想在公司不出事故,那就不要寫代碼。幹活多了容易出事,一身輕鬆無人問津,這就是現實。

但有時候還是要看成果的。新來的研發領導不懂技術,但他懂技術指標,所以就統計大家提交 Git 的數量,如果 Git 活動是一片綠色如 A 股,那就算過關了。

架構師思來想去,決定領一個併發量最高的需求:統計接口的平均響應時間和啓動以來的請求數。

爲什麼說它的併發量高呢?這是因爲,它是統計所有接口的,自然比每一個接口的請求量都要大。AOP 代碼一包,每個接口都得從他這裏走一圈。

該我們的架構師上場了,代碼如下圖:

image

架構師說,我的代碼不需要做註釋。所謂的註釋,都是給垃圾代碼用的。我深以爲是,他明顯是受到了 Netflix 公司的影響。

程序考慮到了高併發場景,使用了線程安全的 ConcurrentHashMap,然後每次通過監控 Key 取出相應的數據,然後在 Value 上遞增。這麼簡單的代碼,確實不需要增加什麼註釋。

作爲項目裏併發量最高的代碼,出於對高級架構師的信任,我們並不需要做什麼代碼 Review,也不需要做什麼測試。大家都很忙,代碼您吶,到線上遛一遛吧。

我建議你先找一找代碼的問題,如果你發現了問題,那就比架構師還厲害;如果你沒發現,也不證明你比架構師弱,沒有什麼好傷心的。

下面插一副圖,阻斷一下思維:

image

裝 B 遭雷劈,線上運行一段時間後,內存溢出了。

大家吵吵個沒完,畢竟我說過,內存溢出問題的排查週期很長,大約平均需要 40 天左右才能解決問題。

在大家開始論證的時候,架構師偷偷的啓動了 Eclipse MAT。MAT 用來分析內存問題是非常合適的,但前提是你需要把堆棧給搗鼓下來。

架構師會用 Jmap,最主要的是權限大,於是自己搞了一份拷貝到線下分析。

我能理解到他的心情,畢竟問題定位到自己的代碼不是一件什麼值得高興的事情。

他發現內存的堆裏面,滿滿的全是 MonitorKey 和 MonitorValue:

image

我和架構師關係比較好,於是他問我:咱們的接口是不是特別的多?

我說:不是啊,你別看訪問量大,就這麼個狗屁業務能有多少接口?幾百個撐了天了。

他說:我在堆裏發現了幾千萬個...

說完他就不言語了,因爲他發現裏面有不少是一樣的接口。一定是參數的原因,所以他在代碼里加了這個,把?後面的給截斷了。

image

結果發佈到線上,過不了多久內存又溢出了。這次終於引起了大牛們的注意,經過大家的分析,發現代碼是忘了給 MonitorKey 重寫 equals 和 hashCode 方法了。

我不禁臉紅起來,作爲好朋友,我不應該讓他出這個醜。但我又是隱隱快樂的,因爲他工資比我高。

所以這就是一個很大的問題。很多同學對 HashMap 的知識點對答如流,甚至還專門記憶了紅黑樹。但換一個方式去問,卻又一臉懵逼。

其中一種問法是這樣的:一個普通的對象,能夠作爲 HashMap 的 Key 麼?

答案顯然是可以的,但需要注意重寫 hashCode 和 equals 方法。如果忘記重寫的話,大概率會造成內存泄漏。

很不幸,現實中忘記的案例很多。大牛架構師也會中招。代碼重寫 hashCode 和 equals 方法後,線上就再也沒發生過內存溢出。

等等,還沒完。畢竟是架構師,僅僅這樣一個 Bug 還是證明不了水平的。架構師寫的 Bug,肯定非比尋常。

這種事出現的多了,研發領導對技術的權威性就不再是那麼感冒。我們決定從併發量最高的代碼開始,進行一下代碼 Review。

很不幸,架構師的 visit 代碼出現問題了。雖然問題不是很大,但它畢竟是個問題。

image

在統計數據的時候,代碼使用了 ConcurrentHashMap,但它並沒有什麼卵用。

visit 方法,首先拿出了 Key,然後判空,再塞值。這明顯不是一個原子操作。

image

此時,B 丟了。業務可以忍受,但嚴謹的技術大牛們忍受不了,提出了修改的意見。

架構師說,給 visit 方法加個 Synchronized 不就成了。

image

我說不行。有更優雅的寫法,效率更高。那就是使用 putIfAbsent 方法,代碼改動如下:

image

大家就這兩種方式爭論了起來。

技術總監託着腮想了半天,看了看爭的面紅耳赤的同學們,說:這就是我不放心你們的緣故。線上環境要儘量保持穩定性,做最小的變更。

既然加個 Synchronized 就能夠很容易簡單解決的問題,爲啥不直接用呢?下面這種代碼改動太大,有風險。

總監接着把頭轉向我:這個 Bug 非比尋常,爲了讓大家引以爲戒,你來做整個事故的覆盤。把問題的排查和得到的教訓分享給大家,讓大家向這種至簡的架構看齊。

我們平常的工作中,也要儘量以結果導向爲主,用什麼手段無所謂,能漂亮把事情辦好就行。

這就是此篇文章的由來,我虛心受教,同時也明白自己的工資是漲不上去了。你要是點個贊或者友情三連,或許還能安慰我一下下。

【雲棲號在線課堂】每天都有產品技術專家分享!
課程地址:https://yqh.aliyun.com/live

立即加入社羣,與專家面對面,及時瞭解課程最新動態!
【雲棲號在線課堂 社羣】https://c.tb.cn/F3.Z8gvnK

原文發佈時間:2020-08-03
本文作者:小姐姐養的狗
本文來自:“51CTO技術棧”,瞭解相關信息可以關注“51CTO技術棧

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