نبض سرور زیر سبابه‌ی شما!

وقتی اتفاق بدی رخ میده، اول باید بفهمیم چه اتفاقی افتاده و این یعنی نیاز به کلی داده از شرایط و محیط در زمان مورد نظر، و به دنبال اون مسئله‌ی جمع‌آوری و جستجو در میان داده‌ها، تشخیص شرایط خطا و... . این یکی از مسئله‌هایی بود که در تیم میان‌افزار باید حل می‌کردیم و برای حل‌ش باید چند تا کار انجام می‌دادیم:

  • انتخاب کنیم که چه داده‌هایی رو باید جمع کنیم (که به پروژه و تکنولوژی‌های مورد استفاده وابسته است)
  • ابزاری برای جمع‌آوری داده‌ها انتخاب و راه‌اندازی کنیم
  • روشی برای استفاده کارآمد از داده‌ها پیدا کنیم. از جستجو تا دیداری‌سازی (Visualization) تا یادگیری ماشین و بیشتر از اون
  • به روشی از وقوع شرایط بد باخبر بشیم
  • و...


کجا ایستاده بودیم؟

ما وب سرویس‌هامون رو با .NET توسعه داده بودیم که روی سرورهای ویندوزی مستقر بودن، و از MongoDB، Redis و Kafka روی ماشین‌های لینوکسی استفاده می‌کردیم. تیم زیرساخت برای پایش سرورها PRTG رو راه‌اندازی کرده بود و موارد مربوط به سخت‌افزار سرورها رو رصد می‌کرد. اما چند تا مشکل با اون داشتیم:

  • برای ساخت نمودار و داشبورد، PRTG واقعا عقب افتاده است (!!) و برای ما Visualization مهم بود.
  • به طور مستقیم امکان جمع‌آوری شاخص‌های عملکردی پایگاه‌داده‌ها و نرم‌افزارهامون رو نداشت.
  • جای ابزار گردآوری Log خالی بود.

کمی قبل از اینکه ما این مسیر رو شروع کنیم، از یه طرف، حامد برای پر کردن خلأ بین اپلیکیشن‌ها و ابزارهایی که می‌تونستن از طریق Web API اطلاعات مورد نظرشون رو جمع کنن (مثل PRTG) پروژه‌ای راه‌انداخته بود به اسم Detectors. و از طرف دیگه، به صورت محدود از ELK و Filebeat برای گردآوری Log استفاده کرده بودیم.

حامد خیلی به اخترفیزیک علاقه‌منده و اسم Detectors رو از آشکارساز ذرات گرفته (عکس از مجله Science)
حامد خیلی به اخترفیزیک علاقه‌منده و اسم Detectors رو از آشکارساز ذرات گرفته (عکس از مجله Science)

چه انتخاب‌هایی داشتیم و چطور انتخاب کردیم؟

تا اینجا PRTG رو داشتیم که در کنار Detectors می‌تونست داده‌های مورد نیاز رو تا حد خوبی جمع‌آوری کنه و با ELK می‌تونستیم فایل‌های Log رو یک‌جا ببینیم. مشکل داشبورد هنوز به قوت خودش باقی بود و اینکه دو ابزار مختلف داشتیم خیلی رضایت‌بخش نبود. آشکارساز مجهز به ماژول‌های Redis و Kafka بود ولی چیزی برای MongoDB نداشت.

در این شرایط می‌تونستیم:

  • آشکارساز رو توسعه بدیم و امکانات مورد نظرمون رو بهش اضافه کنیم (و با همین امکانات PRTG برای دیداری‌سازی و کار با دو ابزار کنار بیایم)
  • از Ops Manager برای MongoDB استفاده کنیم (و یه ابزار دیگه به ابزارهامون اضافه کنیم)
  • از Metricbeat استفاده کنیم و کل راه‌کار رو به سمت الستیک ببریم
  • دنبال یک راه‌کار جایگزین برای کل ابزارها بگردیم

اضافه شدن ابزار یا جایگزینی کل راه‌کار انقدری بد بود که بی‌خیال گزینه ۲ و ۴ بشیم. گزینه‌ی ۱ هم اگرچه کم‌هزینه‌ترین راه بود، اما بعضی از مشکلات‌مون رو حل نمی‌کرد. پس سراغ گزینه ۳ رفتیم! چون:

  • همه‌ی اطلاعات مورد نیاز رو یک جا می‌تونیم جمع کنیم؛ چه Log، چه شاخص‌های عملکردی و...
  • به لطف Elastic search امکان جستجوی فوق العاده‌ای داره
  • به کمک Kibana می‌تونیم انواع نمودارها و داشبوردها رو به سادگی تعریف کنیم
  • امکاناتی مثل هشداردهی (Alerting)، گزارش‌گیری منظم، یادگیری ماشین و... داره (که دور از ذهن نبود بهشون نیاز پیدا کنیم)
  • کل مجموعه متن بازه و توسعه‌پذیری بالایی داره (Highly extensible)
  • و....

البته باید اعتراف کنم که نمی‌شه نقش «شهوت تکنولوژی» و «مد بودن» رو در این انتخاب نادیده گرفت. اگر سرزنش‌مون کردین فکر کنم لازمه با Elastic Stack آشنا بشین؛ ولی مراقب باشین دستتون رو نبرین ؛)

چطور از الستیک استفاده کردیم؟

ما کار عجیبی نمی‌خواستیم بکنیم و تا وقتی عکس هست، کی حال داره نوشته بخونه؟!

پیکره‌بندی متداول برای استفاده از Beatها در کنار ELK (عکس از Elastic.co)
پیکره‌بندی متداول برای استفاده از Beatها در کنار ELK (عکس از Elastic.co)

