ما در Badoo به طور مداوم فناوری های جدید را زیر نظر داریم و ارزیابی می کنیم که آیا آنها را در سیستم خود استفاده کنیم یا نه. ما می خواهیم یکی از این مطالعات را با جامعه به اشتراک بگذاریم. این سیستم به Loki اختصاص داده شده است.
Loki راه حلی برای ذخیره و مشاهده لاگ ها است و این پشته همچنین یک سیستم انعطاف پذیر برای تجزیه و تحلیل آنها و ارسال داده ها به Prometheus ارائه می دهد. در ماه می، به روز رسانی دیگری منتشر شد که به طور فعال توسط سازندگان تبلیغ می شود. ما علاقه مند بودیم که لوکی چه کاری انجام دهد، چه فرصت هایی را فراهم می کند، و تا چه حد می تواند به عنوان جایگزینی برای ELK، پشته ای که اکنون از آن استفاده می کنیم، عمل کند.
لوکی چیه
Grafana Loki مجموعه ای از اجزای یک سیستم ثبت کامل است. بر خلاف سایر سیستمهای مشابه، Loki مبتنی بر این ایده است که فقط ابردادههای گزارش - برچسبها را نمایه میکند (درست مانند Prometheus)، و خود لاگها را در کنار هم در تکههای جداگانه فشرده میکند.
قبل از اینکه به کارهایی که میتوانید با Loki انجام دهید، بپردازم، میخواهم منظور از «ایده فهرستسازی فقط ابرداده» را روشن کنم. بیایید رویکرد Loki و رویکرد نمایهسازی را در راهحلهای سنتی، مانند Elasticsearch، با استفاده از مثال خطی از nginx log مقایسه کنیم:
سیستمهای سنتی کل ردیف را تجزیه میکنند، از جمله فیلدهایی با مقادیر منحصربفرد user_id و item_id، و همه چیز را در فهرستهای بزرگ ذخیره میکنند. مزیت این روش این است که می توانید پرس و جوهای پیچیده را به سرعت اجرا کنید، زیرا تقریباً تمام داده ها در ایندکس هستند. اما شما باید برای این هزینه بپردازید زیرا شاخص بزرگ می شود که به نیازهای حافظه تبدیل می شود. در نتیجه، نمایه متن کامل گزارشها از نظر اندازه با خود لاگها قابل مقایسه است. برای جستجوی سریع از طریق آن، شاخص باید در حافظه بارگذاری شود. و هر چه لاگ بیشتر باشد، شاخص سریعتر افزایش می یابد و حافظه بیشتری مصرف می کند.
رویکرد Loki مستلزم آن است که فقط داده های لازم از رشته استخراج شود که تعداد مقادیر آن کم است. به این ترتیب ما یک نمایه کوچک به دست می آوریم و می توانیم داده ها را با فیلتر کردن آن بر اساس زمان و فیلدهای نمایه شده جستجو کنیم و سپس بقیه را با عبارات منظم یا جستجوهای زیر رشته ای اسکن کنیم. این فرآیند سریعترین به نظر نمیرسد، اما Loki درخواست را به چندین بخش تقسیم میکند و آنها را به صورت موازی اجرا میکند و حجم زیادی از دادهها را در مدت زمان کوتاهی پردازش میکند. تعداد خرده ها و درخواست های موازی در آنها قابل تنظیم است. بنابراین، مقدار دادهای که میتوان در واحد زمان پردازش کرد، بهطور خطی به مقدار منابع ارائهشده بستگی دارد.
این مبادله بین یک شاخص سریع بزرگ و یک شاخص نیروی موازی کوچک به لوکی اجازه می دهد تا هزینه سیستم را کنترل کند. می توان آن را با توجه به نیازهای شما به صورت انعطاف پذیر پیکربندی و گسترش داد.
پشته Loki از سه جزء تشکیل شده است: Promtail، Loki، Grafana. Promtail لاگ ها را جمع آوری می کند، آنها را پردازش می کند و به Loki می فرستد. لوکی آنها را نگه می دارد. و Grafana می تواند داده ها را از Loki درخواست کند و آن را نشان دهد. به طور کلی، Loki را می توان نه تنها برای ذخیره کردن سیاههها و جستجو در آنها استفاده کرد. کل پشته فرصت های خوبی برای پردازش و تجزیه و تحلیل داده های دریافتی با استفاده از روش Prometheus فراهم می کند.
شرح فرآیند نصب را می توان یافت اینجا.
جستجوی گزارش
شما می توانید سیاهههای مربوط را در یک رابط ویژه Grafana — Explorer جستجو کنید. کوئری ها از زبان LogQL استفاده می کنند که بسیار شبیه به PromQL مورد استفاده Prometheus است. در اصل، می توان آن را به عنوان یک grep توزیع شده در نظر گرفت.
رابط جستجو به صورت زیر است:
پرس و جو خود از دو بخش تشکیل شده است: انتخابگر و فیلتر. Selector جستجویی است بر اساس فراداده های نمایه شده (برچسب ها) که به گزارش ها اختصاص داده می شود و فیلتر یک رشته جستجو یا regexp است که رکوردهای تعریف شده توسط انتخابگر را فیلتر می کند. در مثال داده شده: در براکت های فرفری - انتخابگر، همه چیز بعد از - فیلتر.
{image_name="nginx.promtail.test"} |= "index"
به دلیل نحوه کار Loki، نمیتوانید بدون انتخابگر درخواست بدهید، اما برچسبها را میتوان خودسرانه عمومی کرد.
انتخابگر کلید-مقدار مقدار در پرانتزهای فرفری است. شما می توانید انتخابگرها را ترکیب کرده و با استفاده از عملگرهای =، != یا عبارات منظم، شرایط جستجوی مختلف را مشخص کنید:
{instance=~"kafka-[23]",name!="kafka-dev"}
// Найдёт логи с лейблом instance, имеющие значение kafka-2, kafka-3, и исключит dev
فیلتر یک متن یا regexp است که تمام داده های دریافت شده توسط انتخابگر را فیلتر می کند.
امکان دریافت نمودارهای ad-hoc بر اساس داده های دریافتی در حالت متریک وجود دارد. برای مثال، میتوانید فراوانی وقوع را در گزارشهای nginx یک ورودی حاوی رشته فهرست پیدا کنید:
شرح کامل ویژگی ها را می توان در مستندات یافت LogQL.
تجزیه گزارش
چندین راه برای جمع آوری سیاههها وجود دارد:
با کمک Promtail، یک جزء استاندارد پشته برای جمع آوری سیاههها.
از Fluentd یا Fluent Bit استفاده کنید که می تواند داده ها را به Loki ارسال کند. برخلاف Promtail، تقریباً برای هر نوع لاگ تجزیهکنندههای آماده دارند و میتوانند لاگهای چند خطی را نیز مدیریت کنند.
معمولا از Promtail برای تجزیه استفاده می شود. سه کار را انجام می دهد:
منابع داده را پیدا می کند.
برچسب ها را به آنها بچسبانید.
داده ها را برای لوکی ارسال می کند.
در حال حاضر Promtail میتواند گزارشها را از فایلهای محلی و از مجله systemd بخواند. باید روی هر ماشینی که لاگ ها از آن جمع آوری می شوند نصب شود.
ادغام با Kubernetes وجود دارد: Promtail به طور خودکار از طریق Kubernetes REST API وضعیت خوشه را می یابد و گزارش ها را از یک گره، سرویس یا پاد جمع آوری می کند و بلافاصله برچسب هایی را بر اساس ابرداده های Kubernetes (نام پاد، نام فایل و غیره) پست می کند.
همچنین میتوانید برچسبها را بر اساس دادههای گزارش با استفاده از Pipeline آویزان کنید. Pipeline Promtail می تواند از چهار نوع مرحله تشکیل شود. جزئیات بیشتر - در اسناد رسمی، من بلافاصله به برخی از تفاوت های ظریف توجه خواهم کرد.
مراحل تجزیه. این مرحله RegEx و JSON است. در این مرحله داده ها را از لاگ ها در نقشه به اصطلاح استخراج شده استخراج می کنیم. شما می توانید با کپی کردن فیلدهای مورد نیاز در نقشه استخراج شده یا از طریق عبارات منظم (RegEx) از JSON استخراج کنید، جایی که گروه های نامگذاری شده در نقشه استخراج شده "نقشه برداری" می شوند. نقشه استخراجشده یک ذخیرهسازی کلید-مقدار است که کلید نام فیلد است و مقدار مقدار آن از گزارشها است.
مراحل را تبدیل کنید. این مرحله دو گزینه دارد: تبدیل، جایی که قوانین تبدیل را تنظیم می کنیم، و منبع - منبع داده برای تبدیل از نقشه استخراج شده. اگر چنین فیلدی در نقشه استخراج شده وجود نداشته باشد، ایجاد می شود. بنابراین، امکان ایجاد برچسب هایی وجود دارد که بر اساس نقشه استخراج شده نیستند. در این مرحله میتوانیم دادههای موجود در نقشه استخراجشده را با استفاده از یک نقشه نسبتاً قدرتمند دستکاری کنیم قالب گلانگ. علاوه بر این، باید به خاطر داشته باشیم که نقشه استخراج شده در حین تجزیه به طور کامل بارگذاری می شود، که به عنوان مثال، امکان بررسی مقدار موجود در آن را فراهم می کند: "{{if .tag}value tag exists{end}}". الگو از شرایط، حلقهها و برخی توابع رشتهای مانند Replace و Trim پشتیبانی میکند.
مراحل اقدام. در این مرحله می توانید با استخراج شده کاری انجام دهید:
یک برچسب از داده های استخراج شده ایجاد کنید که توسط Loki ایندکس می شود.
زمان رویداد را از گزارش تغییر دهید یا تنظیم کنید.
داده ها (متن ورود به سیستم) را تغییر دهید که به Loki می رود.
معیارها را ایجاد کنید.
مراحل فیلترینگ. مرحله مسابقه، که در آن میتوانیم رکوردهایی را که نیازی به /dev/null ندارند ارسال کنیم یا آنها را برای پردازش بیشتر ارسال کنیم.
با استفاده از مثال پردازش لاگ های معمولی nginx، نشان خواهم داد که چگونه می توانید لاگ ها را با استفاده از Promtail تجزیه کنید.
برای آزمایش، بیایید یک تصویر اصلاح شده nginx jwilder/nginx-proxy:alpine و یک شبح کوچک که می تواند خود را از طریق HTTP به عنوان nginx-proxy جستجو کند. دیمون چندین نقطه پایانی دارد که میتواند پاسخهایی در اندازههای مختلف، با وضعیتهای مختلف HTTP و با تاخیرهای متفاوت به آنها بدهد.
ما گزارشها را از کانتینرهای docker جمعآوری میکنیم که در مسیر /var/lib/docker/containers/ یافت میشوند. / -json.log
در docker-compose.yml ما Promtail را راه اندازی کرده و مسیر پیکربندی را مشخص می کنیم:
مسیر را به گزارشها به promtail.yml اضافه کنید (یک گزینه "docker" در پیکربندی وجود دارد که همین کار را در یک خط انجام میدهد، اما چندان واضح نیست):
scrape_configs:
- job_name: containers
static_configs:
labels:
job: containerlogs
__path__: /var/lib/docker/containers/*/*log # for linux only
وقتی این پیکربندی فعال شود، Loki گزارشها را از همه کانتینرها دریافت میکند. برای جلوگیری از این امر، تنظیمات تست nginx را در docker-compose.yml تغییر میدهیم - ثبت ورود را به فیلد برچسب اضافه کنید:
اگر امکان قرار دادن فیلد برچسب در نقشه استخراج شده وجود داشت، با استفاده از regexp نام تصویر و ظرف را استخراج می کنیم.
- labels:
image_name:
container_name:
ما برچسب ها را اختصاص می دهیم. اگر کلیدهای image_name و container_name در دادههای استخراجشده یافت شوند، مقادیر آنها به برچسبهای مناسب اختصاص داده میشود.
- match:
selector: '{job="docker",container_name="",image_name=""}'
action: drop
ما همه گزارشهایی را که دارای برچسبهای image_name و container_name مجموعه نیستند دور میاندازیم.
برای تمامی لاگ هایی که image_name آنها برابر با nginx.promtail.test است، فیلد log را از سورس log استخراج کرده و با کلید ردیف در نقشه استخراج شده قرار می دهیم.
درخواست_url را تجزیه کنید. با کمک regexp، هدف درخواست را تعیین می کنیم: به استاتیک، به عکس، به API و کلید مربوطه را در نقشه استخراج شده تنظیم می کنیم.
- template:
source: request_type
template: "{{if .photo}}photo{{else if .static_type}}static{{else if .api_request}}api{{else}}other{{end}}"
با استفاده از عملگرهای شرطی در Template، فیلدهای نصب شده را در نقشه استخراج شده بررسی می کنیم و مقادیر مورد نیاز را برای فیلد request_type تنظیم می کنیم: photo، static، API. در صورت عدم موفقیت، موارد دیگر را اختصاص دهید. اکنون request_type حاوی نوع درخواست است.
ما برچسبهای api_request، virtual_host، request_type و status (وضعیت HTTP) را بر اساس آنچه توانستیم در نقشه استخراج شده قرار دهیم، تنظیم کردیم.
- output:
source: nginx_log_row
خروجی را تغییر دهید حالا لاگ تمیز شده nginx از نقشه استخراج شده به Loki می رود.
پس از اجرای پیکربندی بالا، می بینید که هر ورودی بر اساس داده های لاگ برچسب گذاری شده است.
به خاطر داشته باشید که استخراج برچسب هایی با تعداد زیادی مقادیر (کاردینالیته) می تواند به طور قابل توجهی سرعت Loki را کاهش دهد. یعنی نباید در ایندکس مثلا user_id قرار بدید. بیشتر در این مورد در مقاله بخوانیدچگونه برچسبها در Loki میتوانند درخواستهای گزارش را سریعتر و آسانتر کنند". اما این بدان معنا نیست که شما نمی توانید بر اساس user_id بدون فهرست جستجو کنید. هنگام جستجو، استفاده از فیلترها ضروری است (بر اساس داده ها "برداشتن") و ایندکس در اینجا به عنوان شناسه جریان عمل می کند.
تجسم گزارش
Loki می تواند به عنوان منبع داده برای نمودارهای Grafana با استفاده از LogQL عمل کند. ویژگی های زیر پشتیبانی می شوند:
نرخ - تعداد رکورد در ثانیه؛
شمارش در طول زمان - تعداد رکوردها در محدوده داده شده.
همچنین توابع جمع آوری Sum، Avg و غیره وجود دارد. می توانید نمودارهای کاملاً پیچیده بسازید، به عنوان مثال، نموداری از تعداد خطاهای HTTP:
منبع داده پیشفرض Loki کمی عملکرد کمتری نسبت به منبع داده Prometheus دارد (به عنوان مثال، نمیتوانید افسانه را تغییر دهید)، اما Loki میتواند به عنوان منبع نوع Prometheus متصل شود. من مطمئن نیستم که آیا این رفتار مستند است، اما با توجه به پاسخ توسعه دهندگان قضاوت می کنم.چگونه Loki را به عنوان منبع داده Prometheus پیکربندی کنیم؟ · شماره 1222 · grafana/loki"، برای مثال، کاملا قانونی است و Loki کاملاً با PromQL سازگار است.
Loki را به عنوان منبع داده با نوع Prometheus اضافه کنید و URL /loki را اضافه کنید:
و شما می توانید نمودارهایی بسازید، انگار که ما با معیارهای پرومتئوس کار می کنیم:
من فکر می کنم که اختلاف در عملکرد موقتی است و توسعه دهندگان در آینده آن را برطرف خواهند کرد.
معیارهای
Loki امکان استخراج معیارهای عددی را از لاگ ها و ارسال آنها به Prometheus فراهم می کند. به عنوان مثال، گزارش nginx حاوی تعداد بایت در هر پاسخ است، و همچنین، با تغییر خاصی در قالب استاندارد گزارش، زمان بر حسب ثانیه که برای پاسخدهی طول کشید. این داده ها قابل استخراج و ارسال به پرومتئوس هستند.
این گزینه به شما اجازه می دهد تا معیارها را بر اساس داده های نقشه استخراج شده تعریف و به روز کنید. این معیارها به Loki ارسال نمی شوند - آنها در نقطه پایانی Promtail /metrics ظاهر می شوند. پرومتئوس باید برای دریافت داده از این مرحله پیکربندی شود. در مثال بالا، برای request_type="api" متریک هیستوگرام جمع آوری می کنیم. با این نوع معیارها بدست آوردن صدک راحت است. برای استاتیک و عکسها، مجموع بایتها و تعداد ردیفهایی را که بایتهایی دریافت کردهایم جمعآوری میکنیم تا میانگین را محاسبه کنیم.
به این ترتیب می توانید به عنوان مثال، چهار کندترین پرس و جو را پیدا کنید. همچنین می توانید نظارت را برای این معیارها پیکربندی کنید.
مقیاس بندی
Loki می تواند هم در حالت تک باینری و هم در حالت تکه تکه (حالت مقیاس پذیر افقی) باشد. در حالت دوم، میتواند دادهها را در فضای ابری ذخیره کند و تکهها و فهرست بهطور جداگانه ذخیره میشوند. در نسخه 1.5 قابلیت ذخیره سازی در یک مکان پیاده سازی شده است اما هنوز استفاده از آن در تولید توصیه نمی شود.
تکهها را میتوان در فضای ذخیرهسازی سازگار با S3 ذخیره کرد و از پایگاههای دادههای مقیاسپذیر افقی میتوان برای ذخیره ایندکسها استفاده کرد: Cassandra، BigTable یا DynamoDB. سایر بخشهای Loki - توزیعکنندگان (برای نوشتن) و Querier (برای پرسوجوها) - بدون حالت هستند و همچنین به صورت افقی مقیاسبندی میشوند.
برای آزمایش اندازه ایندکس به دست آمده، از ظرف nginx که Pipeline بالا برای آن پیکربندی شده بود، لاگ هایی برداشتم. فایل لاگ شامل 406 خط با حجم کل 624 مگابایت بود. گزارشها در عرض یک ساعت، تقریباً 109 رکورد در ثانیه تولید شدند.
مثالی از دو خط از لاگ:
وقتی توسط ELK ایندکس شد، اندازه ایندکس 30,3 مگابایت بود:
در مورد Loki، این حدود 128 کیلوبایت ایندکس و حدود 3,8 مگابایت داده را به صورت تکهای ارائه داد. شایان ذکر است که لاگ به صورت مصنوعی تولید شده است و دادههای متنوعی را نشان نمیدهد. یک gzip ساده در لاگ اصلی Docker JSON با دادهها، فشردهسازی 95,4٪ را به دست میدهد و با توجه به اینکه فقط لاگ تمیز شده nginx به خود Loki ارسال شده است، فشردهسازی تا 4 مگابایت قابل درک است. تعداد کل مقادیر منحصر به فرد برای برچسب های Loki 35 بود که اندازه کوچک این شاخص را توضیح می دهد. برای ELK، لاگ نیز پاک شد. بنابراین، لوکی داده های اصلی را 96٪ و ELK را 70٪ فشرده کرد.
مصرف حافظه
اگر کل پشته Prometheus و ELK را مقایسه کنیم، آنگاه لوکی چندین برابر کمتر "می خورد". واضح است که مصرف سرویس Go کمتر از سرویس جاوا است و مقایسه اندازه Heap Elasticsearch JVM و حافظه اختصاص داده شده برای Loki نادرست است، اما با این وجود، شایان ذکر است که Loki از حافظه بسیار کمتری استفاده می کند. مزیت CPU آن چندان آشکار نیست، اما وجود دارد.
سرعت
لوکی سریعتر لاگ ها را می بلعد. سرعت به عوامل زیادی بستگی دارد - نوع لاگ ها، چقدر پیچیده آنها را تجزیه می کنیم، شبکه، دیسک و غیره - اما قطعاً از ELK بالاتر است (در آزمایش من - حدود دو برابر). این با این واقعیت توضیح داده می شود که Loki داده های بسیار کمتری را در فهرست قرار می دهد و بر این اساس زمان کمتری را برای نمایه سازی صرف می کند. در این مورد، با سرعت جستجو وضعیت معکوس می شود: Loki به طور قابل توجهی در داده های بزرگتر از چند گیگابایت کاهش می یابد، در حالی که برای ELK، سرعت جستجو به اندازه داده ها بستگی ندارد.
جستجوی گزارش
Loki از نظر قابلیت های جستجوی لاگ به طور قابل توجهی از ELK پایین تر است. Grep با عبارات منظم یک چیز قوی است، اما از پایگاه داده بزرگسالان پایین تر است. فقدان پرس و جوهای محدوده، تجمیع فقط توسط برچسب ها، ناتوانی در جستجوی بدون برچسب - همه اینها ما را در جستجوی اطلاعات مورد علاقه در Loki محدود می کند. این بدان معنا نیست که با استفاده از Loki چیزی پیدا نمیشود، اما جریان کار با لاگها را مشخص میکند، زمانی که شما ابتدا مشکلی را در نمودارهای Prometheus پیدا میکنید و سپس با استفاده از این برچسبها به دنبال آنچه در لاگها افتاده است بگردید.
رابط
اول از همه، زیباست (ببخشید، نتوانستم مقاومت کنم). Grafana رابط کاربری زیبایی دارد، اما Kibana بسیار کاربردی تر است.
جوانب مثبت و منفی لوکی
از نکات مثبت، می توان اشاره کرد که لوکی به ترتیب با Prometheus ادغام می شود، ما معیارها و هشدارهای خارج از جعبه را دریافت می کنیم. برای جمعآوری سیاههها و ذخیره آنها با Kubernetes Pods راحت است، زیرا دارای یک کشف سرویس است که از Prometheus به ارث رسیده است و بهطور خودکار برچسبها را میچسبد.
از معایب - مستندات ضعیف. برخی چیزها، مانند ویژگی ها و قابلیت های Promtail، من فقط در فرآیند مطالعه کد، مزایای منبع باز را کشف کردم. یکی دیگر از معایب، قابلیت تجزیه ضعیف است. به عنوان مثال، Loki نمی تواند گزارش های چند خطی را تجزیه کند. همچنین، معایب شامل این واقعیت است که Loki یک فناوری نسبتاً جوان است (انتشار 1.0 در نوامبر 2019 بود).
نتیجه
Loki یک فناوری 100% جالب است که برای پروژه های کوچک و متوسط مناسب است و به شما این امکان را می دهد تا بسیاری از مشکلات جمع آوری گزارش ها، جستجوی گزارش، نظارت و تجزیه و تحلیل لاگ ها را حل کنید.
ما از Loki در Badoo استفاده نمیکنیم، زیرا ما یک پشته ELK داریم که مناسب ماست و در طول سالها با راهحلهای سفارشی مختلف پر شده است. برای ما، سنگ مانع جستجو در سیاهههای مربوط است. با تقریبا 100 گیگابایت گزارش در روز، برای ما مهم است که بتوانیم همه چیز و کمی بیشتر را پیدا کنیم و آن را به سرعت انجام دهیم. برای ترسیم نمودار و نظارت از راه حل های دیگری که متناسب با نیازهای ما بوده و با یکدیگر ادغام شده اند استفاده می کنیم. پشته Loki مزایای ملموسی دارد، اما بیش از آنچه که داریم به ما نخواهد داد و مزایای آن دقیقاً بیشتر از هزینه مهاجرت نخواهد بود.
و اگرچه پس از تحقیق مشخص شد که ما نمی توانیم از Loki استفاده کنیم، امیدواریم این پست به شما در انتخاب کمک کند.