کیفیت سرویس‌دهی؛ چگونه نجوا را بهبود دادیم؟

شاید بسیاری از شما با اصطلاح SLA یا توافقنامه‌ی سطح کیفیت خدمات آشنا باشید، اما این توافقنامه از کجا میاد؟ چه عواملی در اون دخیل هستن و نحوه‌ی محاسبه‌اش به چه صورته؟ در این نوشتار سعی می‌کنیم به سوالاتی از این دست با چندتا مثال عملی جواب بدیم. ضمنا لازم به ذکره که مرجع بسیاری از مطالب این نوشتار کتاب SRE گوگل هست.

سرواژه‌ی SRE مخفف Site Reliability Engineering هست. اگر بخوام به صورت نادقیق بگم SREها کسانی هستند که زیرساخت امن، پایدار و قابل اتکا ارائه می‌دن و وظیفه‌ی ایجاد فرآیندهای اتوماتیک برای کارهای پرتکرار رو دارن.

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

  • من به عنوان مشتری چه انتظاراتی از این سرویس دارم؟
  • در صورت مشاهده‌ی چه رفتاری از این سرویس اعتماد من به اون کاهش پیدا می‌کنه؟
  • من به عنوان مشتری سرویس تا چه حد خرابی/کارکرد ناصحیح سرویس رو می‌تونم تحمل کنم؟

این سوالات و سوالاتی از این دست ما رو به سمت تعریف SLA یا «توافقنامه‌ی سطح کیفیت خدمات» سوق داد. در ادامه با بررسی موردی سرویس نجوا اصطلاحاتی رو توضیح خواهیم داد که به ما در تعریف SLA کمک کردند.

شاخص‌های سرویس، SLI

یک SLI شاخصی از سطح سرویس‌دهی است؛ به عبارت دیگر یک معیار عددی از یک جنبه‌ی خاص سطح سرویس‌دهی است.
ها ای که گفتی یعنی چه؟
ها ای که گفتی یعنی چه؟

بذارید با یک مثال توضیح بدم. فرض کنید شما یک وب‌سرور دارید که به درخواست‌های کاربرها پاسخ میده؛ تاخیر یا latency می‌تونه یک SLI برای سرویس شما باشه. همینطور میشه نسبت خطاهای سرور (5xx) به کل درخواست‌ها رو یه SLI مناسب برای سرویس در نظر گرفت.

در حالت ایده‌آل یه SLI خوب به صورت مستقیم سطح سرویس مورد نظر رو اندازه میگیره ولی ممکنه گاهی معیار گفته شده قابل اندازه‌گیری نباشه. به عنوان مثال ایده‌آل این هست که تأخیر پاسخ از دید کاربر نهایی اندازه‌گیری بشه ولی این کار شدنی نیست؛ پس تأخیر پاسخ‌دهی در سرور به عنوان معیاری از تأخیر کل اندازه‌گیری میشه.

پس ما باید یک سری SLI رو به عنوان معیار کیفیت سرویس نجوا معرفی می‌کردیم؛ پس از بررسی و ارزیابی جنبه‌های مختلف سرویس به SLIهای زیر رسیدیم:

  • در دسترس بودن وب‌سرور (درصد خطای درخواست‌های رسیده به وب‌سرور)
  • تأخیر وب‌سرور
  • تأخیر در ارسال پوش نوتیفیکیشن‌های غیر VIP
  • تأخیر در ارسال پوش نوتیفیکیشن‌های VIP

اما هنوز یک جای کار می‌لنگید؛ چه میزان از در دسترس بودن سرویس، ایده‌آل مشتری‌های ما بود؟ مشتری‌های ما تا چه میزان تأخیر رو می‌تونستن تحمل بکنن؟ ما هنوز نیاز به تعریف مفاهیم بیشتری داشتیم. نیاز داشتیم که معیارهای گفته شده رو به صورت دقیق و عددی تعیین و محدود کنیم. این کار با استفاده از تعریف SLO انجام شد که در ادامه اون رو توضیح می‌دیم.

اهداف سرویس، SLO

یک SLO هدف معینی برای سطح سرویس‌دهی است. به عبارت دیگر مقدار یا بازه‌ای از مقادیر از سطح سرویس‌دهی است که توسط یک SLI اندازه‌گیری می‌شود.

