Привет, Хабр!

Меня зовут Данил Садриев, и я работаю руководителем одного из платформенных направлений в Тензоре. Наш продукт — Управление Облаком, аналог административных консолей AWS или Azure для сотрудников компании. Управление Облаком предоставляет большое число сервисов: от запуска контейнера до паркинга доменов. А также: хранит логи и статистику, управляет резервным копированием, в общем все, что нужно для полноценной разработки продукта. В этой статье я расскажу о сервисе управления функционалами. Возможно, это пригодится тем, кто готовится к секции интервью по system design, а также будет интересно начинающим product owner'ам, и архитекторам в части метода организации работы с данными.

При создании продукта часто возникают ситуации, когда необходимо на практике проверить гипотезу о том, что новый функционал или внешний вид будут эффективнее/привлекательнее для пользователей. Для задачи сравнения, пользователей необходимо разделить по тому или иному признаку. Иными словами, нужно провести сплит‑тест или А/В тестирование. Сам подход очень близок к клиническим испытаниям эффективности лекарственных препаратов. Истоки A/B‑тестирования при желании можно отнести к библейским временам, найти упоминания у Петрарки, но первым документированным описанием эксперимента на разных группах людей является «Трактат о цинге» Джеймса Линда 1753 года.

Заглавная страница оригинального трактата
Заглавная страница оригинального трактата

Цинга была основной причиной смертей, вызванных заболеванием, среди моряков в XVI-XVIII вв.  Джеймс Линд провел первое в мире клиническое исследование и доказал, что цитрусовые способны предотвратить развитие цинги.

Истории известен ещё один интересный эксперимент, вошедший в книгу британского ученого Роналда Фишера «Планирование экспериментов», изданную в 1935 г. Он описал один из тестов, получивший название «Леди, дегустирующая чай».

Начало главы с описанием эксперимента
Начало главы с описанием эксперимента

Английский чай можно приготовить двумя способами: сначала налить в чашку молоко, а потом чай или наоборот. Фишер организовал эксперимент, в ходе которого леди должна была определить способ приготовления восьми чашек чая, представленных в случайном порядке. В ходе дегустации леди смогла правильно классифицировать все чашки.

В наши дни, определенную известность получил эксперимент Google, иронично названный «50 оттенков синего».

Какой оттенок повысит вероятность перехода по ссылке?
Какой оттенок повысит вероятность перехода по ссылке?

В 2009 году Дуг Боуман, тогда главный дизайнер компании, назвал это одной из причин своего ухода. Компания показывала разные оттенки синего в рекламных рассылках определенному проценту пользователей. Слегка фиолетовый оттенок максимизировал вероятность того, что пользователи нажмут на рекламируемые ссылки, что в конечном счете дало компании Google ощутимый прирост доходов от рекламы.

Данный эпизод показывает постепенное изменение метода принятия решений о внешнем облике продукта от субъективного мнения в сторону численных методов, и на этом вводную часть можно считать законченной.

В целом, задать поведение сервиса или приложения можно несколькими способами. Один из них — это параметры (могут храниться в переменных окружения, ini‑файле, или получаться из базы данных).

Пример параметров одного из сервисов Тензора
Пример параметров одного из сервисов Тензора

Почти любой сервис в облаках Тензора при старте получает наборы данных в виде строк (ключ, значение). Доступ к значению параметра обычно получают вызовом из кода, и дальше, в зависимости от результата, код идет по одной или другой ветке, изменяя поведение сервиса.

Достоинства:

  • Очень удобный, всем понятный и простой способ изменения поведения сервиса;

  • Не требует сетевого вызова;

  • Параметры просты в реализации.

