
در اپیزود دهم پادکست کُدشناسی، به دنیای پیچیده نرمافزارهای امروزی سفر میکنیم تا یکی از مهمترین مفاهیم این حوزه را بررسی کنیم: Observability.
در معماریهای مدرن نرمافزاری، مانیتورینگ سنتی مانند دیدن تنها قله یک کوه یخ است؛ ابزاری که فقط به ما میگوید «مشکلی وجود دارد»، اما هرگز علت اصلی آن را در لایههای پنهان سیستم نشان نمیدهد. در این اپیزود، به عمق آبها نفوذ میکنیم تا با سه رکن اصلی Observability یعنی لاگها، متریکها و تریسها آشنا شویم. این ابزارها به ما کمک میکنند تا ریشهیابی مشکلات را حتی زمانی که کاملاً ناشناس و غیرمنتظره هستند، ممکن سازیم.
منابع :
Observability Engineering - Charity Majors, Liz Fong-Jones& George Miranda
متن اپیزود :
در دنیای پرشتاب توسعه نرمافزار، از استارتاپهای نوپا گرفته تا غولهای تکنولوژی، یک دغدغه مشترک وجود دارد: چگونه از عملکرد صحیح و بدون مشکل پروژههای خود اطمینان حاصل کنیم؟
دههها پیش، با ظهور کامپیوترهای بزرگ و شبکههای پیچیده، نظارت دستی بر سیستمها عملاً غیرممکن شد. این نیاز، تولد ابزارهای مانیتورینگ (Monitoring) را رقم زد؛ ابزارهایی که بهصورت خودکار وضعیت سرویسها را رصد میکردند و در صورت بروز مشکل، هشدارهای لازم را میدادند. با گذر زمان، این ابزارها پیشرفت چشمگیری داشتند و اطلاعات کاربردیتری مانند زمان پاسخدهی، تعداد درخواستها، میزان استفاده از CPU و RAM و حتی خطاهای برنامه را در اختیار ما قرار دادند.
اما با رشد روزافزون پروژههای نرمافزاری و افزایش پیچیدگی آنها، مانیتورینگ و صرف داشتن این نوع دیتاها به تنهایی دیگر کافی نبود. چرا؟ چون مانیتورینگ تنها میتوانست به ما بگوید "مشکلی وجود دارد"، اما بهراحتی نمیگفت "چرا این مشکل به وجود آمده است؟" مانیتورینگ بیشتر برای موقعیتهایی طراحی شده بود که احتمال رخ دادن آنها را پیشبینی میکردیم، مانند بالا رفتن مصرف CPU از یک حد معین.
در سیستمها و پروژههای امروزی، معماری به قدری پیچیده شده که برای مواجهه با یک وضعیت غیرمنتظره و مشکلاتی که شاید ما فقط بخش کوچکی از آن را میبینیم و بخش عظیمش خارج از دید ماست، نیاز به چیزی فراتر داریم.
در سال ۲۰۱۰، همزمان با روند رو به رشد پروژههای نرمافزاری، مفهومی به نام Observability با هدف پر کردن این خلا مطرح شد. Observability دقیقاً همان چیزی است که به ما اجازه میدهد در شرایط غیرمنتظره و ناشناس، عمیقاً سیستم را زیر نظر داشته باشیم و بفهمیم واقعاً چه اتفاقی افتاده و ریشه اصلی مشکل کجاست.
در این اپیزود، قصد داریم به این مفهوم عمیقتر بپردازیم و به سوالات کلیدی زیر پاسخ دهیم:
Observability دقیقاً چیست؟
چرا Observability برای پروژههای مدرن نرمافزاری اهمیت دارد؟
این مفهوم چه تفاوتی با مانیتورینگ دارد و چگونه این دو مفهوم یکدیگر را تکمیل میکنند؟
و در نهایت، وجود این ابزار در چرخه توسعه چه کمکی به ما میکند و چگونه میتوانیم در پروژههایمان از آن استفاده کنیم؟
بخش اول: Observability چیست؟ نگاهی به ریشهها و تعریف
مفهوم Observability اولین بار توسط فردی به نام رودولف کالمان در سال ۱۹۶۰ مطرح شد. به صورت کلی، Observability را میتوان اینگونه تعریف کرد: توانایی درک و تشخیص حالتهای داخلی یک سیستم از طریق خروجیهای خارجی آن.
خوب، این یعنی چه در عمل؟ در سیستمهای نرمافزاری، یعنی بتوانیم به نوعی درک از عملکرد داخلی برنامه، نحوه کار کردن کدها و اتفاقاتی که درون یک برنامه میافتد برسیم، بدون اینکه نیازی به بررسی خط به خط کد باشد! این رویکرد به یک فرد تکنیکال، حتی با دانش محدود نسبت به کدها، این امکان را میدهد که حالتها و اتفاقهای جدید و غیرقابل پیشبینی را با جزئیات بیشتری ببیند و بفهمد برنامه در چه وضعیتی قرار دارد. نکته مهم این است که تمام این مراحل بدون نیاز به تغییر و دیپلوی کردن کد جدید اتفاق میافتد.
اما شاید این سوال پیش بیاید که چطور از خروجیها به حالت داخلی میرسیم؟ برای این کار، ابزارهای Observability از سه نوع خروجی کلیدی استفاده میکنند که به "سه ستون Observability" معروفند:
متریکها (Metrics): اینها اعدادی هستند که از میزان مصرف منابع (ریورسها) در سرویسهای مختلف جمعآوری میشوند. متریکها مانند علائم حیاتی بدناند. مثلاً اگر مصرف CPU بالا برود یا زمان پاسخدهی (response time) زیاد شود، میفهمیم سیستم تحت فشار است یا در حال کند شدن است!
لاگها (Logs): وقتی در هر سرویس خطایی رخ میدهد، لاگها جزئیاتی از نوع و محل آن مشکل را در سرویس مورد نظر ثبت میکنند. آنها روایتگر وقایع درون سیستم هستند.
تریسها (Traces): تریسها مانند یک نقشه عمل میکنند. وقتی درخواستی از سمت کاربر میآید، نشان میدهند که این درخواست از کدام سرویس شروع شده و در کدام سرویس متوقف شده است. اینگونه میتوان فهمید دقیقاً در کدام بخش یا سرویس، مشکلی یا گلوگاهی (bottleneck) وجود دارد.
مسئله اینجاست که هر کدام از این خروجیها به تنهایی کمک چندانی نمیکنند و ترکیب آنهاست که این اطلاعات را ارزشمند میکند. با متریکها میفهمیم "مشکل وجود دارد"، با خروجی لاگها میتوانیم به اطلاعات مربوط به آن مشکل دست یابیم و با تریس میفهمیم "کجا این اتفاق افتاده است!"
بخش دوم: چرا Observability برای پروژههای مدرن نرمافزاری اهمیت دارد؟
حالا که در مورد مفهوم Observability و سه رکن اصلی آن (متریکها، لاگها و تریسها) صحبت کردیم، وقت آن است که به سوال بعدی بپردازیم و ببینیم چرا Observability برای پروژههای نرمافزاری مدرن اینقدر اهمیت پیدا کرده است.
همانطور که قبلاً اشاره شد، روشهای سنتی مانیتورینگ برای سطح پیچیدگی سیستمهای امروزی دیگر جوابگو نیستند. بیایید با جزئیات بیشتری این مسئله را بررسی کنیم:
محدودیتهای مانیتورینگ سنتی:
تمرکز بر منابع: ابزارهای مانیتورینگ بیشتر تمرکزشان روی منابع و ریورسهایی مانند CPU و RAM بود. عملاً از وضعیت داخلی اپلیکیشنها چیزی نمیدانستند.
دادههای سطحی: دادههایی که ارائه میکردند بسیار سطحی و بدون جزئیات خاصی بود و بیشتر به شکل یک هشدار عمل میکرد.
عدم قابلیت ردیابی درخواست: قابلیت اینکه بتوانیم یک درخواست را بین سرویسهای مختلف دنبال کنیم (tracing) را نداشتند.
از طرف دیگر، در پروژههای پیچیده به دلیل نبودن دیتای کافی برای پیدا کردن یک مشکل، معمولاً دست به دامان یک فرد باتجربه میشدیم که سالهاست در شرکت حضور دارد و تقریباً از تمام جزئیات سیستم خبر دارد تا بتواند در پیدا کردن آن مشکل به ما کمک کند!
تغییر معماری پروژههای نرمافزاری:
معماری پروژههای نرمافزاری به شدت تغییر کرده است. دیگر بسیاری از پروژهها از معماری مدرن با کلی سرویس خارجی، چند زبان برنامهنویسی مختلف، چند دیتابیس و موارد دیگر به صورت همزمان استفاده میکنند.
مثلاً، وقتی یک درخواست ساده از سمت کاربر میآید، ممکن است با کلی سرویس و ابزار مختلف در تعامل باشد تا به نتیجه برسد. اگر در آن بین به خطایی بخورد یا زمان پاسخدهی بالاتر از حد معمول شود، میتواند کل یک سیستم را تحت تاثیر قرار دهد و از طرفی، فهمیدن علت آن بسیار دشوار میشود.
در واقع، سختترین بخش برای عیبیابی اینگونه مشکلات، فهمیدن نحوه کار کردن آن بخش از کد نیست؛ زیرا کاملاً امکان دارد همان کد در زمانهای دیگر بدون مشکل و بینقص کار کند، اما در یک شرایط و زمان خاص دچار مشکل شود. پس در این وضعیت باید فهمید "مشکل دقیقاً کجا و چطور اتفاق افتاده است؟" شاید حتی نیاز باشد سرویسها یا دیتابیسهایی که درخواست از آنها عبور کرده، مورد بررسی قرار گیرند!
نقش Observability در مواجهه با مشکلات ناشناخته:
اما Observability برای "مشکلات ناشناخته و پیشبینینشده" طراحی شده است. یعنی مثلاً زمانی که مشکل مشابهی در مورد کند شدن یا به مشکل خوردن یک درخواست را تجربه کردید، به جای بررسی خط به خط کدها، میتوانید جزئیاتی از سرویسهایی که آن ریکوئست با آنها در تعامل بوده را ببینید. مثلاً بررسی کنید که زمان درخواست، یک تعامل با دیتابیس داشته که زمان زیادی گرفته و شاید نیاز به وجود یک ایندکس در آنجا احساس شود، یا مثلاً زمانی که با یک سرویس خارجی در تعامل هستید، متوجه شوید در زمانهای خاصی زمان پاسخگویی از آن سرویسدهنده بیشتر از حد عادی است و هزاران سناریوی دیگر که میتوان از این طریق به آنها رسید.
پس به جای پیشبینی شرایط مختلف، میتوان بر اساس اطلاعات ترکیب شدهای که داریم، فرآیند کلی ایجاد مشکل را پیدا کنیم و بفهمیم ریشه اصلی مشکل کجاست.
بخش سوم: تفاوت Observability و Monitoring: تکمیلکننده یکدیگر
در بخش قبلی گفتیم که Observability به ما این امکان را میدهد که ریشه مشکلات را حتی اگر ناشناس و غیرمنتظره باشند، پیدا کنیم. حالا میخواهیم در مورد یک مفهوم کلیدی به نام "قابلیت کشف مشکل" یا Explorability در پروژههای نرمافزاری صحبت کنیم.
این قابلیت هر چقدر در یک پروژه بیشتر باشد، این امکان را میدهد که در مواجهه با یک مشکل، سریعتر بتوانید آن را بررسی کنید. به زبان سادهتر، یعنی حتی اگر برای اولین بار با یک مشکل عجیب و غریب روبرو شدید، میتوانید قدم به قدم ریشهاش را پیدا کنید، بدون اینکه شاید از قبل برای آن مشکل خاص آماده باشید آن را فیکس کنید.
تفاوت کلیدی:
مانیتورینگ (Monitoring): فقط چیزهایی را نشان میدهد که از قبل برایش تعریف کردی. مثلاً اگر بگویی وقتی CPU زیاد شد، آلارم بده.
Observability: ابزارهای Observability حالت کشف و جستوجو (Explorability) دارند؛ یعنی میتوانی با آنها دنبال علت و جای مشکل بگردی. فرقش این است که فقط به خطاهای شناختهشده محدود نیستند، بلکه حتی وقتی با مشکلی جدید روبهرو شوی هم میتوانند کمک کنند زودتر پیدایش کنی و جلوی تکرارش را بگیری.
پس این تفاوت اصلی مانیتورینگ با مفهوم Observability است. Observability به افرادی که دارند با آن سیستم کار میکنند، این امکان را میدهد که هر بار مشکل را مثل یک مورد جدید بررسی کنند. همانطور که در بخش قبل هم گفتم، حتی اگر شبیه خطاهای قبلی باشد، میتوانند جزئیاتی که سیستم میدهد را مرحلهبهمرحله دنبال کنند و به نتیجه برسند.
اینطوری اگر مشکلی در سیستم پیش بیاید، هر کسی میتواند آن را پیدا کند، حتی اگر شناخت خیلی عمیقی از آن سیستم نداشته باشد. اینگونه، آن تجربه و دانشی که معمولاً فقط در ذهن افراد باتجربه و کلیدی در شرکتهاست، تبدیل به دادههایی میشود که قابل استفاده برای همه است و هر کسی میتواند عیبیابی بخشی از سیستم را به عهده بگیرد و اینگونه قابلیت کشف مشکل یا همان Explorability به شدت افزایش پیدا میکند.
حالا با این توضیحات، آیا مانیتورینگ دیگر کاربردی برای ما دارد؟
بخش چهارم: همزیستی Monitoring و Observability: مکملهای قدرتمند
تا اینجا در مورد تفاوتهای اساسی مانیتورینگ و Observability صحبت کردیم. اما این به این معنی نیست که دیگر نیازی به مانیتورینگ نداریم. در واقع، این دو میتوانند مکمل همدیگر باشند و یک دیدگاه جامع و کامل از سلامت و عملکرد سیستم ما ارائه دهند.
وقتی میگوییم "سیستم"، منظورمان همه چیزی است که در زیرساخت و محیط اجرا لازم است تا یک سرویس کار کند. به عبارت دیگر، سیستم یا همان زیرساخت شامل همه اجزایی است که کسبوکار برای اجرای نرمافزار به آن نیاز دارد؛ از دیتابیسهایی مثل MySQL و MongoDB گرفته تا بخشهای پردازش و ذخیرهسازی مانند کانتینرها یا ماشینهای مجازی. همه اینها باید قبل از اینکه نرمافزار شما اجرا شود، آماده و راهاندازی شده باشند.
شرایطی که روی سلامت زیرساخت اثر میگذارند معمولاً خیلی کم تغییر میکنند و قابل پیشبینی هستند. برای همین هم روشهای شناختهشدهای وجود دارد؛ مثلاً زمانی که ظرفیت یک منبع مانند دیسک، RAM یا CPU رو به اتمام است، پروسههای خودکاری مانند اسکیل کردن (scaling) در صورت بروز چنین مشکلاتی وجود دارد. چون این تغییرات معمولاً کند و قابل پیشبینی هستند، متریکهای کلی و پروسههایی که هر لحظه ظرفیت این منابع را چک کنند کافی به نظر میآیند.
اینجاست که ارتباط بین مانیتورینگ و Observability خودش را نشان میدهد.
وقتی مشکلی در عملکرد پیش میآید، میتوان لایه بالاتر یعنی منابع (ریورسها) را با مانیتورینگ سریع بررسی کرد و مطمئن شد که مشکل از زیرساخت نیست یا برعکس. حالا در قدم بعدی، با دادههای Observability در سطح اپلیکیشن، ریشه اصلی مشکل را پیدا کرد.
پس میتوان گفت این دو ابزار در کنار هم میتوانند این قابلیت را بدهند که یک پروژه نرمافزاری بدون مشکل به کار خود ادامه دهد و دید جامعی از سلامت آن داشته باشیم.
بخش پنجم: چگونه Observability را در پروژههایمان پیادهسازی کنیم؟
در بخشهای قبلی درباره Observability و اهمیت آن صحبت کردیم. حالا میخواهیم وارد بخش عملی بشویم و ببینیم چطور میتوانیم این مفهوم را در پروژههای خودمان پیاده کنیم.
برای Observability ابزارهای مختلفی وجود دارد و هر کدام مزایا و محدودیتهای خودشان را دارند. یکی از ابزارهایی که میتواند همه چیز را یکجا پوشش دهد و تجربه Observability را کاملتر کند، Elastic APM است. این ابزار که مخفف Application Performance Monitoring است، به شما کمک میکند عملکرد نرمافزاریتان را به طور کامل زیر نظر بگیرید و هر سه رکن Observability، یعنی لاگها، متریکها و تریسها را پوشش میدهد.
Elastic APM برای هر زبان برنامهنویسی از Agentهایی استفاده میکند که نیاز است آن Agent را در پروژه خود نصب کنید و آن به صورت خودکار اطلاعات عملکرد کد را جمعآوری و برای سرور APM میفرستد. خوشبختانه برای بیشتر زبانهای برنامهنویسی این ایجنتها ارائه شدهاند و من خودم به شخصه برای زبانهای گولنگ، پیاچپی و جاوااسکریپت از آنها استفاده کردهام. بعد از نصب و کانفیگ آن، میتوانید اطلاعات مربوط به درخواستها، تراکنشها، کوئریهای دیتابیس و خطاها را جمعآوری کنید و میتوانید مسیر هر درخواست را از شروع تا پایان در داشبورد Kibana ببینید. به همین سادگی! سعی میکنم یک پست برای نحوه پیادهسازی و تست روی لوکال برایتان بنویسم که بتوانید این ابزار را روی لوکال یا سرور خودتان هم بررسی کنید.
مزایا و محدودیتهای Elastic APM:
مزیت اصلی: جامع و کامل است و به راحتی با ابزارهای قدرتمند Elasticsearch و Kibana ادغام میشود. نکته مهمتر اینکه میتوانید از نسخه رایگان آن را روی سرور خودتان نصب کنید.
محدودیت: راهاندازی کل اکوسیستم Elastic Stack برای تیمهای کوچک میتواند کمی پیچیده و زمانبر باشد و به منابع سختافزاری زیادی نیاز دارد و مدیریت منابع به عهده خودتان است. البته نسخه کلود الاستیک هم وجود دارد که تمام اطلاعات و مدیریت منابع را خودش مدیریت میکند ولی خوب باید هزینه آن را پرداخت کنید!
سایر ابزارهای موجود:
Prometheus: برای جمعآوری و هشداردهی متریکها بسیار خوب است.
Jaeger: برای Tracing در معماری میکروسرویسها محبوب است.
پلتفرمهای جامع SaaS: Datadog و New Relic هم گزینههای خوبی هستند که همه ابزارها را در یک پلتفرم به شما میدهند، ولی خوب این دو سرویس اوپن سورس نیستند و باید هزینه بابتشان پرداخت کنید.
در نهایت، انتخاب ابزار بستگی به نیازهای تیم و پروژه شما دارد و باید بر اساس نیازمندیها، یک گزینه مناسب انتخاب کنید.
بخش ششم: Observability در چرخه توسعه نرمافزار: تسریع در انتشار و کاهش ریسک
خیلیها فکر میکنند Observability فقط بعد از انتشار نرمافزار و فقط در محیط عملیاتی کاربرد دارد، در حالی که در واقع میتواند و بهتر است بخشی از چرخه توسعه نرمافزار هم باشد.
در چرخه تولید یک محصول نرمافزاری، اصطلاحی به نام (Error Budget) یا حداکثر میزان خطا در سیستم را داریم. این به معنای مقدار زمانی است که سیستم میتواند خراب یا از دسترس خارج باشد و مشکلی به بیزینس و محصول وارد نشود. به عبارت ساده، یک سقف برای اختلال سیستم داریم که میتوانیم تحمل کنیم بدون اینکه عملکرد کلی محصول تحت تاثیر قرار بگیرد.
مثلاً، اگر حداکثر میزان خطا برای پروژه شما ۹۹.۹٪ باشد، یعنی در طول یک سال فقط حدود ۸ ساعت و ۴۵ دقیقه اجازه خرابی دارید. این موضوع روی بسیاری از تیمهای نرمافزاری، مخصوصاً پروژههای حساس، تاثیر مستقیم دارد؛ چون میتواند به صورت مستقیم و غیرمستقیم سرعت توسعه را به خاطر ریسکهای ریلیز محصول کاهش دهد، زیرا افراد مجبورند دست به عصاتر و با احتیاط خیلی بیشتری کار را جلو ببرند تا اشتباهی پیش نیاید.
یکی از مهمترین معیارهای پرفورمنس یک تیم مهندسی، مدت زمانی است که از نوشتن کد تا رسیدن آن بخش به کاربر در محیط پروداکشن زمان گذاشته میشود. یعنی هر چه این زمان بیشتر شود، پرفورمنس آن تیم پایینتر در نظر گرفته میشود. پس هر تیم باید این معیار را رصد کند و برای بهبودش تلاش کند.
در سالهای گذشته، روشهای زیادی برای افزایش سرعت انتشار بدون ترس از خرابیهای بزرگ معرفی شده است. روشهایی مانند Feature Flag، Blue-Green Deployment، Canary Release و روشهای مشابه که اجازه میدهد نسخههای جدید را به صورت محدود برای گروه یا درصد مشخصی از کاربران منتشر کنیم و بازخورد آنها را بگیریم.
اما این روشها به تنهایی کافی نیستند، چون باید تاثیر تغییرات جدید را در لحظه ببینید و اگر مشکلی پیش آمد، دقیقاً بفهمید چرا و کجا اتفاق افتاده و آن را رفع کنید.
وجود Observability در چرخه توسعه نرمافزار این امکان را میدهد که دادههای سیستم را در لحظه رصد کنیم و خیلی سریع مشکلات را پیدا و حل کنیم. میتوان به کمک این روش، زمان بازخوردها را از چندین روز و هفته به چند ثانیه و دقیقه کاهش دهیم و در نهایت اینگونه سرعت انتشار نسخههای جدید خیلی خیلی افزایش پیدا میکند.
جمعبندی نهایی
خب، بیایید یک جمعبندی در مورد این موضوع مهم داشته باشیم!
توی این اپیزود ، از تاریخچه مانیتورینگ شروع کردیم و دیدیم که چطور با پیچیدهتر شدن سیستمهای نرمافزاری، این ابزارها دیگر به تنهایی جوابگو نبودند. بعد، با مفهوم Observability و سه ستون اصلی آن، یعنی متریکها، لاگها و تریسها آشنا شدیم و فهمیدیم که چطور این رویکرد جدید به ما اجازه میدهد مشکلات ناشناخته و غیرمنتظره را پیدا کنیم.
در ادامه، تفاوت اصلی Observability و مانیتورینگ را بررسی کردیم و گفتیم که این دو ابزار در واقع مکمل هم هستند و مانیتورینگ برای سلامت زیرساخت و Observability برای عیبیابی عمیق در سطح اپلیکیشنها به ما کمک میکند. بعد، به بخش عملی قضیه رفتیم و دیدیم که چطور با ابزارهایی مانند Elastic APM و سایر پلتفرمهای Observability، میتوانیم این مفهوم را در پروژههای خودمان پیادهسازی کنیم و در نهایت، نقش کلیدی Observability در افزایش سرعت توسعه و بهبود چرخه انتشار نرمافزار را بررسی کردیم. امیدوارم این مطلب برایتان مفید بوده باشد. اگر تجربه، نظر یا پیشنهادی دارین، خیلی خوشحال میشوم از طریق بخش نظرات یا شبکههای اجتماعی با من در تماس باشید!