به عبارت دیگه میشه SLO رو به صورت "SLI <= value" یا "lower bound <= SLI <= upper bound" تعریف کرد. برای نمونه، مثال وب‌سرور رو در نظر بگیرید؛ اگر SLI ما میانگین تأخیر درخواست‌ها باشه میشه SLO رو به این صورت تعریف کرد که این میانگین کمتر از ۲۵۰ میلی‌ثانیه باشه.

اما هدف از مشخص کردن SLO چیه؟ هدف اینه که کاربران اون سرویس بدونن که باید چه انتظاری از نحوه‌ی کارکرد اون سرویس داشته باشن. اگر SLO به صورت دقیق و مناسب تعیین بشه می‌تونه مانع از ایجاد انتظارات بیش از حد از سرویس بشه. به عنوان یک مثال جالب از چنین انتظاراتی میشه به سرویس Chubby اشاره کرد. Chubby یک سرویس توزیع‌شده‌ی مدیریت قفل (lock service) هست که توسط گوگل توسعه داده شده و هدفش مدیریت قفل برای منابع مختلف و نگهداری فایل‌هایی مثل تنظیمات سیستم‌های توزیع شده است. به مرور زمان گوگل مشاهده کرد که هر بار که Chubby دچار مشکل میشه سرویس‌های متعددی با اون دچار مشکل میشن! دلیل این اتفاق این بود که Chubby اینقدر به ندرت دچار اشکال می‌شد که همه فرض کرده بودن همیشه بالاست و هیچوقت دچار مشکل نمیشه و به مرور زمان وابستگی به اون زیاد شده بود. اما راه‌حلی که گوگل برای این موضوع داشت جالب بود:

تیم SRE گوگل انتهای هر فصل در صورتی که Chubby در اون فصل دچار مشکل نشده بود عمدا سیستم رو پایین میاوردن (البته نه به اندازه‌ای که SLO نقض بشه) تا مطمئن بشن انتظارات بی‌جا راجع به در دسترس بودن همیشگی سیستم شکل نمی‌گیره. اینطوری کسانی که به Chubby وابسته بودن مجبور می‌شدن فکری به حال این سناریوی بعید ولی محتمل بکنن.

اما ما برای سرویس نجوا چه SLOهایی تعیین کردیم؟ بعد از بررسی عملکرد سیستم به نظر رسید که SLOهای زیر برای این سیستم مناسب باشه:

  • ۹۹.۵٪ درخواست‌های رسیده به سرور بدون خطا پاسخ داده شوند. (غیر 5xx)
  • ۹۵٪ درخواست‌های رسیده به سرور زیر ۱ ثانیه جواب داده شوند.
  • ۹۹٪ نوتیفیکیشن‌های کاربران غیر VIP در کمتر از ۱ ساعت ارسال شوند.
  • ۹۵٪ نوتیفیکیشن‌های کاربران VIP زیر ۵ دقیقه ارسال شوند.

شاید برای شما عجیب به نظر برسه که چرا این SLOها به صورت درصدی تعریف شدن؟ برای مثال چه اشکالی داشت که بگیم «میانگین زمان پاسخ به درخواست‌های رسیده به سرور زیر ۱ ثانیه باشد»؟

اینجاست که باید درباره‌ی نحوه‌ی انتخاب شاخص‌ها کمی توضیح بدیم.

نحوه‌ی انتخاب شاخص‌ها

شاید وقتی که در بادی امر راجع به تأخیر صحبت می‌کنیم نحوه‌ی اندازه‌گیری واضح به نظر برسه: مدت‌زمانی که طول می‌کشه تا یک درخواست جواب داده بشه. اما راجع به سیستمی که در ثانیه چندین درخواست رو پاسخ میده چطور؟ آیا اندازه‌گیری همینقدر واضحه؟ چه معیاری باید انتخاب بشه؟ آیا میانگین تأخیر درخواست‌ها در یک ثانیه خوبه؟ میانگین در یک دقیقه چطور؟

