bug千千萬,今天到我家。java
簡要描述:數倉WEB端進行新增事件後,會注入Redis中進行緩存,供給動參服務進行響應各端SDK的請求。程序員
下午,發現海內外redis中存儲的事件數據中僅有停用事件,而沒有啓用事件數據,覺得是個bug,而後找數據負責人、動參負責人以及產品等進行確認,對比數據及綜合意見後統一歸咎爲錯誤數據,經排查業務代碼邏輯,發現數倉WEB端業務邏輯也是按照顛倒方式進行緩存事件數據(即僅緩存停用事件,卻不緩存啓用事件),而後對代碼進行更新後,於晚上進行全部事件的緩存同步。redis
sync完全部事件數據到海內外redis後,同時也伴隨着3個應用的發版,動參一度癱瘓,不能響應請求。apache
從動參的表現來看,彷佛是服務出問題了,測試發送請求,確認的確不可行後,經過jstack processId > processId.log
進行查看線程狀態,發現全部線程所有BLOCKED
在調用org.apache.commons.beanutils.BeanUtils.closeBean(BeanUtils.java:108)
時,鎖等待在PropertyDescritor#getReadMethod
(方法聲明:public synchronized Method getReadMethod()
)。編程
其次,結合今天另外兩個條件:#1,三個應用發版;#2,修復顛倒業務邏輯後,會致使緩存中數據量增多(啓用事件>停用事件等)。緩存
因此多個小几率事件的疊加總和,致使觸發了動參服務中使用的BeanUtils#cloneBean
坑點,這也是進行屢次大對象copy時的服務性能嚴重降低甚至癱瘓的根源。安全
知道問題所在就好解決了,暫時關閉須要調用BeanUtils#cloneBean的API,同時快速進行Redis數據回退,一切恢復正常。markdown
其實不少工具類在多線程模式下都是多多少少存在性能或者安全問題的,好比BeanUtils#cloneBean
,SimpleDateFormat
等等。因此,咱們須要時刻注意本身所寫代碼,也要注意成長積累,避開那些槽點,同時規避潛在的不安全點,也算是防護性編程思想的運用吧!(此處推薦閱讀下阿里的Java開發手冊)多線程
既然要作一名程序員,那麼請從每一行代碼作起,保證代碼質量,魔鬼總在細節中,不要最終千里之堤潰於蟻穴。各位,come on, hold on!app
[1] 各種對象屬性拷貝工具性能測試對比:BeanCopier、BeanUtils、DozerBeanMapper、PropertyUtils