<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          架構師寫的BUG,非比尋常!

          共 2883字,需瀏覽 6分鐘

           ·

          2020-08-11 22:45

          Java技術棧

          www.javastack.cn

          關注閱讀更多優(yōu)質文章


          部門新來了個架構師,BAT背景,住在三環(huán),開寶馬上班,有車位。
          小伙話不多,但一旦說話斬釘截鐵,帶著無法撼動的自信。原因就是,有他著數(shù)億高并發(fā)經(jīng)驗,每一秒鐘的請求,都是其他企業(yè)運行一年也無法企及的。這就讓人非常羨慕,畢竟他靠這個比我賺的錢要多。
          俗話說,要想在公司不出事故,那就不要寫代碼。干活多了容易出事,一身輕松無人問津,這就是現(xiàn)實。
          但有時候還是要看成果的。新來的研發(fā)領導不懂技術,但他懂技術指標,所以就統(tǒng)計大家提交git的數(shù)量,如果git活動是一片綠色如A股,那就算過關了。
          架構師思來想去,決定領一個并發(fā)量最高的需求:統(tǒng)計接口的平均響應時間和啟動以來的請求數(shù)。
          為什么說它的并發(fā)量高呢?這是因為,它是統(tǒng)計所有接口的,自然比每一個接口的請求量都要大。AOP代碼一包,每個接口都得從他這里走一圈。
          該我們的架構師上場了。代碼如圖。
          架構師說,我的代碼不需要做注釋。所謂的注釋,都是給垃圾代碼用的。我深以為是,他明顯是受到了Netflix公司的影響。
          程序考慮到了高并發(fā)場景,使用了線程安全的ConcurrentHashMap,然后每次通過監(jiān)控key取出相應的數(shù)據(jù),然后在value上遞增。這么簡單的代碼,確實不需要增加什么注釋。
          作為項目里并發(fā)量最高的代碼,出于對高級架構師的信任,我們并不需要做什么代碼review,也不需要做什么測試。大家都很忙,代碼您吶,到線上遛一遛吧。
          我建議你先找一找代碼的問題,如果你發(fā)現(xiàn)了問題,那就比架構師還厲害;如果你沒發(fā)現(xiàn),也不證明你比架構師弱,沒有什么好傷心的。
          下面插一副圖,阻斷一下思維。
          裝B遭雷劈,線上運行一段時間后,內(nèi)存溢出了。
          大家吵吵個沒完,畢竟我說過,內(nèi)存溢出問題的排查周期很長,大約平均需要40天左右才能解決問題。在大家開始論證的時候,架構師偷偷的啟動了Eclipse MAT。MAT用來分析內(nèi)存問題是非常合適的,但前提是你需要把堆棧給搗鼓下來。
          架構師會用jmap,最主要的是權限大,于是自己搞了一份拷貝到線下分析。這個工作不會用的可以關注公眾號Java技術棧搜索閱讀。
          我能理解到他的心情,畢竟問題定位到自己的代碼不是一件什么值得高興的事情。他發(fā)現(xiàn)內(nèi)存的堆里面,滿滿的全是MonitorKeyMonitorValue。
          Monitor$MonitorKey@15aeb7ab
          我和架構師關系比較好,于是他問我:咱們的接口是不是特別的多?
          我說:不是啊,你別看訪問量大,就這么個狗屁業(yè)務能有多少接口?幾百個撐了天了。
          他說:我在堆里發(fā)現(xiàn)了幾千萬個...
          說完他就不言語了,因為他發(fā)現(xiàn)里面有不少是一樣的接口。一定是參數(shù)的原因,所以他在代碼里加了這個,把?后面的給截斷了。
          key = key.split("\\?")[0];
          結果發(fā)布到線上,過不了多久內(nèi)存又溢出了。這次終于引起了大牛們的注意,經(jīng)過大家的分析,發(fā)現(xiàn)代碼是忘了給MonitorKey重寫equalshashCode方法了。
          我不禁臉紅起來。作為好朋友,我不應該讓他出這個丑。但我又是隱隱快樂的,因為他工資比我高。
          所以這就是一個很大的問題。很多同學對HashMap的知識點對答如流,甚至還專門記憶了紅黑樹。但換一個方式去問,卻又一臉懵逼。
          其中一種問法是這樣的:一個普通的對象,能夠作為HashMap的key么?
          答案顯然是可以的,但需要注意重寫hashCode和equals方法。如果忘記重寫的話,大概率會造成內(nèi)存泄漏。
          很不幸,現(xiàn)實中忘記的案例很多。大牛架構師也會中招。
          代碼重寫hashCode和equals方法后,線上就再也沒發(fā)生過內(nèi)存溢出。

          等等,還沒完。畢竟是架構師,僅僅這樣一個bug還是證明不了水平的。架構師寫的bug,肯定非比尋常。
          這種事出現(xiàn)的多了,研發(fā)領導對技術的權威性就不再是那么感冒。我們決定從并發(fā)量最高的代碼開始,進行一下代碼review。
          很不幸,架構師的visit代碼出現(xiàn)問題了。雖然問題不是很大,但它畢竟是個問題。
          在統(tǒng)計數(shù)據(jù)的時候,代碼使用了ConcurrentHashMap,但它并沒有什么卵用。
          visit方法,首先拿出了key,然后判空,再塞值。這明顯不是一個原子操作。
          線程1:獲取key為a的值
          線程2:獲取key為a的值
          線程1:a為null,生成一個b
          線程2:a為null,生成一個c
          線程1:保存a=b
          線程2:保存a=c
          此時,B丟了。
          業(yè)務可以忍受,但嚴謹?shù)募夹g大牛們?nèi)淌懿涣?,提出了修改的意見?/section>
          架構師說,給visit方法加個synchronized不就成了。
          public synchronized void visit(String url, String desc, long timeCost)
          我說不行。有更優(yōu)雅的寫法,效率更高。那就是使用putIfAbsent方法,代碼改動如下:
          MonitorKey key = new MonitorKey(url, desc);
          MonitorValue value = monitors.putIfAbsent(key, new MonitorValue());
          value.count.getAndIncrement();
          value.totalTime.getAndAdd(timeCost);
          value.avgTime = value.totalTime.get() / value.count.get();
          大家就這兩種方式爭論了起來。
          技術總監(jiān)托著腮想了半天,看了看爭的面紅耳赤的同學們,說:這就是我不放心你們的緣故。線上環(huán)境要盡量保持穩(wěn)定性,做最小的變更。既然加個synchronized就能夠很容易簡單解決的問題,為啥不直接用呢?下面這種代碼改動太大,有風險。
          總監(jiān)接著把頭轉向我:這個BUG非比尋常,為了讓大家引以為戒,你來做整個事故的復盤。把問題的排查和得到的教訓分享給大家,讓大家向這種至簡的架構看齊。我們平常的工作中,也要盡量以結果導向為主,用什么手段無所謂,能漂亮把事情辦好就行。

          最近熱文:

          1、重磅!《Java開發(fā)手冊(嵩山版)》最新發(fā)布

          2、打破你的認知!Java空指針居然還能這樣玩

          3、Java 強、弱、軟、虛,你屬于哪一種?

          4、Spring Boot 太狠了,一次發(fā)布 3 個版本!

          5、Spring Boot 如何快速集成 Redis?

          6、盤點 6 個被淘汰的 Java 技術,曾經(jīng)風光過!

          7、Spring Boot Redis 實現(xiàn)分布式鎖,真香!

          8、Spring Boot 干掉了 Maven 擁抱 Gradle!

          9、公司來了個新同事不會用 Lombok!

          10、同事寫了個隱藏 bug,我排查了 3 天!

          掃碼關注Java技術棧公眾號閱讀更多干貨。

          點擊「閱讀原文」獲取面試題大全~
          瀏覽 34
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费色情电影链接 | 欧美级一人在线视频播放 | 白丝美女自慰网站 | 青青草国产亚洲精品久久 | 东方AV100在线观看 |