فرض کنید که میانگین تأخیر درخواست‌ها در هر دقیقه SLIای هست که ما اندازه می‌گیریم. فرض کنید وب‌سرور ما دو API فراهم می‌کنه که اولی میانگین تأخیر ۱۰ میلی‌ثانیه و دومی میانگین تأخیر ۵۰۰ میلی‌ثانیه داره. حالا برای راحتی کار فرض کنید که در هر دقیقه تعداد مساوی از دو نوع درخواست به وب‌سرور می‌رسه. پس میانگین تأخیر ما در هر دقیقه ۲۵۵ میلی‌ثانیه خواهد بود. اما آیا این عدد معیار خوبی از کندی سیستم ماست؟ فرض کنید که تمامی درخواست‌ها از وبسایتی میاد که کاربر به صورت مستقیم باهاش کار می‌کنه و صفحه‌ای لود نمیشه مگر اینکه هر دو API مذکور رو فراخوانی کنه. درسته که در این حالت هم میانگین پاسخ ما عملا ۲۵۵ میلی‌ثانیه‌اس ولی لود شدن یک صفحه برای کاربر در بهترین حالت ۵۰۰ میلی‌ثانیه طول خواهد کشید. از طرف دیگه تجربه نشون داده که کاربران سیستم کند رو به سیستمی که واریانس زیادی در زمان پاسخش وجود داره ترجیح میدن؛ پس ما باید دنبال معیاری باشیم که اثر این واریانس رو بهتر در خودش نشون بده.

اینجاست که توصیه میشه به جای میانگین، توزیع آماری SLI مورد توجه قرار بگیره. برای مثال شکل زیر رو که از کتاب SRE گوگل برداشته شده رو مشاهده کنید:

رنگ‌ها به ترتیب از پایین نماینده‌ی ۵۰٪، ۸۵٪، ۹۵٪ و ۹۹٪ از درخواست‌ها هستند.
رنگ‌ها به ترتیب از پایین نماینده‌ی ۵۰٪، ۸۵٪، ۹۵٪ و ۹۹٪ از درخواست‌ها هستند.

محور عمودی میزانی هست که یک درخواست طول کشیده (به میلی‌ثانیه) و محور افقی زمان رو نشون میده. رنگ‌ها هم از پایین به بالا به ترتیب نشون‌دهنده‌ی ۵۰ درصد اول، ۸۵ درصد اول، ۹۵ درصد اول و ۹۹ درصد اول درخواست‌ها از نظر زمان پاسخگویی هستند.

همونطور که می‌بینید گرچه یک درخواست در حالت عادی ممکنه ۵۰ میلی‌ثانیه طول بکشه (توی ۵۰ درصد اول باشه) ولی درخواست‌هایی هستند که تا ۲۰ برابر کندترن!

به این ترتیب با اندازه‌گیری بازه‌های درصدی مختلف می‌تونید شکل توزیع آماری شاخص موردنظرتون رو تخمین بزنید. برای مثال بازه‌ی ۹۹.۹٪ تا ۱۰۰٪ معیار خوبی از بدترین حالت برای شاخص موردنظره.

حالا شاید برای شما واضح شده باشه که چرا هنگام تعریف SLOهای نجوا از عباراتی شبیه به «۹۹.۵٪ درخواست‌های رسیده به سرور بدون خطا پاسخ داده شوند. (غیر 5xx)» استفاده کردیم.

در ادامه مختصرا SLA رو توضیح میدیم و در باقی این نوشتار به توضیح فنی نحوه‌ی اندازه‌گیری این شاخص‌ها می‌پردازیم.

قرارداد سطح سرویس، SLA

قرارداد سطح سرویس یا SLA قراردادی است که به صورت التزامی یا ضمنی با کاربران سرویس منعقد شده و شامل تبعات ارضا و یا عدم ارضای SLOهاست.

این بخش به صورت خاص مربوط به بخش مالی و بیزنسی کسب و کار و سرویس هست. برای مثال ممکنه شما به صورت دقیق با کاربرانتون توافق کنید که اگر سرویس شما بیش از مدت معینی در دسترس نبود بهشون مبلغی رو به عنوان جریمه پرداخت کنید؛ البته SLA همیشه به صورت ضمنی تعریف نمی‌شه. برای مثال ممکنه شما هیچ قراردادی با کاربرانتون برای سرویسی که بهشون میدین امضا نکرده باشین اما سرویس شما اینقدر حیاتی باشه که حتی یک وقفه‌ی کوتاه در عملکرد اون به اعتبار شما صدمه بزنه و یا باعث بشه منبع درآمدی شما دچار مشکل بشه.

