آشنایی با زبان کوئری زدن در پرومتئوس یا همان PromQL
Prometheus یک زبان پر کاربرد دارد که به عنوان PromQL (زبان کوئری Prometheus) خوانده می شود. کوئری در پرومتئوس به کاربر این امکان را می دهد که داده های سری زمانی را بصورت بلادرنگ انتخاب و جمع آوری کند. نتیجه یک کوئری می تواند به صورت نمودار نشان داده شود یا به صورت داده های جدولی در مرورگر Prometheus مشاهده شود و یا توسط سیستم های خارجی از طریق HTTP API مورد استفاده قرار بگیرد. در این مطلب سعی می کنیم با نحوه ایجاد کوئری در پرومتئوس بیشتر آشنا شویم:
انواع داده ها در زبان پرومتئوس
برای نوشتن کوئری در پرومتئوس ابتدا باید با انواع داده ها آشنا باشید. یک عبارت یا عبارت فرعی می تواند به صورت یکی از چهار مدل زیر ارزیابی شود:
بردار فوری: مجموعهای از سریهای زمانی حاوی یک نمونه واحد برای هر سری زمانی که همه دارای واحد زمانی یکسانی هستند.
بردار محدوده: این نوع داده شامل مجموعه ای از سری های زمانی حاوی محدوده ای از نقاط داده در طول زمان برای هر سری زمانی است.
اسکالر: یک مقدار عددی float ساده است.
رشته: یک مقدار رشته ساده است که در حال حاضر در برنامه استفاده نمی شود.
بسته به هدف شما از استفاده داده ها (مثلاً هنگام ترسیم نمودار در مقابل نمایش خروجی یک عبارت)، فقط برخی از این انواع به عنوان نتیجه یک عبارت مشخص شده مجاز هستند. برای مثال، عبارتی که یک بردار فوری را برمی گرداند، تنها نوعی است که می تواند مستقیماً نمودار شود.
لیترال ها در زبان کوئری پرومتئوس
لیترال های string
رشته های کوئری در پرومتئوس ممکن است به صورت لیترال در کوتیشن، دابل کوتیشن و یا بکتیک ها مشخص شوند.
PromQL از قوانین مشابه زبان Go پیروی می کند. در کوتیشن و دابل کوتیشن، یک بک اسلش دنباله فرار (escape sequence) را آغاز میکند که پس از آن عبارات a، b, f, n, r, یا t قرار می گیرند. کاراکترهای خاص را می توان با استفاده از اکتال (nnn\ ) یا هگزا دسیمال نمایش داد. مانند دنباله زیر:
.v\nnn\xnn\unnnn\Unnnnnnnn
هیچ مدل داده ی گسترده ای در داخل بکتیک ها پردازش نمی شود. در پرومتئوس بر خلاف زبان GO خطوط جدید را در داخل بکتیک ها کنار نمی گذارد. به مثال زیر توجه کنید:
"this is a string"
'these are unescaped: \n \\ \t'
`these are not unescaped: \n ' " \t`
لیترال های float
مقادیر float اسکالر را می توان به صورت اعداد صحیح واقعی یا اعداد float و ممیزی در قالب قطعه کد زیر نوشت: (توجه داشته باشید که اسپیس ها فقط برای خوانایی بکار رفته است و در برنامه می توان این اسپیس ها را حذف نمود).
[-+]?(
[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?
| 0[xX][0-9a-fA-F]+
| [nN][aA][nN]
| [iI][nN][fF]
)
مثال:
23
-2.43
3.4e-9
0x8f
-Inf
NaN
سلکتورهای سری زمانی در زبان کوئری پرومتئوس
سلکتور بردار فوری
سلکتورهای بردار فوری امکان انتخاب مجموعه ای از سری های زمانی و یک مقدار نمونه واحد را در هر تایم استمپ فراهم می کند. در ساده ترین حالت کوئری در پرومتئوس، فقط یک نام متریک تعیین می شود. برای تمامی سری های زمانی که این نام متریک را داشته باشند، نتایج در یک بردار فوری حاوی عناصر، قرار می گیرند.
در مثال زیر، تمام سری های زمانی که نام متریک آن ها http_requests_total است، انتخاب می شوند.
http_requests_total
می توان سری های زمانی را با اضافه کردن لیست تطبیق دهنده های لیبل که با کاما از هم جدا می شوند و درون دو آکولاد ({}) قرار می گیرند، فیلتر کرد.
در مثال زیر فقط سری های زمانی انتخاب می شود که نام متریک آنها http_requests_total باشد و علاوه بر این لیبل job آنها برابر با prometheus و لیبل group آنها برابر با canary باشد.
http_requests_total{job="prometheus",group="canary"}
در پرومتئوس می توان برای اختصاص دادن یک مقدار از عملگرهای تطبیق استفاده کرد. عملگرهای تطبیق شامل موارد زیر هستند:
=: لیبل هایی را انتخاب می کند که دقیقاً برابر با رشته ارائه شده باشند.
!=: لیبل هایی را انتخاب می کند که با رشته ارائه شده برابر نیستند.
=~: لیبل هایی را انتخاب می کند که با رشته ارائه شده مطابقت دارند.
!~: لیبل هایی را انتخاب می کند که با رشته ارائه شده مطابقت ندارند.
برای مثال، دستور http_requests_total سریهای زمانی staging، testing و development را با متد GET انتخاب میکند. به قطعه کد زیر توجه کنید:
http_requests_total{environment=~"staging|testing|development",method!="GET"}
عملگرهای تطبیق که با مقادیر تهی مطابقت دارند، تمام سریهای زمانی را که مجموعه لیبل خاصی ندارند، انتخاب میکنند. ممکن است چندین تطبیق برای نام یک لیبل وجود داشته باشد.
Selector های برداری باید یک نام یا حداقل یک تطبیق برچسب را مشخص کنند که با رشته خالی مطابقت نداشته باشد. بنابراین استفاده از عبارت زیر غیر مجاز است:
{job=~".*"} # Bad!
در مقابل، این عبارات معتبر هستند زیرا هر دو دارای یک سلکتور هستند که با مقادیر لیبل خالی مطابقت ندارد.
{job=~".+"} # Good!
{job=~".*",method="get"} # Good!
تطبیقکنندههای لیبل را میتوان با تطبیق لیبل داخلی __name__ ، با نامهای متریک نیز اعمال کرد. به عنوان مثال، عبارت http_requests_total معادل {__name__=”http_requests_total”} است. همچنین ممکن است از تطبیقهایی غیر از =( !=،،، =~) !~استفاده شود. عبارت زیر تمام متریک هایی که با نام job شروع می شوند را انتخاب می کند:
{__name__=~"job:.*"}
نام متریک نباید با یکی از کلیدواژه های bool, on, ignoring, group_leftو group_right شروع شود. به طور مثال عبارت زیر غیر مجاز است:
on{} # Bad!
یک راه حل برای این محدودیت استفاده از لیبل __name__
است:
{__name__="on"} # Good!
تمام عبارات منظم در Prometheus از سینتکس RE2 استفاده می کنند.
سلکتورهای بردار محدوده (Range Vector Selectors)
Range Vector Selectors یا سلکتور بردار محدوده مانند بردار فوری کار می کنند، با این تفاوت که طیفی از نمونه ها را از لحظه فعلی انتخاب می کند. از نظر سینتکس، یک مدت زمان در براکتهای مربع ([]) در انتهای انتخابگر بردار ( Vector Selectors) اضافه میشود تا مشخص شود که مقادیر زمانی برای هر عنصر بردار محدوده، چقدر به عقب واکشی شوند. در مثال زیر، ما تمام مقادیری را که در 5 دقیقه گذشته در prometheus ثبت کردهایم برای همه تایم استمپ ها انتخاب میکنیم که نام متریک http_requests_total و یک لیبل job روی آن ها تنظیم شده است:
http_requests_total{job="prometheus"}[5m]
مدت زمان (Time Durations)
(Time Durations) یا مدت زمان کوئری در پرومتئوس به صورت یک عدد با واحدهای زیر مشخص می شود:
- ms- میلی ثانیه
- s- ثانیه
- m- دقایق
- h- ساعت ها
- d- روز – با فرض اینکه یک روز همیشه 24 ساعت است
- w- هفته – با فرض اینکه یک هفته همیشه 7d است
- y- سال – با فرض اینکه یک سال همیشه 365d باشد
مدت زمان را می توان با ذکر واحد آن نوشت. واحدها باید از طولانی ترین به کوتاه ترین مرتب شوند. یک واحد معین باید فقط یک بار ظاهر شود. به مثال زیر توجه کنید:
5h
1h30m
5m
10s
اصلاح کننده افست (Offset modifier)
اصلاح کننده offset اجازه می دهد تا تغییر زمان برای بردارهای فوری و یک محدوده خاص در یک کوئری را تغییر دهید.
به عنوان مثال، عبارت زیر مقدار http_requests_total
را در 5 دقیقه گذشته، نسبت به زمان اجرای کوئری فعلی برمی گرداند:
http_requests_total offset 5m
توجه داشته باشید که offset یا اصلاح کننده همیشه به همراه انتخابگر نوشته می شود، یعنی موارد زیر صحیح است:
sum(http_requests_total{method="GET"} offset 5m) // GOOD.
در حالی که استفاده از دستورات زیر کاملا نادرست است:
sum(http_requests_total{method="GET"}) offset 5m // INVALID.
همین امر برای بردارهای محدوده نیز صادق است. دستور http_requests_total نرخ 5 دقیقه ای را که یک هفته قبل داشت برمی گرداند:
rate(http_requests_total[5m] offset 1w)
برای مقایسه با جابجایی های زمانی به جلو یا به عقب، می توان یک افست منفی را مشخص کرد:
rate(http_requests_total[5m] offset -1w)
توجه داشته باشید که این کار اجازه می دهد تا یک کوئری، محدوده زمانی خود را محاسبه کند.
اصلاح کننده ( modifier@)
اصلاح کننده یا modifier@ اجازه می دهد تا زمان ارزیابی را برای بردارهای فوری و محدوده فردی در یک کوئری تغییر دهید. اصلاح کننده با یک کلمه شناور توصیف می شود. به عنوان مثال، عبارت http_requests_totalat مقدار 2021-01-04T07:40:00+00:00 را بر می گرداند:
http_requests_total @ 1609746000
توجه کنید که بعد از اصلاح کننده یا modifier@ یک سلکتور یا انتخابگر می آید:
sum(http_requests_total{method="GET"} @ 1609746000) // GOOD.
و استفاده از آن به صورت زیر نادرست است:
sum(http_requests_total{method="GET"}) @ 1609746000 // INVALID.
اصلاح کننده یا modifier@ تمامی متغیرهای شناور را در محدوده int64 نمایش می دهد. همچنین میتواند همراه با اصلاح کننده offset که نسبت به زمان modifier@ اعمال میشود، استفاده شود. به مثال زیر توجه کنید. این دو مثال مقدار T07:40:00+00:00 را در 2021-01-04 با نرخ 5 دقیقه نمایش می دهند:
# offset after @
http_requests_total @ 1609746000 offset 5m
# offset before @
http_requests_total offset 5m @ 1609746000
علاوه بر این، دو تابع ()start و ()end به عنوان مقادیر ویژه اصلاح کننده استفاده می شوند. برای یک جستجوی محدوده، آن ها به ترتیب به ابتدا و انتهای کوئری محدود می شوند و تا انتهای مراحل اجرایی، یکسان می مانند.
http_requests_total @ start()
rate(http_requests_total[5m] @ end())
ساب کوئری (Subquery) در پرومتئوس
Subquery به شما امکان می دهد یک کوئری فوری را برای یک محدوده و وضوح مشخص اجرا کنید. نتیجه یک ساب کوئری یک بردار محدوده است.
سینتکس آن به صورت زیر است:
<instant_query> '[' <range> ':' [<resolution>] ']' [ @ <float_literal> ] [ offset <duration> ]
استفاده از عبارت <resolution> اختیاری است.
اپراتورها
Prometheus از بسیاری از عملگرهای باینری و تجمیع پشتیبانی می کند.
کارکرد
Prometheus از چندین عملکرد برای کار بر روی داده ها پشتیبانی می کند.
کامنت
PromQL از توضیحات خطی پشتیبانی می کند که با # آغاز می شود. به مثال زیر توجه کنید:
# This is a comment
هنگامی که کوئری ها اجرا می شوند، تایم استمپ به صورت مستقل انتخاب می شود. این امر برای پشتیبانی از مواردی مانند ( sum، avg و غیره) پیش بینی شده است. در این موارد تایم استمپ یکسان نیست و برای هر تابع متفاوت است. بنابراین پرومتئوس باید برای هر تابع مربوطه، تایم استمپ مستقل در نظر بگیرد و این کار را با گرفتن نمونه جدید انجام می دهد.
اجتناب از کوئری های کند و اضافه بار
اگر کوئری در پرومتئوس باید روی حجم بسیار زیادی از داده ها پردازش شود، ترسیم نمودار برای هر کوئری موجب وارد شدن بار زیاد به سرور می شود. بنابراین، هنگام ایجاد یک کوئری بر روی داده های ناشناخته، همیشه تا زمانی که مجموعه نتایج معقول به نظر برسد، شروع به ساخت کوئری در نمای جدولی مرورگر عبارت Prometheus کنید و فقط زمانی که داده های خود را به اندازه کافی فیلتر یا جمع آوری کردید، به حالت نمودار بازگردید.
به خاطر داشته باشید که عباراتی که در چندین سری زمانی جمع می شوند، بار روی سرور ایجاد می کنند، حتی اگر خروجی فقط تعداد کمی سری زمانی باشد. این شبیه به چگونگی جمع کردن تمام مقادیر یک ستون در یک پایگاه داده رابطهای است، حتی اگر مقدار خروجی فقط یک عدد باشد.
از همراهی در مقاله کوئری در پرومتئوس از زمین هاست متشکریم. در صورت وجود هر گونه ابهام یا سوال می توانید از طریق درج کامنت با ما همراه باشید.