چرا اول باید کد رو بهینه کنی، نه garbage collector رو
خلاصهٔ کاملتر
به گفتهٔ پیتر لاوری، بهینهکردن تخصیص حافظه تو جاوا میتونه خیلی بیشتر از انتخاب garbage collector فرق ایجاد کنه و حتی اینکه کدوم GC بهتره رو عوض کنه. برای نشوندادنش یه بنچمارک تأخیرِ رویداد-به-پاسخ روی Chronicle-FIX راه انداخته: تبدیل MarketDataSnapshot به NewOrderSingle با نرخ ۵۰ هزار پیام در ثانیه به مدت ۳۰ دقیقه، با ابزار JLBH.
حالت اول یه خط لاگ SLF4J از هر پیامو به کد بهینه اضافه میکنه. به گفتهٔ نویسنده یه خط لاگ زیاد به نظر نمیرسه، ولی وقتی روی هر پیام تکرار بشه — اونهم وقتی بقیهٔ کد برای تأخیر کم نوشته شده — فرق بزرگی میسازه. تو این حالت برای p99 انتخاب GC تقریباً همارزِ نحوهٔ لاگکردن اثر داره، ولی برای p99.99 (بدترین ۱ از ۱۰ هزار) نحوهٔ لاگکردن چند مرتبه مهمتر از انتخاب GC میشه.
بعد نشون میده که IO دیسک چقدر از تأخیرو میسازه: فقط با جابهجاکردن محل نوشتن لاگ به یه فایلسیستم tmpfs روی رم، بدترین حالتها تقریباً نصف شدن. یعنی بخش زیادی از اون تأخیر اصلاً ربطی به GC نداشته.
قدم آخر حذف لاگ اضافهست. چون Chronicle-FIX خودش هر پیامو با Chronicle Queue ثبت میکنه، اون لاگ SLF4J کاملاً زائده. با حذفش p99 حدود ۲ میکروثانیه بهتر شد، ولی نکتهٔ مهم اینه که p99.99 سه مرتبهٔ بزرگی (بیش از هزار برابر) بهتر شد. جالبتر اینکه بهترین GC هم عوض شد: با این بار کاری، Parallel GC بهترین و Shenandoah بدترین دراومد — همه بهخاطر یه خط لاگ.
جمعبندی نویسنده اینه که بهترین GC و نحوهٔ تنظیمش به بار کاری تو بستگی داره، پس منطقیه اول بار کاریتو بهینه کنی: هم چون گاهی اثر بیشتری داره، هم چون میتونه ترجیح GC رو هم عوض کنه. سیاست تیم اونا هم اینه که بعد از راهاندازی لاگ سطح info نداشته باشن — یا خطا/هشدار که پیشفرض روشنه، یا دیباگ که پیشفرض خاموشه.
نکات کلیدی:
- تو جاوا بهینهکردن حافظه و حذف کار اضافه میتونه بیشتر از انتخاب GC روی تأخیر اثر بذاره
- بنچمارک روی Chronicle-FIX با نرخ ۵۰ هزار پیام در ثانیه و ابزار JLBH انجام شده
- فقط یه خط لاگ SLF4J اضافه، تأخیر بدترین حالتها (p99.99) رو خیلی بالا میبره
- حذف لاگ زائد، p99.99 رو بیش از هزار برابر بهتر کرد و بهترین GC رو عوض کرد
- اول بار کاری رو بهینه کن، بعد سراغ تنظیم garbage collector برو




