مصاحبه ها
بسترهای نوین مدیریت لاگ
این مطلب عیناً از وب سایت مطلبچه های مهندسی نرم افزار برداشته شده است که با همت جناب محمدعلی بزرگ زاده به زیبایی ترجمه شده است و مهندسی داده، با هدف جمع آوری مطالب مناسب فارسی در حوزه کلان داده به بازنشر آن پرداخته است .
در این مصاحبه که در فوریه ۲۰۱۵ منتشر شده است، رابرت بلومن با جان گیفارد در ساختمان اداری زیبای شرکت Loggly واقع در مرکز شهر سانفرانسیسکو صحبت میکند. جان در رشته کامپیوتر از دانشگاه کانتربری، فارغالتحصیل شده است. او بیش از ۲۵ سال است که در زمینه مهندسی نرمافزار مشغول است. تمرکز او بر روی سیستمهای Back End بزرگ مقیاس با کارایی بالا و اخیراً برنامههای جستجو با تأخیر پایین بوده است. او بنیانگذار و کارمند ارشد در مباحث جستجو در Loggly است. این شرکت، زیرساختهای لاگهای میزبانیشده را فراهم میکند.
جان، به SE Radio خوش آمدید.
خیلی ممنون. خوشحالم که اینجا هستم.
من امروز در مورد لاگ کردن و زیرساختهای لاگ کردن صحبت میکنم. ما جلسات زیادی در مورد نحوه طراحی نرمافزار، تست آن، تولید آن، فرآیندهای خوب داخل تیم و … داشتهایم. اما جایی میرسد که باید آن را اجرا کنید…
بله، و اینجاست که موضوع لاگ کردن پیش میآید. وقتی زمان زیادی را برای نوشتن نرمافزار صرف کردهاید، لاگ کردن هم یکی از آن چیزهایی است که به زعم خیلی از افراد تا حدی مانند مستندسازی است. از این جهت که ایده خیلی خوبی است اما همیشه چیزی است که از قلم میافتد؛ به نوعی مثل یک فرزند ناتنی برای مهندسی نرمافزار است.
لاگ کردن یعنی چه؟
فکر میکنم موارد زیادی از چیزهای مختلف است. در سادهترین سطح آن، تنها برخی پیامهای استاتیک است که از کرنل و درایورهای کرنل میگیرید؛ خیلی مختصر و مبهم هستند و به نوع خاصی از رمزگشایی نیاز دارید تا بفهمید چه میگویند. از چنین چیزهایی تا ماتریسهای خیلی ساختیافته دادههای مربوط به کارایی میتواند باشد و حتی -همانطور که خیلی از این نوع لاگها را میبینیم- میتواند تنها یک رشته باشد که تفکرات برنامهنویس باشد. جالب است که به لاگها سر بزنیم و ناسزاهایی که در آن هست را جستجو کنیم، هرگاه ناسزایی را در لاگها ببینید میفهمید که در جای جالبی از سیستم قرار گرفتهاید. چیزهای زیاد متفاوتی هست.
ما نمیخواهیم که نمرهی خوبمان در iTune در زمینه مناسب برای خانوادهها! را از دست بدهیم، بنابراین از شما نمیخواهم که مثال بزنید! 🙂
مطمئنم که مهندسها چیزهای زیادی دارند که در موردش جستجو کنند 🙂
هرچند این، عموماً روش خوبی در یک مصاحبه نیست اما از آنجاییکه این ۴ سئوال به نظرم خیلی به هم مرتبط هستند میخواهم همه این ۴ سئوال را یکجا از شما بپرسم: محتوای لاگها چیست؟ کدام بخشهای سیستم لاگها را تولید میکنند؟ مصرفکننده لاگ کیست؟ و به چه منظوری لاگها تولید میشوند؟
بله، اینها پیوند تنگاتنگی با هم دارند. وقتی در مورد لاگهای رایج فکر میکنیم، لاگهای سیستمی و لاگهای برنامه، به ذهن میرسند. در اینجا منظور از برنامه، برنامههایی که شما مینویسید یا برنامههای شخص ثالث (Third Party) متنباز یا تجاری دیگر است. همه این گونه لاگها در همه سطوح مختلف را شامل میشود. این حقیقت که لاگ زدن یک تاریخچه طولانی دارد به این معناست که کاربردهای مختلفی برایش داریم. اگر جاوا کار کرده باشید -من مدت طولانی به آن مشغول بودهام- در آنجا فریمورکهایی برای تولید لاگ وجود دارد که هدف اصلی طراحی آن خوانایی برای انسان بوده است. وقتی تکه کد جاوایی بنویسید و چیز جالب توجهی بیابید احتمالاً آن را با سطح info لاگ میزنید. اگر چیز جالب توجهی بیابید که بد باشد، آن را با سطح warn لاگ میزنید و اگر خیلی بد باشد احتمالاً آن را بعنوان error لاگ میزنید.
شاید یک رویه برتر در نوشتن لاگ این باشد که سعی شود لاگها هدایتتان کنند که چه کاری انجام دهید. وقتی لاگ میزنید حتماً باید به مخاطبین خود فکر کنید. برای بیشتر توسعهدهندهها، مصرفکنندهای لاگ، خودشان هستند. همانند مثال ناسزاگویی که گفتیم، توسعهدهندهها هستند که سیستم را میشناسند و میدانند که تست کردن، سخت یا حتی غیرممکن است با این وجود حتماً میخواهند بدانند که چه اتفاقی میافتد. آنها برای خودشان لاگ میزنند و تمام اطلاعاتی که دارند را انباشت میکنند تا بفهمند که چه رخ میدهد. بنابراین محتوای لاگها میتواند هرچیزی باشد که کمک کند که کسی که سیستم را اجرا میکند بفهمد چه رخ میدهد. یکی از راههایی که من به آن فکر میکنم این است که در دنیای ایدهآل، شما میتوانید هر چیزی که در محیط عملیاتی در حال اجرا است را با gdb یا پروفایلر یا یک ابزار پوشش (Coverage) زیرنظر بگیرید اما اکثر مردم آن قدر پول ندارند. بنابراین لاگها روشی برای فهمیدن آن چه رخ میدهد بدون داشتن دسترسی کامل به آن است. یک روش آن، از طریق صدای برنامهتان است که تلاش میکند که به شما کمک کند که بفهمید چه کار دارد میکند. من فکر میکنم هدف اصلی بیشتر لاگها همین است که تلاش میکنند به شما بفهمانند که چه دارد رخ میدهد. این توضیحات میتواند به همین سادگی باشد که مثلاً من یک درخواست دریافت کردم و آن را برآورده کردم.
یک مثال خوب آن، لاگهای Apache است (که در آن ثبت میشود) که درخواست چه بوده است، چه مقدار زمان برده است، جواب چه بوده است و … . از این جور چیزها که هر کسی وبسرور راه انداخته باشد، با نگاه به لاگهای Apache متوجه آن شده است. این به شما کمک میکند که بفهمید که کلیت سیستمتان چگونه عمل میکند. در عین حال میتواند اهداف دیگری هم باشد بعنوان مثال ما میخواهیم بفهمیم که دادهها چطور از خلال سیستم ما میگذرند و سیستم ما چطور عمل میکند، به همین علت مقادیر سرسامآوری از اطلاعات کارایی را لاگ میکنیم. این دو خیلی متفاوت به نظر میرسند اما هر دو در خدمت یک مقصودند و آن، این است که به ما اجازه میدهد بفهمیم برنامه دارد چه کار میکند. بنابراین فکر میکنم اگر کمی تمرکز کنید برنامهتان به شما میگوید که چه کار میکند.
بسیار خوب، شما اینطور توضیح دادهاید که لاگ زدن کاری است که برنامهنویسها به عنوان بخشی از کار تولید یک برنامه انجام میدهند. کمی در این مورد توضیح دهید که مدل برنامهنویسی برای لاگ زدن چیست؟ برنامهنویسها در قبال چه چیزی کد میزنند تا اطلاعات لاگها را فراهم کنند؟
فکر میکنم روشهای متفاوت زیادی برای این کار وجود دارد. سادهترین مثال در چاپ Hello Word هم به نوعی لاگ است اما امروزه افراد به استفاده از فریمورکها عادت دارند. همه زبانهای برنامهنویسی مدرن، نوعی فریمورک لاگ دارند که کارهایی که به نوعی آزاردهنده است را به عهده میگیرند، (مثلاً شما برای لاگهایتان) برچسب زمان میخواهید، سطح (Level) یا شدت (Severity) میخواهید، بالقوه نام نخ (Thread) را میخواهید، نام متد را میخواهید و بعد میخواهید یک پیام داشته باشید. فریمورکها کاری میکنند که بخش اول آن (متادیتاهایی که کنار پیام قرار میگیرد)، از شما مخفی شود. شما تنها از آن استفاده میکنید و فقط میگویید که این را لاگ بزن و لاگ شما شامل همه آن متادیتاها خواهد بود و واقعاً نیازی نیست که کار چندانی بکنید. بنابراین اگر میبینید که دارید در خروجی استاندارد (Standard Output) یا کنسول خطای استاندارد (Standard Error) مینویسید، احتمالاً دارید کار اشتباهی انجام میدهید، برای همه زبانها، فریمورکهای خوبی وجود دارد و باید از آنها استفاده کنید.
توسعهدهندهها اغلب از فریمورکها برای نوشتن پیامهای لاگ استفاده میکنند اما فکری که به ذهنم خطور کرده است این است که خیلی از چیزهایی که لاگ زده میشود مثلاً اینکه یک متد فراخوانی شد، میتواند یا بخشی از زمان اجرای زبان (Language Runtime) باشد و یا اینکه یک فریمورک جنبهگرا (Aspect Oriented) مانند AspectJ یا SpringAOP خیلی از این لاگ زدنها را برایتان انجام دهد تا از درهم پیچیده شدن پیامهای لاگها با کدهای برنامه جلوگیری کنند. نظر شما در این ارتباط چیست که آیا باید بر روی این نوع فریمورکهای جنبهگرا برای لاگ زدن تکیه کنیم یا اینکه باید آن را مستقیماً در کد انجام دهیم؟
فکر میکنم اینکه بدهید که یک فریمورک همه کارها را برایتان انجام دهد قطعاً یک مزیت است. اما چیزهایی هست که نمیتوانید از اینکه خودتان آنها را انجام دهید، به سادگی اجتناب کنید. اما اگر بتوانید مقداری لاگهای مفید را بصورت مجانی داشته باشید باید اینکار را بکنید. این یکی از جنبههایی است که من با همکارانم در مورد آن مباحثههای جالبی داریم. من بر این اعتقادم که باید هرچقدر میتوانید لاگ بزنید چرا که بدون داده نمیتوانید مشکل را تشخیص دهید. بنابراین اگر فراموش کنید که چیزی را لاگ بزنید و آن چیز در لاگها نباشد، حتی نمیفهمید که آن لاگ وجود ندارد. به قول رامسفلد وضعیت «نمیدانم که نمیدانم» رخ میدهد! اگر بیش از آنچه فکر میکنید لازم است، لاگ بزنید، این شانس را دارید که چیزهایی که اهمیت دارد را در جایی لاگ زده باشید.
حوزه نرمافزار، حوزه پیچیدهای است و به طور خاص، سیستمهای توزیعشده خیلی پیچیده هستند. اگر لاگ نزنید نخواهید فهمید که چه اتفاقی دارد میافتد، بنابراین من به زیاد لاگ زدن، اعتقاد کامل دارم. من عیبی در آن نمیبینم. ممکن است افراد در مورد مسأله کارایی (Performance) آن بحث کنند؛ من به شخصه اعتقاد دارم اگر فریمورک لاگگذاری شما، بزرگترین معضل در کارایی شده است، احتمالاً در موقعیت خیلی خوبی قرار دارید زیرا احتمالاً مسئله خیلی کوچکی دارید. بنابراین من (در بحث لاگ زدن) فکر میکنم بیشترش بهتر است.
شما در مورد برخی انواع فیلدهای ساختیافته که در لاگها ظاهر میشوند صحبت کردید، به عنوان مثال برچسب زمان، IP ماشینی که در حال اجرا است و … . من لاگهای زیادی دیدهام که در آن هر توسعهدهندهای یک پیام متنی محتوی اطلاعات مختلف را لاگ میزند، هر کسی به میل خود این متن را تعیین میکند، بعد باید این پیامها را تجزیه و تفسیر (Parse) کرده و به خاطر آوریم. آیا نباید از فرمتهای ساختیافتهتری مانند JSON و XML استفاده کنیم که راحتتر بشود آنها را تجزیه و تحلیل کرد؟
فکر میکنم برای حجم زیادی از لاگها، بیشک پاسخ مثبت است. فکر میکنم ابزارهای زیادی (از جمله ابزار ما) وجود دارد که به شما اجازه میدهد که از دادههای ساختیافته به نسبت متن تنها، ارزش بیشتری استخراج کنید. اگر شما با این مشکل ندارید که هر زمان برای هر کاری بر روی لاگها از دستورات شخصی سازی شده grep و بدنبال آن sed یا awk و بدنبال آن perl یا phyton یا … استفاده کنید، اگر با این مشکل ندارید، میتوانید نگرانش نباشید. اما یکی از چیزها در مورد لاگها این است که آنها حاوی اطلاعات واقعی هستند. آنها حاوی اطلاعات تأخیرها، اندازه فایلها و مقدار عظیمی دادههای ساختیافته مفید هستند. اگر همه آنها را فقط داخل تکهای متن (یک جمله) بریزید، کار کردن با آنها خیلی سختتر میشود. برقراری همبستگی بین جمله A و جمله B سختتر میشود اما اگر مقداری بر روی ساختیافتگی تلاش کنید، در نتیجه قادر خواهید بود که بگویید این دو پیام با همدیگر ارتباط دارند و دارند به من میگویند که چیزی از کار افتاده یا دارد درست کار میکند.
ما افراد را تشویق میکنیم که (لاگها را در قالبِ) JSON برایمان بفرستند. فکر میکنم همه فریمورکهای لاگی که در عالم وجود دارد بر اساس این فرض هستند که کامپیوترها نسبت به شما در برخورد با هشتاد میلیون خط لاگ بهتر عمل میکنند. فکر میکنم هر کسی که هر روزه صدها گیگابایت لاگ را رسیدگی کرده، میگوید که نمیخواهد این کار را به صورت دستی انجام دهد.
آنچه که نیاز دارید در مورد آن فکر کنید این است که مصرفکننده آن کیست یا در واقع چیست؟ اگر مصرفکننده آن کامپیوتر است، آن را طوری طراحی کنید که برای کامپیوتر راحت باشد. زیرا در صورتی که ابزار کار کند و آنچه نیاز دارید را به شما بدهد، این واقعیت که تحلیل کردن چیزهای تولید شده (اولیه) برای شما به عنوان یک بشر سخت است، دیگر وجهی ندارد زیرا وقتی آن را به هر سیستم دیگری میدهید، آنچه از خروجی میگیرید خیلی ارزشمندتر است.
در گذشته مرسوم بوده که لاگها در فایل نوشته میشدند. ما در حال گذار از آن هستیم و من در این مورد صحبت خواهم کرد. اما کمی در مورد معماری لاگهای مبتنی بر فایل صحبت کنید، فرآیند کار چگونه است و فایلها چگونه پردازش میشوند؟
بله، این به همان grep و sed و perl و این جور چیزها بر میگردد. فکر میکنم فایلها خوب هستند به این معنا که فایلها یکی از مقاومترین انتزاعهایی هستند که هر کسی میتواند به آن برسد و لاگ کردن در فایل هیچ مشکلی ندارد. مشکل اینجاست که (این روش) امروزه مقیاسپذیر نیست. از چندین جهت مختلف مقیاسپذیر نیست. به عنوان مثال، اگر شما بر روی EC2 باشید و نمونههای مختلف (ماشین مجازی) باشند که میآیند و میروند. اگر مراقب نباشید وقتی میروند، لاگهای شما هم از دست میرود. بعد به این فکر میافتید که به یک اسکریپت نیاز دارید تا قبل از خاموش شدن اجرا شود تا این لاگها را بردارد و درجای دیگری بگذارد. همه این جور مسائل را دارید. حتی اگر تعداد کمی ماشین داشته باشید نیاز دارید که به این فکر کنید که اگر یک ماشین، بیدوام است این برای لاگهای روی آن ماشین به چه معناست؟ و برخی از آنها کاملاً بیدوام هستند. منظورم این است که اگر ماشینی آنطور که انتظار داشتهاید، عمل کرده، لاگهای سیستمی آن ماشین که چندین روز در حال اجرا بوده و بعد خاموش شده است، احتمالاً کاملاً بیارزش هستند اما فکر میکنم لاگهای برنامههای کاربردی آن ماشین احتمالاً اینطور نیستند. آنها احتمالاً چیزهایی هستند که میخواهید داشته باشید و مطمئن شوید که ماشین کاری که لازم بوده را انجام داده باشد. این یک جنبه دیگرش است.
همینطور چیزهای دیگری هم هست که هرکسی آنها را دارد، (به عنوان مثال) در نهایت خود را در شرایطی مییابید که اگر استراتژی چرخشی درستی برای لاگها نداشته باشید، ماشین را از لاگ پر میکنید تا از کار بیافتد چرا که دیسک پر میشود. ابزارهای زیادی وجود دارد که چرخش لاگها و منقضی شدن لاگها را برایتان انجام میدهد اما مجبورید که برای برخورد با این مشکل، یک لایه ابزار دیگر را بیافزایید که امروزه میتوانست اصلاً وجود نداشته باشد. شما باید لاگ را خارج از ماشین بگذارید و آن را در جایی مرکزی قرار دهید و نگرانش نباشید.
شما به یکی از مسائلی که من فکر میکنم یکی از بزرگترین مشکلات کار با فایل است اشاره نکردید، اینکه اگر به دنبال چیزی باشم باید صبر کنم که درایو چرخشی دیسک، کلی چرخ بزند تا به رکوردی برسد که من به دنبالش میگردم.
این درست است. مانند grep که اینطور است. تکنولوژیهای بهتری نسبت به sed و awk برای تحلیل دادههایتان وجود دارد. یک مثال برجسته آن موتورهای جستجو هستند. اگر بدانم که برنامه جاوای من Exception ها را لاگ میزند، جستجوی آن در یک موتور جستجو نسبت به گشتن برای آن در هزارها فایل، بسیار راحتتر است. این یکی از چیزهایی است که افراد تا زمانی که آن را در حین کار کردن نبینند، قدرتش را نمیفهمند. افراد عادت دارند که خیلی سریع در گوگل و بینگ جستجو کنند اما برخلاف انتظار، فکر نمیکنند که همان قدرت باید برای جستجوی لاگها بر روی ماشینها بکار رود. مدیرسیستمها (Sys Admin)، افراد توسعه و عملیات (DevOps) و توسعهدهندهها به همین لاگ زدن بر روی ماشین و دنبال فایل گشتن و بعد تلاش برای استخراج اطلاعات از آن، راضی هستند و سخت است که این عادت را عوض کنیم. فکر میکنم بخشی از چالش کار این است که سعی کنیم افراد بفهمند که ابزارهای بهتری وجود دارد و تنها باید از آنها استفاده کنند.
شما من را به سمت سئوال بعدیام بردید که درباره معماریهای پیشرفته لاگ کردن مبتنی بر شبکه و موتورهای جستجو است. درباره تاریخچه معماریهای پیشرفته لاگ کردن صحبت کنید و توضیح دهید که زیرساختهای پیشرفته لاگ چطور کار میکنند.
فکر میکنم این یک تکامل است. حداقل در دنیای Unix همواره، SysLog وجود داشته است. SysLog براساس این ایده است که لاگهایتان را به یک محل مجتمع، بفرستید. یک دلیل خیلی خوب برای آن وجود دارد که پیش از این در مورد آن صحبت کردم (و آن این است) که دیسک پر نشود. فکر میکنم این ایده که همه لاگهای تمامی سیستم در یک محل باشد، به شدت قدرتمند است و فکر میکنم افرادی که لاگها را جدی میگیرند همواره با استفاده از هر تکنولوژی که فراهم باشد، این رهیافت را به خدمت میگیرند که در ابتدا میتواند چیزهایی از قبیل SysLog باشد یا هر ابزار دیگری برای انتقال سریع در شبکه باشد. اما همچنان سرانجام باید، با مسأله انتقال سریع در شبکه درگیر شوید و همچنان مجبورید که برای پیدا کردن چیزها با ابزارهای کاملاً ابتدایی از قبیل grep درگیر شوید.
فکر میکنم این ایده که در یک موتور جستجو، مجتمع شوید انقلاب بزرگی بوده است که در چند سال اخیر رخ داده است و با Splunk آغاز شد. فکر میکنم افراد متوجه شدند که وقتی چیزها را در یک جا جمع کنند هرکاری بخواهند میتوانند انجام دهند، چه (اینکه بصورت) توزیعشده باشد و چه حتی در فایلهای مجزا جمع شود. وقتی که همریخت باشد، یعنی وقتی یک واسط یکسان برای همه دادههای لاگتان دارید میتوانید کارهایی را انجام دهید که به روشهای دیگر به سادگی نمیتوانید انجام دهید. و فکر میکنم جستجو، روش بسیار قدرتمندتری فراهم میکند. زبان جستجو، نسبت به زبان grep خیلی گویاتر است و قدرت بیشتری دارد.
ما عادت داریم که در کار با فایل به عبارات منظم (RegExp) فکر کنیم زیرا عبارات منظم یک روش قوی برای پیدا کردن چیزهای مورد نظر در فایل است. عبارات منظم یکی از چیزهایی است که اگر بدانید که دارید چه کار میکنید، فوقالعاده قدرتمند و مفید هستند اما فکر میکنم مشکل اینجاست که خیلی از افراد فکر میکنند که میدانند چطور از عبارات منظم استفاده کنند اما واقعاً نمیدانند و زمان طولانی برای پیدا کردن عبارت منظم درست برای پیدا کردن یک چیز، هدر میدهند و بهتر است که از ابزاری استفاده کنند که صراحتاً برای پیدا کردن چیزها طراحی شده است که همان موتور جستجو است. و امروزه موتورهای جستجو فراتر از فقط grep هستند. موتورهای جستجو از خیلی از جنبهها به غیر از آنکه فقط چیزها را پیدا کنند، تحلیل هم میکنند. به عنوان مثال میتوانید تحلیلهای آماری بومی را اجرا کنید؛ شما جستجویی میکنید که به سندهای خاصی محدود میشود و بعد تحلیلهای آماری را بر روی آنها و بر روی فیلد خاصی در سند انجام میدهید. شما این موتور تحلیل فوقالعاده قدرتمند را بر روی ابزاری بدست میآورید که به صراحت بگویم که افراد از قدرت آن آگاه نیستند.
شما درباره فیلدهای دارای نوع ساختیافته مانند برچسب زمانی و گره (Node) و نام کاربری و … صحبت کردید و بعد از آن Lucene را داریم که ایندکس کل متن را به شما میدهد و میتوانید پرسوجو (Query) بر روی آنها را آغاز کنید. آیا این یک حوزه جدید برای تحلیلگران نمیگشاید که در دادههای لاگ خبره شوند و بتوانند از آن دادهها، با استفاده از قابلیتهای مشابه با پرسوجوهای از پایگاه داده، ارزش کسب و کار ایجاد کنند؟
قطعاً. اگر از پیشزمینه پایگاه دادههای سنتی رابطهای آمده باشید، کمی دلهرهآور است. واضح است که زبان متفاوت است و طیف ابزارهایی که فراهم است خیلی محدودتر از آن چیزی است که عادت داشتهاید. اما بله،
وقتی یک ایندکس توزیعشده داشته باشید به این معنی که بین ده یا صد یا هزار ماشین، پخش شده باشد، میتوانید موتور جستجو را نوعی موتور MapReduce کوچک درنظر بگیرید زیرا آنچه در پشت صحنه اتفاق میافتد این است که شما جستجویی را انجام میدهید و مستنداتی که با آن جستجو مطابقت دارند را مییابید و یک طیف جریان از آنها راه میاندازید. مثال سادهاش، طیف جریان براساس امتیاز است که مستنداتی که امتیاز بالاتری نسبت به بقیه گرفتهاند برای نمایش در خروجی انتخاب میشوند اما این جریانها، بصورت موازی و همزمان بر روی همه دادههایتان در تمامی ایندکس رخ میدهد. و شما میتوانید کدهایی را حین عبور هر مستند بر روی آن اجرا کنید.
بعنوان مثال اگر لاگهای Apache داشته باشید و هم برای رسیدن درخواست و هم آماده شدن حجمی از صفحه بازگشتی تأخیر داشته باشید، میتوانید تعداد بایتهای بازگشتی در تأخیر مشخصی از زمان درخواست را محاسبه نمایید که ارزشی است که از پیام لاگ شما مشتق میشود و مستقیماً از آن قابل دریافت نبود. اگر میخواستید میتوانستید این کار را در لاگ هم انجام دهید اما میتوانید اینکار را در همه جا به صورت موازی انجام دهید و بعد کارهای آماری از قبیل پیدا کردن مینیمم و ماکزیمم و انحراف از معیار و … میتواند بر روی این دادههایی که بصورت مستنداتِ در حال عبور، سادهسازی شدهاند، انجام شود، مانند ضبط صوت که جریان صوتی از روی هد عبور میکند و این هد است که آنچه میخواهیم را انجام میدهد.
یکی از دلایل اصلی استفاده از لاگها، خطازدایی و Debug است اما اکنون که برای لاگ یک سیستم توزیعشده داریم و ایندکسی را جستجو میکنید که ممکن است بر روی سرورهای مختلف توزیع شده باشد، آیا این خود باعث ایجاد انواعی از خطاها نمیشود؟ مثلاً فایروالی که در مقابل مسیر عبور پیامها تنظیم شده باشد و یا اینکه یک گره، خاموش باشد و …
مطلب جالبی است. قطعاً در مورد هر کسی که سیستم توزیعشده ای بسازد این درست است. حتی در مورد سیستمهای دیگر هم همینطور است اما در مورد سیستمهای توزیع شده به صورت خاص اینگونه است. نوعی مسأله بازگشتی جالب رخ میدهد به این معنی که ما سیستم توزیعشدهای داریم که قرار است مسألهای را حل کنند اما وقتی چیزها خراب میشود، روشی که برای متوجه شدن این خرابیها داریم، از طریق لاگهایی است که در خود سیستم جاسازی شده است بنابراین نمیتوانیم مشکلات درون سیستم را شناسایی کنیم.
ما به نوعی، از مشکل دسترسپذیری (Availability) دائماً رنج میبریم. چیزهای بزرگ مثلاً اینکه یک گره از کلاستر، خارج شده است را میفهمیم اما چیزهای کوچکتری هم هستند مثلاً اینکه بروزرسانی یک گره هنوز انجام نشده است و به همین خاطر در نتایج جستجو ناسازگاری خواهیم داشت.
همه این چیزها، مواردی است که ما لاگ میزنیم و آنها را در سیستم قرار میدهیم تا بتوانیم مشکلات را شناسایی کنیم. اما درست است، مسأله برای ما کمی مانند مرغ و تخممرغ است. مهمترین چیز برای ما این است که دادهها را از دست ندهیم یعنی حتی اگر مشکلی در سیستم باشد نوعی خوددرمانی داشته باشیم که هر از چندوقتی، خرابیها را تعمیر کنیم. ما قطعاً در این جهت حرکت میکنیم و فکر میکنم راههای زیادی وجود دارد که سیستمی لاگها را دریافت کرده و تلاش کند که متوجه اتفاقات رخ داده، بشود و به شما این اجازه را بدهد که از مکانیزمی مانند هشدار استفاده کنید تا یک پایانهی REST را در جای دیگری فراخوانی کند که این امکان را بدهد که بتوانیم در آینده، زمانی، یک سیستم خوددرمانی کامل بسازیم. این مسأله جالبی است و یک چالش است اما من فکر میکنم هرچه درباره موارد کاربرد سیستممان عمیقتر شویم، این موارد کاربرد اطلاعات بیشتری به ما نمایان خواهند کرد.
آیا مشاهده کردهاید که افراد برای انتقال رکوردهای لاگ به سرورهای لاگ، یک کارت شبکه دیگر را به گرههای خود اضافه کنند تا (این دادهها) برای انتقال یافتن به رقابت با دادههای کابران و برنامهها نپردازند؟
معمولاً خیر. عموماً دادههای عظیمی را نمیبینیم که از یک ماشین منفرد بیایند. واضح است که اگر صدها یا هزارها ماشین درکار باشد، مجموع دادههایشان زیاد خواهد شد اما معمولاً بر روی برنامه مشتری تأثیر نمیگذارد. منظورم این است که نوعی نویز ایجاد میکند، شاید ۵ یا ۱۰ درصد ترافیک شبکه به لاگ مشغول شود اما از افرادی که تا به حال شنیدهام، این دلیل اصلی ندامت نبوده است.
به طور معمول برنامهها چه حجمی لاگ دارند؟ چند گیگابایت یا ترابایت از رکوردهای لاگ، معمول است؟
ما دادههای زیادی میگیریم. برخی برنامهها و مشتریهای ما هستند که لاگهای زیادی تولید میکنند اما بیشتر برنامهها لاگهای زیادی تولید نمیکنند. سخت است که یک چیز خیلی عمومی درموردش بگوییم. برای ما به طور معمول هر پیام لاگ بین نیم کیلو تا یک کیلوبایت است. البته این (رقم) کمی گمراهکننده است چون ما افراد را ترغیب میکنیم که (دادهها را با فرمت) JSON بفرستند و JSON، حجیم است.
من فکر میکنم اگر ما لاگها را به دو دستهی لاگهایی که افراد بر روی آنها کنترل دارند و لاگهایی که بر روی آنها کنترل ندارند، تفکیک کنیم، قطعاً یک تفاوت اساسی وجود خواهد داشت زیرا بر روی لاگهایی که کنترلی بر روی آن ندارید یعنی در لاگهای سیستمی و لاگهای مربوط به محصولات متنباز یا تجاری که استفاده میکنید، معمولاً پیامهای لاگ، کوتاهتر هستند زیرا عموماً برای این منظور نوشته شدهاند که مصرفکننده آنها آدمها باشند اما امروزه خیلی افراد لاگهایی مینویسند که مصرفکننده آنها ماشین است و به همین خاطر، مطوّلتر هستند و بنابراین بزرگتر میشوند.
فکر میکنم لاگهای کاملاً خالص به سبک قدیمی حدود ۲۰۰ یا ۳۰۰-۴۰۰ بایت باشند و لاگهای با سبک جدید ۱ کیلو و بالاتر هستند. البته ما مشتریهایی داریم که پیامهایی با طول ۱۰۰ یا ۲۰۰ کیلوبایت هم میفرستند و مشکلی هم نیست، اگر دادههایی که میخواهید لاگ بزنید این حجم را دارد میتوانید آنها را لاگ بزنید.
شما اشاره کردید که مثلاً میشود دادههایی برای یک سرور پایگاه داده تولید کرد اما شما این کار را نمیکنید. آیا یک گام میانی وجود ندارد که لاگهایی که سرور تصمیم گرفته که ثبت کند در آنجا جمع شوند و بعد آنها به JSON یا قالب دیگری تبدیل شوند؟
بله، چندین راه مختلف برای حل این مشکل وجود دارد که وابسته به محصولی است که استفاده میکنید. آنچه ما انجام میدهیم این است که ما دستهای از قالبهای استاندارد را پشتیبانی میکنیم، من به (لاگهای) Apache اشاره کردم اما ۱۰ یا ۱۵ یا ۲۰ قالب استاندارد دیگر هم وجود دارد. مثلاً قالب پایگاه داده و شما میتوانید (دادهها را با همان قالب) مستقیماً برای ما بفرستید و ما آنها را دریافت کرده و عمل صحیح را درقبالشان انجام میدهیم.
یک رهیافت جداگانه این است که خودتان یک چیزی بنویسید. ما در واقع برای اموری که خیلی خیلی ساده باشد این کار را میکنیم. برای مثال ما مشکلاتی با ZooKeeper داشتیم. ZooKeeper هم یک پروژه Apache است یک پروژه Apache است اما لاگهایشان متنی و به صورت جمله بود. در واقع آنچه آنجا انجام دادیم این بود که در انتهای فایل مینوشتیم و به دنبال پیام خاصی که در مورد انتقال فایل لاگ به دیسک (fsync) بود میگشتیم و یک اخطار در این زمینه وجود داشت که انتقال فایل خیلی طول کشیده است و در حالتی که این اخطار رخ میداد، انتهای فایل را خوانده (tail) و عبارت منظم را در آن جستجو کرده (grep) و بعد محتوا را استخراج کرده و با استفاده از لاگر آن را در سیستم خودمان لاگ میزدیم.
این یکی از کارهایی است که میتوانید انجام دهید. البته چیزی نیست که من توصیه کنم بر روی آن خیلی سرمایهگذاری کنید زیرا به جهات مختلفی ممکن است به خطا بخورد و مجبور شوید مدت زیادی را صرف آن کنید.
روش سومی هم وجود دارد که از چیزی مشابه با Logstash استفاده کنید. یکی از راههایی که میتوان Logstash را توضیح داد این است که نوعی ATL برای همه نوع داده است که تعداد زیادی منبع (Source) و تعداد زیادی سینک (Sink) دارد. شما میتوانید فایل را خوانده و تبدیل به Logstash کنید به این ترتیب که تعدادی قاعده در Logstash تعریف کنید تا هر نوع ساختار دادهای که میخواهید را منتشر کرده و برای ما بفرستد. محصولات مختلف دیگری هم وجود دارند که عاملهایی (Agent) دارند که اینکار (عمل تبدیل) را برایتان انجام میدهند.
بنابراین تنها سئوالی که باقی میماند این است که چه چیزی میخواهید بر روی ماشین خود راهاندازی کنید تا این مسائل را حل کنید. اما ما به این رهیافت رسیدهایم که هیچ چیز نمیخواهیم. SysLog فراگیر است و همه با آن راحت هستند، روش ما این است که آن را به دست ما برسانید و ما حلش میکنیم. اگر میخواهید خودتان این کار را انجام دهید، قطعاً میتوانید این کار را انجام دهید اما در اینصورت دارید یک لایه اضافی به سیستمتان اضافه کنید که بالقوه میتوانستید از آن اجتناب کنید.
وقتی به این معماریهایی که سیستمهای لاگ پیشرفته دارند، نگاه میکنم، سئوالی برایم پیش میآید و آن، این است که اگر به قدیم برگردیم، آنجا شما دادههای کسب و کار را در یک پایگاه داده واقعی قرار میدادید که به شدت مانیتور میشد و از آن نسخه پشتیبان گرفته میشد و تلاش زیادی صرف این میکردید که هیچگاه دادهای را از دست ندهید و کاملاً در دسترس باشد و در کنار آن، این روش خیلی مستحکم لاگگذاری مبتنی بر فایل هم وجود داشت که اگر فایلی را از دست میدادید، تنها دادههای لاگ از دست میرفتند. به این ترتیب اینکه برنامه، (لاگها) را مستقیماً به داخل فایل بریزد روش خیلی مستحکمی فراهم میکرد. اما الان به روشی از لاگگذاری رسیدهایم که لاگها به پایگاه داده میروند و بنابر گفته شما، خیلی وسواس به خرج میدهیم که در این پایگاه داده هیچگاه دادهها از دست نرود و در آن (لاگها) به صورت فیلدهای ساختیافته در قالب تعدادی ستون ذخیره میشوند و یک پروتکل شبکه برای آن تدارک دیده شده است.
بنابراین آیا در این نقطه، به جایی رسیدهایم که همه چیز در پایگاه داده قرار میگیرد و فقط انواع مختلفی از پایگاههای داده داریم که برای انواع مختلف دادهها بهینه شدهاند؟ و آن تفاوت اساسی که (در گذشته) بین دادههای مهم و دادههای غیرمهم بود دیگر وجود ندارد؟
بنابراین آیا در این نقطه، به جایی رسیدهایم که همه چیز در پایگاه داده قرار میگیرد و فقط انواع مختلفی از پایگاههای داده داریم که برای انواع مختلف دادهها بهینه شدهاند؟ و آن تفاوت اساسی که (در گذشته) بین دادههای مهم و دادههای غیرمهم بود دیگر وجود ندارد؟
فکر میکنم داریم به آن نقطه میرسیم. یکی از چیزهایی که همواره در مورد لاگها برای من جالب بوده است این است که آنها اطلاعات متادیتای واقعاً مهمی همراه خود دارند که خیلی از دادههای دیگر آن را ندارند و آن برچسب زمانی است. یکی از راههای فکر کردن به سیستمهای لاگ این است که آنها واقعاً سریهای زمانی هستند و علاوه بر این، آنها بلادرنگ هستند و علاوه بر اینها، آنها در واقع، بیش از اینکه فقط سیستمهای جستجو باشند، سیستمهای تحلیلگر (Analytic Systems) هستند.
فکر میکنم برای برخی از انواع خاص دادهها، (این سیستمهای پیشرفته لاگ)، بهترین تطابق را دارند. البته من توصیه نمیکنم که افراد، ۱۵ پتابایت پایگاه داده مقالات را انباشت کنند و از ElasticSearch استفاده کنند زیرا همانطور که گفتم کارهایی هست که نمیتوانید انجامش دهید اما واقعاً فکر میکنم که این مرز در حال کمرنگ شدن است.
در واقع، اگر پایگاه داده سری زمانی بلادرنگی داشته باشید که تحلیل بر روی دادههای شبهساختیافته را پشتیبانی کند، میتوانید از آن برای حل مسائلی به غیر از لاگ هم استفاده کنید. ما مشتریهایی داریم که این کار را میکنند و دادههایی برای ما میفرستند که به معنای دقیق کلمه، دادههای لاگ نیستند. (اینکار را میکنند) زیرا میتوانند از سیستم ما برای تحلیلهایی که میخواهند بر روی دادههایشان داشته باشند، استفاده کنند.
بنابراین فکر میکنم خطوط در حال کمرنگ شدن هستند و واقعاً جذاب است که عرضه تکنولوژیهای مختلف ادامه دارد. دلیلی که پیش از این اشاره کردم که به نظر من جستجو نوعی MapReduce کوچک است، این است که فکر میکنم امروزه افراد واقعاً با MapReduce به عنوان روشی برای حل مسائل آشنا هستند. این (تکنولوژیها) وجود دارند و به علاوه انواع پایگاه دادههای NoSQL از قبیل Cassandra و CouchDB و … را هم داریم، همینطور پایگاه دادههای رابطهای سنتی را هم داریم. انواع مختلفی از تکنولوژیهای دیگر ذخیره دادهها هم وجود دارند که هر کدام قدرت خود را دارند و شما باید گزینه درستش را استفاده کنید.
اغلب برای افراد جذاب است که بنشینند و فکر کنند که در تمایز با پایگاه دادههای سنتی و حتی چیزی مانند Hadoop، چه کارهایی با چیزی که خاصیت مبتنی بر زمان دارد و بلادرنگ است میتوانند انجام دهند. در واقع، همان مسأله را به شکل دیگری حل میکنید، برخی مسائل به خوبی تطبیق مییابند و برخی تطبیق ندارند. در واقع، (آنچه گفتم) روش طولانیتری برای گفتن همین است که ابزار مناسب را انتخاب کنید 🙂
در فضای سیستمهای لاگ، دو روش -که ممکن است شما آنها را مدلهای تجاری بخوانید- وجود دارد. یکی ابزارهای متنباز از قبیل Graylog و دیگری میزبانهای لاگ بعنوان خدمت هستند که Loggly و Splunk و … از آن دسته هستند. برای یک برنامهریز فضای ذخیرهسازی و یا معمار IT، برای اینکه سیستمش را در یک پلتفرم مناسب قرار دهد در این زمینه کدام رویه فکری خوب است؟
در اینجا چند نکته وجود دارد. یکی این است که این ابزارها لذتبخش هستند. اگر میخواهید لذت ببرید و قیود سختی هم ندارید میتوانید با Graylog ، Silk یا ELK یا هر چیز متن باز دیگری کار کنید (وقتی ۳ ابزار متنباز ElasticSearch و Logstash و Kibana در ترکیب با هم استفاده میشوند، به آنها استک ELK اطلاق میشود – مترجم). چیزهای زیادی برای یادگیری وجود دارد و از انجام آن لذت زیادی خواهید برد اما فکر میکنم از دیدگاه تجاری، استفاده از ابزاری که بعنوان خدمت (as a Service) عرضه شود، منطقیتر است. شما میتوانید ابزارهای متنباز را بیابید و آنها را به راه بیاندازید. معمولاً میتوانید آنها را خیلی سریع راه بیاندازید، نمیخواهم اینجور وانمود کنم که راه انداختنش خیلی پیچیده یا پرهزینه است اما فکر میکنم در طی زمان متوجه میشوید که برای آن، هزینه زمانی، پرداخت کردهاید و لزوماً این کار را دوباره انجام نخواهید داد.
مانند این است که بحث کنید که چرا یک سرور ایمیل نداشته باشید؟ قطعاً میتوانید اینکار را بکنید اما Gmail و هزارها شرکت دیگر این کار را کردهاند و این کار را بهتر از آنچه شما بتوانید، انجام دادهاند. به نظر من، مانند این بحث است. فکر میکنم افراد کاملاً متوجه نیستند که چه مدت باید زمان صرف کنند تا این سیستمها را به کاری بیاندازند که واقعاً میخواهند. در واقع، فکر میکنم این حقیقت که شرکتهای زیادی وجود دارند، به این معنی است که محصولات تجاری، خیلی خیلی سریع رشد میکنند. ما تیمی داریم که در آن ۲۵ نفر به تنها چیزی که فکر میکنند نحوه برخورد با لاگها است، بنابراین شانس اینکه بتوانید بهتر از ما این کار را انجام دهید، کم و کمتر میشود.
فکر میکنم احتمال اینکه در یک ابزار کاملاً متنباز، یک نفر قبلاً مسألهای که شما دارید را حل کرده باشد، غیرممکن نیست اما فکر میکنم لازم باشد جمعیت زیادی حول یک پروژهی متن باز گرد آیند تا چنین چیزی محقق شود. چون همه لاگهای Apache دارند بنابراین لاگهای Apache با همه پروژههای متن باز، سازگاری دارد اما مثلاً همه، Zookeeper ندارند و ممکن است Zookeeper با آنها سازگار نباشد. بنابراین فکر میکنم مزایای مشخصی هم وجود دارد که به کس دیگری پول بدهید که مسأله را برایتان حل کند.
همانطور که گفتم اگر هیچ قیود سختی ندارید و زمان و بودجه نامحدود دارید، بروید و این کار را بکنید، لذت زیادی دارد و کاملاً توصیه میکنم اما احتمالاً در این زمانی که دارید کارهای بهتری میتوانید انجام دهید.
در مورد واسطهای (گرافیکی) که برای پیدا کردن دادههای لاگ پس از جمعآوری آنها در یک سیستم فراهم شده است، صحبت کنید.
این یکی از چیزهای خیلی مهم برای رسیدگی به حجم زیاد دادهها و حتی مقدار کمتر آنها است. فکر میکنم افراد در گشتن به دنبال دادهها جنبه بصریسازی (Visualization) آن را نادیده میگیرند. در این مورد مثالی میزنم. اگر شما مانند ما به صورت دورهای، یک نسخهای از سرویس جاوایتان را مستقر کنید، و به دنبال Exception بگردید، به سادگی با مشاهده تعداد مطابقتها در محور زمان، میتوانید بفهمید که آیا دارید بهتر میشوید یا خیر. به سادگی میتوانید مشاهده کنید که آدمها، در شناسایی ناهنجاریها به صورت بصری، قابلیت خوبی دارند. فکر میکنم یکی از مسائلی که به شدت مهم است یافتن روشهایی است که دادهها را نمایش دهیم. سیستم، کارهای سخت از قبیل تولید (دادهها) و بصریسازی را انجام میدهد اما همچنان از این مزیت که آدمها در این امور (شناساییهای بصری) خیلی خوب هستند، استفاده میبریم.
نکته جالب برای من این بوده است که چیزهایی را فهمیدهایم که مهم بودهاند که واقعاً فکر نمیکردیم. برایتان مثالی میزنم: میدانیم در مورد دادههای ساختیافته ما میتوانیم مقدار هر کدام از فیلدها را ببینیم، یکی از امکاناتی که اول نداشتیم اما بعداً اضافه کردیم این است که اگر بر روی یک فیلد مثلاً Http Status کلیک کنید، یک گراف خیلی کوچک میبینید که بلافاصله به شما نشان میدهد که فرضاً شما اغلب مقدار ۲۰۰ را (برای این فیلد) داشتهاید و گاهی نیز شاید ۳۰۳ و ۴۰۴ را داشتهاید. اما این اطلاعات به صورت آنی به شما داده میشود و میتوانید ادامه داده و به باقی کارتان بپردازید. یکی از چیزهایی که واقعاً انتظار نداشتیم و به آن بر خوردیم این بود که باید کاملاً یکنواخت عمل کنیم، به این طریق است که افراد از امکانات یک محصول استفاده میکنند. ما فکر میکردیم که این ویژگی وجود داشته تا بتوانید برای اصلاح جستجوها از آن استفاده کنید اما آنچه در واقع متوجه شدیم این بود که این ویژگی وجود داشته تا بتوانید بر روی چیزی یک بررسی سلامتی انجام دهید. چیزهایی از این قبیل همواره جالب هستند. فکر میکنم افراد قدرت برخی بصریسازیها از قبیل گرافهای سری زمانی و نمودارهای دایرهای و … که ما تولید کردهایم را دست کم گرفتهاند. اینها یکی از ویژگیهای خیلی خیلی مهم سیستمهای تحلیل لاگ هستند که کمک میکند که بتوانید عملکرد سیستمتان در طی زمان را متوجه شوید.
مثال دیگری میزنم. وقتی برنامهنویسی میکنیم ممکن است بازههایی با تأخیرهای زیاد ببینیم. در این حال، همه سردرگم هستند و از هم میپرسند که چه رخ داده است؟ اما اگر در طی زمان به آن نگاه کنید، آنچه دیده میشود این است که سر هر ساعت یک پالس شدید رخ میدهد که ناشی از یک وظیفه پشت صحنه (Background Job) است که در آن محیط در حال انجام است. بنابراین اگر قادر نباشیم که روز قبل، یا هفته قبل یا ماه قبل را ببینیم و الگوها را دریابیم، اینها رفتارهای کاملاً غلطاندازی خواهند بود، مانند این خواهد بود که بخواهیم مشکلی را تشخیص دهیم که وجود ندارد به این معنا که ما آن مشکل را خیلی جدیتر از آنچه واقعاً هست میبینیم اما اگر بتوانیم آن را در طول زمان ببینیم، میفهمیم که بله، یک مشکلی داریم، اما آنقدر که فکر میکردیم جدی نیست و سیستم همواره از آن نجات مییابد و ما دقیقاً میدانیم که چه زمانی رخ میدهد بنابراین میتوانیم کار تشخیص آن را بهتر انجام دهیم.
بنابراین اگر به عنوان فردی که در قبال سیستم مسئول است بتوانید با نوعی نمودارها و گرافها از نحوه رفتار سیستمتان اطلاع پیدا کنید، به حس بهتری خواهید رسید. دلیل قدرتمند بودن گرافهای ترافیک و نمودارهای چرخههای روزانه و هفتگی و این جور چیزها این است که میتوانید به آنها نگاه کنید و مثلاً بفهمید که بله، همه در ساعت ۷ صبح در ساحل شرقی از خواب بیدار میشوند و در ساحل غربی در نیمه شب به خواب میروند به همین خاطر است که حجم ترافیک در این زمان بیشتر است. این چیزها بیاهمیت به نظر میرسد و تا حدودی همینطور هم هستند اما اگر در دادههایی که قبلاً آنها را نمیدیدهاید -که در مورد بیشتر دادههای لاگ این اتفاق میافتد و بیشتر مانند این است که بخواهید از سوراخ یک سوزن آنها را ببینید و خیلی دشوار است- بتوانید آنها را ببینید، نحوه فکر شما در مورد سیستمتان را تغییر میدهد.
این اطلاعات همیشه وجود داشته است اما راهی برای بدست آوردنشان نداشتهایم.
دقیقاً. آنها دادههای تاری هستند که همه جا قرار گرفتهاند، نه فقط در مورد لاگها بلکه در مورد همه چیزها اینطور است.
چه منابعی برای یادگیری بیشتر در مورد لاگ، وجود دارد؟ آیا شما توصیهای دارید؟
یک کتاب واقعاً خوب وجود دارد که اسمش از خاطرم رفته.
بعداً به من بگویید تا آن را در نوتهای مصاحبه قرار دهیم. (کتابی که لینکش قرار گرفته است، کتاب لاگ زدن و مدیریت لاگ است – مترجم)
اطلاعات زیادی در بلاگ ما و بلاگهای رقیبان ما وجود دارد. در اجتماع Logstash چیزهای خوبی وجود دارد که در مورد آن صحبت نکردیم اما فکر میکنم احتمالاً بزرگترین اجتماع متن باز در مورد لاگ باشد.
اگر افرادی بخواهند در مورد Loggly بیشتر بدانند چه کار کنند؟
آیا توییتر یا بلاگی دارید که بخواهید به شنوندگان ما معرفی کنید تا سر بزنند؟
ما یک بلاگ در Loggly داریم: Loggly.com/blog دوست داریم افراد بیایند و آن را بخوانند.
جان گیفارد، از اینکه برای مصاحبه به رادیوی مهندسی نرمافزار آمدی خیلی ممنونم.