После прохождения одного из серии собеседований на SRE мне анонсировали, что на следующем будут задачки про SLO/SLI. Задач не было, но в ходе подготовки я сделал тематический конспект нескольких материалов, посвященных этой теме. Возможно, он будет вам полезен.
Понятно, что основной источник информации по теме – это Google SRE Book, но книга была опубликована давно, и мне было интересно, что по этой теме есть нового. В основном конспект основан на четырех материалах от Google: Implementing SLO, Art of SLOs (slides), SLO Document, Setting SLO Step by Step. Впоследствии я дополнил их несколькими интересными идеями из выступления Ивана Круглова.
Буду рад замечаниям и дополнениям.
Для чего SLO?
…Сложно хорошо делать свою работу не определившись с тем, что такое «хорошо». SLOs предоставляют язык для того, чтобы определить «хорошо». (c) Seeking SRE
SLOs служит для оценки качества сервиса с точки зрения его пользователей. Идея в том, чтобы определив SLO, пытаться оставаться немного выше его, используя бюджет ошибок для архитектурных улучшений и реализации новых фич в ПО.
SLOs также используется для того, чтобы приоретизировать инженерную работу. Например, у нас есть две проблемы с надежностью: почти каждую неделю некоторые серверы начинают отдавать 500-ые коды ответа. Каждый раз мы тратим немного времени, чтобы вернуть их в строй. Вторая проблема в том, что очень редко у нас сбоит база данных. Сбой сервера съездает 5% нашего бюджета ошибок, а сбой базы данных – сразу 20%. Но первое случается чаще, и в итоге съедает больше, поэтому серверами следует заняться в первую очередь.
Как определить SLO?
Это почти никогда не будет 100%, поскольку в нашем мире практически нет систем и сервисов, которые требуют такой надежности. Чем больше девяток в SLO, тем сложнее этого достичь.
Сегодня гугл предлагает пользоваться при определении SLO “happiness test”: SLO устанавливается на том уровне, который нечасто случаясь оставляет типичного пользователя сервиса счастливым.
Если речь идет о веб-странице, то можно взять например исследование о пользовательском восприятии скорости ее открытия:
![(c) High Performance Browser Networking by Ilya Grigorik (c) High Performance Browser Networking by Ilya Grigorik](https://webcf.waybackmachine.org/web/20230225213957/https://habrastorage.org/getpro/habr/upload_files/4c3/e88/45f/4c3e8845fd8b81930a4714047612111a.jpeg)
Мы бы конечно хотели, чтобы пользователь никогда не сталкивался со small perception delay, однако ничего страшного, если иногда это будет случаться. При этом нас однозначно не устраивает, когда пользователь переключается на другую задачу или бросает сайт.
В книге была рекомендация не отталкиваться при определении SLOs от своих текущих SLIs. Причина в том, что это может искусственно ограничить в выборе хороших SLOs. Сегодня Google считает, что SLI – неплохое начало. В том числе потому, что если наши пользователи привыкли к высоким показателям доступности, уменьшение этих показателей может уменьшить их счастье, хотя этого не произошло бы, если бы у пользователей не было предшествующего опыта.
Что такое SLI?
Это индикаторы, отражающие фактическую удовлетворенность пользователей нашим сервисом. Показатели те же, что SLO, поскольку мы сравниваем реальность (SLI) с нашими целями (SLO).
Общая формула: SLI = количество хороших событий / количество валидных событий * 100%
В идеале мы должны смотреть на то, что отражает удовлетворенность пользователей. Но на практике найти такие метрики может быть непросто. При выборе надо учитывать signal-to-noice ratio, то есть брать такие метрики, которые коррелируют со счастьем пользователей: если они идут вниз, то и счастье идет вниз.
![(c) Google Art of SLOs Handbook (c) Google Art of SLOs Handbook](https://webcf.waybackmachine.org/web/20230225213957/https://habrastorage.org/getpro/habr/upload_files/b4b/d2c/94d/b4bd2c94d83d37c45a257e35144e8da5.jpg)
«Девятки» имеют в том числе следующий смысл: если мы хотим достичь четырех-пяти девяток, то у людей просто нет физической возможности за необходимое время отреагировать на сбой – значит все это должно выполняться автоматически.
Еще один момент, на который надо обратить внимание – надежность системы находится в зависимости от количества компонентов в ней. При огромном количестве компонентов обеспечить ее практически невозможно.
Интересно, что если SLI будет сильно выше SLO, то у пользователей могут появляться необоснованные ожидания. У Google была такая история с сервисом Chubby. Его отключения происходили настолько редко, что владельцы других сервисов стали обращаться к нему, не учитывая возможности его отключения. В результате для Chubby был выбран SLO, при некотором превышении которого инженеры устраивали искусственный сбой. Вывод – важно учитывать ожидания своих пользователей и в некоторых случаях управлять ими.
Выбор временного окна
Понятно, что рассчитывать SLOs/SLIs можно за разные периоды. Можно использовать календарное окно (например, по месяцам) или rolling window (например, предшествующие 28 дней).
Последний вариант ближе к пользовательскому опыту: ведь если в последний день месяца у нас произошел крупной сбой, пользователи не забывают об этом на следующий день. В случае rolling window рекомендуется выбирать целое число недель для того, чтобы окно всегда содержало равное количество выходных. Если выбрать, скажем, окно в 30 дней, то некоторые периоды будут содержать не 4, а 5 викендов. Если трафик в выходные сильно отличается, SLIs могут сильно варьировать по неинтересным причинам.
Плюсы календарного окна в том, что оно больше соответствует бизнес-планированию и управлению проектами. Скажем можно каждый квартал оценивать достижение своих SLOs для того, чтобы планировать проекты на следующий квартал.
Короткие периоды хороши для быстрого принятия решений. Если не достигнут SLO за прошлую неделю, приоритизируешь исправление багов на следующую и исправляешь ситуацию. Более долгие периоды хороши для стратегического планирования. Если у тебя три крупных проекта, оценка показателей за квартал/полгода позволят правильно расставить приоритеты.
Google рекомендует начинать с четырехнедельного rolling window. У них он используется для приоритизации задач, а обобщенные отчеты за квартал – для проектного планирования.
Способы измерения SLIs?
Существует пять способов каждый со своими достоинствами и недостатками. В целом есть принцип, что чем ближе к пользователю, тем лучше, поскольку наша задача измерить реальный пользовательский опыт.
В порядке отдаленности от пользователей:
Logs Processing – можно смотреть ретроспективно (включая воссоздание сессии пользователя), но не содержит информации о запросах, которые не достигли сервера и требуют больших усилий для обработки
Application Server Metrics – можно быстро и легко добавить, но не узнаешь о запросах, которые не достигли приложения, и сложно отследить весь путь пользователя, если у нас stateless приложения
Front-end Infrastracture Metrics – берем с load balancer, скорее всего эти данные уже есть, и это довольно близко к пользователю, однако подходит для не всех SLI (например, не для data processing)
Synthetic Clients (Probers) or Data – надо сделать клиент, который регулярно направляет сфабрикованные запросы; хорошо тем, что позволяет смоделировать весь опыт пользователя и оценить маршрут до endpoint, но усредняет реальный пользовательский опыт и сложно сделать клиент, измеряющий весь возможный опыт
Client Implementation – добавляем в приложение/javascript функцию отслеживания, что дает наиболее точное представление о пользовательском опыте, но зависит в том числе от независящих от нас факторов и пользователи могут быть против отслеживания
Важно понимать, что одни и те же показатели, снятые с разных компонентов, могут очень сильно отличаться. Например, бывает такое, что сервер отвечает очень быстро, а load balancer очень медленно.
В качестве базового способа часто используется как раз Front-end Infrastracture Metrics, но лучше добавить к нему еще несколько в зависимости от сервиса. Например, в Booking.com только мониторинг на стороне пользователя позволил обнаружить проблему с обновлением сертификатов безопасности. На стороне сервера все выглядело хорошо, поскольку соединение обрывалось на уровне TCP и на application-level ничего не было видно.
Какие бывают SLOs/SLIs?
Основные показатели (в процентах):
Availability – сколько валидных запросов успешно обработано
Latency – сколько валидных запросов обработано быстрее выбранного порога
Quality – сколько валидных запросов обработано без ухудшения качества
Correctness – какое количество валидных данных обработано корректно
Freshness – какое количество валидных данных обновилось ранее выбранного порога
Throughput – сколько времени скорость обработки данных быстрее выбранного порога
Coverage – какое количество валидных данных обработано успешно
Completeness – какой процент времени 100% данных обрабатывается нормально
Durability – какова вероятность того, что данные будут храниться долгий период времени
Например, у нас есть сервисы, обеспечивающие мобильную игру. Запросы от мобильного приложения идут на API через REST API. Data store хранит результаты игр. Pipeline на сервере читает из data store и формирует таблицу результатов за сегодня, неделю и все время. Таблица доступна в приложении через API и на публичном HTTP сервере. Как установим SLO и какие SLI будем использовать?
API server – снимаем метрики с load balancer:
Availability – total requests сравниваем с 500-ми, устанавливаем SLO на 97%
Latency – total requests сравниваем с количество ответов, отданных быстрее «достаточно быстро», например, < 400 ms. Тогда SLO: 90% of requests < 400ms, 99% of requests < 850ms
HTTP server – снимаем метрики с load balancer:
Availability – total requests сравниваем с 500-ми, устанавливаем SLO на 99%
Latency – total requests сравниваем с количество ответов, отданных быстрее «достаточно быстро», например, < 200 ms. Тогда SLO: 90% of requests < 200ms, 99% of requests < 1000ms
Pipeline – в основном берем метрики с API server и HTTP:
Freshness – сравниваем общее количество отданных записей с теми, которые отданы «свежими», например, «свежие» это обновленные не более минуты назад; SLO: 90% получают свежие данные, а 99% данные, обновленные в течение последних 10 минут
Correctness – специально с помощью prober записываем данные в таблицу результатов и смотрим, что они записаны корректно, считаем процент корректных; SLO: 99,99999% записанных записей дают корректный выход
Completeness – количество часов из их общего числа, в которые 100% данных нормально обрабатываются в data store; SLO: 99% запусков pipeline обрабатывают 100% данных
Расчет бюджета ошибок
SLI всегда измеряется в процентах, где 0% означает, что ничего не работает, а 100%, что ничего не сломано. SLO – это наша цель в отношении SLI, тогда бюджет ошибок это: 100% - SLO.
Например, если у нас SLO 99,9%, а наш сервис получает 3 миллиона запросов в каждый 4-х недельный период. Тогда наш бюджет 3000 (0,1%) ошибок. Если одна авария ответственна за 1500 ошибок, то она съела 50% бюджета ошибок.
Для чего служит бюджет ошибок?
релиз новых фич
запланированные изменения системы
предсказуемые отказы железа
запланированный downtime
рискованные эксперементы
Используют один бюджет ошибок и разработчики, и инженеры инфраструктуры. Из-за того, что разработчики вынуждены думать о стабильности, достигается баланс между инновациями и надежностью (они сами оценивают риски и контроллируют нововведения).
Бюджет ошибок лишается смысла, если он не поддержан всеми участниками (менеджерами, рабработчиками и SRE), а также если нет политики на случай его превышения. Например, политикой может быть предусмотрено, что в случае превышения разработчики перестают обрабатывать внешние тикеты, сосредотачиваются на bugfixes и не внедряют новые возможности, а SRE перестают производить инфраструктурные нововведения и направляют все усилия на поддержание надежности в текущих условиях.
Подробнее об основных показателях SLI
Availability
Процент количества успешно обработанных реквестов от числа валидных реквестов. Валидными считаются реквесты, которые поданы правильно (правильный url и т.п.). Измеряем например по статус-кодам HTTP и RPC-ответов. В качестве плохих следует рассматриваться только ответы с 500-ми кодами. Очень важно, чтобы веб-сервер был настроен правильно, и отдавал 500-ые коды, когда случается ошибка сервера, но не в других случаях.
Для виртуальных машин availability будет определяться по доли времени, когда они загружены и доступны по ssh.
Иногда требуется сложная логика проверки, тогда можно написать healthchecker, и он будет возвращать статус-код.
Latency
Количество реквестов, обработанных быстрее установленного порога. Здесь много общего с SLO, поскольку нам нужно ориентироваться на пользовательский опыт. В результате может быть установлено даже несколько порогов, поскольку нам волнует в первую очередь та быстрота, которая влияет на восприятие.
Бывают задачи, ставящиеся в очередь. В этом случае нас вообще не волнует успешность их завершения для SLI. Важно будет обновлять SLI, если запрос не успел выполниться в определенный срок.
Измерение latency API с помощью PromQL: sum(rate(http_server_requests_total(app="backend", code!~"5.."}[5m])) / sum(rate(http_server_requests_total{app="backend"}[5m]))
Quality
Это будет процент запросов, который обработан без деградации качества.
В некоторых случаях мы жертвуем качеством ради доступности, латенси или меньшего потребления ресурсов. Тогда компонент, который снижает качество, может помечать запросы, которые прошли через него, что позволяет нам посчитать их.
Durability
Это вероятность того, что мы сможем прочитать все записанные данные спустя заданный промежуток времени. Теоретически это SLO понятно, но не ясно, как ее считать на практике. Есть только несколько идей. Можно попробовать пойти по внешнему списку данных и верифицировать; иначе приходится считать после инцидента. Промежуток времени может быть установлен равным одному году.