پایگاه داده سری زمانی (TSDB) در Prometheus 2 یک نمونه عالی از یک راه حل مهندسی است که پیشرفت های عمده ای را نسبت به ذخیره سازی v2 در Prometheus 1 از نظر سرعت انباشت داده، اجرای پرس و جو و کارایی منابع ارائه می دهد. ما پرومته 2 را در مانیتورینگ و مدیریت Percona (PMM) پیادهسازی میکردیم و من این فرصت را داشتم که عملکرد Prometheus 2 TSDB را درک کنم. در این مقاله در مورد نتایج این مشاهدات صحبت خواهم کرد.
متوسط بار کاری پرومتئوس
برای کسانی که با پایگاه های داده با هدف عمومی سروکار دارند، حجم کاری معمولی Prometheus بسیار جالب است. نرخ انباشت دادهها ثابت است: معمولاً سرویسهایی که نظارت میکنید تقریباً همان تعداد معیارها را ارسال میکنند و زیرساخت نسبتاً آهسته تغییر میکند.
درخواست اطلاعات ممکن است از منابع مختلف باشد. برخی از آنها مانند هشدارها نیز برای یک ارزش پایدار و قابل پیش بینی تلاش می کنند. سایر موارد، مانند درخواستهای کاربر، ممکن است باعث انفجار شوند، اگرچه این مورد برای اکثر بارهای کاری صادق نیست.
تست بار
در طول آزمایش، من روی توانایی جمع آوری داده ها تمرکز کردم. من Prometheus 2.3.2 کامپایل شده با Go 1.10.1 (به عنوان بخشی از PMM 1.14) را در سرویس Linode با استفاده از این اسکریپت مستقر کردم:
همه آزمایشهای زیر بر روی یک سرور Linode با هشت هسته مجازی و 32 گیگابایت حافظه انجام شد و 20 شبیهسازی بار را اجرا کرد و دویست نمونه MySQL را نظارت کرد. یا به عبارت پرومتئوس، 800 هدف، 440 خراش در ثانیه، 380 هزار رکورد در ثانیه و 1,7 میلیون سری زمانی فعال.
طرح
رویکرد معمول پایگاههای داده سنتی، از جمله مورد استفاده توسط Prometheus 1.x، این است که storage.tsdb.min-block-duration
، که تعیین می کند چه مدت ضبط شده قبل از شستشو روی دیسک در حافظه نگهداری می شود (پیش فرض 2 ساعت است). مقدار حافظه مورد نیاز به تعداد سری های زمانی، برچسب ها و خراش های اضافه شده به جریان خالص ورودی بستگی دارد. از نظر فضای دیسک، Prometheus قصد دارد از 3 بایت در هر رکورد (نمونه) استفاده کند. از سوی دیگر، نیاز به حافظه بسیار بالاتر است.
اگرچه امکان پیکربندی اندازه بلوک وجود دارد، اما توصیه نمی شود آن را به صورت دستی پیکربندی کنید، بنابراین مجبور هستید به اندازه حجم کاری خود به Prometheus حافظه بدهید.
اگر حافظه کافی برای پشتیبانی از جریان معیارهای ورودی وجود نداشته باشد، Prometheus از حافظه خارج می شود یا قاتل OOM به آن می رسد.
افزودن swap برای به تاخیر انداختن خرابی زمانی که حافظه Prometheus تمام می شود واقعا کمکی نمی کند، زیرا استفاده از این عملکرد باعث مصرف انفجاری حافظه می شود. من فکر می کنم این چیزی است که به Go، زباله جمع کن و روشی که با مبادله می پردازد.
یکی دیگر از روشهای جالب این است که به جای شمارش آن از ابتدای فرآیند، بلوک هد را به گونهای پیکربندی کنید که در زمان خاصی روی دیسک ریخته شود.
همانطور که از نمودار می بینید، فلاش به دیسک هر دو ساعت یکبار اتفاق می افتد. اگر پارامتر min-block-duration را به یک ساعت تغییر دهید، این بازنشانیها هر ساعت و بعد از نیم ساعت شروع میشوند.
اگر می خواهید از این نمودار و سایر نمودارها در نصب Prometheus خود استفاده کنید، می توانید از آن استفاده کنید
ما یک بلوک فعال به نام head block داریم که در حافظه ذخیره می شود. بلوکهای با دادههای قدیمیتر از طریق در دسترس هستند mmap()
. این امر نیاز به پیکربندی حافظه پنهان را به طور جداگانه حذف می کند، اما همچنین به این معنی است که اگر می خواهید داده های قدیمی تر از آنچه که بلوک head می تواند در خود جای دهد، باید فضای کافی برای کش سیستم عامل بگذارید.
این همچنین به این معنی است که مصرف حافظه مجازی Prometheus بسیار بالا به نظر می رسد، که جای نگرانی نیست.
یکی دیگر از نکات جالب طراحی، استفاده از WAL (نوشتن پیش ثبت نام) است. همانطور که از اسناد ذخیره سازی می بینید، Prometheus از WAL برای جلوگیری از خرابی استفاده می کند. مکانیسم های خاص برای تضمین بقای داده ها، متأسفانه، به خوبی مستند نشده است. Prometheus نسخه 2.3.2 هر 10 ثانیه یک بار WAL را روی دیسک فلاش می کند و این گزینه توسط کاربر قابل تنظیم نیست.
فشرده سازی ها
Prometheus TSDB مانند یک فروشگاه LSM (Log Structured Merge) طراحی شده است: بلوک هد به صورت دوره ای روی دیسک شسته می شود، در حالی که یک مکانیسم تراکم چندین بلوک را با هم ترکیب می کند تا از اسکن کردن بلوک های بیش از حد در طول پرس و جو جلوگیری کند. در اینجا می توانید تعداد بلوک هایی را که پس از یک روز بارگذاری روی سیستم آزمایش مشاهده کردم، مشاهده کنید.
اگر میخواهید درباره فروشگاه اطلاعات بیشتری کسب کنید، میتوانید فایل meta.json را که اطلاعاتی در مورد بلوکهای موجود و نحوه پیدایش آنها دارد، بررسی کنید.
{
"ulid": "01CPZDPD1D9R019JS87TPV5MPE",
"minTime": 1536472800000,
"maxTime": 1536494400000,
"stats": {
"numSamples": 8292128378,
"numSeries": 1673622,
"numChunks": 69528220
},
"compaction": {
"level": 2,
"sources": [
"01CPYRY9MS465Y5ETM3SXFBV7X",
"01CPYZT0WRJ1JB1P0DP80VY5KJ",
"01CPZ6NR4Q3PDP3E57HEH760XS"
],
"parents": [
{
"ulid": "01CPYRY9MS465Y5ETM3SXFBV7X",
"minTime": 1536472800000,
"maxTime": 1536480000000
},
{
"ulid": "01CPYZT0WRJ1JB1P0DP80VY5KJ",
"minTime": 1536480000000,
"maxTime": 1536487200000
},
{
"ulid": "01CPZ6NR4Q3PDP3E57HEH760XS",
"minTime": 1536487200000,
"maxTime": 1536494400000
}
]
},
"version": 1
}
فشردگی در Prometheus به زمانی که بلوک هد روی دیسک ریخته می شود گره خورده است. در این مرحله، ممکن است چندین عملیات از این دست انجام شود.
به نظر می رسد که فشرده سازی ها به هیچ وجه محدود نمی شوند و می توانند باعث ایجاد اسپایک های بزرگ ورودی/خروجی دیسک در حین اجرا شوند.
بار CPU افزایش می یابد
البته، این تأثیر نسبتاً منفی بر سرعت سیستم دارد، و همچنین یک چالش جدی برای ذخیره سازی LSM ایجاد می کند: چگونه می توان فشرده سازی را انجام داد تا نرخ درخواست بالا را بدون ایجاد سربار زیاد پشتیبانی کند؟
استفاده از حافظه در فرآیند فشرده سازی نیز بسیار جالب به نظر می رسد.
ما میتوانیم ببینیم که چگونه، پس از فشردهسازی، بیشتر حافظهها از Cached به Free تغییر حالت میدهند: این بدان معناست که اطلاعات بالقوه ارزشمند از آنجا حذف شدهاند. کنجکاو است که آیا آن را در اینجا استفاده می شود fadvice()
یا یکی دیگر از روش های کوچک سازی، یا به این دلیل است که حافظه پنهان از بلوک هایی که در طول فشرده سازی از بین رفته اند، آزاد شده است؟
بازیابی پس از شکست
بهبودی از شکست ها زمان می برد و دلیل خوبی هم دارد. برای جریان ورودی یک میلیون رکورد در ثانیه، باید حدود 25 دقیقه صبر می کردم تا بازیابی با در نظر گرفتن درایو SSD انجام شود.
level=info ts=2018-09-13T13:38:14.09650965Z caller=main.go:222 msg="Starting Prometheus" version="(version=2.3.2, branch=v2.3.2, revision=71af5e29e815795e9dd14742ee7725682fa14b7b)"
level=info ts=2018-09-13T13:38:14.096599879Z caller=main.go:223 build_context="(go=go1.10.1, user=Jenkins, date=20180725-08:58:13OURCE)"
level=info ts=2018-09-13T13:38:14.096624109Z caller=main.go:224 host_details="(Linux 4.15.0-32-generic #35-Ubuntu SMP Fri Aug 10 17:58:07 UTC 2018 x86_64 1bee9e9b78cf (none))"
level=info ts=2018-09-13T13:38:14.096641396Z caller=main.go:225 fd_limits="(soft=1048576, hard=1048576)"
level=info ts=2018-09-13T13:38:14.097715256Z caller=web.go:415 component=web msg="Start listening for connections" address=:9090
level=info ts=2018-09-13T13:38:14.097400393Z caller=main.go:533 msg="Starting TSDB ..."
level=info ts=2018-09-13T13:38:14.098718401Z caller=repair.go:39 component=tsdb msg="found healthy block" mint=1536530400000 maxt=1536537600000 ulid=01CQ0FW3ME8Q5W2AN5F9CB7R0R
level=info ts=2018-09-13T13:38:14.100315658Z caller=web.go:467 component=web msg="router prefix" prefix=/prometheus
level=info ts=2018-09-13T13:38:14.101793727Z caller=repair.go:39 component=tsdb msg="found healthy block" mint=1536732000000 maxt=1536753600000 ulid=01CQ78486TNX5QZTBF049PQHSM
level=info ts=2018-09-13T13:38:14.102267346Z caller=repair.go:39 component=tsdb msg="found healthy block" mint=1536537600000 maxt=1536732000000 ulid=01CQ78DE7HSQK0C0F5AZ46YGF0
level=info ts=2018-09-13T13:38:14.102660295Z caller=repair.go:39 component=tsdb msg="found healthy block" mint=1536775200000 maxt=1536782400000 ulid=01CQ7SAT4RM21Y0PT5GNSS146Q
level=info ts=2018-09-13T13:38:14.103075885Z caller=repair.go:39 component=tsdb msg="found healthy block" mint=1536753600000 maxt=1536775200000 ulid=01CQ7SV8WJ3C2W5S3RTAHC2GHB
level=error ts=2018-09-13T14:05:18.208469169Z caller=wal.go:275 component=tsdb msg="WAL corruption detected; truncating" err="unexpected CRC32 checksum d0465484, want 0" file=/opt/prometheus/data/.prom2-data/wal/007357 pos=15504363
level=info ts=2018-09-13T14:05:19.471459777Z caller=main.go:543 msg="TSDB started"
level=info ts=2018-09-13T14:05:19.471604598Z caller=main.go:603 msg="Loading configuration file" filename=/etc/prometheus.yml
level=info ts=2018-09-13T14:05:19.499156711Z caller=main.go:629 msg="Completed loading of configuration file" filename=/etc/prometheus.yml
level=info ts=2018-09-13T14:05:19.499228186Z caller=main.go:502 msg="Server is ready to receive web requests."
مشکل اصلی فرآیند بازیابی مصرف بالای حافظه است. علیرغم این واقعیت که در شرایط عادی سرور می تواند با همان مقدار حافظه به طور پایدار کار کند، اگر از کار بیفتد ممکن است به دلیل OOM بازیابی نشود. تنها راه حلی که پیدا کردم این بود که جمع آوری داده ها را غیرفعال کنم، سرور را بالا بیاورم، بگذارم بازیابی شود و با فعال بودن مجموعه راه اندازی مجدد شود.
گرم شدن
رفتار دیگری که باید در حین گرم کردن به خاطر داشت، رابطه بین عملکرد کم و مصرف بالای منابع بلافاصله پس از شروع است. در برخی از شروع ها، اما نه همه آنها، بار جدی روی CPU و حافظه مشاهده کردم.
شکاف در استفاده از حافظه نشان می دهد که Prometheus نمی تواند تمام مجموعه ها را از ابتدا پیکربندی کند و برخی از اطلاعات از بین می روند.
من دلایل دقیقی برای بار بالای CPU و حافظه پیدا نکردم. من گمان می کنم که این به دلیل ایجاد سری های زمانی جدید در بلوک سر با فرکانس بالا باشد.
افزایش بار CPU
علاوه بر فشردهسازیها، که بار ورودی/خروجی نسبتاً بالایی ایجاد میکند، هر دو دقیقه یک بار متوجه جهشهای جدی در بار CPU شدم. انفجارها زمانی که جریان ورودی زیاد است طولانیتر میشوند و به نظر میرسد که توسط زبالهگیر Go ایجاد میشوند و حداقل برخی از هستهها کاملاً بارگذاری شدهاند.
این پرش ها چندان هم کم نیستند. به نظر میرسد که وقتی این اتفاق میافتد، نقطه ورودی داخلی پرومتئوس و معیارهای اندازهگیری در دسترس نمیشوند و باعث ایجاد شکاف دادهها در همان دورههای زمانی میشوند.
همچنین می توانید متوجه شوید که صادرکننده Prometheus برای یک ثانیه خاموش می شود.
ما می توانیم ارتباط با جمع آوری زباله (GC) را متوجه شویم.
نتیجه
TSDB در Prometheus 2 سریع است و قادر است میلیونها سری زمانی و در عین حال هزاران رکورد در ثانیه را با استفاده از سختافزار نسبتاً متوسط مدیریت کند. استفاده از CPU و I/O دیسک نیز چشمگیر است. مثال من تا 200 متریک در ثانیه در هر هسته استفاده شده را نشان داد.
برای برنامه ریزی توسعه، باید مقدار کافی حافظه را به خاطر بسپارید، و این باید حافظه واقعی باشد. مقدار حافظه استفاده شده ای که مشاهده کردم حدود 5 گیگابایت به ازای هر 100 رکورد در ثانیه جریان ورودی بود که همراه با کش سیستم عامل حدود 000 گیگابایت حافظه اشغال شده را ارائه می دهد.
البته، هنوز کارهای زیادی باید انجام شود تا CPU و اسپایک های ورودی/خروجی دیسک را مهار کنیم، و با توجه به اینکه TSDB Prometheus 2 چقدر جوان در مقایسه با InnoDB، TokuDB، RocksDB، WiredTiger است، تعجب آور نیست، اما همه آنها مشابه بودند. مشکلات در اوایل چرخه زندگی آنها
منبع: www.habr.com