Недостатки:

  • Задание параметров в ini-файле — это простой, но плохо управляемый способ;

  • Большое количество параметров замедляет доступ к их значениям и расходует память сервиса;

  • Трудно отследить, когда параметры перестали использоваться в коде и их следует удалить. Со временем они превращаются в мусор;

  • Чтобы сервис узнал о новых параметрах, его надо перезагрузить или вызвать специальную процедуру применения параметров, когда сервис медленно один за другим завершает свои процессы и поднимает новые. Обе процедуры, если их делать массово для сотен сервисов, очень затратные по ресурсам ЦОД;

  • Параметры очень неудобно делать действующими для конкретного клиента или пользователя;

  • Параметры доступны только на сервисах. Во фронте параметры недоступны.

Иной подход к изменению поведения сервиса — переключатели функционала (feature toggles). Более подробно можно почитать, к примеру, здесь. Отметим лишь плюсы и минусы применительно к сервисам Тензора.

Достоинства:

  • Состояние переключателя можно задавать как для крупных множеств клиентов, так и для конкретного пользователя;

  • Не требуется перезагрузка сервисов;

  • Можно использовать везде — фронт, бэк, мобильные приложения;

  • Использование переключателя можно наблюдать в статистике.

Недостатки:

  • В целом, обращение к состоянию переключателя в некоторых случаях может оказаться существенно дороже обращения к параметру. Переключатели хорошо кэшируются, но могут затребовать сетевое взаимодействие, а оно ненадежно.

  • В силу распределенности наших сервисов изменения состояния переключателей не происходит одновременно в разных частях облака Тензора, а с некоторым лагом.

  • Переключатели сложнее в реализации.

Соответствующий сервис для управления feature toggles в Тензоре называется «Управление функционалами»

Участок пользовательского интерфейса управления функционалами
Участок пользовательского интерфейса управления функционалами

Его основные операции:

  • Ввод в работу нового функционала;

  • Предоставление отчетов: сколько клиентов, каким функционалом пользуется и как давно;

  • Ответ на вопрос — включен или выключен функционал для пользователя.

Состояние переключателей хранится в Postgres, начальный вариант архитектуры предусматривал nginx в качестве кэширующего кластера. Число rps было порядка 300, и с ростом вызовов и количества переключателей Postgres медленнее отдавал ответ:

Статистика по сервису в варианте nginx + postgres
Статистика по сервису в варианте nginx + postgres

Чтобы улучшить ситуацию, добавили Redis, и за счет кэширования нагрузка на сервис снизилась до 100 rps, среднее время ответа также уменьшилось (отметим, что число переключателей при этом возросло кратно):

Статистика по сервису в варианте nginx + redis + postgres
Статистика по сервису в варианте nginx + redis + postgres

Однако, в ходе эксплуатации столкнулись с тем, что nginx при кэшировании создавал очень много файлов, приходилось периодически его сбрасывать (удалять файлы), поэтому от него решили отказаться, но для этого сервис управления функционалами нужно было подготовить к высокой нагрузке.

Пропускную способность сервиса расширили за счет использования в коде корутин, дополнительной таблицы в Postgres и ключа setnx в Redis. Если Redis кластер оказывается пустым, вероятны очереди, поскольку каждый запрос также пойдет на сервис управления функционалами с требованием восстановить в кэше значение запрашиваемого переключателя. Для решения этой проблемы в Postgres создана таблица f_redis, в которой на сервисе мы храним абсолютно тоже самое, что и в Redis. Эта буферная таблица служит предохранителем после обновления Redis. На схеме ниже изображен упрощенный процесс прохождения запроса.

Процесс получения состояния переключателя сервисом
Процесс получения состояния переключателя сервисом

Сейчас среднее количество вызовов к сервису за сутки приближается к 108, при этом время отклика осталось на прежнем уровне, а это значит, что сервис успешно справляется с нагрузками:

Статистика числа вызовов за последние 12 месяцев
Статистика числа вызовов за последние 12 месяцев

Чтобы не перегружать статью, некоторые технические аспекты были опущены, но я с удовольствием отвечу на ваши вопросы в комментариях!

Комментарии (0)