Hadi Varposhti
Hadi Varposhti
خواندن ۷ دقیقه·۲ سال پیش

مدیریت خطاها در لاگ استش

احتمالا با این مشکل برخوردین که وقتی الستیک رو راه انداختین و دارین داده های موردنیازتون رو با کمک لاگ استش داخلش میفرستین اگر سیستمتون خطایی داشته باشه، لاگی که بشه ازش کمک گرفت تا مشکل رو فهمید تقریبا وجود نداره،مگر اینکه برای مثال از داکر استفاده کرده باشین که اونم به خاطر حجم بالای داده های ورودی اضافی که همراه هر ایونت میاد در بهترین حالت واقعا گیج کنندس.

حالا چطور میشه این مشکل رو حل کرد؟ یکی از راه حل هایی که وجود داره استفاده از ((دد لتر کیو)) Dead letter queue که با توجه به امکاناتی که داره حداقل میشه بهش فکر کرد.[از این به بعد به اختصار میگم dlq]

براساس تعریفی که خود وبسایت الستیک درباره dlq میگه :

The dead letter queue (DLQ) is designed as a place to temporarily write events that cannot be processed.
dlq به عنوان مکانی موقتی برای ذخیره ایونت هایی که قابل پردازش نیستن طراحی شده است.

براساس همین تعریف که نیاز ما به dlq مشخص میشه، بیاید تصور کنیم که شما با توجه به نیاز کسب و کارتون لازم دارین تا لاگ های ورودی رو جایی نگه دارین و این لاگ ها بسیار زیادن بطوری که ایونت های ورودی در ساعت بیشتر از چند هزارتاست.

با تصور همین سناریو هم پیدا کردن مشکل تقریبا کار غیر ممکنی به حساب میاد پس لازم که بجای بررسی همه ایونت ها به لاگ استش بگیم که اونهایی رو که قابل پردازش نیستن رو جدا کنه تا حل مسئله راحتتر بشه.

قبل از ادامه دادن باید توضیحی رو راجع به مدل نگه داری داده ها توی الستیک بگم، همونطوری که قبلا گفتم الستیک یک موتور جستجو با معماری no sql به این معنی که ساختار مشخصی مثل پایگاه های داده sql نداره، این یعنی که به ازای داده های ورودی نوع داده رو باید بتونه مدیریت کنه اما اتفاقی که میبفته اینه که الستیک داده های ورودیش رو به دو صورت میتونه نگه میداره.

داینامیک میپینگ ((dynamic mapping)) و یا اکسپلیسیت مپینگ ((explicit mapping))

داینامیک میپنیگ به این معنی که این امکان رو به الستیک میدیم تا خودش براساس هوش مصنوعی که داره شروع کنه به حدس زدن نوع داده فیلد ها و اونها رو ذخیره کنه اما در اکسپلیسیت مپنیگ این ماهستم که مشخص میکنم فیلد های ورودی رو با چه نوع داده ای میخوایم ذخیره کنیم.

تا اینجاشاید به نظر نکته مهمی نباشه اما قضیه از جایی مهم میشه که زمانی که اولین ایونت در داخل یک ایندکس قرار میگیره الستیک نوع داده رو ثابت در نظر میگیره این به این معنی که درصورتی که ایونت بعدی که وارد این ایندکس میشه اگه نوع دادش فرق کنه الستیک به شما کد خطای ۴۰۰ بر میگردونه، به این مفهوم که نوع داده ای برای فیلد مشابهی از قبل وجود داره و این فیلد با نوع داده متفاوت نمیتونه توی همین ایندکس ذخیره بشه.

حالا راه حل چیه: دوتا راه حل وجود داره اول اینکه اسم اون فیلد رو تغییر بدیم که عملا امکان پذیر نیست و یا اینکه اون ایونت رو در داخل همون ایندکس ذخیره نکنیم براش ایندکس جدید بسازیم و یا کلا اون رو در جای جداگونه این ذخیره کنیم تا بعدا براش راه حلی پیدا کنیم.

DLQ چطوری کار میکنه؟

بصورت پیش فرض ایونت ها میان سمت لاگ استش و از طریق اون داخل الستیک ذخیره میشن، در صورتی که این ایونت دارای مشکلی باشه که خطای ۴۰۰ برگردونه مثل موردی که بالاتر اشاره کردم لاگ استش ترجیح میده که کلا از اون ایونت رد بشه و اون رو ذخیره نکنه، که این به معنی از دست دادن دیتاست.

حالا برای جلوگیری از این اتفاق میشه لاگ استش رو طوری تنظیم کرد تا اون ها رو داخل DLQ بنویسه به جای این که کلا اونها رو حذف کنه.

قبل از هرچیزی لازم که تکرار کنم تمام سناریوهای که توضیح میدم در ساختار استک هستن ( الستیک - لاگ استش و کیبانا) که معنی پیدا میکن. همونطوری که توضیح دادم ایونت های ورودی به سمت لاگ استش میان و لاگ استش اونها رو بصورت bulk یا دسته ای به سمت الستیک میفرسته.