اگر به مثال این نوشتار راجع به سرویس نجوا برگردیم می‌بینیم که ما SLOای تحت عبارت «۹۵٪ نوتیفیکیشن‌های کاربران VIP زیر ۵ دقیقه ارسال شوند» تعریف کردیم. اگر این SLO محقق نشه به اعتبار این سرویس لطمه می‌خوره چون کاربری که پول داده و نوتیفیکیشن VIP تعریف کرده انتظار داره که در کوتاه‌ترین زمان ممکن نوتیفیکیشن ارسال بشه.

نحوه‌ی تعریف اهداف سرویس

برای تعریف هر SLO لازمه که گفته بشه چطور اندازه‌گیری شده و تحت چه شرایطی معتبر هست. برای مثال:

  • باید ۹۹٪ از پاسخ درخواست‌های وب‌سرور زیر ۱۰۰ میلی‌ثانیه پاسخ داده شوند (میانگین تمامی سرورها که در بازه‌های ۱ دقیقه‌ای اندازه‌گیری شده است).

تعریف ۱۰۰ درصدی یک هدف معمولا اشتباه و یک کار بی‌معنیه چون باعث میشه افراد از خطا دوری کنن و در نتیجه تعداد دیپلوی‌ها و خلاقیت افراد کاهش پیدا کنه. اینجاست که مفهوم بودجه‌ی خطا یا Error Budget مطرح میشه.

بودجه‌ی خطا معیاری عددی از میزان اجازه داده شده برای هزینه‌کردن از SLO در بازه‌ی معین (روز، هفته یا ماه) است.

فرآیند تعریف بودجه‌ی خطا

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

نحوه‌ی محاسبه‌ی شاخص‌های سرویس

اما ما چطور این متریک‌ها رو اندازه میگیریم؟ با استفاده از پرومتئوس! پرومتئوس یک ابزار رایگان و متن‌باز هست که برای مانیتورینگ و اطلاع‌رسانی (Alerting) استفاده میشه. این ابزار متریک‌ها رو به صورت real-time در یک دیتابیس سری‌زمانی ذخیره میشه و زبان جستجوی نسبتا ساده‌ای داره. برای اطلاعات بیشتر می‌تونید به اینجا مراجعه کنید.

در ادامه به جزئیات محاسبه‌ی یکی از متریک‌ها به صورت نمونه می‌پردازیم.

سرویس نجوا یک اندپوینت برای تیم SRE فراهم کرده که از طریق اون متریک‌های مربوط به تأخیر در ارسال نوتیفیکیشن‌ها رو به صورت هیستوگرام در اختیار ما می‌ذاره. اگر با تایپ متریک‌های پرومتئوس آشنا نیستید اینجا رو مطالعه کنید. اگر بخوام به صورت مختصر هیستوگرام رو تعریف کنم باید بگم:

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

برای مثال در تصویر زیر می‌تونید نتیجه‌ی کوئری روی این متریک رو در سرویس نجوا مشاهده کنید:

نتیجه‌ی جستجو روی هیستوگرام تأخیر در ارسال نوتیفیکیشن‌های نجوا
نتیجه‌ی جستجو روی هیستوگرام تأخیر در ارسال نوتیفیکیشن‌های نجوا

همونطور که از تصویر می‌بینید هر خط یک سری برچسب تحت عنوان "le" داره. یعنی «کوچکتر یا مساوی». به زبان ساده هر خط بیان می‌کنه که در یک زمان خاص، چه تعداد از نوتیفیکیشن‌ها تأخیری کوچکتر یا مساوی یک عدد خاص داشتن. برای مثال:‌ خط سبز رنگ نشون میده که در ۱۱:۳۰ تعداد ۱۵۰ نوتیفیکیشن وجود داشته که تأخیری کوچکتر یا مساوی ۱۰ ثانیه داشتن. واضحه که هرچیزی که کوچکتر یا مساوی ۱۰ باشه کوچکتر یا مساوی ۱۰۰ هم هست پس خط "le: +inf" نمایانگر تمامی نوتیفیکیشن‌هاست.