یکم دقیق‌تر بخوام توضیح بدم:

  • روی همه‌ی سرورها Filebeat نصب کردیم (چون همه جا Log هست!)
  • روی همه‌ی سرورها Metricbeat نصب کردیم چون حداقل سنجه‌های مرتبط با ماشین رو باید گردآوری می‌کردیم. ماژول‌های دیگه (مثل کافکا، ردیس و...) بر اساس کاربری اون ماشین فعال می‌شد. به این هم توجه داشتیم که بیشتر سنجه‌ها مربوط به کل Cluster هستن و به همین خاطر کافیه فقط یکی از ماشین‌ها این داده‌ها رو گزارش بکنه.
  • برای یکی از پروژه‌ها نیاز داشتیم ترافیک سرور رو رصد کنیم که از Packetbeat استفاده کردیم
  • خروجی Filebeat به Logstash می‌رفت و بعد از تجزیه و اصلاحات به سمت Elasticsearch روانه می‌شد
  • خروجی‌های دیگر Beatها (یا به قول حامد «ابیات»!) به صورت مستقیم به الستیک‌سرچ فرستاده می‌شد.
  • چون هنوز به نتیجه مطمئن نبودیم، نمی‌خواستیم خرج روی دست شرکت بگذاریم برای خرید جواز الستیک. پس برای هشداردهی از یه راه‌حل متن‌باز استفاده کردیم به اسم ElastAlert.
  • تو رودربایستی با حامد مجبور بودیم یه جایی Detectors رو استفاده کنیم! پس با تمام قوا فکر کردیم و دیدیم که بله، کارهایی هست که جزء تعریف Metricbeat نیست و میشه از آشکارسازها کمک گرفت. مواردی مثل بررسی طول یه صف در ردیس، نقطه شروع (Offset) کافکا و... . فقط لازم بود در زمان‌های مشخص، APIهای مورد نظر فراخوانی بشه و افزونه‌ی HTTP poller برامون این کار رو انجام می‌داد.

هووف! به نظر میاد وقت شادی پس از گل باشه، نه؟ اما من یکم از اصغر فرهادی ایده گرفتم و چیزهایی که خودمون زودتر فهمیده بودیم رو بهتون نگفتم که بتونم تا اینجا بیارمتون و بگم: متأسفانه اینطور که فکر می‌کنین نیست!

در مراحل بررسی گزینه‌ها متوجه شده بودیم که ماژول‌های Redis و MongoDB از متریک‌بیت همه‌ی سنجه‌های مورد نظر ما رو گردآوری نمی‌کنن. لعنت به ‌متن‌باز، گنو و هر چی بهش مربوطه!!

اما ما اینطوری بهش فکر نکردیم و با خودمون گفتیم:

مردم از کاشتن زیان نبرند؛
دگران کاشتند و ما خوردیم،
ما بکاریم و دیگران بخورند.

پس آستین‌هامون رو بالا زدیم، محیط توسعه رو آماده کردیم، چیزهایی که لازم داشتیم رو نوشتیم و بهشون PR دادیم (۷۶۹۵،‌ ۷۶۱۳، ۷۶۱۱، ۷۶۰۴)؛ حالا توی نسخه‌ی ۶.۵ اغلب این تغییرات منتشر شده.


سخن آخر: فوت کوزه‌گری

در مسیر استفاده از این تکنولوژی، نکته‌های کوچکی فهمیدیم که زندگی رو برامون شیرین‌تر می‌کرد. اولی‌ش استفاده از قابلیت اضافه کردن field به Beatها برای دسترسی بهتر به داده‌ها بود. و به طور عمومی از این فیلدها استفاده کردیم:

  • مقر (site): چون در چند موقعیت مختلف سرور داشتیم
  • پروژه (project): برای تفکیک پروژه‌ها
  • محیط (environment): برای جدا کردن داده‌های محیط‌های مختلف (test، production و...)
  • قالب (format): برای انتخاب روش تجزیه (parse) در Logstash خیلی راحت‌تره که توی مبدأ قالب داده رو مشخص کنیم.

تجربه دوم این بود که باید بر اساس بسامد تولید داده و حجم داده‌ها، قالب indexها رو مشخص کنیم. برای نمونه حجم داده‌هایی که توسط پکت‌بیت در یه روز تولید می‌شد، حدود ۵-۱۰ گیگابایت بود ولی حجم لاگ‌های گردآوری شده تو یه هفته به سختی به همین رقم می‌رسید!

درس سوم این بود که وقتی نگاشت (mapping) برای یه نمایه (index) ایجاد بشه، دیگه به این راحتی نمی‌شه اصلاحش کرد. به همین خاطر برای تست تجزیه با grok یا خروجی ماژول جدید، از یه نمایه مجزا برای عیب‌یابی استفاده می‌کردیم (و برای سهولت در شناسایی بهش پسوند debug می‌دادیم).


این داستان ادامه دارد

در این نوشته، بیشتر به انتخاب ابزار برای گردآوری، تحلیل، دیداری‌سازی و هشداردهی پرداختیم. اما هنوز سؤالاتی مثل این که «چه اطلاعاتی باید جمع کنیم؟»، «چطور از ElastAlert استفاده کردیم؟» و... بی‌جواب مونده. اگر عمری بود در قسمت‌های بعدی در مورد این چیزها می‌نویسم. تا اون موقع، می‌تونین نگاهی به «راهنمای کامل برای ELK» و «راه‌اندازی کلاستر عملیاتی Elasticsearch با رنچر» بندازین.