باید یاداوری کنم که "لاگ استش تنها کارش انتقال دادست و هیچ تاثیری روی اصل داده نداره " پس وقتی داره داده ها رو ارسال میکنه این الستیک که مشخص میکنه ایا این ایونت درسته یا نه؟

در صورتی که ایونت ورودی خطا داشته باشه این الستیک که ایونت رو رد میکنه نه لاگ استش اما لاگ استش این امکان رو داره تا از این اتفاق جلوگیری که به این صورت که؛ برای لاگ استش باید پایپ لاینی «pipeline» بنویسیم تا این مشکل رو برامون حل کنه.

تنظیمات لاگ استش برای استفاده از DLQ

DLQ بصورت پیش فرض بر روی لاگ استش غیر فعال، برای اینکه اون رو فعالش کنیم باید با کمک فایل لاگ استش «logstash.yml» در مسیر

logstash > config > logstash.yml

و دستور زیر رو داخل اون قرار میدیم

dead_letter_queue.enable: true

DLQ بصورت پیش فرض ایونت هایی که دچار خطا شده باشن رو در داخل مسیر خودش نگه داری میکنه اما اگه شرایط خاصی دارین که لازم این ایونت ها در جای دیگه ای ذخیره بشن میتونین با اضافه کردن دستور زیر مثل قبل مسیر ذخیره این ایونت ها رو هم مشحص کنین.

path.dead_letter_queue: "path/to/data/dead_letter_queue"

نکته دیگه ای که لازم بدونین این که ایونت هایی که دچار خطا شد در ابتدا بصورت موقت داخل یک فایل نگه داری میشن و بعدش با تغییر نام به اسم ایونت ذخیره میشن.

اتفاقی که میفته اینطوری که به ازای هر فایل موقتی که ساخته میشه بازه زمانی طول میکشه تا این فایل پر بشه و فایل بعدی ایجاد بشه که شما میتونین برای این بازه زمانی رو با اضافه کردن دستور زیر مشخص کنین.

dead_letter_queue.flush_interval: 5000

تا این جای کار تنظیمات اصلی رو انجام دادیم، از اینجا به بعد شرایط بسته به نوع پیاده سازی شماست که مشخص میشه مثلا اگر شما استکتون رو با استفاده از داکر بالا اورده باشین پس لازم دارین تا مسیر ذخیره شدن DLQ رو بیرون از داکر هم تعیین کنین تا بتونین فایل های خطا رو از بیرون داکر هم تعین کنین تا بتونین فایل های خطا رو از بیرون داکر بینین و مشکلشون رو حل کنین.

نکته ای که احتمالا براتون کاربردی تر، این که ما تا اینجا این ایونت های خطا رو نگه داشتیم این جا به بعد باهاشون چیکار کنیم؟

برای این شرایط سه راه حل مشخص وجود داره،

  • کلا بیخیال ایونت ها بشیم
  • اون ها رو ویرایش کنیم و دوباره بفرستیم برای ایندکس شدن
  • در نهایت اینکه اون ها رو از طریقی به فرستنده ایونت برگردونیم تااون ایونت هارو درست بکنه و دوباره بفرسته

تکلیف دو راه حل اول که مشخص اما برای راه حل سوم چیکار باید انجام بدیم؟

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

در داخل مسیر لاگ استش حتما متوجه شدین که دوتا پوشه وجود داره که یکی برای قرار گیری فایل تنظمیات لاگ استش، برای مثال تعریف مدل ورودی و دومی برای قرار گیری تنظیمات خود لاگ استش هستش، شما کافیه که داخل پوشه دوم یک فایل pipeline برای خودتون بسازین و تنظیمات زیر رو که ساده ترین مدل هستش داخلش قرار بدین.

input {
dead_letter_queue {
path => "/path/to/data/dead_letter_queue"
commit_offsets => true
pipeline_id => "main"
}
}
output {
stdout {
codec => rubydebug { metadata => true }
}
}

اگر از نوشته های قبلی یادتون باشه این فایل تنظیمات تقریبا مشابه بقیه فایل های لاگ استش که توی پوشه pipeline هستن، هستش با این تفاوت که این بار این فایل رو داخل پوشه config میسازیم.

از طریق این فایل تنظیمات شما میتونین تصمیم بگیرین که برای ایونت های از دست رفته چه کاری درست ترین به حساب میاد.

درنهایت:

اینکه من سعی کردم، تمام اون چیزی که شما برای حفظ داده هاتون در صورت بروز خطای ۴۰۰ در داخل الستیک لازم دارین رو توضیح بدم، اما جزیاتی وجود داره که سعی میکنم اونهارو بعدا تو نوشته ای جدا توضیح بدم، بصورت کلی شما میتونین با جستجو در داخل منابع اصلی اطلاعات تکمیلی رو بدست بیارین.

پی نوشت:

- مثل همیشه لازم میدونم که بگم، اگر جایی پیچیده بود و یا نیاز به اصلاح داشت کافیه برام بنویسین تا حتما اون رو اصلاح کنم.

الستیک سرچ
سعی میکنم چیزی رو بنویسم که نیاز آدما باشه
شاید از این پست‌ها خوشتان بیاید