- पहले मेरे सिस्टम में CPU उपयोग 3,200% तक पहुंच गया था, यानी सभी 32 कोर पूरी तरह भर गए थे
- मैं Java 17 runtime का उपयोग कर रहा था, और thread dump में CPU time देखकर उसे CPU time के अनुसार sort किया, तो कई मिलते-जुलते threads मिले
- समस्या वाले कोड का विश्लेषण
- stack trace के जरिए
BusinessLogic class की 29वीं line की जांच की
- वह कोड
unrelatedObjects list पर iterate करते हुए relatedObject की value को treeMap में insert कर रहा था
- यह loop के अंदर
unrelatedObject का उपयोग न करने वाला एक अक्षम कोड था
कोड संशोधन और टेस्ट
- अनावश्यक loop हटाकर इसे एक line
treeMap.put(relatedObject.a(), relatedObject.b()); में बदल दिया गया
- बदलाव से पहले और बाद में unit test चलाए गए, लेकिन समस्या को reproduce नहीं किया जा सका
treeMap और unrelatedObjects दोनों का size 1,000,000 से अधिक होने पर भी समस्या नहीं हुई
समस्या का कारण मिला
treeMap को कई threads एक साथ access कर रहे थे, और उसमें synchronization नहीं था
- यह समस्या कई threads द्वारा
TreeMap को एक साथ modify करने से हुई थी
प्रयोग के जरिए समस्या को reproduce करना
- कई threads द्वारा shared
TreeMap को random तरीके से update करने का प्रयोग किया गया
try-catch block का उपयोग करके NullPointerException को ignore करने के लिए सेट किया गया
- प्रयोग के नतीजे में CPU उपयोग 500% तक बढ़ने की घटना देखी गई
निष्कर्ष
- synchronization के बिना
TreeMap को एक साथ modify करना गंभीर performance समस्याएं पैदा कर सकता है
- ऐसी समस्याओं से बचने के लिए
TreeMap को synchronize करना या ConcurrentMap जैसी thread-safe collection का उपयोग करने की सिफारिश की जाती है
1 टिप्पणियां
Hacker News राय
मैं सोचता था कि race condition से data corruption या deadlock होता है, लेकिन यह performance समस्याएँ भी पैदा कर सकता है, यह नहीं सोचा था। data इस तरह corrupt हो सकता है कि infinite loop बन जाए
ऐसे code में जहाँ कई threads काम कर रहे हों, हर object को immutable बनाना, और जिन्हें immutable नहीं बनाया जा सकता उन्हें छोटे, self-contained, और सख्ती से नियंत्रित sections तक सीमित रखना ही एकमात्र भरोसेमंद रणनीति है
"ssh में लगभग लॉग इन नहीं हो पा रहा था" वाली बात ने graduate school के दिनों की याद दिला दी, जब Sun UltraSparc 170 इस्तेमाल करते थे
code को बस इस तरह घटाया जा सकता है
infinite loop पाने का एक और तरीका है ऐसा <i>Comparator</i> या <i>Comparable</i> implementation इस्तेमाल करना जो consistent total ordering लागू नहीं करता
बढ़ते हुए counter का इस्तेमाल करके cycle detect करने, और tree depth या collection size से अधिक होने पर exception throw करने का तरीका विचार किया जा सकता है
Java में thread-safe न होने वाले objects पर concurrent operations चलाना सबसे दिलचस्प bugs पैदा करता है
यह सवाल है कि क्या unprotected TreeMap 3,200% utilization पैदा कर सकता है
लेखक ने Poison Pill का एक प्रकार खोज लिया था। यह event sourcing systems में अधिक आम होता है, और ऐसा message होता है जो जिस किसी से भी टकराए उसे मार देता है
threads में exceptions बिल्कुल गंभीर समस्या होती हैं