حالا ما از این متریک چطور برای محاسبه‌ی SLI استفاده می‌کنیم؟ اینجاست که باید کمی با زبان PromQL یا زبان جستجوی پرومتئوس آشنا باشید. برای اطلاعات بیشتر به این صفحه مراجعه کنید.

برای محاسبه‌ی SLI از این متریک ابتدا افزایش هر باکت و افزایش کل رو در بازه‌ی ۳۰ روزه محاسبه می‌کنیم:

- record: najva:notification_delay_bucket:increase30d
  expr: |-
    increase(najva_najva_notification_delay_bucket[30d])
- record: najva:notification_delay_counter:increase30d
  expr: |-
    increase(najva_najva_notification_delay_count[30d])

و سپس نسبت این دو رو به هم حساب می‌کنیم:

- record: najva:non_vip_wait_time_slo:ratio_rate30d
  expr: |-
    (
      sum(
        najva:notification_delay_bucket:increase30d{le=&quot3600.0&quot, queue=&quot1&quot}
      )
      /
      sum(
        najva:notification_delay_counter:increase30d{queue=&quot1&quot}
      )
    ) * 100

عدد ۳۶۰۰ به ثانیه (برابر با ۱ ساعت) و queue=1 بیانگر غیر VIP بودن نوتیفیکیشن هست. عدد نهایی درصد نوتیفیکیشن‌هایی رو نشون میده که کمتر از ۱ ساعت منتظر ارسال بودن.

حالا برای محاسبه‌ی بودجه‌ی خطا کافیه که این مقدار رو از SLO کم کنیم (اگر یادتون نیست SLO برای این متریک برابر با ۹۹٪ تعریف شده بود) یعنی:

najva:non_vip_wait_time_slo:ratio_rate30d - 99

که برای این سرویس در ابتدا نتیجه به صورت زیر شد:

بودجه‌ی خطای نجوا برای نوتیفیکیشن‌های غیر VIP در روزهای اول
بودجه‌ی خطای نجوا برای نوتیفیکیشن‌های غیر VIP در روزهای اول

این نمودار نشون میده که در طول زمان بودجه‌ی خطای سرویس نجوا برای SLOی مورد نظر چقدر هست. یعنی چی؟ به زبان ساده یعنی اینکه چقدر دیگه حق داریم که از این SLO مایه بذاریم! توی نمودار بالا می‌بینید که این مقدار منفی هست. به عبارت دیگه اگر SLOی مورد نظر ۹۹٪ بوده باشه این نشون میده که حوالی ساعت ۲ ظهر در نمودار بالا ۹۹ منهای ۲ درصد از نوتیفیکیشن‌های غیر VIP ما کمتر از ۱ ساعت منتظر ارسال بودن. به عبارت دیگه ۳ درصد از نوتیفیکیشن‌ها زمانی بیش از این مقدار رو در انتظار ارسال سپری کردن.

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

الان که در حال اعمال اصلاحات نهایی روی این نوشتار هستم بودجه‌ی خطای نجوا به شکل زیر در اومده:

بودجه‌ی خطای نجوا برای نوتیفیکیشن‌های غیر VIP هنگام انتشار این نوشتار
بودجه‌ی خطای نجوا برای نوتیفیکیشن‌های غیر VIP هنگام انتشار این نوشتار

و بله! می‌بینید که نه تنها از SLO تخطی نشده بلکه بودجه‌ی خطا روند صعودی داره و دولوپرهای نجوا با خیال آسوده می‌تونن به توسعه‌ی قابلیت‌های جدید بپردازن! و این نتیجه‌ی مانیتورینگ صحیح و آگاهی از وضعیت سیستم هست.

سخن آخر

همانطور که در این نوشتار دیدیم تعریف SLI و SLO برای سرویس اهمیت بالایی داره و باعث شفافیت انتظارات از سرویس میشه. یکی از وظایف ما در تیم SRE یکتانت ایجاد زیرساخت برای تعریف، محاسبه و مانیتورینگ SLOهاست. در صورتی که علاقه‌مندید تا با مسائلی از این دست دست و پنجه نرم کنید خوشحال میشیم سری به صفحه‌ی فرصت‌های شغلی ما بزنید.