最近線上發生的兩個坑爹鍋

艾小仙發表於2021-01-13

最近由於在技改,發生了不少問題,前文中說的快取穿透只是其中之一,想了想,雖然都是比較簡單的問題,但是應該實際中還是有不少人碰到過,這些問題看似很簡單,但是你絕對應該踩過。

==和equals

關於==和equals區別,我相信稍微做過一兩年開發的同學都應該很清楚,可是,然而,這個坑在很多開發的時候仍然頻繁出現,為什麼?因為有時候有的同學認為沒什麼區別,就用==吧,然而,一些意外總是如期而至。

不久前,由於線上RPC框架切換,我們就發生了一點小問題。

本來,線上的介面是這樣定義的:

最近線上發生的兩個坑爹鍋

然後,介面查詢中使用到了一個列舉型別,根據id獲取列舉值,只不過這裡使用的是==號來判斷。

最近線上發生的兩個坑爹鍋

呼叫方的寫法:

最近線上發生的兩個坑爹鍋

本來,這個程式碼線上上跑了兩年了,一點問題沒有,怎麼就突然不行了呢?

但是,切換框架之後,這個介面報錯了,當時我也看了這個地方半天,猜測是這裡的問題,但是想了想貌似又不應該啊。

結果最後發現,原來的RPC框架傳輸中使用的是valueOf,從快取中取值,加上自動裝箱拆箱,判斷可以通過。但是,新的框架使用的是new Byte(),所以這個老程式碼就永遠無法通過了,因為這是一個新的物件。

看看這個測試的結果。

最近線上發生的兩個坑爹鍋

後面,通過安裝Alibaba Java Coding Guidelines外掛統一掃描所有程式碼,還又發現了一個坑爹的問題。

這個寫法又不太一樣,這個列舉只是單純的把code成員變數定義成了byte基礎型別,不是包裝型別。這樣,程式碼用==判斷又都OK了。

坑爹1

想象一下,因為是基礎資料型別,拆箱後==判斷當然是通過的。

還有更奇葩的寫法,成員變數是Byte包裝型別,getEnumByCode(byte code)這裡用的又是基礎型別,當然,這種寫法也能判斷通過。

坑爹2

所以,心累... ...

最後,我想再補充一下關於基礎資料型別快取的知識。能用==判斷的原因也都是依賴於快取的原因。

資料型別包裝型別快取型別快取值範圍
byte Byte ByteCache -128~127
short Short ShortCache -128~127
int Integer IntegerCache -128~127
long Long LongCache -128~127
char Character CharacterCache 0~127

最後,奉勸大家一句,千萬,千萬,在專案中判斷包裝資料型別都用equals,因為就算這段程式碼你很確信現在是對的,然而鬼都不知道後面會發生什麼!不要抱有僥倖心理。

 

日誌打滿

專案技改上線後不久,發現介面成功率直接跌0(跌0的告警監控必須得有,不然死都不知道怎麼死的)。排查了很久,看其他都是正常的,最後發現GC耗時狂增,登入伺服器一看,居然是硬碟被打滿了。

最近線上發生的兩個坑爹鍋

然後果斷去看日誌,因為我們的硬碟實際上很小,先懷疑日誌,果不其然,日誌炸了。通過ls -lht檢視檔案大小。

最近線上發生的兩個坑爹鍋

通過rm -rf刪除後發現硬碟空間並沒有釋放。正常情況下是不會出現這個問題的,但是如果檔案被鎖定或者有另外的程式在向檔案寫資料的話就會有問題了。

在Linux中,一個檔案在檔案系統中存放包含兩個部分:

  1. 指標部分:指標位於檔案系統的meta-data中,在將資料刪除後,這個指標就從meta-data中清除了。

  2. 資料部分:而資料部分儲存在磁碟中。

像上面的情況,雖然我們刪除了service.log,但是由於程式鎖定,指標部分沒有從meta-data中刪除,所以也就看到儲存空間沒有釋放的問題。

解決辦法有兩種:

  1. 使用lsof -n |grep delete檢視什麼程式在寫service.log,通過命令發現是我們的java程式在一直寫檔案,然後通過後臺工具直接重啟應用,重啟之後發現恢復正常。

  2. 清空日誌檔案,執行命令echo "">/service.log,這個方法可以立刻釋放磁碟空間,程式繼續寫入日誌也不會受到影響。

相關文章