زمان مطالعه: حدود ۷ دقیقه
مخاطب: تیمهای توسعه، DevOps، مدیران فنی و محصول
وقتی همهچیز سبزه ولی کار نمیکنه!
کاربر دکمه پرداخت رو میزنه. پاسخ API میاد، بدون ارور. هیچکس توی تیم هشدار خاصی دریافت نمیکنه. لاگها عادیه، مانیتورینگ چیزی نشون نمیده. اما پشتیبانی پر شده از پیامهایی که میگن سفارش ثبت نشده یا تایید پرداخت دریافت نشده. این دقیقاً همون نقطهایه که میفهمی خطاهایی هستن که با هیچ اروری اعلام نمیشن فقط تجربه کاربر رو خراب میکنن، بیصدا و مداوم.
ما توی این مقاله دربارهی همین خطاهای پنهان حرف میزنیم. نه اونهایی که با HTTP 500 و صفحه سفید خودشون رو فریاد میزنن. درباره خطاهایی صحبت میکنیم که از دید همه چیز درستن ولی واقعاً درست نیستن.
در معماری مدرن اپلیکیشنها، مسیر یک درخواست ساده ممکنه از دهها ماژول و سرویس رد بشه. از فرانتاند گرفته تا لایه API، صفهای پیام، پردازشهای async، کش، سرویسهای شخص ثالث، و دیتابیس. در این ساختار، خطا همیشه به شکل exception یا crash ظاهر نمیشه. گاهی فقط تأخیر غیرعادی وجود داره، گاهی بخشی از داده گم میشه، گاهی یک event با تأخیر چند دقیقهای میرسه. هیچکدوم از اینها ارور نیست اما همهشون میتونن اپلیکیشن رو بیاعتماد کنن.
تجربهای داشتیم در یک سرویس مالی که در ظاهر login موفق بود، اما تا event مربوط به refresh token با تأخیر اجرا میشد، داشبورد خالی نمایش داده میشد. نه خطایی، نه اخطاری. و تیم dev تا چند روز تصور میکرد این فقط یک مشکل UX سادهست. اینها خطاهایی هستن که اگر فقط به crashها نگاه کنیم، هیچوقت دیده نمیشن.
چرا ابزارهای سنتی برای این خطاها ناکارآمد هستن؟
بیشتر ابزارهای مانیتورینگ روی یک منطق ساده کار میکنن: آیا چیزی fail شد؟ آیا ارور ۵xx دریافت کردیم؟ آیا latency از حدی بالاتر رفت؟ ولی واقعیت اینه که بسیاری از مشکلات مدرن در همین چارچوب جا نمیگیرن.
تصور کن کاربری از سمت موبایل، از یک منطقه با اینترنت کند، سفارشی ثبت میکنه. پاسخ API برمیگرده، اما کند. callback با تأخیر اجرا میشه. session sync نمیشه. و کاربر حس میکنه عملیات شکست خورده. اما برای تیم، چون همهچیز "200 OK" بوده، چیزی دیده نمیشه. ابزار سنتی توی این سناریو کاملاً بیدفاعه. چون هیچچیز از نظر فنی "خراب" نیست. اما رفتار نرمال هم نیست.
روایت یک درخواست، چیزی فراتر از status code
در observability مدرن، ما بهجای تماشای نتیجه، مسیر رو دنبال میکنیم. وقتی میخوای بدونی چرا یه API بعضی وقتا مشکل داره، باید بدونی: این درخواست کی وارد شد؟ از کجا عبور کرد؟ کجا معطل شد؟ آیا retry شد؟ چند ثانیه منتظر پردازش async موند؟ پاسخش با چی برگشت؟
این یعنی مشاهدهپذیری واقعی. یعنی نه فقط ببینی "چی شد"، بلکه بفهمی "چرا اینجوری شد".
ما توی یک پروژه، با همین رویکرد تونستیم متوجه بشیم که delay در یک صف پیام باعث میشه بعضی callbackها دیر به API برسن. نتیجهاش؟ سفارشی که ثبت میشه ولی تأیید نمیشه. اگر فقط لاگ response رو ببینی، همهچیز خوبه. ولی وقتی مسیر حرکت ریکوئست رو ببینی، متوجه گره پنهان داستان میشی.
ناهمگامیهای کوچک، تهدیدهای بزرگ
یکی از خطرناکترین مدلهای خطا، زمانی اتفاق میافته که سرویسهای مختلف با هم sync نیستن. کاربر login کرده، ولی توی یک microservice هنوز session قدیمیه. نتیجه: درخواست رد میشه یا جواب ناقص میگیره. از بیرون هیچ خطایی نیست، ولی از درون بیاعتمادی ساخته میشه.
در سناریوی دیگهای، تصور کن که در زمان بار بالا، بعضی از کوئریها فقط تا نصفه اجرا میشن. یعنی داده ثبت میشه ولی نه کامل. کاربر انتظار یه رفتار داره، سیستم یه چیز دیگه ارائه میده. این خطاها نه توی لاگها میان، نه توی alertها فقط در رفتار سیستم دیده میشن.
و دقیقاً همینجاست که امنیت هم زیر سوال میره. اگر کاربر بدون اینکه لاگ شده باشه وارد سیستم بشه، یا بدون session معتبر به صفحهای دسترسی پیدا کنه، اونجا دیگه فقط یه bug نیست. یه تهدیده.
ابزارهای کلاسیک دنبال خطا میگردن، نه الگو
مشکل اصلی اینجاست: بیشتر ابزارها به دنبال "رخ دادن یک خطا" هستن. اما چیزی که ما باید ببینیم، تغییر در الگوست. اینکه چرا response یک API که همیشه ۲۰۰ میلیثانیه بود، امروز داره ۲ ثانیه طول میکشه. اینکه چرا تعداد درخواستهای موفق در یک بازه زمانی خاص کم شده، بدون اینکه خطایی ثبت بشه. اینکه چرا session rate پایین اومده ولی همه چیز سبزه.
اینجا ابزارهایی که فقط روی error rate کار میکنن، بهدرد نمیخورن. ما نیاز به دید عمیقتر داریم دیدی که فقط از observability کامل به دست میاد.
برنت چه کمکی میکنه؟
در برنت، مسیر درخواست بهصورت end-to-end قابل مشاهدهست. یعنی از لحظهای که کاربر دکمه رو فشار میده تا لحظهای که دیتا وارد دیتابیس یا صف میشه، همهچیز با شناسه یکتا، قابل ردیابیست. میتونی ببینی کجا معطل شد، چه سرویسی کند بود، چه eventی ارسال نشد، و چطور نتیجه نهایی ناقص موند.
برنت ابزار نیست بستریه برای دیدن داستان کامل. همراه با alertهایی که روی الگوی غیرعادی تنظیم میشن، نه فقط ارورهای تکراری. اگر response یک endpoint بهطور ناگهانی کاهش پیدا کنه یا delayها بالا بره، بدون اینکه خطایی رخ بده، سیستم بهت هشدار میده. و همین یعنی: پیدا کردن چیزی قبل از اینکه به بحران برسه.
خاموشی خطرناکتر از اروره!
وقتی سیستم ارور میده، حداقل میفهمی مشکلی هست. ولی وقتی چیزی نمیگه و فقط رفتار غیرعادی داره، اونجاست که خطر واقعی شروع میشه.
خیلی از این خطاهای پنهان، از دل رفتار بیرون میان. از requestهایی که دیر برمیگردن، از eventهایی که گم میشن، از دادههایی که sync نمیشن. و اگر فقط به ارورها نگاه کنیم، هیچوقت پیداشون نمیکنیم.
مشاهدهپذیری واقعی یعنی فهمیدن رفتار، نه فقط نتیجه.
و برنت، این بینش رو بهت میده. با tracing، log هوشمند، alert رفتارمحور، و ساختاری که اجازه میده همیشه چند قدم جلوتر از مشکل باشی.