یک توسعهدهنده متوجه شد که اتصال دیباگر Chrome DevTools از طریق Playwright یا Puppeteer، سرعت آپلودهای مبتنی بر fetch را بیش از ۲۰ برابر محدود میکند و بنچمارکهای عملکردی روزمره را به دادههای گمراهکننده تبدیل میکند.
معمایی که باعث شروع تحقیقات شد
Coffer، یک فضای ذخیرهسازی فایل مبتنی بر مرورگر که دادهها را قبل از ارسال به سرور رمزنگاری میکند، بهطور معمول آپلودهایی در کلاس گیگابیت را روی یک شبکه محلی انجام میدهد. وقتی تیم سرعت آپلود را اندازهگیری کرد، متوجه یک شکاف شد: دانلودها پهنای باند را اشباع میکردند، اما آپلودها با سرعتی تقریباً یکهشتم پهنای باند موجود پیش میرفتند. این اختلاف باعث شد سه مرحله تغییر در کد انجام شود که هیچ تأثیری در نتیجه نداشت، تا اینکه چهارمین «اصلاحیه» به نظر رسید جهش بزرگی ایجاد میکند—اما بلافاصله با حذف دیباگر، این بهبود ناپدید شد.
آنچه تیم ابتدا امتحان کرد
مهندسان به سراغ مظنونان همیشگی رفتند:
- Chunk size – دو برابر کردن اندازه بلوک از 16 MiB به 32 MiB، نرخ انتقال داده (throughput) را بدون تغییر باقی گذاشت.
- Pipelining – همپوشانی رمزنگاری بلوک بعدی با آپلود فعلی، تنها منجر به بهبود ناچیز ۱۳ درصدی شد که از نویز اندازهگیری قابل تشخیص نبود.
- Concurrency – اجرای چندین آپلود بهصورت موازی، به همان سرعت کل محدود شد که نشاندهنده یک سقف جهانی (global ceiling) بود.
هیچکدام از این تغییرات، کاهش سرعت ۸ برابری را توضیح نمیدادند.
یک مقایسه مستقیم و غافلگیرکننده
برای جداسازی مشکل، تیم پیادهسازی کلاینت را تغییر داد. با استفاده از .NET HttpClient، آنها روی همان شبکه سرعت 700 Mbps را ثبت کردند؛ در حالی که همان درخواست از طریق API fetch() در Chromium روی 140 Mbps متوقف میشد. این تضاد آشکار، پشته شبکه (network stack) مرورگر را به عنوان مقصر نشان میداد—تا اینکه آزمایش بعدی خلاف آن را ثابت کرد.
هزینه پنهان دیباگر
Playwright و Puppeteer کروم را از طریق Chrome DevTools Protocol (CDP) هدایت میکنند. این پروتکل یک دیباگر را به فرآیند مرورگر متصل میکند و رویدادهای شبکه، اسنپشاتهای DOM و لاگهای کنسول را در دسترس قرار میدهد. تیم یک تست متمرکز انجام داد: یک فراخوانی fetch() که یک محموله (payload) از نوع Uint8Array ارسال میکرد؛ یک بار با اتصال دیباگر CDP و یک بار بدون آن.
- Debugger attached: 113 Mbps
حضور دیباگر سرعت آپلود را بیش از 20× کاهش داد. یک تست دستی در یک پنجره معمولی Edge—بدون اتصال دیباگر—به سرعت 600+ Mbps رسید که تأیید کرد مرورگر خود میتواند در صورت عدم محدودیت، ترافیک را مدیریت کند.
یک بهبود واقعی و اندک
اگرچه دیباگر عامل اصلی کاهش سرعت بود، اما تیم همچنان به یک بهینهسازی واقعی دست یافت: تغییر بدنه درخواست از Uint8Array به Blob سرعت Chromium را تقریباً 30% افزایش داد. این یک تغییر مفید است، اما به هیچ وجه به آن جهش «معجزهآسایی» که در ابتدا انتظار میرفت، نمیرسد.
چرا این موضوع برای مهندسان اهمیت دارد
- ابزارها میتوانند دروغ بگویند. ابزارهای عملکردی که مرورگرها را خودکار میکنند، خود بخشی از زنجیره اندازهگیری هستند.
- بنچمارکهایی که غیرممکن به نظر میرسند، نیاز به بررسی صحت (sanity check) دارند. اگر اعداد با ظرفیت شبکه تفاوت فاحشی داشتند، محیط اندازهگیری باید اولین مظنون باشد.
- نتیجه صفر (null result) ارزشمند است. تأیید اینکه یک تغییر هیچ تأثیری ندارد، از هدر رفتن وقت برای دنبال کردن باگهای خیالی جلوگیری میکند.
- کنترلهای دستی، یک بیمه ارزان هستند. اجرای همان عملیات در یک پنجره معمولی مرورگر میتواند سربار پنهان ابزارهای اندازهگیری را آشکار کند.
نکته مقابل: زمانی که دیباگرها ضروری هستند
دیباگرها دیدی نسبت به رفتار صفحه، ردپای خطاها (error traces) و خطوط زمانی شبکه (network timelines) فراهم میکنند که در غیر این صورت غیرقابل دسترس هستند. برای تست رگرسیون، ممیزیهای امنیتی یا تعاملات پیچیده رابط کاربری (UI)، اتصال دیباگر CDP اغلب غیرقابل مذاکره است. نکته کلیدی این است که تست عملکردی را از اندازهگیری عملکرد خام جدا کنید و زمانی که هدف دوم است، دیباگر را غیرفعال کنید.
نتیجهگیری: ابزارهایی که تست خودکار را ممکن میسازند، میتوانند به بزرگترین منبع تحریف عملکرد نیز تبدیل شوند. قبل از مقصر دانستن مرورگر، شبکه یا کد، بررسی کنید که آیا دیباگری در حال محدود کردن بیصدای جریان داده است یا خیر.
